001: /*
002: * MapperFactory.java July 2003
003: *
004: * Copyright (C) July, Niall Gallagher <niallg@users.sf.net>
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General
016: * Public License along with this library; if not, write to the
017: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
018: * Boston, MA 02111-1307 USA
019: */
020:
021: package simple.http.load;
022:
023: import java.lang.reflect.Constructor;
024: import simple.http.serve.Context;
025:
026: /**
027: * The <code>MapperFactory</code> retrieves the <code>Mapper</code>
028: * implementation for the system. This is used so that a mapping
029: * scheme can be imposed on the system using the command line. This
030: * has a number of advantages. For one it enables a mapping to be
031: * used without any changes to code, the <code>Mapper</code> object
032: * only needs to be implemented and specified at the command line.
033: * <p>
034: * In order to define a system wide implementation a property is
035: * needed to define the object. This uses the <code>System</code>
036: * properties to define the class name for the default instance.
037: * The property is the <code>simple.http.load.mapper</code>
038: * property that can be set using an argument to the VM.
039: * <pre>
040: * java -Dsimple.http.load.mapper=demo.example.ExampleMapper
041: * </pre>
042: * This will set the <code>System</code> property to the class
043: * name <code>demo.example.ExampleMapper</code>. When the factory
044: * method <code>getInstance</code> is invoked it will return an
045: * implementation of this object or if the implementation cannot
046: * be loaded by this classes class loader a default implementation
047: * <code>DefaultMapper</code> is returned instead.
048: *
049: * @author Niall Gallagher
050: */
051: public final class MapperFactory {
052:
053: /**
054: * This is used to produce the system wide <code>Mapper</code>
055: * implementation so that the <code>MapperEngine</code> objects
056: * can remain consistant. This will use a system property
057: * <code>simple.http.load.mapper</code> to define the
058: * class name of the implementation that will be used for the
059: * system wide <code>Mapper</code>. The property should contain
060: * the fully qualified class name of the object and should be
061: * loadable by this classes class loader. If the specified class
062: * cannot be loaded the <code>DefaultMapper</code> is used.
063: *
064: * @param context this is context used by the implementation
065: *
066: * @return the systems <code>Mapper</code> implementation
067: */
068: public static Mapper getInstance(Context context) {
069: String property = "simple.http.load.mapper";
070: String className = System.getProperty(property);
071:
072: if (className == null) {
073: return new PatternMapper(context);
074: }
075: try {
076: return getInstance(context, className);
077: } catch (Exception e) {
078: return new PatternMapper(context);
079: }
080: }
081:
082: /**
083: * This is used to create a <code>Mapper</code> instance with
084: * the issued class name. The class name issued represents the
085: * fully qualified package name of the implementation to be
086: * used. The implementation must contain a single argument
087: * constructor that takes a <code>Context</code> object of it
088: * is to be instantiated by this method. If there is any
089: * problem instantiating the object an exception is thrown.
090: *
091: * @param context the context used to create the mapper
092: * @param className this is the name of the implementation
093: *
094: * @return an instance of the <code>Mapper</code> object
095: */
096: private static Mapper getInstance(Context context, String className)
097: throws Exception {
098: Constructor method = getConstructor(className);
099: return (Mapper) method.newInstance(new Object[] { context });
100: }
101:
102: /**
103: * Here a <code>ClassLoader</code> is selected to load the class.
104: * This will load the class specified using this classes class
105: * loader. If there are no problems in loading the class then a
106: * <code>Constructor</code> is created from the loaded class.
107: * <p>
108: * The constructor for any <code>Mapper</code> implementation
109: * must contain a one argument constructor that takes a context
110: * object as the argument. If such a constructor does not exist
111: * then this will throw an <code>Exception</code>.
112: *
113: * @param className the name of the mapper implementation
114: *
115: * @return this returns a constructor for the specified class
116: */
117: private static Constructor getConstructor(String className)
118: throws Exception {
119: return getConstructor(Class.forName(className, false,
120: MapperFactory.class.getClassLoader()));
121: }
122:
123: /**
124: * Creates the <code>Constructor</code> for the implementation
125: * so that an instance can be created. This will use the class
126: * which has been previously loaded to acquire the constructor.
127: * The constructor object acquired is for a single argument
128: * constructor that takes a <code>Context</code> object.
129: *
130: * @param type this is the implementation class to be used
131: *
132: * @return this returns a constructor for the specified class
133: */
134: private static Constructor getConstructor(Class type)
135: throws Exception {
136: Class[] types = new Class[] { Context.class };
137: return type.getDeclaredConstructor(types);
138: }
139: }
|