Wadjet -Utils 5.3.0

Introduction

Wadjet-Utils is set of utilities intended to be used to solve many of the common pogramming problems that are regularly encountered and to increase your productivity by supplying flexible, usable, well documented and tested solutions as Open Source.

This module contains set of general utilities that is used by many of the other Wadjet modules.

Using Wadjet-Utils

The following sections describe how to use some of the utilities in Wadjet-Utils

Service Location

A lot of the classes in Wadjet-Libs are loaded as services using Service Location. This uses a factory class that extends the abstract AServiceLocator class that supplies the method for creating the service which must implement the IService interface.

The locator obtains the class name from the IServicesConfiguration implementation using a key. The IServicesConfiguration implementation itself contains initially all the default service class names and their keys, any of these can be overridden by changing an entry in the services.conf file. You will only need to add new services or changes to this file as all the defaults are held as constants in the IServicesConfiguration implementation.

To create a new factory and integrate it into the services framework, all you need to is extend the AServiceLocator class, add a property to the services.conf file and use the factory:

import com.addc.util.InitialisationException;
import com.addc.util.locator.AServiceLocator;
import com.addc.util.locator.IServicesConfiguration;

/**
 * The WhatsitServiceFactory class supplies a Factory for the Watsit Service.
 * 
 */
public final class WhatsitServiceFactory extends AServiceLocator {

    private static final String WHATSIT_KEY = "whatsit-service";
    private static IWhatsitService s_service = null;

    /**
     * Create or get the singleton. If the singleton already exists it is
     * returned unchanged.
     * 
     * @return the singleton Whatsit service instance.
     */
    public static IWatsit getWhatsitService() {
        if (s_service == null) {
            WhatsitServiceFactory factory = new WhatsitServiceFactory();
            s_service = (IWhatsitService) factory.locateService(WHATSIT_KEY);
            try {
                s_service.initialise();
            } catch (InitialisationException e) {
                throw new RuntimeException("Failed to initialise Watsit Service", e);
            }
        }
        return s_service;
    }

    /**
     * Sets the singleton to null allowing you to change to a new destination by
     * calling one of the creator methods.
     */
    public static void reset() {
        s_service = null;
    }

    /**
     * Cannot create a new AlarmingServiceFactory
     */
    private WhatsitServiceFactory() {
        super();
    }

}

NOTE The locator should also invoke the initialise() method on the newly created object.

The Service interface would look something like:

import com.addc.util.locator.IService;

/**
 * The IWhatsitService interface bla bla bla
 */
public interface IWhatsitService extends IService {
    /**
     * Get a string description of the object.
     * 
     * @param thingummy
     *            the Object to get a description for.
     * @return a string description of the thingummy.
     */
    String whatisIt(Object thingummy);

}

The services.conf file would then need an entry looking like this:

    whatsit-service=com.mycompany.some.package.name.WhatsitImpl

Which contains the implementation class to create when the service is located.


Back to top

Properties Service

The IServiceProperties implementation is widely used throughout Wadjet Libraries , it supplies a loader for properties from a file anywhere on the class path.

As a service, the IServiceProperties implementation is obtained using a locator:

    IServiceProperties props = ServicePropertiesFactory.getServiceProperties();

Properties are obtained from the service by prepending the file name to the property name you are seeking. The first time a property is requested, the service will try to load the file, first as a .conf file, then as a .properties file and finally as a .xml file. Thus, if you request MyProduct.some.property , this will look for files named MyProduct.conf , MyProduct.properties or MyProduct.xml on the class path or as a resource and return the property named some.property found in that file.

Once a file has been loaded, the properties are kept in memory.

The service expects the files to conform to the Java Properties convention whether they are text files (.conf and .properties ) or xml files .xml .

From file MyProduct.conf:

    query.name=GobbleDeGook
    db.user=fred

This call will return GobbleDeGook :

    String name = props.getProperty("MyProduct.query.name");

This will return not here :

    String name = props.getProperty("MyProduct.db.location", "not there");

WARNING If the service cannot find a property and you do not use the method that supplies a default, it will throw a RuntimeException . This is designed so that missing required properties for a process will crash the program.

These call will throw a RuntimeException :

    String name = props.getProperty("MyProduct.db.location");
    String name = props.getProperty("query.name");

NOTE Both the file prefix and the property name are case sensitive.


Back to top

Shutdown Hooks

Java supplies a shutdown hook which you can add threads to but this method has always seemed to be a little off the cuff as you don't really have much control over what happens when.

