Singleton pattern

Today I started to remove the hardcoded strings from my Duke Web Server. My requirement is, there should be only one object instance exists and it should provide the service of retrieving values from LocalStrings.properties. Hence I looked for help from Singleton pattern.

Singleton pattern,

“In software engineering, the singleton pattern is a design pattern that restricts the Instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects. The term comes from the mathematical concept of a singleton.” — from wiki.

Let’s its UML diagram,

Its implementation must satisfy below principles:

1. its constructor is private. In other word, it can not be created outside but just from getInstance() to get its single instance.

2. it should have a private static instance.

Below is an sample from wiki,

public class SingletonDemo {
        private static SingletonDemo instance = null;

        private SingletonDemo() {       }

        public static synchronized SingletonDemo getInstance() {
                if (instance == null) {
                        instance = new SingletonDemo ();
                }
                return instance;
        }
}

Let’s explain it:

1. If anyone wants to use SingletonDemo, he can just invoke SingletonDemo.getInstance() to retrieve its static private SingletonDemo. In this way, it can be ensured that it has only one instance exists anytime.

2. To avoid conflict, use keyword synchronized to obtain its class lock to control its access to static private SingletonDemo.

In Tomcat, it adopts the same pattern to design its StringManager. If you are interested, you can refert to the source code of org.apache.catalina.util.StringManager.

Typically, in each Tomcat package,

it will has its local LocalStrings.properties files

singleton1

In Constants.java, it contains all of the necessary static parameters. It has one parameter as below

public static final String Package = “org.apache.catalina.connector”;

everytime StringManager runs, it will retrieve the LocalStrings and try to retrieve an StringManager instance,

private static Hashtable managers = new Hashtable();

 * Get the StringManager for a particular package. If a manager for
 * a package already exists, it will be reused, else a new
 * StringManager will be created and returned.
 *
 * @param packageName The package name
public synchronized static StringManager getManager(String packageName) {
 StringManager mgr = (StringManager)managers.get(packageName);
if (mgr == null) {
 mgr = new StringManager(packageName);
 managers.put(packageName, mgr);
 }
 return mgr;
 }

Here you can see it uses a hashtable to store those StringManager instances. Actually it is not a strict Singleton. It is ‘Singleton’ for every package only. I think that is easy to understand. As Tomcat has lots of strings and it is very terrible if tomcat has only one StringManager instance. Hence here Tomcat will maintain one StringManager instance for every package.

In my Duke Server, I just copied and simplified it as below,

package com.duke.moyan.util;

import java.util.Hashtable;
 import java.util.MissingResourceException;
 import java.util.ResourceBundle;

public class StringManager {
 private ResourceBundle bundle;

private StringManager(String packageName) {
 String bundleName = packageName + ".LocalStrings";
 try {
 bundle = ResourceBundle.getBundle(bundleName);
 return;
 } catch (MissingResourceException e) {
 System.out.println("Failed to load " + bundleName);
 }
 }

public String getString(String key) {
 String str = null;
 if (bundle == null){
 return key;
 }
 try {
 str = bundle.getString(key);
 } catch (MissingResourceException mre) {
 System.out.println("Cannot find message associated with key '" + key + "'");
 }

return str;
 }

@SuppressWarnings("rawtypes")
 private static Hashtable managers = new Hashtable();

@SuppressWarnings("unchecked")
 public synchronized static StringManager getManager(String packageName) {
 StringManager mgr = (StringManager) managers.get(packageName);

if (mgr == null) {
 mgr = new StringManager(packageName);
 managers.put(packageName, mgr);
 }
 return mgr;
 }
 }

// below is the sample how to use it:

protected static StringManager sm = StringManager.getManager(constants.Package);

sm.getString("HttpResonpse.ERROR_404");

//in LocalString.properties, it has line: HttpResponse.ERROR_404=Oops, File Not Found