blob: 1ccd9b725a502b54db03f5f8cc714d100de984a9 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../jacoco-resources/report.gif" type="image/gif"/><title>DefaultFactoryService.java</title><link rel="stylesheet" href="../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../index.html" class="el_report">Fulcrum Factory</a> &gt; <a href="index.source.html" class="el_package">org.apache.fulcrum.factory</a> &gt; <span class="el_source">DefaultFactoryService.java</span></div><h1>DefaultFactoryService.java</h1><pre class="source lang-java linenums">package org.apache.fulcrum.factory;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* &quot;License&quot;); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* &quot;AS IS&quot; BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.avalon.framework.activity.Disposable;
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=&quot;factory&quot; lifestyle=&quot;singleton&quot; avalon.service
* type=&quot;org.apache.fulcrum.factory.FactoryService&quot;
*
* @author &lt;a href=&quot;mailto:epugh@upstate.com&quot;&gt;Eric Pugh&lt;/a&gt;
* @author &lt;a href=&quot;mailto:ilkka.priha@simsoft.fi&quot;&gt;Ilkka Priha&lt;/a&gt;
* @author &lt;a href=&quot;mailto:mcconnell@apache.org&quot;&gt;Stephen McConnell&lt;/a&gt;
* @version $Id$
*
*/
<span class="fc" id="L51">public class DefaultFactoryService extends AbstractLogEnabled</span>
implements FactoryService, Configurable, Initializable, Disposable {
/**
* The property specifying a set of additional class loaders.
*/
private static final String CLASS_LOADER = &quot;classloader&quot;;
/**
* The property prefix specifying additional object factories.
*/
private static final String OBJECT_FACTORY = &quot;object-factory&quot;;
/**
* The name of the default factory.
*/
protected static final String DEFAULT_FACTORY = &quot;default&quot;;
/**
* Primitive classes for reflection of constructors.
*/
<span class="fc" id="L72"> private static HashMap&lt;String, Class&lt;?&gt;&gt; primitiveClasses = new HashMap&lt;String, Class&lt;?&gt;&gt;(8);</span>
{
<span class="fc" id="L75"> primitiveClasses.put(Boolean.TYPE.toString(), Boolean.TYPE);</span>
<span class="fc" id="L76"> primitiveClasses.put(Character.TYPE.toString(), Character.TYPE);</span>
<span class="fc" id="L77"> primitiveClasses.put(Byte.TYPE.toString(), Byte.TYPE);</span>
<span class="fc" id="L78"> primitiveClasses.put(Short.TYPE.toString(), Short.TYPE);</span>
<span class="fc" id="L79"> primitiveClasses.put(Integer.TYPE.toString(), Integer.TYPE);</span>
<span class="fc" id="L80"> primitiveClasses.put(Long.TYPE.toString(), Long.TYPE);</span>
<span class="fc" id="L81"> primitiveClasses.put(Float.TYPE.toString(), Float.TYPE);</span>
<span class="fc" id="L82"> primitiveClasses.put(Double.TYPE.toString(), Double.TYPE);</span>
}
/**
* temporary storage of class names between configure and initialize
*/
private String[] loaderNames;
/**
* Additional class loaders.
*/
<span class="fc" id="L92"> private ArrayList&lt;ClassLoader&gt; classLoaders = new ArrayList&lt;ClassLoader&gt;();</span>
/**
* Customized object factories.
*/
<span class="fc" id="L96"> private ConcurrentHashMap&lt;String, Factory&lt;?&gt;&gt; objectFactories = new ConcurrentHashMap&lt;String, Factory&lt;?&gt;&gt;();</span>
/**
* Customized object factory classes.
*/
<span class="fc" id="L100"> private ConcurrentHashMap&lt;String, String&gt; objectFactoryClasses = new ConcurrentHashMap&lt;String, String&gt;();</span>
/**
* Gets the class of a primitive type.
*
* @param type a primitive type.
* @return the corresponding class, or null.
*/
protected static Class&lt;?&gt; getPrimitiveClass(String type)
{
<span class="fc" id="L110"> return primitiveClasses.get(type);</span>
}
/**
* Gets an instance of a named class.
*
* @param className the name of the class.
* @return the instance.
* @throws FactoryException if instantiation fails.
*/
@Override
public &lt;T&gt; T getInstance(String className) throws FactoryException
{
<span class="pc bpc" id="L123" title="1 of 2 branches missed."> if (className == null) {</span>
<span class="nc" id="L124"> throw new FactoryException(&quot;Missing String className&quot;);</span>
}
<span class="fc" id="L126"> Factory&lt;T&gt; factory = getFactory(className);</span>
<span class="pc bpc" id="L127" title="1 of 2 branches missed."> if (factory == null) {</span>
Class&lt;T&gt; clazz;
try {
<span class="fc" id="L130"> clazz = loadClass(className);</span>
<span class="nc" id="L131"> } catch (ClassNotFoundException x) {</span>
<span class="nc" id="L132"> throw new FactoryException(&quot;Instantiation failed for class &quot; + className, x);</span>
<span class="fc" id="L133"> }</span>
<span class="fc" id="L134"> return getInstance(clazz);</span>
} else {
<span class="nc" id="L136"> return factory.getInstance();</span>
}
}
/**
* Gets an instance of a named class using a specified class loader.
*
* &lt;p&gt;
* 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 &lt;T&gt; T getInstance(String className, ClassLoader loader) throws FactoryException
{
<span class="fc" id="L155"> Factory&lt;T&gt; factory = getFactory(className);</span>
<span class="pc bpc" id="L156" title="1 of 2 branches missed."> if (factory == null) {</span>
<span class="pc bpc" id="L157" title="1 of 2 branches missed."> if (loader != null) {</span>
Class&lt;T&gt; clazz;
try {
<span class="nc" id="L160"> clazz = loadClass(className, loader);</span>
<span class="nc" id="L161"> } catch (ClassNotFoundException x) {</span>
<span class="nc" id="L162"> throw new FactoryException(&quot;Instantiation failed for class &quot; + className, x);</span>
<span class="nc" id="L163"> }</span>
<span class="nc" id="L164"> return getInstance(clazz);</span>
} else {
<span class="fc" id="L166"> return getInstance(className);</span>
}
} else {
<span class="nc" id="L169"> return factory.getInstance(loader);</span>
}
}
/**
* 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 &lt;T&gt; T getInstance(String className, Object[] params, String[] signature) throws FactoryException
{
<span class="fc" id="L187"> Factory&lt;T&gt; factory = getFactory(className);</span>
<span class="pc bpc" id="L188" title="1 of 2 branches missed."> if (factory == null) {</span>
Class&lt;T&gt; clazz;
try {
<span class="fc" id="L191"> clazz = loadClass(className);</span>
<span class="nc" id="L192"> } catch (ClassNotFoundException x) {</span>
<span class="nc" id="L193"> throw new FactoryException(&quot;Instantiation failed for class &quot; + className, x);</span>
<span class="fc" id="L194"> }</span>
<span class="fc" id="L195"> return getInstance(clazz, params, signature);</span>
} else {
<span class="nc" id="L197"> return factory.getInstance(params, signature);</span>
}
}
/**
* 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.
*
* &lt;p&gt;
* Class loaders are supported only if the isLoaderSupported method returns
* true. Otherwise the loader parameter is ignored.
* &lt;/p&gt;
*
* @param &lt;T&gt; 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 &lt;T&gt; T getInstance(String className, ClassLoader loader, Object[] params, String[] signature)
throws FactoryException
{
<span class="fc" id="L223"> Factory&lt;T&gt; factory = getFactory(className);</span>
<span class="pc bpc" id="L224" title="1 of 2 branches missed."> if (factory == null) {</span>
<span class="pc bpc" id="L225" title="1 of 2 branches missed."> if (loader != null) {</span>
Class&lt;T&gt; clazz;
try {
<span class="nc" id="L228"> clazz = loadClass(className, loader);</span>
<span class="nc" id="L229"> } catch (ClassNotFoundException x) {</span>
<span class="nc" id="L230"> throw new FactoryException(&quot;Instantiation failed for class &quot; + className, x);</span>
<span class="nc" id="L231"> }</span>
<span class="nc" id="L232"> return getInstance(clazz, params, signature);</span>
} else {
<span class="fc" id="L234"> return getInstance(className, params, signature);</span>
}
} else {
<span class="nc" id="L237"> return factory.getInstance(loader, params, signature);</span>
}
}
/**
* 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
{
<span class="fc" id="L251"> Factory&lt;?&gt; factory = getFactory(className);</span>
<span class="pc bpc" id="L252" title="1 of 2 branches missed."> return factory != null ? factory.isLoaderSupported() : true;</span>
}
/**
* Gets an instance of a specified class.
*
* @param &lt;T&gt; Type of the class
* @param clazz the class.
* @return the instance.
* @throws FactoryException if instantiation fails.
*/
@Override
public &lt;T&gt; T getInstance(Class&lt;T&gt; clazz) throws FactoryException
{
try {
<span class="fc" id="L267"> return clazz.newInstance();</span>
<span class="nc" id="L268"> } catch (Exception x) {</span>
<span class="nc" id="L269"> throw new FactoryException(&quot;Instantiation failed for &quot; + clazz.getName(), x);</span>
}
}
/**
* 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 &lt;T&gt; 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 &lt;T&gt; T getInstance(Class&lt;T&gt; clazz, Object params[], String signature[])
throws FactoryException
{
/* Try to construct. */
try {
<span class="fc" id="L290"> Class&lt;?&gt;[] sign = getSignature(clazz, params, signature);</span>
<span class="fc" id="L291"> return clazz.getConstructor(sign).newInstance(params);</span>
<span class="nc" id="L292"> } catch (Exception x) {</span>
<span class="nc" id="L293"> throw new FactoryException(&quot;Instantiation failed for &quot; + clazz.getName(), x);</span>
}
}
/**
* 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&lt;?&gt;[] getSignature(Class&lt;?&gt; clazz, Object params[], String signature[])
throws ClassNotFoundException
{
<span class="pc bpc" id="L312" title="1 of 2 branches missed."> if (signature != null) {</span>
/* We have parameters. */
ClassLoader tempLoader;
<span class="fc" id="L315"> ClassLoader loader = clazz.getClassLoader();</span>
<span class="fc" id="L316"> Class&lt;?&gt;[] sign = new Class[signature.length];</span>
<span class="fc bfc" id="L317" title="All 2 branches covered."> for (int i = 0; i &lt; signature.length; i++) {</span>
/* Check primitive types. */
<span class="fc" id="L319"> sign[i] = getPrimitiveClass(signature[i]);</span>
<span class="pc bpc" id="L320" title="1 of 2 branches missed."> if (sign[i] == null) {</span>
/* Not a primitive one, continue building. */
<span class="pc bpc" id="L322" title="1 of 2 branches missed."> if (loader != null) {</span>
/* Use the class loader of the target object. */
<span class="nc" id="L324"> sign[i] = loader.loadClass(signature[i]);</span>
<span class="nc" id="L325"> tempLoader = sign[i].getClassLoader();</span>
<span class="nc bnc" id="L326" title="All 4 branches missed."> if (params[i] != null &amp;&amp; tempLoader != null</span>
<span class="nc bnc" id="L327" title="All 2 branches missed."> &amp;&amp; !tempLoader.equals(params[i].getClass().getClassLoader())) {</span>
/*
* The class uses a different class loader, switch the parameter.
*/
<span class="nc" id="L331"> params[i] = switchObjectContext(params[i], loader);</span>
}
} else {
/* Use the default class loader. */
<span class="fc" id="L335"> sign[i] = loadClass(signature[i]);</span>
}
}
}
<span class="fc" id="L339"> return sign;</span>
} else {
<span class="nc" id="L341"> return null;</span>
}
}
/**
* 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)
{
<span class="nc" id="L355"> ByteArrayOutputStream bout = new ByteArrayOutputStream();</span>
try
{
<span class="nc" id="L359"> ObjectOutputStream out = new ObjectOutputStream(bout);</span>
<span class="nc" id="L360"> out.writeObject(object);</span>
<span class="nc" id="L361"> out.flush();</span>
}
<span class="nc" id="L363"> catch (IOException x) </span>
{
<span class="nc" id="L365"> return object;</span>
<span class="nc" id="L366"> }</span>
<span class="nc" id="L368"> ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());</span>
<span class="nc" id="L369"> ObjectInputStreamForContext in = null;</span>
try
{
<span class="nc" id="L373"> in = new ObjectInputStreamForContext(bin, loader);</span>
<span class="nc" id="L374"> return in.readObject();</span>
}
<span class="nc" id="L376"> catch (Exception x) </span>
{
<span class="nc" id="L378"> return object;</span>
}
finally
{
<span class="nc bnc" id="L382" title="All 2 branches missed."> if (in != null) </span>
{
try
{
<span class="nc" id="L386"> in.close();</span>
}
<span class="nc" id="L388"> catch (IOException e) </span>
{
// close quietly
<span class="nc" id="L391"> }</span>
}
}
}
/**
* 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(&quot;unchecked&quot;)
protected &lt;T&gt; Class&lt;T&gt; loadClass(String className) throws ClassNotFoundException
{
<span class="fc" id="L406"> ClassLoader loader = this.getClass().getClassLoader();</span>
try
{
Class&lt;T&gt; clazz;
<span class="pc bpc" id="L411" title="1 of 2 branches missed."> if (loader != null) </span>
{
<span class="fc" id="L413"> clazz = (Class&lt;T&gt;) loader.loadClass(className);</span>
}
else
{
<span class="nc" id="L417"> clazz = (Class&lt;T&gt;) Class.forName(className);</span>
}
<span class="fc" id="L420"> return clazz;</span>
}
<span class="nc" id="L422"> catch (ClassNotFoundException x) </span>
{
/* Go through additional loaders. */
<span class="nc bnc" id="L425" title="All 2 branches missed."> for (ClassLoader l : classLoaders) </span>
{
try
{
<span class="nc" id="L429"> return (Class&lt;T&gt;) l.loadClass(className);</span>
}
<span class="nc" id="L431"> catch (ClassNotFoundException xx) </span>
{
// continue
}
<span class="nc" id="L435"> }</span>
/* Give up. */
<span class="nc" id="L437"> throw x;</span>
}
}
/**
* 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(&quot;unchecked&quot;)
protected &lt;T&gt; Class&lt;T&gt; loadClass(String className, ClassLoader loader) throws ClassNotFoundException
{
<span class="nc bnc" id="L452" title="All 2 branches missed."> if (loader != null) </span>
{
<span class="nc" id="L454"> return (Class&lt;T&gt;) loader.loadClass(className);</span>
}
else
{
<span class="nc" id="L458"> return loadClass(className);</span>
}
}
/**
* 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(&quot;unchecked&quot;)
protected &lt;T&gt; Factory&lt;T&gt; getFactory(String className) throws FactoryException
{
<span class="fc" id="L473"> Factory&lt;T&gt; factory = (Factory&lt;T&gt;) objectFactories.get(className);</span>
<span class="pc bpc" id="L474" title="1 of 2 branches missed."> if (factory == null) </span>
{
// No named factory for this; try the default, if one exists
<span class="fc" id="L477"> factory = (Factory&lt;T&gt;) objectFactories.get(DEFAULT_FACTORY);</span>
}
<span class="pc bpc" id="L480" title="1 of 2 branches missed."> if (factory == null) {</span>
/* Not yet instantiated... */
<span class="fc" id="L483"> String factoryClass = objectFactoryClasses.get(className);</span>
<span class="pc bpc" id="L484" title="1 of 2 branches missed."> if (factoryClass == null) </span>
{
<span class="fc" id="L486"> factoryClass = objectFactoryClasses.get(DEFAULT_FACTORY);</span>
}
<span class="pc bpc" id="L489" title="1 of 2 branches missed."> if (factoryClass == null) {</span>
<span class="fc" id="L490"> return null;</span>
}
try {
<span class="nc" id="L494"> factory = getInstance(factoryClass);</span>
<span class="nc" id="L495"> factory.init(className);</span>
}
<span class="nc" id="L497"> catch (ClassCastException x) </span>
{
<span class="nc" id="L499"> throw new FactoryException(&quot;Incorrect factory &quot; + factoryClass + &quot; for class &quot; + className, x);</span>
<span class="nc" id="L500"> }</span>
<span class="nc" id="L502"> Factory&lt;T&gt; _factory = (Factory&lt;T&gt;) objectFactories.putIfAbsent(className, factory);</span>
<span class="nc bnc" id="L503" title="All 2 branches missed."> if (_factory != null) </span>
{
// Already created - take first instance
<span class="nc" id="L506"> factory = _factory;</span>
}
}
<span class="nc" id="L510"> return factory;</span>
}
// ---------------- 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
{
<span class="fc" id="L522"> final Configuration[] loaders = conf.getChildren(CLASS_LOADER);</span>
<span class="pc bpc" id="L523" title="1 of 2 branches missed."> if (loaders != null) </span>
{
<span class="fc" id="L525"> loaderNames = new String[loaders.length];</span>
<span class="pc bpc" id="L526" title="1 of 2 branches missed."> for (int i = 0; i &lt; loaders.length; i++) </span>
{
<span class="nc" id="L528"> loaderNames[i] = loaders[i].getValue();</span>
}
}
<span class="fc" id="L532"> final Configuration factories = conf.getChild(OBJECT_FACTORY, false);</span>
<span class="pc bpc" id="L533" title="1 of 2 branches missed."> if (factories != null) </span>
{
// Store the factory to the table as a string and
// instantiate it by using the service when needed.
<span class="nc" id="L537"> Configuration[] nameVal = factories.getChildren();</span>
<span class="nc bnc" id="L538" title="All 2 branches missed."> for (Configuration entry : nameVal)</span>
<span class="nc" id="L539"> objectFactoryClasses.put(entry.getName(), entry.getValue());</span>
}
<span class="fc" id="L542"> }</span>
/**
* 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
{
<span class="pc bpc" id="L553" title="1 of 2 branches missed."> if (loaderNames != null) </span>
{
<span class="pc bpc" id="L555" title="1 of 2 branches missed."> for (String className : loaderNames) </span>
{
try
{
<span class="nc" id="L559"> ClassLoader loader = (ClassLoader) loadClass(className).newInstance();</span>
<span class="nc" id="L560"> classLoaders.add(loader);</span>
}
<span class="nc" id="L562"> catch (Exception x) </span>
{
<span class="nc" id="L564"> throw new Exception(&quot;No such class loader '&quot; + className + &quot;' for DefaultFactoryService&quot;, x);</span>
<span class="nc" id="L565"> }</span>
}
<span class="fc" id="L567"> loaderNames = null;</span>
}
<span class="fc" id="L569"> }</span>
/**
* Avalon component lifecycle method Clear lists and maps
*/
@Override
public void dispose()
{
<span class="fc" id="L577"> objectFactories.clear();</span>
<span class="fc" id="L578"> objectFactoryClasses.clear();</span>
<span class="fc" id="L579"> classLoaders.clear();</span>
<span class="fc" id="L580"> }</span>
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.6.202009150832</span></div></body></html>