ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

The Singleton as a Network Management Pattern
Pages: 1, 2

The Provisioning Server

The provisioning server is implemented as a single class using the Singleton pattern. The main element is a list collection into which GUI orders are placed. In a production system, the server might be implemented as an RMI (or CORBA) endpoint. The implementation here is much simpler but allows for extension. The key element is the use of the Singleton pattern. The server class provides a private constructor and maintains a private static instance of itself.



As we'll see below, the list collection maintained by the provisioning server is synchronized. Given that we can have just one instance of the server class, this means that the list is protected against multiple thread access. In addition, each list entry represents a complete end-user order (i.e., each entry represents an atomic action of the part of the server). Once an entry is created, the client can invoke the appropriate server action. Let's look at these actions.

The server offers four public methods to clients:

  • getInstance()
  • executeCommand()
  • undoCommand()
  • toString()

The getInstance() method returns a reference to the provisioning server Singleton class. The client can use this to call the other public methods, as described below.

The executeCommand() method dispatches an order (formed via the GUI) to the server. This order takes the form of a textual message that includes the operation count, the user ID, and the order details. Orders are appended to an operations list object. The server could store these details in the database (via JDBC) and apply the required updates to the network routers (via SNMP or some other device access technology).

The undoCommand() reverses the most recent order submitted by the associated GUI client. An important part of this is that the orders from the user types are not mixed up. If the enterprise network manager decides to reverse an order, then it's essential that this has no effect on the home office user.

The toString() method returns a string representation of the operations list for a specific user. In this program, we have two possible users: "Home Office User" and "Enterprise User", respectively.

The Java Code

Three Java classes make up the code base in this example:

  • RunPattern.java
  • ServicePortal.java
  • ProvServer.java

RunPattern.java executes the software. It opens with a brief description of the program. Next, two GUI user instances are created (Figures 2 and 4, respectively). The associated users can then interact with their GUIs and update their service provider links as required. A production system would package this differently, perhaps as a web service.

public class RunPattern {
    public static void main(String [] arguments) {

        ServicePortal portal1 = new ServicePortal();
        portal1.createUserView("Home Office User",
        "Service - 56Kbps link");

        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.

	// Call into Prov Server to update portal
    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 void executeCommand(String message) {
        ProvServer.getInstance().executeCommand(
        (++operationCount) + message);
refreshTextDisplay();
    }

    private void undoCommand() {
        Object result =
        ProvServer.getInstance().
        undoCommand(userId);

		if (operationCount > 0)
		operationCount--;
		refreshTextDisplay();
    }
}

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 itself. The latter is crucial in the design, because no client can call the constructor. Assuming there is just a single provisioning server installed in the network, this avoids having more than the required one instance. 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) {
		return "Succeeded";
	}

    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();
    }
}

Conclusion

The Singleton pattern is an excellent candidate for a class that must not be instantiated more than once. As with patterns in general, it offers a simple and elegant solution to the case at hand in this article--a provisioning server. The ease with which the Singleton pattern can be employed helps to free the developer to get to grips with solving the complex application domain issues. This provides a powerful combination of a solid pattern-based foundation and more time than usual to focus on application value add features. It allows for better product differentiation.

I didn't look at any of the middleware code that typically forms part of our service provisioning system. Typically, this code makes use of network device technology, such as SNMP, command-line interface, etc. I'll cover some of these technologies as part of an upcoming article on SNMP (JDMK) and JMX. As usual, I'll make use of some other patterns for this--most notably the GoF (Gang of Four) Adapter pattern. The latter is employed to hide the complexities of technologies such as the ones mentioned.

Patterns provide fertile design-level ground for top-grade software development. By solving significant generic problems, such as single instance control, patterns should become an indispensable tool for all software developers. They allow for rapid solutions to difficult recurring problems.

One aspect of patterns that particularly appeals to me is that their application can cross industry segments. In other words, if a practitioner makes an honest effort to understand and apply a wide range of patterns in their application domain, then there's a good chance that this knowledge is portable to another industry. A patterns-literate developer could (with some additional domain training) move, for example, from programming telecom to finance systems.

Resources

Stephen B. Morris is an independent writer/consultant based in Ireland.


Return to ONJava.com.