//Source file: I:\\isf\\util\\DynamicInstance.java /* CmIdentification //////////////////////////////////////////////////////////////////////////////// // Version History: $Log: DynamicInstance.java,v $ Revision 1.5 2003/07/28 16:18:08 UF367151 Extension to the isf.util package, to be included on the kernel of SGCv10. Utility classes. //////////////////////////////////////////////////////////////////////////////// */ /* //////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000 Unión Fenosa - Soluziona - S.A. All Rights Reserved. // //////////////////////////////////////////////////////////////////////////////// // // This sotfware is the confidential and proprietary information of // Union Fenosa - Soluziona S.A.. You shall not disclose such confidential // information and shall not accordance with the terms of the licence // agreements you entered into with Union Fenosa - Soluziona S.A.. // //////////////////////////////////////////////////////////////////////////////// */ package isf.util; import java.io.IOException; import java.io.FileNotFoundException; import java.util.Properties; import java.util.NoSuchElementException; import java.io.FileInputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Constructor; /** Allows dynamically create instances of a possible set of objects, it assumes the class name, input argument and types are defined on a {@link Properties Properties} instance field.

The class assume the following propertise are defined:

This class uses the java reflection mechanism for creating dynamically new instances.

If the static information of the class is not set, we assume the properties are stored on a file with name: "DynamicInstance.properties", localized on the {@link java.lang.System#getProperty(java.lang.String) System.getProperty("user.dir")}.

@invariant ((_path != null) && (_path.length() > 0)) @author David Leal Valmaña (DLE) @version $Revision: 1.5 $ @see java.lang.reflect.Constructor */ public final class DynamicInstance { /** The name of the properties file. If no path is indicated then the name is relative to the {@link java.lang.System#getProperty(java.lang.String) System.getProperty("user.dir")} localization. By default its value is the name of the class plus the extension: "DynamicInstance.properties". If the class was initialized it uses the method {@link #defaultFileName() defaultFileName()} to construct the name of the class using dynamically the name of any subclass. */ private static String _fileName = Token._NAME; /** Path of the properties file name. The default value new {@link String#String() String()} (empty string) indicates that the path is {@link java.lang.System#getProperty(java.lang.String) System.getProperty("user.dir")} value. The user can change this value using a setter method. */ private static String _path = new String (); /** Stores the properties where are defined all the information to create a new instance of the classes. */ private static Properties _properties = null; /** It just initializes the file name using the default value: "DynamicInstance.properties. @pre $none @post $none @roseuid 3DA182DA0359 */ protected DynamicInstance() { if (_fileName == null) { _fileName = defaultFileName(); } } /** Set the name of the properties file (without the extension) @param value The value to assign, it will be assigned if it satisfies: value != null and value.length() > 0. @pre $none @post ((_fileName != null) && (_fileName.length() > 0)) @roseuid 3DA153CC02FB */ public static final void setFileName(String value) { if ((value != null) && (value.length() > 0)) { _fileName = value + Token._EXT; } } /** Set the localization of the properties file, that is the path. @param value The value to assign, it will be assigned if it satisfies: value != null and value.length() > 0. @pre $none @post $none @roseuid 3DA152140201 */ public static final void setPath(String value) { if ((value != null) && (value.length() > 0)) { _path = value; } } /** Set the properties used for creating a new instance process. The new properties should follow the same syntax for defining the class information. @param value The value to assign, it will be assigned if it satisfies: value != null. @pre $none @post $none @roseuid 3DA15A2A008A */ public static final void setProperties(final Properties value) { if (value != null) { _properties = value; } } /** Creates a new instance of the class represented by the property key (instance of {@link Properties Properties})

The dynamic invocation process use the java reflection mechanism for creating new instance, see {@link java.lang.reflect.Constructor java.lang.reflect.Constructor}.

@pre $none @post $none @param key The property that stores the information about the class for creating the new instance. The value, lets say case associated with key is used to get also information about other keys that uses on the property names this value as prefix, for example: case.package, case.class, case.nArgs, case.type#, case.arg#, where # represents a number between 0,..., N-1, where N is the value of the property case.nArgs. @return An instance of the object represented by the property: @throws java.lang.NoSuchMethodException If a matching method (constructor) is not found. @throws java.util.NoSuchElementException If for the input argument key, or any property derived from this one,there is no property defined on the properties field. @throws java.lang.InstantiationException If the class (the value stored on case.class, where case, is the value stored on key) that declares the underlying constructor represents an abstract class. @throws java.lang.IllegalAccessException If the underlying constructor is inaccessible. @throws java.lang.reflect.InvocationTargetException If the constructor to invoke throws an exception. @throws java.lang.ClassNotFoundException If the class associated with the property case.class, was not found, where case is the value stored on key. This exception is thrown by: {@link Class#forName(java.lang.String) Class.forName(String)}. @throws java.io.FileNotFoundException If the Properties information has to be loaded from a file and this file can't be localized. @throws java.io.IOException If the Properties information has to be loaded from a file and any fail occurs when getting information from the file. @see java.lang.reflect.Constructor @roseuid 3DA1504602FB */ public static Object newInstance(String key) throws NoSuchMethodException, NoSuchElementException, InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException, ClassNotFoundException, FileNotFoundException, IOException { isf.util.DynamicInstance.Constructor constructor = getKeyInfo(key); return constructor.newInstance(); } /** Converts to string the field information of the instance class. It uses the standard string format for printing the instance information. @return The field and class information of the instance class in a string format. @pre $none @post $none @roseuid 3DA188A0030B */ public String toString() { final String EQUAL = Token._EQUAL; final String COMMA = Token._SEPARATOR; final String RESULT = getClass().getName() + Token._BEGIN + Token._FILE_NAME_FIELD + EQUAL + _fileName + COMMA + Token._PATH_FIELD + EQUAL + _path + COMMA + Token._PROPERTIES_FIELD + EQUAL + _properties + Token._END; return RESULT; } /** Loads the constructor information from the {@link Properties Properties} instance {@link #_properties _properties}. It uses the key property for taking all the necessary information.

This method is used by {@link #newInstance(java.lang.String) #newInstance(String)}

@param key The property that represents the case to instance. @return An DynamicInstance.Constructor that stores all the necessary information for making an instance of the class. @throws ClassNotFoundException If the class associated with the property case.class, was not found, where case is the value stored on key. This exception is thrown by: {@link Class#forName(java.lang.String) Class.forName(String)}. @throws java.io.FileNotFoundException Thrown by the method {@link #getProperties() getProperties()}. @throws java.io.IOException Thrown by the method {@link #getProperties() getProperties()}. @throws java.util.NoSuchElementException thrown by the method {@link #getProperty(java.lang.String) DynamicInstance.getProperty(String)}, in case the key to look for on the properties instance was not defined. @pre $none @post $none @roseuid 3DA1549A0136 */ private static isf.util.DynamicInstance.Constructor getKeyInfo(String key) throws ClassNotFoundException, FileNotFoundException, IOException, NoSuchElementException { // Defining the properties that depends on the key value final String CASE = getProperty(key); final String CLASS_PTY = CASE + Token._CLASS; final String PACKAGE_PTY = CASE + Token._PACKAGE; final String N_ARGS_PTY = CASE + Token._N_ARGS; final String ARG_PTY = CASE + Token._ARG; final String TYPE_PTY = CASE + Token._TYPE; // Getting the values final String PACKAGE = getProperty(PACKAGE_PTY); final String CLASS_NAME = getProperty(CLASS_PTY); final String N_ARGS = getProperty(N_ARGS_PTY); final Class CLASS = Class.forName(PACKAGE + Token._DOT + CLASS_NAME); // Getting the types and arguments final int INT_N_ARGS = (N_ARGS != null) ? Integer.parseInt(N_ARGS) : 0; Class[] types = null; Object[] args = null; if (INT_N_ARGS != 0) { String type = null; // the argument type String arg = null; // the value of the argument types = new Class[INT_N_ARGS]; args = new Object[INT_N_ARGS]; for (int i = 0; i < INT_N_ARGS; i++) { type = getProperty(TYPE_PTY + i); types[i] = getTheClass(type); arg = getProperty(ARG_PTY + i); args[i] = getTheObject(type, arg); } // for(i) } // if return new isf.util. DynamicInstance.Constructor(CLASS, types, args); } /** Returns the class associated with the input argument. @param type String representing a basic type and could have one of the following values: "int", "double", "float", "double", "long", "short", "boolean" or "String". @return the class instance associated with the input argument, that is a instance of one of the classes: {@link Integer Integer}, {@link Double Double}, {@link Float Float}, {@link Short Short}, {@link Long Long}, {@link Boolean Boolean}, {@link String String}. @throws NoSuchElementException If the input argument type, doesn't corresponds to any valid basic java type or to the class String. @throws java.util.NoSuchElementException @pre $none @post $none @roseuid 3DA1622401E2 */ private static Class getTheClass(String type) throws NoSuchElementException { Class result = null; if (type != null) { if ("String".equals(type)){ result = String.class; } else if ("double".equals(type)) { result = Double.class; } else if ("float".equals(type)) { result = Float.class; } else if ("int".equals(type)) { result = Integer.class; } else if ("short".equals(type)) { result = Short.class; } else if ("long".equals(type)) { result = Long.class; } else if ("boolean".equals(type)) { result = Boolean.class; } else {// Non valid input throw new NoSuchElementException(type); } } // if (type != null) return result; } /** Returns the object instance (associated with type) initialized to the input argument value. @param value The value to initialize the instance of type. @param type String representing the type of value and could have one of the following values: "int", "double", "float", "double", "long", "short", "boolean" or "String". @return A instance of the wrapper classes or {@link String String} class represented by type. If the input value is null, then return the same value. @throws NoSuchElementException If the input argument type, doesn't corresponds to any valid basic java type or to the class String. @throws java.util.NoSuchElementException @pre $none @post $none @roseuid 3DA1629402AD */ private static Object getTheObject(String type, String value) throws NoSuchElementException { Object result = null; if (value != null) { if ("String".equals(type)){ result = value; } else if ("double".equals(type)) { result = new Double(value); } else if ("float".equals(type)) { result = new Float(value); } else if ("int".equals(type)) { result = new Integer(value); } else if ("short".equals(type)) { result = new Short(value); } else if ("long".equals(type)) { result = new Long(value); } else if ("boolean".equals(type)) { result = new Boolean(value); } else {// Non valid input throw new NoSuchElementException(type); } } // if (value != null) return result; } /** Returns the field {@link #_properties _properties}, if this field has the null value, then it loads the contents using the method {@link #load() load()} and set it. @return The properties for creating the objects, it returns the value stored on the field {@link #_properties _properties}, if the field has the null value, then first it loads it, invoking the method {@link #load() load()}. @throws java.io.FileNotFoundException Thrown by the method {@link #load() load()}. @throws java.io.IOException Thrown by the method {@link #load() load()}. @pre $none @post ($result != null) @roseuid 3DA16CFD0240 */ private static Properties getProperties() throws FileNotFoundException, IOException { if (_properties == null) { _properties = load(); } return _properties; } /** Load the properties file from the file, it uses information stored on {@link #_fileName _fileName} and {@link #_path _path}. @return The properties used for creating the objects. If no exception will be thrown a non null value will be returned. @throws FileNotFoundException If the properties file can't be localized. @throws IOException If any output exception occurs, when reading the properties file. @throws java.io.FileNotFoundException @throws java.io.IOException @pre $none @post ($result != null) @roseuid 3DA16C1803E6 */ private static Properties load() throws FileNotFoundException, IOException { String name = (_path != null) ? (_path + _fileName) : _fileName; _properties = new Properties(); final java.io.FileInputStream FILE = new java.io.FileInputStream(name); if (FILE != null) { _properties.load(FILE); } return _properties; } /** Returns the value associated to key, on the field {@link #_properties _properties}, if the key doesn't exist an exception of type {@link NoSuchElementException NoSuchElementException} will be thrown. @param key The to look for on the properties instance {@link #_properties _properties}. @return The value associated with key @throws NoSuchElementException If the input argument was not defined on _properties. @throws java.io.FileNotFoundException Thrown by the method {@link #load() load()}. @throws java.io.IOException Thrown by the method {@link #load() load()}. @pre $none @post $none @roseuid 3DA2BF5B01D2 */ private static String getProperty(String key) throws NoSuchElementException, IOException, FileNotFoundException { String value = null; // We ensure that the _properties was loaded invoking the getProperties() Properties properties = getProperties(); if (key != null) { if (properties != null) { value = properties.getProperty(key); if (value == null) { throw new NoSuchElementException(key); } } } else { // evidently, the key doesn't exist, Properties.getProperty() // returns a NullPointerException for this case. throw new NoSuchElementException(key); } return value; } /** Returns the default file name, that is the name of the class plus the extension: "DynamicInstance.properties" or the corresponding subclass name. @return The default file name, that is the name of the class plus the extension file. @pre $none @post $none @roseuid 3DA18A8502EC */ private final String defaultFileName() { String result = new String(); final String LONG_NAME = getClass().getName(); // Extracting the class name only: final int LENGTH = LONG_NAME.length(); if (LENGTH > 0) { final int LAST = LONG_NAME.lastIndexOf(Token._DOT); if ((LAST > 0) && ((LAST + 1) < LENGTH)) { result = LONG_NAME.substring(LAST + 1) + Token._EXT; } // if } // if return result; } /** Stores some token used by the outer class, usually tokens for converting the instance class information into string format. @invariant $none @author David Leal Valmaña (DLE) @version $Revision: 1.5 $ */ private static class Token { /** Represents the dot character. This field has to be defined first, other fields are defined in terms of this one. */ private static final String _DOT = "."; /** Extension of the file name (".properties" */ private static final String _EXT = _DOT + "properties"; /** Argument property of a given constructor. */ private static final String _ARG = _DOT + "arg"; /** Represents the begin delimiter used on the {DynamicInstance#toString() DynamicInstance.toString} method, to delimit the beginning of the class information. */ private static final String _BEGIN = "["; /** Represents the property that stores the name of the class. */ private static final String _CLASS = _DOT + "class"; /** Represents the end delimiter used on the {DynamicInstance#toString() DynamicInstance.toString} method, to delimit the end of the class information. */ private static final String _END = "]"; /** Represents the equal character ("=="). Used at toString() method. */ private static final String _EQUAL = "="; /** The name of the corresponding field ("_fileName") */ private static final String _FILE_NAME_FIELD = "_fileName"; /** Number of arguments property of the class. */ private static final String _N_ARGS = _DOT + "nArgs"; /** The default name of the file, that is the name of the class plus the extension: "DynamicInstance.properties" */ private static final String _NAME = "DynamicInstance" + _EXT; /** Represents the property that stores the package of the class. */ private static final String _PACKAGE = _DOT + "package"; /** The name of the corresponding field ("_path") */ private static final String _PATH_FIELD = "_path"; /** The name of the corresponding field ("_properties") */ private static final String _PROPERTIES_FIELD = "_properties"; /** Represents the comma character (", ") Used at the {@link DynamicInstance#toString() DynamicInstance.toString()} method. */ private static final String _SEPARATOR = ", "; /** Represents the property prefix that stores the types of the variables. */ private static final String _TYPE = _DOT + "type"; /** Default constructor for preventing public instantiation. @roseuid 3DA15BEF0230 */ private Token() { } } /** Stores the necessary information for creating a new instance and invokes creation of new instances. It use the java reflection mechanims for creating the new instance. @invariant $none @author David Leal Valmaña (DLE) @version $Revision: 1.5 $ @see java.lang.reflect.Constructor */ private final static class Constructor { /** The arguments to be use on the invocation of the constructor of the class. */ private Object _args[] = null; /** The class for creating the new instance. */ private Class _theClass = null; /** The types that defines the constructor to invoke. */ private Class _types[] = null; /** Initialize the fields of the class with the input arguments. @param aClass A class instance. @param types The class types that defines the constructor. @param args The current arguments that defines the constructor. @pre $none @post $none @roseuid 3DA28471001D */ public Constructor(final Class aClass, final Class[] types, final Object[] args) { _theClass = aClass; _types = types; _args = args; } /** Instanciate the class _class, using a constructor with the input argument types defined on _types, with the current arguments d efined on _args. @return An instance of the class className. @throws NoSuchMethodException If a matching method (constructor) is not found. @throws InstantiationException If the class (_class) that declares the underlying constructor represents an abstract class. It is thrown by (thrown by {@link Constructor#newInstance(java.lang.Object[]) Constructor#newInstance(Object[])}. @throws IllegalAccessException If the underlying constructor is inaccessible. It is thrown by {@link Constructor#newInstance(java.lang.Object[]) Constructor#newInstance(Object[])}. @throws InvocationTargetException If the constructor to invoke throws an exception. It is thrown by {@link Constructor#newInstance(java.lang.Object[]) Constructor#newInstance(Object[])}. @pre $none @post $none @roseuid 3DA28EC503E6 */ public Object newInstance() throws NoSuchMethodException, InstantiationException, IllegalAccessException, java.lang.reflect.InvocationTargetException { Object result = null; final java.lang.reflect.Constructor CONSTRUCTOR = (_theClass != null) ? _theClass.getConstructor(_types) : null; result = (CONSTRUCTOR != null) ? CONSTRUCTOR.newInstance(_args) : null; return result; } /** Converts to a string format the instance of the class. @return the instance class information in a string format. @pre $none @post $none @roseuid 3DA28C62030B */ public String toString() { return getClass().getName() + "[" + "_theClass=" + _theClass + ", " + "_types=" + _types + ", " + "_args=" + _args + ", " +"]"; } } }