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);


Reply via email to