Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Server-side Java: Patterns for flexible initialization, Part 2

Customizing command targets in your system initialization

  • Print
  • Feedback

Page 3 of 4

Invoking the launch method

Your system has indeed created an object from a class specified in the configuration file, thus fully decoupling the application initialization class from the application setup code. This process was covered in Part 1, so the only remaining issue is to call a method in that class to actually launch the system. A setup system can do all the initialization and required object creation from within a single constructor call; the system can then work properly. However, some systems will be better off not launching vast numbers of new threads from within the constructor of one of its classes. This is especially true of systems where race conditions may occur for reasons beyond your control. Such systems need to construct and set up all required objects, then have a specific method called afterward to launch the normal working thread.

To keep with the tradition of creating the launcher object completely from configuration-file specifications, you should place the name of the method to invoke in the configuration file. Since all proper object setup should have been done from within the launcher class's constructor, the launcher method should rarely, if ever, need any parameters to control its execution. The Invocation pattern of the launcher method can therefore be greatly simplified.

You will have to provide the launcher method name in the configuration file. The only modification of this file is the single, boldface row at the end of the following list, which provides the startupMethod directive.

Listing 3. Augmented configuration file

############################################
#                                          #
# jGuru Sample Configuration file          #
# Created by Lennart Jörelid, lj@jguru.com #
#                                          #
############################################
startupClass=com.jguru.initHandler.TestClass
arg0=A custom config string
type0=java.lang.String
arg1=42
type1=java.lang.Integer
startupMethod=loadSystem

These equivalent Java statements should be performed after parsing the configuration file above:

Listing 4. Pseudo code from configuration file

TestClass launcher = new 
com.jguru.initHandler.TestClass("A custom config string", 42);
launcher.loadSystem();

The first statement sets up all the objects in the system, as was demonstrated in Part 1. Your task is to invoke the loadSystem method from instructions read in the configuration file. This is another task handled well by the Java reflection API of package java.lang.reflect. Thus, the Startup class is slightly altered to handle the method invocation. The alterations from the former Startup class are small, and have been marked in bold below:

Listing 5. Startup.java

// Copyright (c) 1999 jguru.com
// All rights reserved.
package com.jguru.initHandler;
import java.util.Map;
import java.lang.reflect.*;
import java.io.*;
import java.util.*;
/**
 * Driver class that starts up the system.
 *
 * @author <a href="mailto:lj@jguru.com">Lennart 
J&ouml;relid</a>,
 *                  <a href="http://www.jguru.com">jGuru 
Europe</a>
 * @version $Id$
 * @since January 2000
 */
public class Startup
{
    /** The ObjectFactory used to create the dynamic 
(first) instance. */
    private ObjectFactory    objFactory;
    /** The ConfigFileParser used to read and 
interpret the Config file. */
    private ConfigFileParser confParser;
    /** Absolute path of the config file. */
    private String           configFilePath;
    /** All parsed directives found in the config 
file. */
    private Map              configDirectives;
    /**
     * Creates a new Startup object, using an old-style Java property
     * file for storing configuration properties, and a simple
     * object factory for creating objects.
     */
    public Startup(String configFilePath)
    {
        // Create internal state variables
        this.confParser = new PropertyConfigParser();
        this.objFactory = new SimpleObjectFactory();
        this.configFilePath = configFilePath;
    }
    /**
     * Main setup method, that reads the configuration file
     * interprets all directives, and creates the launcher
     * dynamic object that could startup the entire application.
     */
    public Object doSetup() throws StartupException
    {
       // Read all directives from the config 
file
       configDirectives = confParser.parseConfigFile(configFilePath);
       // Find the startup class to load
       String startupClassName = (String) 
configDirectives.get("startupClass");
       // Find the number of arguments and create 
the Object array
       // where all the parameters go.
       int numArgs = 0;
       Object[] params = null;
       for(int i = 0; configDirectives.containsKey("type" + i); 
i++) numArgs++;
       params = new Object[numArgs];
       for(int j = 0; j < numArgs; j++)
       {
           // Find the type of the argument
           String theType     = (String) 
configDirectives.get("type" + j);
           String theArgument = (String) 
configDirectives.get("arg" + j);
           params[j] = objFactory.createObject(theType, new 
Object[]{theArgument});
       }
       // Create the startup object
       Object startupObject = 
this.objFactory.createObject(startupClassName, params);
       return startupObject;
    }
    public void invokeStartupMethod(Object target) throws 
StartupException
    {       // If the user has defined a startup 
method, invoke it.   String startupMethodName = (String) 
configDirectives.get("startupMethod");
       if(startupMethodName == null || 
startupMethodName.equals(""))
       {
          System.out.println("Found no startup method in config 
file.");
          System.out.println("Exiting startup.");
          return;
       }
       System.out.println("\nInvoking method " + 
startupMethodName);
       Method[] allMethods = target.getClass().getDeclaredMethods();
       for(int i = 0; i < allMethods.length; i++)
       {          // Make sure the method have no 
parameters.      if(allMethods[i].getName().equals(startupMethodName)
             && allMethods[i].getParameterTypes().length == 0)
          {
                // This is the method to 
invoke.            try
                {
                   // Finally invoke the 
method.               allMethods[i].invoke(target, null);
                }
                catch(InvocationTargetException itex)
                {
                    System.err.println("Could not invoke startup 
method " + startupMethodName);
                    System.err.println("" + 
itex.getTargetException());
                }
                catch(Exception ex)
                {
                    System.err.println("Could not invoke startup 
method " + startupMethodName);
                    System.err.println("" + ex.getMessage());
                }
          }
       }
    }
    public static void main(String[] args)
    {
       // First, create a dynamic setup object from 
the
       // given directives of the configuration file.
       Startup launcher = new Startup("/setupApp/settings.cfg");
       Object dynObject = launcher.doSetup();
       System.out.println("Created instance of " + 
dynObject.getClass().getName());
       System.out.println("[Instance]: " + dynObject);
       // Invoke the startup method on the 
dynamically created object.
       launcher.invokeStartupMethod(dynObject);
    }
}

  • Print
  • Feedback