This is an automated email from the ASF dual-hosted git repository.
tv pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/turbine-fulcrum-factory.git
The following commit(s) were added to refs/heads/master by this push:
new 24c0804 Modernize
24c0804 is described below
commit 24c0804e3dec6657a9646e7a07bbcee8412617a2
Author: Thomas Vandahl <[email protected]>
AuthorDate: Mon Jan 12 21:01:39 2026 +0100
Modernize
---
.../fulcrum/factory/DefaultFactoryService.java | 1142 +++++++++++---------
src/java/org/apache/fulcrum/factory/Factory.java | 1 -
.../apache/fulcrum/factory/FactoryException.java | 15 +-
.../org/apache/fulcrum/factory/FactoryService.java | 7 +-
.../factory/utils/ObjectInputStreamForContext.java | 9 +-
.../apache/fulcrum/factory/FactoryServiceTest.java | 39 +-
6 files changed, 643 insertions(+), 570 deletions(-)
diff --git a/src/java/org/apache/fulcrum/factory/DefaultFactoryService.java
b/src/java/org/apache/fulcrum/factory/DefaultFactoryService.java
index 3fd26a6..f9eaa87 100644
--- a/src/java/org/apache/fulcrum/factory/DefaultFactoryService.java
+++ b/src/java/org/apache/fulcrum/factory/DefaultFactoryService.java
@@ -24,7 +24,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.avalon.framework.activity.Disposable;
@@ -32,550 +32,624 @@ import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
-import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.fulcrum.factory.utils.ObjectInputStreamForContext;
/**
* The Factory Service instantiates objects using specified class loaders. If
* none is specified, the default one will be used.
- *
+ *
* avalon.component name="factory" lifestyle="singleton" avalon.service
* type="org.apache.fulcrum.factory.FactoryService"
*
* @author <a href="mailto:[email protected]">Eric Pugh</a>
* @author <a href="mailto:[email protected]">Ilkka Priha</a>
* @author <a href="mailto:[email protected]">Stephen McConnell</a>
- * @version $Id$
*
*/
-public class DefaultFactoryService extends AbstractLogEnabled
- implements FactoryService, Configurable, Initializable,
Disposable {
-
- /**
- * The property specifying a set of additional class loaders.
- */
- private static final String CLASS_LOADER = "classloader";
-
- /**
- * The property prefix specifying additional object factories.
- */
- private static final String OBJECT_FACTORY = "object-factory";
-
- /**
- * The name of the default factory.
- */
- protected static final String DEFAULT_FACTORY = "default";
-
- /**
- * Primitive classes for reflection of constructors.
- */
- private static HashMap<String, Class<?>> primitiveClasses = new
HashMap<String, Class<?>>(8);
-
- {
- primitiveClasses.put(Boolean.TYPE.toString(), Boolean.TYPE);
- primitiveClasses.put(Character.TYPE.toString(), Character.TYPE);
- primitiveClasses.put(Byte.TYPE.toString(), Byte.TYPE);
- primitiveClasses.put(Short.TYPE.toString(), Short.TYPE);
- primitiveClasses.put(Integer.TYPE.toString(), Integer.TYPE);
- primitiveClasses.put(Long.TYPE.toString(), Long.TYPE);
- primitiveClasses.put(Float.TYPE.toString(), Float.TYPE);
- primitiveClasses.put(Double.TYPE.toString(), Double.TYPE);
- }
-
- /**
- * temporary storage of class names between configure and initialize
- */
- private String[] loaderNames;
- /**
- * Additional class loaders.
- */
- private ArrayList<ClassLoader> classLoaders = new
ArrayList<ClassLoader>();
- /**
- * Customized object factories.
- */
- private ConcurrentHashMap<String, Factory<?>> objectFactories = new
ConcurrentHashMap<String, Factory<?>>();
- /**
- * Customized object factory classes.
- */
- private ConcurrentHashMap<String, String> objectFactoryClasses = new
ConcurrentHashMap<String, String>();
-
- /**
- * Gets the class of a primitive type.
- *
- * @param type a primitive type.
- * @return the corresponding class, or null.
- */
- protected static Class<?> getPrimitiveClass(String type)
- {
- return primitiveClasses.get(type);
- }
-
- /**
- * Gets an instance of a named class.
- *
- * @param className the name of the class.
- * @return the instance.
- * @throws FactoryException if instantiation fails.
- */
- @Override
- public <T> T getInstance(String className) throws FactoryException
- {
- if (className == null) {
- throw new FactoryException("Missing String className");
- }
- Factory<T> factory = getFactory(className);
- if (factory == null) {
- Class<T> clazz;
- try {
- clazz = loadClass(className);
- } catch (ClassNotFoundException x) {
- throw new FactoryException("Instantiation
failed for class " + className, x);
- }
- return getInstance(clazz);
- } else {
- return factory.getInstance();
- }
- }
-
- /**
- * Gets an instance of a named class using a specified class loader.
- *
- * <p>
- * Class loaders are supported only if the isLoaderSupported method
returns
- * true. Otherwise the loader parameter is ignored.
- *
- * @param className the name of the class.
- * @param loader the class loader.
- * @return the instance.
- * @throws FactoryException if instantiation fails.
- */
- @Override
- public <T> T getInstance(String className, ClassLoader loader) throws
FactoryException
- {
- Factory<T> factory = getFactory(className);
- if (factory == null) {
- if (loader != null) {
- Class<T> clazz;
- try {
- clazz = loadClass(className, loader);
- } catch (ClassNotFoundException x) {
- throw new
FactoryException("Instantiation failed for class " + className, x);
- }
- return getInstance(clazz);
- } else {
- return getInstance(className);
- }
- } else {
- return factory.getInstance(loader);
- }
- }
-
- /**
- * Gets an instance of a named class. Parameters for its constructor
are given
- * as an array of objects, primitive types must be wrapped with a
corresponding
- * class.
- *
- * @param className the name of the class.
- * @param params an array containing the parameters of the
constructor.
- * @param signature an array containing the signature of the
constructor.
- * @return the instance.
- * @throws FactoryException if instantiation fails.
- */
- @Override
- public <T> T getInstance(String className, Object[] params, String[]
signature) throws FactoryException
- {
- Factory<T> factory = getFactory(className);
- if (factory == null) {
- Class<T> clazz;
- try {
- clazz = loadClass(className);
- } catch (ClassNotFoundException x) {
- throw new FactoryException("Instantiation
failed for class " + className, x);
- }
- return getInstance(clazz, params, signature);
- } else {
- return factory.getInstance(params, signature);
- }
- }
-
- /**
- * Gets an instance of a named class using a specified class loader.
Parameters
- * for its constructor are given as an array of objects, primitive
types must be
- * wrapped with a corresponding class.
- *
- * <p>
- * Class loaders are supported only if the isLoaderSupported method
returns
- * true. Otherwise the loader parameter is ignored.
- * </p>
- *
- * @param <T> Type of the class
- * @param className the name of the class.
- * @param loader the class loader.
- * @param params an array containing the parameters of the
constructor.
- * @param signature an array containing the signature of the
constructor.
- * @return the instance.
- * @throws FactoryException if instantiation fails.
- */
- @Override
- public <T> T getInstance(String className, ClassLoader loader, Object[]
params, String[] signature)
- throws FactoryException
- {
- Factory<T> factory = getFactory(className);
- if (factory == null) {
- if (loader != null) {
- Class<T> clazz;
- try {
- clazz = loadClass(className, loader);
- } catch (ClassNotFoundException x) {
- throw new
FactoryException("Instantiation failed for class " + className, x);
- }
- return getInstance(clazz, params, signature);
- } else {
- return getInstance(className, params,
signature);
- }
- } else {
- return factory.getInstance(loader, params, signature);
- }
- }
-
- /**
- * Tests if specified class loaders are supported for a named class.
- *
- * @param className the name of the class.
- * @return true if class loaders are supported, false otherwise.
- * @throws FactoryException if test fails.
- */
- @Override
- public boolean isLoaderSupported(String className) throws
FactoryException
- {
- Factory<?> factory = getFactory(className);
- return factory != null ? factory.isLoaderSupported() : true;
- }
-
- /**
- * Gets an instance of a specified class.
- *
- * @param <T> Type of the class
- * @param clazz the class.
- * @return the instance.
- * @throws FactoryException if instantiation fails.
- */
- @Override
- public <T> T getInstance(Class<T> clazz) throws FactoryException
- {
- try {
- return clazz.newInstance();
- } catch (Exception x) {
- throw new FactoryException("Instantiation failed for "
+ clazz.getName(), x);
- }
- }
-
- /**
- * Gets an instance of a specified class. Parameters for its
constructor are
- * given as an array of objects, primitive types must be wrapped with a
- * corresponding class.
- *
- * @param <T> Type of the class
- * @param clazz the class
- * @param params an array containing the parameters of the
constructor
- * @param signature an array containing the signature of the constructor
- * @return the instance
- * @throws FactoryException if instantiation fails.
- */
- protected <T> T getInstance(Class<T> clazz, Object params[], String
signature[])
- throws FactoryException
- {
- /* Try to construct. */
- try {
- Class<?>[] sign = getSignature(clazz, params,
signature);
- return clazz.getConstructor(sign).newInstance(params);
- } catch (Exception x) {
- throw new FactoryException("Instantiation failed for "
+ clazz.getName(), x);
- }
- }
-
- /**
- * Gets the signature classes for parameters of a method of a class.
- *
- * @param clazz the class.
- * @param params an array containing the parameters of the method.
- * @param signature an array containing the signature of the method.
- * @return an array of signature classes. Note that in some cases
objects in the
- * parameter array can be switched to the context of a
different class
- * loader.
- * @throws ClassNotFoundException if any of the classes is not found.
- */
- @Override
- public Class<?>[] getSignature(Class<?> clazz, Object params[], String
signature[])
- throws ClassNotFoundException
- {
- if (signature != null) {
- /* We have parameters. */
- ClassLoader tempLoader;
- ClassLoader loader = clazz.getClassLoader();
- Class<?>[] sign = new Class[signature.length];
- for (int i = 0; i < signature.length; i++) {
- /* Check primitive types. */
- sign[i] = getPrimitiveClass(signature[i]);
- if (sign[i] == null) {
- /* Not a primitive one, continue
building. */
- if (loader != null) {
- /* Use the class loader of the
target object. */
- sign[i] =
loader.loadClass(signature[i]);
- tempLoader =
sign[i].getClassLoader();
- if (params[i] != null &&
tempLoader != null
- &&
!tempLoader.equals(params[i].getClass().getClassLoader())) {
- /*
- * The class uses a
different class loader, switch the parameter.
- */
- params[i] =
switchObjectContext(params[i], loader);
- }
- } else {
- /* Use the default class
loader. */
- sign[i] =
loadClass(signature[i]);
- }
- }
- }
- return sign;
- } else {
- return null;
- }
- }
-
- /**
- * Switches an object into the context of a different class loader.
- *
- * @param object an object to switch.
- * @param loader the ClassLoader to use
- * @param loader the loader of the new context.
- * @return the object
- */
- protected Object switchObjectContext(Object object, ClassLoader loader)
- {
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
-
- try
- {
- ObjectOutputStream out = new ObjectOutputStream(bout);
- out.writeObject(object);
- out.flush();
- }
- catch (IOException x)
- {
- return object;
- }
-
- ByteArrayInputStream bin = new
ByteArrayInputStream(bout.toByteArray());
- ObjectInputStreamForContext in = null;
-
- try
- {
- in = new ObjectInputStreamForContext(bin, loader);
- return in.readObject();
- }
- catch (Exception x)
- {
- return object;
- }
- finally
- {
- if (in != null)
- {
- try
- {
- in.close();
- }
- catch (IOException e)
- {
- // close quietly
- }
- }
- }
- }
-
- /**
- * Loads the named class using the default class loader.
- *
- * @param className the name of the class to load.
- * @return {@inheritDoc} the loaded class.
- * @throws ClassNotFoundException if the class was not found.
- */
- @SuppressWarnings("unchecked")
- protected <T> Class<T> loadClass(String className) throws
ClassNotFoundException
- {
- ClassLoader loader = this.getClass().getClassLoader();
- try
- {
- Class<T> clazz;
-
- if (loader != null)
- {
- clazz = (Class<T>) loader.loadClass(className);
- }
- else
- {
- clazz = (Class<T>) Class.forName(className);
- }
-
- return clazz;
- }
- catch (ClassNotFoundException x)
- {
- /* Go through additional loaders. */
- for (ClassLoader l : classLoaders)
- {
- try
- {
- return (Class<T>)
l.loadClass(className);
- }
- catch (ClassNotFoundException xx)
- {
- // continue
- }
- }
- /* Give up. */
- throw x;
- }
- }
-
- /**
- * Loads the named class using a specified class loader.
- *
- * @param className the name of the class to load.
- * @param loader the loader to use.
- * @return {@inheritDoc} the loaded class.
- * @throws ClassNotFoundException if the class was not found.
- */
- @SuppressWarnings("unchecked")
- protected <T> Class<T> loadClass(String className, ClassLoader loader)
throws ClassNotFoundException
- {
- if (loader != null)
- {
- return (Class<T>) loader.loadClass(className);
- }
- else
- {
- return loadClass(className);
- }
- }
-
- /**
- * Gets a customized factory for a named class. If no class-specific
factory is
- * specified but a default factory is, will use the default factory.
- *
- * @param className the name of the class to load.
- * @return {@inheritDoc} the factory, or null if not specified and no
default.
- * @throws FactoryException if instantiation of the factory fails.
- */
- @SuppressWarnings("unchecked")
- protected <T> Factory<T> getFactory(String className) throws
FactoryException
- {
- Factory<T> factory = (Factory<T>)
objectFactories.get(className);
- if (factory == null)
- {
- // No named factory for this; try the default, if one
exists
- factory = (Factory<T>)
objectFactories.get(DEFAULT_FACTORY);
- }
-
- if (factory == null) {
-
- /* Not yet instantiated... */
- String factoryClass =
objectFactoryClasses.get(className);
- if (factoryClass == null)
- {
- factoryClass =
objectFactoryClasses.get(DEFAULT_FACTORY);
- }
-
- if (factoryClass == null) {
- return null;
- }
-
- try {
- factory = getInstance(factoryClass);
- factory.init(className);
- }
- catch (ClassCastException x)
- {
- throw new FactoryException("Incorrect factory "
+ factoryClass + " for class " + className, x);
- }
-
- Factory<T> _factory = (Factory<T>)
objectFactories.putIfAbsent(className, factory);
- if (_factory != null)
- {
- // Already created - take first instance
- factory = _factory;
- }
- }
-
- return factory;
- }
-
- // ---------------- Avalon Lifecycle Methods ---------------------
-
- /* (non-Javadoc)
- * Avalon component lifecycle method
- * @see
org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
- */
- @Override
- public void configure(Configuration conf) throws ConfigurationException
- {
- final Configuration[] loaders = conf.getChildren(CLASS_LOADER);
- if (loaders != null)
- {
- loaderNames = new String[loaders.length];
- for (int i = 0; i < loaders.length; i++)
- {
- loaderNames[i] = loaders[i].getValue();
- }
- }
-
- final Configuration factories = conf.getChild(OBJECT_FACTORY,
false);
- if (factories != null)
- {
- // Store the factory to the table as a string and
- // instantiate it by using the service when needed.
- Configuration[] nameVal = factories.getChildren();
- for (Configuration entry : nameVal)
- objectFactoryClasses.put(entry.getName(),
entry.getValue());
-
- }
- }
-
- /**
- * Avalon component lifecycle method Initializes the service by loading
default
- * class loaders and customized object factories.
- *
- * @throws Exception if initialization fails.
- */
- @Override
- public void initialize() throws Exception
- {
- if (loaderNames != null)
- {
- for (String className : loaderNames)
- {
- try
- {
- ClassLoader loader = (ClassLoader)
loadClass(className).newInstance();
- classLoaders.add(loader);
- }
- catch (Exception x)
- {
- throw new Exception("No such class
loader '" + className + "' for DefaultFactoryService", x);
- }
- }
- loaderNames = null;
- }
- }
-
- /**
- * Avalon component lifecycle method Clear lists and maps
- */
- @Override
- public void dispose()
- {
- objectFactories.clear();
- objectFactoryClasses.clear();
- classLoaders.clear();
- }
+public class DefaultFactoryService
+ implements FactoryService, Configurable, Initializable, Disposable
+{
+ /**
+ * The property specifying a set of additional class loaders.
+ */
+ private static final String CLASS_LOADER = "classloader";
+
+ /**
+ * The property prefix specifying additional object factories.
+ */
+ private static final String OBJECT_FACTORY = "object-factory";
+
+ /**
+ * The name of the default factory.
+ */
+ protected static final String DEFAULT_FACTORY = "default";
+
+ /**
+ * Primitive classes for reflection of constructors.
+ */
+ private static Map<String, Class<?>> primitiveClasses = Map.of(
+ Boolean.TYPE.toString(), Boolean.TYPE,
+ Character.TYPE.toString(), Character.TYPE,
+ Byte.TYPE.toString(), Byte.TYPE,
+ Short.TYPE.toString(), Short.TYPE,
+ Integer.TYPE.toString(), Integer.TYPE,
+ Long.TYPE.toString(), Long.TYPE,
+ Float.TYPE.toString(), Float.TYPE,
+ Double.TYPE.toString(), Double.TYPE
+ );
+
+ /**
+ * temporary storage of class names between configure and initialize
+ */
+ private String[] loaderNames;
+
+ /**
+ * Additional class loaders.
+ */
+ private ArrayList<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
+
+ /**
+ * Customized object factories.
+ */
+ private ConcurrentHashMap<String, Factory<?>> objectFactories = new
ConcurrentHashMap<String, Factory<?>>();
+
+ /**
+ * Customized object factory classes.
+ */
+ private ConcurrentHashMap<String, String> objectFactoryClasses = new
ConcurrentHashMap<String, String>();
+
+ /**
+ * Gets the class of a primitive type.
+ *
+ * @param type
+ * a primitive type.
+ * @return the corresponding class, or null.
+ */
+ protected static Class<?> getPrimitiveClass(String type)
+ {
+ return primitiveClasses.get(type);
+ }
+
+ /**
+ * Gets an instance of a named class.
+ *
+ * @param className
+ * the name of the class.
+ * @return the instance.
+ * @throws FactoryException
+ * if instantiation fails.
+ */
+ @Override
+ public <T> T getInstance(String className) throws FactoryException
+ {
+ if (className == null)
+ {
+ throw new FactoryException("Missing String className");
+ }
+ Factory<T> factory = getFactory(className);
+ if (factory == null)
+ {
+ Class<T> clazz;
+ try
+ {
+ clazz = loadClass(className);
+ }
+ catch (ClassNotFoundException x)
+ {
+ throw new FactoryException("Instantiation failed for class " +
className, x);
+ }
+ return getInstance(clazz);
+ }
+ else
+ {
+ return factory.getInstance();
+ }
+ }
+
+ /**
+ * Gets an instance of a named class using a specified class loader.
+ *
+ * <p>
+ * Class loaders are supported only if the isLoaderSupported method returns
+ * true. Otherwise the loader parameter is ignored.
+ *
+ * @param className
+ * the name of the class.
+ * @param loader
+ * the class loader.
+ * @return the instance.
+ * @throws FactoryException
+ * if instantiation fails.
+ */
+ @Override
+ public <T> T getInstance(String className, ClassLoader loader) throws
FactoryException
+ {
+ Factory<T> factory = getFactory(className);
+ if (factory == null)
+ {
+ if (loader != null)
+ {
+ Class<T> clazz;
+ try
+ {
+ clazz = loadClass(className, loader);
+ }
+ catch (ClassNotFoundException x)
+ {
+ throw new FactoryException("Instantiation failed for class
" + className, x);
+ }
+ return getInstance(clazz);
+ }
+ else
+ {
+ return getInstance(className);
+ }
+ }
+ else
+ {
+ return factory.getInstance(loader);
+ }
+ }
+
+ /**
+ * Gets an instance of a named class. Parameters for its constructor are
+ * given as an array of objects, primitive types must be wrapped with a
+ * corresponding class.
+ *
+ * @param className
+ * the name of the class.
+ * @param params
+ * an array containing the parameters of the constructor.
+ * @param signature
+ * an array containing the signature of the constructor.
+ * @return the instance.
+ * @throws FactoryException
+ * if instantiation fails.
+ */
+ @Override
+ public <T> T getInstance(String className, Object[] params, String[]
signature) throws FactoryException
+ {
+ Factory<T> factory = getFactory(className);
+ if (factory == null)
+ {
+ Class<T> clazz;
+ try
+ {
+ clazz = loadClass(className);
+ }
+ catch (ClassNotFoundException x)
+ {
+ throw new FactoryException("Instantiation failed for class " +
className, x);
+ }
+ return getInstance(clazz, params, signature);
+ }
+ else
+ {
+ return factory.getInstance(params, signature);
+ }
+ }
+
+ /**
+ * Gets an instance of a named class using a specified class loader.
+ * Parameters for its constructor are given as an array of objects,
+ * primitive types must be wrapped with a corresponding class.
+ *
+ * <p>
+ * Class loaders are supported only if the isLoaderSupported method returns
+ * true. Otherwise the loader parameter is ignored.
+ * </p>
+ *
+ * @param <T>
+ * Type of the class
+ * @param className
+ * the name of the class.
+ * @param loader
+ * the class loader.
+ * @param params
+ * an array containing the parameters of the constructor.
+ * @param signature
+ * an array containing the signature of the constructor.
+ * @return the instance.
+ * @throws FactoryException
+ * if instantiation fails.
+ */
+ @Override
+ public <T> T getInstance(String className, ClassLoader loader, Object[]
params, String[] signature)
+ throws FactoryException
+ {
+ Factory<T> factory = getFactory(className);
+ if (factory == null)
+ {
+ if (loader != null)
+ {
+ Class<T> clazz;
+ try
+ {
+ clazz = loadClass(className, loader);
+ }
+ catch (ClassNotFoundException x)
+ {
+ throw new FactoryException("Instantiation failed for class
" + className, x);
+ }
+ return getInstance(clazz, params, signature);
+ }
+ else
+ {
+ return getInstance(className, params, signature);
+ }
+ }
+ else
+ {
+ return factory.getInstance(loader, params, signature);
+ }
+ }
+
+ /**
+ * Tests if specified class loaders are supported for a named class.
+ *
+ * @param className
+ * the name of the class.
+ * @return true if class loaders are supported, false otherwise.
+ * @throws FactoryException
+ * if test fails.
+ */
+ @Override
+ public boolean isLoaderSupported(String className) throws FactoryException
+ {
+ Factory<?> factory = getFactory(className);
+ return factory != null ? factory.isLoaderSupported() : true;
+ }
+
+ /**
+ * Gets an instance of a specified class.
+ *
+ * @param <T>
+ * Type of the class
+ * @param clazz
+ * the class.
+ * @return the instance.
+ * @throws FactoryException
+ * if instantiation fails.
+ */
+ @Override
+ public <T> T getInstance(Class<T> clazz) throws FactoryException
+ {
+ try
+ {
+ return clazz.getDeclaredConstructor().newInstance();
+ }
+ catch (Exception x)
+ {
+ throw new FactoryException("Instantiation failed for " +
clazz.getName(), x);
+ }
+ }
+
+ /**
+ * Gets an instance of a specified class. Parameters for its constructor
are
+ * given as an array of objects, primitive types must be wrapped with a
+ * corresponding class.
+ *
+ * @param <T>
+ * Type of the class
+ * @param clazz
+ * the class
+ * @param params
+ * an array containing the parameters of the constructor
+ * @param signature
+ * an array containing the signature of the constructor
+ * @return the instance
+ * @throws FactoryException
+ * if instantiation fails.
+ */
+ protected <T> T getInstance(Class<T> clazz, Object params[], String
signature[])
+ throws FactoryException
+ {
+ /* Try to construct. */
+ try
+ {
+ Class<?>[] sign = getSignature(clazz, params, signature);
+ return clazz.getConstructor(sign).newInstance(params);
+ }
+ catch (Exception x)
+ {
+ throw new FactoryException("Instantiation failed for " +
clazz.getName(), x);
+ }
+ }
+
+ /**
+ * Gets the signature classes for parameters of a method of a class.
+ *
+ * @param clazz
+ * the class.
+ * @param params
+ * an array containing the parameters of the method.
+ * @param signature
+ * an array containing the signature of the method.
+ * @return an array of signature classes. Note that in some cases objects
in
+ * the parameter array can be switched to the context of a
different
+ * class loader.
+ * @throws ClassNotFoundException
+ * if any of the classes is not found.
+ */
+ @Override
+ public Class<?>[] getSignature(Class<?> clazz, Object params[], String
signature[])
+ throws ClassNotFoundException
+ {
+ if (signature != null)
+ {
+ /* We have parameters. */
+ ClassLoader tempLoader;
+ ClassLoader loader = clazz.getClassLoader();
+ Class<?>[] sign = new Class[signature.length];
+ for (int i = 0; i < signature.length; i++)
+ {
+ /* Check primitive types. */
+ sign[i] = getPrimitiveClass(signature[i]);
+ if (sign[i] == null)
+ {
+ /* Not a primitive one, continue building. */
+ if (loader != null)
+ {
+ /* Use the class loader of the target object. */
+ sign[i] = loader.loadClass(signature[i]);
+ tempLoader = sign[i].getClassLoader();
+ if (params[i] != null && tempLoader != null
+ &&
!tempLoader.equals(params[i].getClass().getClassLoader()))
+ {
+ /*
+ * The class uses a different class loader, switch
+ * the parameter.
+ */
+ params[i] = switchObjectContext(params[i], loader);
+ }
+ }
+ else
+ {
+ /* Use the default class loader. */
+ sign[i] = loadClass(signature[i]);
+ }
+ }
+ }
+ return sign;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Switches an object into the context of a different class loader.
+ *
+ * @param object
+ * an object to switch.
+ * @param loader
+ * the ClassLoader to use
+ * @param loader
+ * the loader of the new context.
+ * @return the object
+ */
+ protected Object switchObjectContext(Object object, ClassLoader loader)
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+
+ try (ObjectOutputStream out = new ObjectOutputStream(bout))
+ {
+ out.writeObject(object);
+ out.flush();
+ }
+ catch (IOException x)
+ {
+ return object;
+ }
+
+ ByteArrayInputStream bin = new
ByteArrayInputStream(bout.toByteArray());
+
+ try (ObjectInputStreamForContext in = new
ObjectInputStreamForContext(bin, loader))
+ {
+ return in.readObject();
+ }
+ catch (Exception x)
+ {
+ return object;
+ }
+ }
+
+ /**
+ * Loads the named class using the default class loader.
+ *
+ * @param className
+ * the name of the class to load.
+ * @return {@inheritDoc} the loaded class.
+ * @throws ClassNotFoundException
+ * if the class was not found.
+ */
+ @SuppressWarnings("unchecked")
+ protected <T> Class<T> loadClass(String className) throws
ClassNotFoundException
+ {
+ ClassLoader loader = this.getClass().getClassLoader();
+ try
+ {
+ Class<T> clazz;
+
+ if (loader != null)
+ {
+ clazz = (Class<T>) loader.loadClass(className);
+ }
+ else
+ {
+ clazz = (Class<T>) Class.forName(className);
+ }
+
+ return clazz;
+ }
+ catch (ClassNotFoundException x)
+ {
+ /* Go through additional loaders. */
+ for (ClassLoader l : classLoaders)
+ {
+ try
+ {
+ return (Class<T>) l.loadClass(className);
+ }
+ catch (ClassNotFoundException xx)
+ {
+ // continue
+ }
+ }
+ /* Give up. */
+ throw x;
+ }
+ }
+
+ /**
+ * Loads the named class using a specified class loader.
+ *
+ * @param className
+ * the name of the class to load.
+ * @param loader
+ * the loader to use.
+ * @return {@inheritDoc} the loaded class.
+ * @throws ClassNotFoundException
+ * if the class was not found.
+ */
+ @SuppressWarnings("unchecked")
+ protected <T> Class<T> loadClass(String className, ClassLoader loader)
throws ClassNotFoundException
+ {
+ if (loader != null)
+ {
+ return (Class<T>) loader.loadClass(className);
+ }
+ else
+ {
+ return loadClass(className);
+ }
+ }
+
+ /**
+ * Gets a customized factory for a named class. If no class-specific
factory
+ * is specified but a default factory is, will use the default factory.
+ *
+ * @param className
+ * the name of the class to load.
+ * @return {@inheritDoc} the factory, or null if not specified and no
+ * default.
+ * @throws FactoryException
+ * if instantiation of the factory fails.
+ */
+ @SuppressWarnings("unchecked")
+ protected <T> Factory<T> getFactory(String className) throws
FactoryException
+ {
+ Factory<T> factory = (Factory<T>)
objectFactories.getOrDefault(className,
+ // No named factory for this; try the default, if one exists
+ objectFactories.get(DEFAULT_FACTORY));
+
+ if (factory == null)
+ {
+ /* Not yet instantiated... */
+ String factoryClass = objectFactoryClasses.get(className);
+ if (factoryClass == null)
+ {
+ factoryClass = objectFactoryClasses.get(DEFAULT_FACTORY);
+ }
+
+ if (factoryClass == null)
+ {
+ return null;
+ }
+
+ try
+ {
+ factory = getInstance(factoryClass);
+ factory.init(className);
+ }
+ catch (ClassCastException x)
+ {
+ throw new FactoryException("Incorrect factory " + factoryClass
+ " for class " + className, x);
+ }
+
+ Factory<T> _factory = (Factory<T>)
objectFactories.putIfAbsent(className, factory);
+ if (_factory != null)
+ {
+ // Already created - take first instance
+ factory = _factory;
+ }
+ }
+
+ return factory;
+ }
+
+ // ---------------- Avalon Lifecycle Methods ---------------------
+
+ /*
+ * (non-Javadoc) Avalon component lifecycle method
+ *
+ * @see
+ * org.apache.avalon.framework.configuration.Configurable#configure(org.
+ * apache.avalon.framework.configuration.Configuration)
+ */
+ @Override
+ public void configure(Configuration conf) throws ConfigurationException
+ {
+ final Configuration[] loaders = conf.getChildren(CLASS_LOADER);
+ if (loaders != null)
+ {
+ loaderNames = new String[loaders.length];
+ for (int i = 0; i < loaders.length; i++)
+ {
+ loaderNames[i] = loaders[i].getValue();
+ }
+ }
+
+ final Configuration factories = conf.getChild(OBJECT_FACTORY, false);
+ if (factories != null)
+ {
+ // Store the factory to the table as a string and
+ // instantiate it by using the service when needed.
+ Configuration[] nameVal = factories.getChildren();
+ for (Configuration entry : nameVal)
+ {
+ objectFactoryClasses.put(entry.getName(), entry.getValue());
+ }
+ }
+ }
+
+ /**
+ * Avalon component lifecycle method Initializes the service by loading
+ * default class loaders and customized object factories.
+ *
+ * @throws Exception
+ * if initialization fails.
+ */
+ @Override
+ public void initialize() throws Exception
+ {
+ if (loaderNames != null)
+ {
+ for (String className : loaderNames)
+ {
+ try
+ {
+ ClassLoader loader = (ClassLoader)
loadClass(className).getDeclaredConstructor().newInstance();
+ classLoaders.add(loader);
+ }
+ catch (Exception x)
+ {
+ throw new Exception("No such class loader '" + className +
"' for DefaultFactoryService", x);
+ }
+ }
+ loaderNames = null;
+ }
+ }
+
+ /**
+ * Avalon component lifecycle method Clear lists and maps
+ */
+ @Override
+ public void dispose()
+ {
+ objectFactories.clear();
+ objectFactoryClasses.clear();
+ classLoaders.clear();
+ }
}
diff --git a/src/java/org/apache/fulcrum/factory/Factory.java
b/src/java/org/apache/fulcrum/factory/Factory.java
index bb7e7b4..1014512 100644
--- a/src/java/org/apache/fulcrum/factory/Factory.java
+++ b/src/java/org/apache/fulcrum/factory/Factory.java
@@ -29,7 +29,6 @@ package org.apache.fulcrum.factory;
*
* @author <a href="mailto:[email protected]">Ilkka Priha</a>
* @author <a href="mailto:[email protected]">Stephen McConnell</a>
- * @version $Id$
*/
public interface Factory<T>
{
diff --git a/src/java/org/apache/fulcrum/factory/FactoryException.java
b/src/java/org/apache/fulcrum/factory/FactoryException.java
index d87033b..fccab13 100644
--- a/src/java/org/apache/fulcrum/factory/FactoryException.java
+++ b/src/java/org/apache/fulcrum/factory/FactoryException.java
@@ -23,7 +23,6 @@ package org.apache.fulcrum.factory;
* Exception thrown when there is a problem with the FactoryService
*
* @author <a href="mailto:[email protected]">Eric Pugh</a>
- * @version $Id$
*/
public class FactoryException extends Exception {
/**
@@ -34,38 +33,38 @@ public class FactoryException extends Exception {
/**
* Default constructor
*/
- public FactoryException()
+ public FactoryException()
{
super();
}
/**
* {@link java.lang.Exception#Exception(String, Throwable)}
- *
+ *
* @param message the message
* @param e the exception
*/
- public FactoryException(String message, Throwable e)
+ public FactoryException(String message, Throwable e)
{
super(message, e);
}
/**
* {@link java.lang.Exception#Exception(Throwable)}
- *
+ *
* @param e the exception to bubble up
*/
- public FactoryException(Throwable e)
+ public FactoryException(Throwable e)
{
super(e);
}
/**
* {@link java.lang.Exception#Exception(String)}
- *
+ *
* @param msg the message to bubble up
*/
- public FactoryException(String msg)
+ public FactoryException(String msg)
{
super(msg);
}
diff --git a/src/java/org/apache/fulcrum/factory/FactoryService.java
b/src/java/org/apache/fulcrum/factory/FactoryService.java
index 8f4347f..c4baea2 100644
--- a/src/java/org/apache/fulcrum/factory/FactoryService.java
+++ b/src/java/org/apache/fulcrum/factory/FactoryService.java
@@ -27,7 +27,6 @@ package org.apache.fulcrum.factory;
*
* @author <a href="mailto:[email protected]">Eric Pugh</a>
* @author <a href="mailto:[email protected]">Ilkka Priha</a>
- * @version $Id$
*/
public interface FactoryService
{
@@ -64,7 +63,7 @@ public interface FactoryService
*
* Class loaders are supported only if the isLoaderSupported
* method returns true. Otherwise the loader parameter is ignored.
- *
+ *
* @param <T> Type of the class
* @param className the name of the class.
* @param loader the class loader.
@@ -130,11 +129,11 @@ public interface FactoryService
* @param clazz the class.
* @param params an array containing the parameters of the method.
* @param signature an array containing the signature of the method.
- *
+ *
* @return {@inheritDoc} an array of signature classes. Note that in some
cases
* objects in the parameter array can be switched to the context
* of a different class loader
- *
+ *
* @throws ClassNotFoundException if any of the classes is not found.
*/
Class<?>[] getSignature(Class<?> clazz,
diff --git
a/src/java/org/apache/fulcrum/factory/utils/ObjectInputStreamForContext.java
b/src/java/org/apache/fulcrum/factory/utils/ObjectInputStreamForContext.java
index f7b2e40..3db021f 100644
--- a/src/java/org/apache/fulcrum/factory/utils/ObjectInputStreamForContext.java
+++ b/src/java/org/apache/fulcrum/factory/utils/ObjectInputStreamForContext.java
@@ -1,5 +1,7 @@
package org.apache.fulcrum.factory.utils;
+import java.io.IOException;
+
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -20,7 +22,6 @@ package org.apache.fulcrum.factory.utils;
*/
import java.io.InputStream;
-import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
@@ -28,7 +29,6 @@ import java.io.ObjectStreamClass;
* A deserialization stream for a specific class loader context.
*
* @author <a href="mailto:[email protected]">Ilkka Priha</a>
- * @version $Id$
*/
public class ObjectInputStreamForContext extends ObjectInputStream
{
@@ -39,7 +39,7 @@ public class ObjectInputStreamForContext extends
ObjectInputStream
/**
* Required to make satisfy the proxy methods
- *
+ *
* @throws IOException Generic exception
*/
public ObjectInputStreamForContext()
@@ -64,12 +64,13 @@ public class ObjectInputStreamForContext extends
ObjectInputStream
/**
* {@link java.io.ObjectInputStream#resolveClass(ObjectStreamClass)}
- *
+ *
* @param v ObjectStreamClass to resolve
* @return {@inheritDoc} class to resolve
* @throws IOException if object stream not found
* @throws ClassNotFoundException if class not found
*/
+ @Override
protected Class<?> resolveClass(ObjectStreamClass v)
throws IOException,
ClassNotFoundException
diff --git a/src/test/org/apache/fulcrum/factory/FactoryServiceTest.java
b/src/test/org/apache/fulcrum/factory/FactoryServiceTest.java
index c2b04c7..f1ca710 100644
--- a/src/test/org/apache/fulcrum/factory/FactoryServiceTest.java
+++ b/src/test/org/apache/fulcrum/factory/FactoryServiceTest.java
@@ -1,6 +1,7 @@
package org.apache.fulcrum.factory;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -33,11 +34,11 @@ import org.junit.jupiter.api.Test;
/**
* Basic tests of the fulcrum factory service
- *
+ *
* @author <a href="mailto:[email protected]">Eric Pugh</a>
* @author <a href="mailto:[email protected]">Stephen McConnell</a>
- *
- * @version $Id$
+ *
+ * @version $Id$
*/
public class FactoryServiceTest extends BaseUnit5Test
{
@@ -49,9 +50,9 @@ public class FactoryServiceTest extends BaseUnit5Test
{
setConfigurationFileName("src/test/TestComponentConfig.xml");
setRoleFileName("src/test/TestRoleConfig.xml");
- factoryService = (FactoryService)
this.lookup(FactoryService.class.getName());
+ factoryService = (FactoryService)
this.lookup(FactoryService.class.getName());
}
-
+
/**
* Class to test for Object getInstance(String)
* @throws Exception if factory fails to generate object
@@ -60,9 +61,9 @@ public class FactoryServiceTest extends BaseUnit5Test
public void testGetInstanceString() throws Exception
{
Object object = factoryService.getInstance("java.lang.StringBuilder");
- assertTrue(object instanceof StringBuilder);
+ assertInstanceOf(StringBuilder.class, object);
}
-
+
/**
* Class to test for Object getInstance(String, ClassLoader)
*
@@ -72,9 +73,9 @@ public class FactoryServiceTest extends BaseUnit5Test
public void testGetInstanceStringClassLoader() throws Exception
{
Object object = factoryService.getInstance("java.lang.StringBuilder",
StringBuilder.class.getClassLoader());
- assertTrue(object instanceof StringBuilder);
+ assertInstanceOf(StringBuilder.class, object);
}
-
+
/**
* Class to test for Object getInstance(String, Object[], String[])
* @throws Exception Generic exception
@@ -87,15 +88,15 @@ public class FactoryServiceTest extends BaseUnit5Test
String signature[] = new String[] { "java.lang.String" };
Object object = factoryService.getInstance("java.lang.StringBuilder",
params, signature);
- assertTrue(object instanceof StringBuilder);
+ assertInstanceOf(StringBuilder.class, object);
assertEquals(sourceValue, object.toString());
}
-
+
/**
* Class to test for Object getInstance(String, ClassLoader, Object[],
String[])
- *
+ *
* @throws Exception Generic exception
- */
+ */
@Test
public void testGetInstanceStringClassLoaderObjectArrayStringArray()
throws Exception
{
@@ -109,14 +110,14 @@ public class FactoryServiceTest extends BaseUnit5Test
StringBuilder.class.getClassLoader(),
params,
signature);
- assertTrue(object instanceof StringBuilder);
+ assertInstanceOf(StringBuilder.class, object);
assertEquals(sourceValue, object.toString());
}
-
+
/**
* Test if the loader is supported
- *
+ *
* @throws Exception Generic exception
*/
@Test
@@ -125,11 +126,11 @@ public class FactoryServiceTest extends BaseUnit5Test
// TODO Need to run a test where the loader is NOT supported.
assertTrue(factoryService.isLoaderSupported("java.lang.String"));
}
-
+
/**
* Test get signature
- *
+ *
* @throws Exception Generic exception
*/
@Test
@@ -143,7 +144,7 @@ public class FactoryServiceTest extends BaseUnit5Test
assertEquals(1, results.length);
assertTrue(results[0].equals(String.class));
- Integer sourceValueInteger = new Integer(10);
+ Integer sourceValueInteger = Integer.valueOf(10);
params[0] = sourceValueInteger;
signature[0] = "java.lang.Integer";
results = factoryService.getSignature(ArrayList.class, params,
signature);