Wadjet-Utils supplies an interface IShutdownHook and a shutdown manager the ShutdownHookThread. Many of the classes in the wadjet-Libs package implement the IShutdownHook interface to make sure that resources are properly released and that they will always clean up correctly.

The ShutdownHookThread supplies a singleton thread that will be run in the Java shutdown processing and which keeps an ordered list of IShutdownHook implementation objects that will have their atexit() method invoked during system exit. This allows you to program clean-up for your classes.

An example class:

    public class MsgConnectionFactory extends AbstractJmsMBean implements IShutdownHook {
        ...
        ...
        /**
         * Destroy the instance closing all connections and destroying all children.
         * This is called on exit as a shutdoen hook.
         */
        public void destroy() {
            if (!m_destroyed) {
                Map<String, MsgConnection> factories = new HashMap<String, MsgConnection>();
                factories.putAll(m_factoriesMap);
                for (Iterator<Map.Entry<String, MsgConnection>> iter = 
                                factories.entrySet().iterator(); iter.hasNext();) {
                    MsgConnection cf = (MsgConnection) iter.next().getValue();
                    cf.destroy();
                }
                m_factoriesMap.clear();
                MessagingServiceFactory.getMessengingService().removeJmsFactory(this.m_id);
                if (m_server != null) {
                    try {
                        m_server.unregisterMBean(this.getObjectName());
                    } catch (Exception e) {
                        m_logger.info(e);
                    }
                }
                ShutdownHookThread.getInstance().removeHook(this);
                m_destroyed = true;
            }
        }
    
        /**
         * On exit destroy all the JMS components cleanly.
         * @see com.addc.util.shutdown.IShutdownHook#atexit()
         */
        public void atexit() {
            destroy();
        }
    
        /**
         * @see com.addc.messaging.jms.AbstractJmsMBean#initialise()
         */
        public void initialise() throws MessagingException {
            super.initialise();
            registerJmsComponent(this, 
                "JMS:type=MsgConnectionFactory,name=" + m_id + ",clid=" + getClientId());
            ShutdownHookThread.getInstance().addHook(this);
        }
        ...
        ...    
    }

As you can see, the class above has a destry method that ensures that sessions and connections get closed cleanly and this is invoked from the atexit() method. In the initialise method you can see

    ShutdownHookThread.getInstance().addHook(this);

The first time this call is made it will create the ShutdownHookThread and register it with the Java VM.


Back to top

Queues and Fifos

Although Java 1.5 supplies queueing classes, the functionality is missing a timeout in the get methods. There is also no way of triggering events as a queue or fifo fills up or empties. There is also no supplied way of locating a queue that is created by another object.

There are 2 types of queue supplied, a simple Fifo and a FifoWithThresholds . Both these classes allow you to set the maximum depth the fifo may have; if you put an object on the fifo when it is full, QueueDepthExceedeException is thrown, this can be used to supply a certain amount of throttling to the application:

    private Fifo m_fifo;
    ...
    ...
    void sendMessage(MyObject msg) {
        try {
            m_fifo.put(msg);
        } catch(QueueDepthExceedeException e) {
            m_logger.warn("Fifo is full");
            boolean sent = false;
            while(!sent) {
                try {
                    m_fifo.put(msg);
                    sent = true;
                } catch(QueueDepthExceedeException e) {
                }
            }
        }
    }

The FifoWithThresholds implementation, sets up 3 thresholds for the fifo, 1/3 full, 2/3 full and full. as each of these thresholds is crossed, any listeners are notified with a ThresholdEvent informing them whether the fifo is filling or emptying. This can be used to tune the priority of a reader thread:

    public class ReaderThread extends Thread implements IThresholdListener {
    
        private FifoWithThresholds m_fifo;
        ...
        ...
        public void run() {
            m_fifo.addListener(this); // Register with the fifo to receive events
            ...
            ...
        }
        
        pubic void void threshholdPassed(ThresholdEvent event) {
            if (event == ThresholdEvent.FILLING) {
                this.setPriority(this.getPriority() + 1);
            } else {
                this.setPriority(this.getPriority() - 1);
            }
        }
        ...
        ...
    } 

Discovering a Fifo can be accomplished using the NamedFifoFactory which stores Fifo and FifoWithThresholds objects in an internal map keyed by a unique name. The first time a queue is requested from the factory it will be created, thereafter it will obtained from the map until it is released.

    FifoWithThreaholds tfifo = NamedFifoFactor.getFifoWithThresholds("A-Fifo-Name");

    Fifo fifo = NamedFifoFactor.getFifo("B-Fifo-Name");
    

