package org.marketcetera.module;
import org.marketcetera.util.log.I18NBoundMessage;
import org.marketcetera.util.log.ActiveLocale;
import org.marketcetera.util.misc.ClassVersion;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/* $License$ */
/**
* A factory for creating module instance(s). Each module
* factory must have an public constructor that doesn't
* accept any arguments.
* <p>
* Instances of module factory are created automatically
* by the {@link ModuleManager} when {@link ModuleManager#init() initializing}.
* The module manager uses the {@link java.util.ServiceLoader} mechanism for
* discovering <code>ModuleFactory</code> and loading implementations.
* <p>
* Only a single instance of <code>ModuleFactory</code> implementation exists
* within the module manager. However, do note that multiple instances
* may be created and then discarded when
* {@link org.marketcetera.module.ModuleManager#refresh() reloading}
* the factories.
* <p>
* If the factory does not support
* {@link #isMultipleInstances() multiple}
* module instances, a singleton module instance is
* created, when the module factory is loaded, <b>if</b> the
* factory doesn't need any parameters to create module
* instance. If the factory does need parameters to create
* module instance, the instance needs to manually created
* by the user via the <code>ModuleManager</code> by supplying the
* value of those parameters.
* <p>
* If the factory supports modules that can be
* {@link #isAutoInstantiate() auto-instantiated} its
* create method should be able to create new module
* instances by accepting the module instance URN as the
* only parameter to its {@link #create(Object[])} method.
*
* And the {@link #getParameterTypes()} method should return
* a List that contains <code>ModuleURN.class</code> as its first element,
* otherwise an error is thrown when initializing the factory.
* <p>
* {@link #isAutoInstantiate()} value is ignored when the factory
* doesn't support multiple instances.
*
* @author anshul@marketcetera.com
* @version $Id: ModuleFactory.java 16841 2014-02-20 19:59:04Z colin $
* @since 1.0.0
*/
@ClassVersion("$Id: ModuleFactory.java 16841 2014-02-20 19:59:04Z colin $") //$NON-NLS-1$
public abstract class ModuleFactory {
/**
* Creates an instance of the factory, given the parameters.
* <p>
* This operation is never invoked concurrently. The module framework
* ensures that only a single instance of this operation is active in
* a thread at any point in time. If this operation is slow, it may delay
* creation of other modules from the same provider.
*
* @param inParameters the parameters for creating the module, the types
* of these parameters match those returned by
* {@link #getParameterTypes()}
*
* @return the module instance
*
* @throws ModuleCreationException if there were errors creating
* the module instance.
*/
public abstract Module create(Object... inParameters)
throws ModuleCreationException;
/**
* Returns the list of parameter types as expected by the
* {@link #create(Object[])} method above.
*
* @return the list of parameter types, cannot be null.
*/
public final Class<?>[] getParameterTypes() {
return mParameterTypes.clone();
}
/**
* Returns true if factory supports multiple module instances
*
* @return true if the factory supports multiple module instances
*/
public final boolean isMultipleInstances() {
return mMultipleInstances;
}
/**
* Returns true if the factory supports auto-instantiated modules.
* ie. modules that are automatically instantiated by the framework
* when a request to create a data flow references their URN
* (with the instance name) when they do not exist.
* The framework extracts the instance name and supplies it to the
* factory to instantiate the module.
* <p>
* If a factory supports auto-instantiated modules, it should be
* able to create new module instances by accepting a single string
* attribute the value of which is the module instance URN as
* requested in the original data flow request.
* Such factory classes's {@link #getParameterTypes()} should always
* return a list of size 1, only containing <code>ModuleURN.class</code>.
*
* This condition is verified when the factory is loaded by the
* module framework, and if this condition is not found to be true,
* the module framework fails to load the factory class.
*
* @return if the factory supports auto-instantiated modules.
*/
public final boolean isAutoInstantiate() {
return mAutoInstantiate;
}
/**
* Returns the name of the module provider. A module
* provider URI has the following form.<br/>
* <code>metc:provType:providerName</code>
*
* @return the provider's URN
*/
public final ModuleURN getProviderURN() {
return mURN;
}
/**
* Returns the localized description of this module.
*
* @return the localized description
*/
public final I18NBoundMessage getProviderDescription() {
return mDescription;
}
/**
* Creates an instance.
*
* @param inURN the provider URN.
* @param inDescription the provider's description
* @param inMultipleInstances if the factory supports multiple
* module instances
* @param inAutoInstantiate if the factory supports auto-instantiated
* modules. This parameter is ignored if
* <code>inSupportsMultipleInstances</code> parameter is false. If this
* parameter is true, the factory should only need a parameter of
* type {@link ModuleURN} when creating new instances.
* @param inParameterTypes the types of parameters expected when creating
* new module instances via {@link #create(Object[])}
*/
protected ModuleFactory(ModuleURN inURN,
I18NBoundMessage inDescription,
boolean inMultipleInstances,
boolean inAutoInstantiate,
Class<?>... inParameterTypes) {
mURN = inURN;
mDescription = inDescription;
mMultipleInstances = inMultipleInstances;
mAutoInstantiate = inAutoInstantiate;
mParameterTypes =
inParameterTypes == null
? new Class[0]
: inParameterTypes.clone();
}
/**
* Returns the provider info describing the factory.
*
* @return the provider info for the factory.
*/
final ProviderInfo getProviderInfo() {
return new ProviderInfo(
getProviderURN(),
getParameterTypes(),
isMultipleInstances(),
isAutoInstantiate(),
getProviderDescription().getText(ActiveLocale.getLocale()),
mLock.isLocked(),
mLock.getQueueLength());
}
/**
* Returns the lock that should be used for serializing
* factory operations.
*
* @return the factory lock.
*/
final Lock getLock() {
return mLock;
}
private final ReentrantLock mLock = new ReentrantLock();
private final ModuleURN mURN;
private final I18NBoundMessage mDescription;
private final boolean mMultipleInstances;
private final boolean mAutoInstantiate;
private final Class<?>[] mParameterTypes;
}