//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:
key
Identify the case for creating a new
instance. Its value, lets say case
will be
considered as prefix property.case.class
The class name
of the class to create a new instance of case
.case.package
The package name of the
case.class
value.case.nArgs
The number of input arguments of the
constructor to be invoked. Lets say its value is N
.
case.type0, case.type1,..., case.typeN-1
. The
types of the constructor input arguments. Where N
is the value of the property case.nArgs
. The types
allowed are the basic types: int, float, double, short,
long, boolean
and the {@link String String} class.case.arg0, case.arg1,..., case.argN-1
. The
arguments of the constructor input arguments. Where N
is the value of the property case.nArgs
. The values
are parsed to the corresponding types defined on the types
properties.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")}.
"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 saycase
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 AnDynamicInstance.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 + ", " +"]";
}
}
}