NOTE Both types are kept in the same map, so making the wrong call raise a ClasscastException .


Back to top

Dynamic Object Pools

The Dynamic Pool service allows you to create pools of objects or threads (see the Wadjet-HTTP package). Pools have a minimum number of objects that must be kept ready in the pool, and a maximum number of object allowed in pool. As objects are requested they are either recovered from the pool or created until there are the maximum allowed. At this point any request for a pooled object will raise a PoolEmptyException .

Pooled objects must implement the IPooledObject interface and have a simple empty constructor.

Each pool has a unique name which is used by the pool to extract its initialisation information from an IServicesproperties file named DynamicPool . This file will contain properties starting with the pool name, these are

Key Description Default value
poolName.type The IPoolObject implementation class for the pool None
poolName.maxObject The maximum number of objects in the pool 10
poolName.minObject The minimum number of objects in the pool 2

For example, the DynamicPool conf for the HTTPD is :

    RequestProcessor.type=com.addc.httpd.impl.HttpClientThread
    RequestProcessor.maxObjects=5
    RequestProcessor.minObjects=2

The daemon server thread initialises the pool like this:

    public ServerThread(ThreadGroup group, 
                        IHttpd server, 
                        ServerSocket sock) throws DynamicPoolException {
        super(group, "Httpd-" + server.getPort());
        m_server = server;
        m_sock = sock;
        m_threadPool = DynamicPoolFactory.getDynamicPool("RequestProcessor");
        m_logger = Logger.getLogger(getClass());
    }

and gets threads from the pool like this:

    m_logger.debug("Waiting for connection...");
    Socket client = m_sock.accept();
    if (!m_shutdown) {
        m_reqCount++;
        String host = client.getInetAddress().getCanonicalHostName();
        if (m_logger.isDebugEnabled()) {
            m_logger.debug("Received connection from " + host);
        }
        if (!m_shutdown) {
            HttpClientThread clthr = (HttpClientThread) m_threadPool.getPooledObject();
            if (!clthr.isInitialised()) {
                Map<String, Object> iniData = new HashMap<String, Object>();
                iniData.put("server", m_server);
                iniData.put("sock", client);
                iniData.put("host", host);
                clthr.initialise(iniData);
                clthr.start();
            } else {
                clthr.trigger(client, host);
            }
        }
    }

Back to top

File Resolver Service

The File Resolver Service can be used to get the URL or open a stream using just the file name.

The file is first treated as a URL, if this fails the FileResolver optionally tries to open it as a resource of the calling object. If that fails it is searched for on the class path and finally, if that fails, it is searched for in a list of URLs representing directories.

    FileResolver fr = new FileResolverFactory.getFileResolver();
    URL url = fr.urlForFileName( “services.conf”);

would return file:/C://Wadjet/config/services.conf

If you have a file in the same package as the calling class, you could open it like this

    InputStream is = fr.streamForFileName( this, “test.com”);

If you want to load the test.dtd from a web site but you are not sure which one it is, you can set up a URL search list:

    ArrayList list = new ArrayList();
    List.add( "http://www.somewhere.ch/dtd/");
    List.add( "http://www.corbasol.com/dtd/");
    List.add( "http://www.kekpart.fr/dtd/");
    fr.addURL( list);
    URL url = fr.urlForFileName( “test.dtd”);

The URL returned will be http://www.addc.com/dtd/test.dtd .


Back to top

Resource Loading

In the same package as the File Resolver Service there is a ResourceLoader which eases loading resources. It is essentially designed to load SQL statements from xx.sql files that are on the class path or in the same package as the object using them.

You can use the ResourceLoader directly:

    ResourceLoader loader = new ResourceLoader();
    String fileContents = loader.getResourceAsString(this, fileName);

or use the helper methods in the FileUtils class:

    String fileContents = FileUtils.getResourceAsString(this, fileName);

Back to top

XML Loader

The IXmlLoader implementation classes require the xerces jars if you are loading XML that uses schemas and the jdom jar to build the Document.

There are two types of IXmlLoader , a pooled version and a simple one. The pooled loader creates a pool of SAX parsers and is more efficient if you need to load multiple XML files as it can re-use the parsers. The simple one has to re-initialise its SAX parser every time it used and is only recommended if it used once.

Like many of the implementation classes you obtain XmlLoader instances through a locator factory class:

    IXmlLoader loader = XmlLoaderFactory.getXmlLoader();

