The Java Code
Three Java classes make up the code base in this example:
- RunPattern.java
- ServicePortal.java
- ProvServer.java
RunPattern.java
RunPattern.java executes the software. It opens with a brief description of the program. Next, two GUI user instances are created—i.e., Figures 2 and 3, respectively. The associated users can then interact with their GUIs and update their service provider link as required. A production system would package this differently, perhaps as a Web service.
public class RunPattern { public static void main(String [] arguments) { System.out.println(" This program illustrates the use of the Singleton pattern"); System.out.println(" by creating two GUI-based clients. These clients submit"); System.out.println(" operation requests to the single instance of a provisioning"); System.out.println(" server. The latter is implemented as a Singleton. The requests"); System.out.println(" are actioned by the provisioning server. Each client"); System.out.println(" can view the changes it has made to the provisioning server"); System.out.println(" operations list."); System.out.println("Creating the first GUI portal"); System.out.println(); ServicePortal portal1 = new ServicePortal(); portal1.createUserView("Home Office User", "Service - 56Kbps link"); System.out.println("Creating the second GUI portal"); System.out.println(); ServicePortal portal2 = new ServicePortal(); portal2.createUserView("Enterprise User", "Service - 5Mbps link"); } }
ServicePortal.java
The ServicePortal class provides a simple Swing GUI that is coupled to the ProvServer class. The buttons on the GUI provide access to the appropriate methods in the latter.
import java.awt.Container; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JTextArea; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; public class ServicePortal implements ActionListener { private JFrame mainFrame; private JTextArea textDisplay; private JButton updateService, undoButton, exitButton; private JPanel controlPanel, displayPanel; private static int operationCount; private String userId; public void createUserView(String userName, String serviceDescription) { userId = userName; mainFrame = new JFrame("Provisioning Server as Singleton"); Container content = mainFrame.getContentPane(); content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS)); displayPanel = new JPanel(); textDisplay = new JTextArea(20, 60); textDisplay.setEditable(false); textDisplay.setText(userName + ". " + serviceDescription); displayPanel.add(textDisplay); content.add(displayPanel); controlPanel = new JPanel(); updateService = new JButton("Update Profile"); undoButton = new JButton("Undo"); exitButton = new JButton("Exit"); controlPanel.add(updateService); controlPanel.add(undoButton); controlPanel.add(exitButton); content.add(controlPanel); updateService.addActionListener(this); undoButton.addActionListener(this); exitButton.addActionListener(this); mainFrame.addWindowListener(new WindowCloseManager()); mainFrame.pack(); mainFrame.setVisible(true); } public void refreshTextDisplay() { textDisplay.setText("Provisioning Server Command History for " + userId +"\n" + ProvServer.getInstance().toString(userId)); } public void actionPerformed(ActionEvent evt) { Object originator = evt.getSource(); if (originator == updateService) { executeCommand(" " + userId + " Increase bandwidth by 1Mbps"); } else if (originator == undoButton) { undoCommand(); } else if (originator == exitButton) { exitApplication(); } } private class WindowCloseManager extends WindowAdapter { public void windowClosing(WindowEvent evt) { exitApplication(); } } private void executeCommand(String message) { ProvServer.getInstance().executeCommand((++operationCount) + message); refreshTextDisplay(); } private void undoCommand() { Object result = ProvServer.getInstance().undoCommand(userId); if (operationCount > 0) operationCount--; refreshTextDisplay(); } private void exitApplication() { System.exit(0); } }
ProvServer.java
The ProvServer class implements the required provisioning server. As described earlier, it has two private data members: an operations list and an instance of the ProvServer class. Clients access the methods via the getInstance() method.
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ProvServer { private List opList = Collections.synchronizedList(new ArrayList()); private static ProvServer instance = new ProvServer(); private ProvServer() { } public static ProvServer getInstance() { return instance; } public void executeCommand(String command) { opList.add(command + " Operation --> " + updateBackendSystems(command)); } private String updateBackendSystems(String command) { // Call into backend systems, e.g., database, SNMP, CLI, etc. return "Succeeded"; } public Object undoCommand(String userId) { if (opList.isEmpty()) { return opList; } else { for (int i = opList.size() - 1; i >= 0; i--) { if (((String) opList.get(i)).indexOf(userId) != -1) { opList.remove(i); return opList; } } } return opList; } public String toString(String userId) { StringBuffer result = new StringBuffer(); for (int i = 0; i < opList.size(); i++) { if (((String) opList.get(i)).indexOf(userId) != -1) { result.append(" "); result.append(opList.get(i)); result.append("\n"); } } return result.toString(); } }
Notice the getInstance() method; this is used by clients to gain access to services of the Provisioning Server. The combination of the private constructor and the static instance of the class ensure that only one Provisioning Server is created. This single instance is then used as needed throughout the JVM.