and the kind of loader that is returned is defined in the services.conf file, the default is the simple one.

The PooledXmlLoader requires the following entries in the DynamicPool.conf file:

    DTDLoaders.maxObjects=5
    DTDLoaders.minObject=1
    DTDLoaders.type=com.addc.util.xml.SaxBuilder
    XSDLoaders.maxObjects=5
    XSDLoaders.minObjects=1
    XSDLoaders.type=com.addc.util.xml.SaxBuilder

Once you have a loader, you can easily load a JDOM document by simply passing the file names of the XML and DTD or XSD file. The loader decides what kind of loader is needed based on the file extension:

  • DTD for extensions .dtd ( case insensitive).
  • Schema for extensions .xsd (case insensitive).

If your DTD or schema is in the package of the class which is loading, you must use the load method which takes an Object parameter. This method uses the object to try and load the file from the local package directory even inside a jar file.

    Document doc = loader.load(xmlName, dtdName);

will load an XML document from anywhere on the classpath,

    doc = loader.load(this, xmlName, xsdName);

will load an XML document where either the XML or the schema is in the package directory of the calling class.

    doc = loader.load(MyApplObject.class, xmlName, xsdName);

will load an XML document where either the XML or the schema is in the package directory of the given class.

The XmlLoader also supplies methods to set the URL search path for the FileResolver used (see File Resolver Service ).


Back to top

Object Persistence Service

The IObjectPersistence interface and its simple implementation class FilePersistence offer a simple method for storing Objects. The interface was originally developed for saving persistent CORBA objects in a Naming Service and uses the Object ID as a key for storing the object. The FilePersistence implementation converts the OID to a String and uses the hash code as a file name for storing the serialised object.

A dB version could simply use the hash code as an index to the table of persisted objects.

To obtain the configured IObjectPersistence implementation, use its locator;

    IObjectPersistence objPersit = ObjectPersistenceFactory.getObjectPersistence();

    byte[] oid = new byte[32];
    random.nextBytes(oid);

    objPersist.writeObject(oid, myObject)
    ...
    myObject = (MyObjectType) objPersist.readObject(oid);
…   ...
    objPersist.deleteObject(oid);

All IObjectPersistence implementations should be initialised using a IServiceProperties object see Properties Service .


Back to top

State Change Listeners

The StateChangeListener is a simple interface for creating observers for state changes in other objects. The listener will receive StateChangeEvents. You have to program the sending of events, it is not automated.

The listener will receive a StateChangeEvent which can be one of the constants StateChangeEvent.EVT_START or StateChangeEvent.EVT_STOP or any int your program is capable of interpreting and acting upon.

In a class which notifies of state changes:

    private Set<StateChangeListener> m_listeners;
    
    ...
    ...
    
    public void addListener(StateChangeListener listener) {
        m_listeners.add(listener);
    }
    
    public void removeListener(StateChangeListener listener) {
        m_listeners.remove(listener);
    }
    
    ....
    
    private void notifyChangeListeners(int eventId) {
        StateChangeEvent event = new StateChangeEvent(this, eventId); 
        for(Iterator<StateChangeListener> iter = m_listeners.iterator();iter.hasNext();) {
            iter.next().stateChanged(event);
        }
    }
    ...
    ...

Back to top

Stoppable Threads & Termination Notifier

The AStoppableThread class is a simple extension of the Java Thread class that implements the IStoppable interface. It is abstract and designed so be extended so that you can develop multi-threaded programs that can co-ordinate termination of the threads using the TerminationNotifier. For example in the creation phase:

    public class MyStoppableThread extends AStoppableThread {
    ...
    }

    IStoppable st = new MyStoppableThread(data);
    TerminationNotifier.addListener(st);

In the Thread, the run() method should not block:

    /**
     * @see java.lang.Runnable#run()
     */
    public void run() {
        m_logger.info("starts");
        while (!m_shutdown) {
            try {
                sleep(5000);
            } catch (InterruptedException e) {
            }
            if (!m_shutdown) {
                updateRefsToService();
            }
        }
        m_logger.info("ends");
    }

Possibly override the shutdown() method:

    /**
     * @see com.addc.util.Stoppable#shutdown()
     */
    public void shutdown() {
        super.shutdown();
        try {
            join(5000);
        } catch (InterruptedException e) {
        }
    }

When the program is about to terminate, and probably in a shutdown hook as well:

    TerminationNotifier.terminate();

Note that the TerminationNotifier can take any object that implements the IStoppable interface as a listener.


Back to top

String Manipulations and Conversions

there sre three classes that supply static, thread-safe string manipulation:

  • Conversions which supplies conversion facilities to and from String, byte[], char[], list (of words), hex strings, class and object.
  • Encoding which supplies two encoding algorithms, base 64 and a proprietary one that puts a tag in font of a hex string with no spaces.
  • StrUtils which supplies methods for padding strings, replacing strings in other strings, reading passwords without echoing and a quick string array sort.
The Encoding class

The Encoding class supplies methods to convert byte arrays to encoded String objects that can be saved to human readable media like XML files. A classic usage for this would be to store encrypted passwords in a configuration, properties or XML file:

    PBECipher pbe = new PBECipher();
    pbe.init(pass);
    ...
    byte[] ba = pbe.encrypt(a_password);
    String base64 = Encoding.encodeBase64(ba);
    ...
    // save the string somewhere
    ...
    // read the string back
    ...
    byte[] ba = Encoding.decodeBase64(str);
    a_password = pbe.decryptToChars(ba);

or using the proprietary encoding with the default tag enc :

    byte[] ba = pbe.encrypt( a_password);
    String enc = Encoding.encodedBytes( ba);
    ...
    // save the string somewhere
    ...
    // read the string back
    ...
    byte[] ba = Encoding.decodeString( str);
    a_password = pbe.decryptToChars( ba);

or if you want your own tag:

    byte[] ba = pbe.encrypt( a_password);
    String enc = Encoding.encodedBytes( “{MY_TAG}”, ba);

    byte[] ba = Encoding.decodeString( “{MY_TAG}”, str);
    a_password = pbe.decryptToChars( ba);
The Conversions class

The Conversions class supplies the following conversions:

  • char[] - byte[].
  • String - byte[] enforcing UTF-8 encoding (important when crossing encoding boundaries, e.g. EBCDIC ISO).
  • Hex - byte.
  • Hex string - byte[] with or without a given separator.
  • List of String - String i.e. extract words and build String from list of words inserting spaces.
  • Class - String including primitive types (int, boolean, etc). This will try all the possible class loaders starting with the current thread’s context class loader.
  • String pair (class + value) –> Object. Like the previous method, all the class loaders are tried.
  • String -> boolean
  • String -> int
  • String -> long
The StrUtils class

The StrUtils class supplies String manipulation routines:

  • Align a string to a given field width, strings are padded a left justified, numeric strings are right justified.
  • Pad a string to given length.
  • Right align a String with any padding char.
  • Find the number of occurrences of a character within a String.
  • Replace all the occurrences of a given sub-string with another sub-string within a given string.
  • Read a password without echo.
  • Get a confirmed password without echo.
  • Get a Yes/No reply as a boolean.
  • Sort an array of Strings returning the sorted array.

Back to top

Statistics Collection

Wadjet-Utils supplies a set of classes to help you collect statistics from your applications. The main class is the StatisticsImpl class that does the actual collection and calculation.

You get a Statistics object using a factory that will get an IStatistics object with a name that is made up of the calling class and method:

    package com.mycompany.product;

    public class MyClass {
    ...
        public int someMethod() {
            IStatistics stats = StatisticsFactory.getStatistics();
            ...
        }
    }

This will get a Statistics object named com.mycompany.product.MyClass.someMethod.

The Statistics object is designed to collect timing data in your code. It has two modes of operation:

  1. By collecting the timings and keeping track of the number of readings, the sum of the squares of the values and the sum of the values.
  2. The same as 1 but the values are stored in an internal vector and can later be dumped to CSV files, normalised and distributions calculated.

The IStatistics implemntation has two methods that you need to place in your code around the part you want to time:

    public int someMethod() {
        IStatistics stats = StatisticsFactory.getStatistics();
        ...
        stats.start();
        ...
        ...
        stats.end();
        ...
    }

Unfortunately, the timing is no better than Java’s System.currentTimeMillis() method. This means that on Windows the granularity is very poor and on UNIX the best you can expect is 1 ms. It is only really useful for timing lengthy operations, although you can always use it to get the number of calls being made.

The IStatistics implementaion is thread safe and can measure the time for a call concurrently, the start time being stored in a ThreadLocal variable.

The IStatistics interface supplies the following functionality:

  • Timing calls.
  • Calculate the standard deviation.
  • Calculate the algebraic mean.
  • Calculate the arithmetic mean.
  • Calculate the coefficient of variation.
  • Print statistics data to an output stream.
  • Normalise data.
  • Calculate a distribution.

Back to top