All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.anotheria.anoprise.metafactory.MetaFactory Maven / Gradle / Ivy

Go to download

Collection of utils for different enterprise class projects. Among other stuff contains Caches, Mocking, DualCrud, MetaFactory and SessionDistributorService. Visit https://opensource.anotheria.net for details.

There is a newer version: 4.0.0
Show newest version
package net.anotheria.anoprise.metafactory;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;

import net.anotheria.moskito.core.util.storage.Storage;

/**
 * Utility class for dynamic instance creation of multiple possible instance types.
 * 
 * @author lrosenberg
 * @author dmetelin
 */
public class MetaFactory {

	/**
	 * Storage for instances.
	 */
	private static Map instances;
	/**
	 * Storage for aliases.
	 */
	private static Map aliases;
	/**
	 * Storage for factory classes.
	 */
	@SuppressWarnings("rawtypes")
	private static Map factoryClasses;
	/**
	 * Storage for factories.
	 */
	private static Map> factories;

	private static List otfConflictResolvers;

	/**
	 * List of additional resolvers for aliases.
	 */
	private static List resolverList;

	/**
	 * Factory resolver by service class name
	 */
	private static FactoryResolver factoryResolver;

	static {
		reset();
	}

	/**
	 * Performs a complete reset of the inner state. Useful for unit testing to call @AfterClass or @After.
	 */
	public static void reset() {
		resolverList = new CopyOnWriteArrayList();
		resolverList.add(new SystemPropertyResolver());
		resolverList.add(ConfigurableResolver.create());
		factoryResolver = ConfigurableFactoryResolver.create();
		factoryClasses = Storage.createConcurrentHashMapStorage("mf-factoryClasses");
		factories = Storage.createConcurrentHashMapStorage("mf-factories");
		aliases = Storage.createConcurrentHashMapStorage("mf-aliases");
		instances = Storage.createConcurrentHashMapStorage("mf-instances");
		otfConflictResolvers = new CopyOnWriteArrayList();
	}

	/**
	 * Performs reset of created instances for some service.
	 */
	public static  void resetInstances(Class pattern) {
		String className = pattern.getName();
		for (String key : instances.keySet())
			if (key.contains(className))
				instances.remove(key);
	}

	public static  T create(Class pattern, Extension extension) throws MetaFactoryException {
		return pattern.cast(_create(pattern, extension, null));
	}

	public static  T create(Class pattern) throws MetaFactoryException {
		return pattern.cast(create(pattern, Extension.NONE));
	}

	@SuppressWarnings("unchecked")
	private static  T _create(Class pattern, Extension extension, String name) throws MetaFactoryException {
		if (name==null)
			name = extension.toName(pattern);
		ServiceFactory factory = (ServiceFactory) factories.get(name);
		if (factory != null)
			return factory.create();		

		FactoryHolder factoryConfiguration = factoryClasses.get(name);		
		Class> clazz = factoryConfiguration != null ? factoryConfiguration.getFactoryClass() : null;
		if (clazz == null) {
			clazz = (Class>) factoryResolver.resolveFactory(name);
			if (clazz != null)
				addFactoryClass(name, clazz);
		}

		if (clazz == null){
			if (extension!=Extension.NONE)
				throw new FactoryNotFoundException(name);
			//attempt to dynamically load from reflections.
			Collection> implementations = OnTheFlyResolver.resolveOnTheFly(pattern);
			if (implementations==null)
				throw new FactoryNotFoundException(name);
			if (implementations.size()>1){
				for (OnTheFlyConflictResolver conflictResolver : otfConflictResolvers){
					Class resolved = conflictResolver.resolveConflict(implementations);
					if (resolved!=null){
						try{
							return resolved.newInstance();
						}catch(Exception e){
							throw new MetaFactoryException("Found implementations and picked ("+resolved+" by "+conflictResolver+"  but couldn't instantiate it "+e.getMessage(), e);
						}
					}
				}
				throw new MetaFactoryException("No configured factory and multiple subclasses found: "+implementations);
			}

			try{
				return implementations.iterator().next().newInstance();
			}catch(Exception e){
				throw new MetaFactoryException("Found implementation but couldn't instantiate it "+e.getMessage(), e);
			}
		}

		synchronized (factories) {
			factory = (ServiceFactory) factories.get(name);
			if (factory == null) {
				try {
					factory = clazz.newInstance();
					if (factory instanceof ParameterizedServiceFactory) {
						ParameterizedServiceFactory parameterizedFactory = (ParameterizedServiceFactory) factory;
						parameterizedFactory.setParameters(factoryConfiguration.getParameters());
					}
					
					factories.put(name, factory);
				} catch (IllegalAccessException e) {
					throw new FactoryInstantiationError(clazz, name, e.getMessage());
				} catch (InstantiationException e) {
					e.printStackTrace();
					throw new FactoryInstantiationError(clazz, name, e.getMessage());
				}
			}

		}
		return factory.create();
	}
	
	private static  T _create(final Class service, final String serviceKey) throws MetaFactoryException {
		@SuppressWarnings("unchecked")
		FactoryHolder factoryConfiguration = factoryClasses.get(serviceKey);
		if (factoryConfiguration == null)
			throw new FactoryNotFoundException(serviceKey);

		try {
			ServiceFactory factory = factoryConfiguration.getFactoryClass().newInstance();
			if (factory instanceof ParameterizedServiceFactory) {
				ParameterizedServiceFactory parameterizedFactory = (ParameterizedServiceFactory) factory;
				parameterizedFactory.setParameters(factoryConfiguration.getParameters());
			}

			return factory.create();
		} catch (IllegalAccessException e) {
			throw new FactoryInstantiationError(factoryConfiguration.getFactoryClass(), service.getName(), e.getMessage());
		} catch (InstantiationException e) {
			throw new FactoryInstantiationError(factoryConfiguration.getFactoryClass(), service.getName(), e.getMessage());
		}
	}

	public static  T get(Class pattern) throws MetaFactoryException {
		return get(pattern, Extension.NONE);
	}

	public static  T get(Class pattern, Extension extension) throws MetaFactoryException {

		out("get called, pattern: " + pattern + ", extension: " + extension);

		if (extension == null)
			extension = Extension.NONE;
		String name = extension.toName(pattern);
		out("name is " + name);

		name = resolveAlias(name);
		out("resolved alias to " + name);

		T instance = pattern.cast(instances.get(name));

		out("instance of " + name + " is: " + instance);

		if (instance != null)
			return instance;

		synchronized (instances) {
			instance = pattern.cast(instances.get(name));
			if (instance == null) {
				out("creating new instance of " + name);
				instance = pattern.cast(_create(pattern, extension, name));
				out("created new instance of " + name + " ---> " + instance);
				instances.put(name, instance);
			}
		}

		return instance;
	}
	
	public static  T get(final Class service, final String extension) throws MetaFactoryException {
		if (service == null)
			throw new IllegalArgumentException("service argument is null.");

		String innerExtension = extension != null ? "." + extension.replaceAll("\\.", "_").toLowerCase() : ".null";
		String serviceKey = service.getName() + innerExtension;

		T instance = service.cast(instances.get(serviceKey));
		if (instance != null)
			return instance;

		synchronized (instances) {
			instance = service.cast(instances.get(serviceKey));
			if (instance == null) {
				instance = service.cast(_create(service, serviceKey));
				instances.put(serviceKey, instance);
			}
		}

		return instance;
	}

	public static String resolveAlias(String name) {

		// first check resolvers
		synchronized (resolverList) {
			for (AliasResolver resolver : resolverList) {
				String resolved = resolver.resolveAlias(name);
				if (resolved != null)
					return resolveAlias(resolved);
			}
		}

		String alias = aliases.get(name);
		return alias == null ? name : resolveAlias(alias);
	}

	public static String resolveAlias(Class clazz) {
		return resolveAlias(clazz.getName());
	}

	public static void addAlias(String name, String alias) {
		aliases.put(alias, name);
	}

	public static  void addAlias(Class pattern, Extension nameExtension) {
		addAlias(pattern, nameExtension, null);
	}

	public static  void addAlias(Class pattern, Extension nameExt, Extension aliasExtension) {
		if (nameExt == null)
			nameExt = Extension.NONE;
		if (aliasExtension == null)
			aliasExtension = Extension.NONE;
		addAlias(nameExt.toName(pattern), aliasExtension.toName(pattern));
	}

	public static  void createOnTheFlyFactory(Class service, Extension extension, T serviceInstance) {
		OnTheFlyFactory factory = new OnTheFlyFactory(serviceInstance);
		factories.put(extension.toName(service), factory);
	}

	public static  void addFactoryClass(Class service, Extension extension, Class> factoryClass) {
		addFactoryClass(extension.toName(service), factoryClass);
	}

	public static  void addFactoryClass(String name, Class> factoryClass) {
		factoryClasses.put(name, new FactoryHolder(factoryClass, null));
	} 
	
	public static > void addParameterizedFactoryClass(final Class service, final String extension, final Class factoryClass, final Map parameters) {
		if (service == null)
			throw new IllegalArgumentException("service argument is null.");
		if (factoryClass == null)
			throw new IllegalArgumentException("factoryClass argument is null.");
		
		String innerExtension = extension != null ? "." + extension.replaceAll("\\.", "_").toLowerCase() : ".null";
		factoryClasses.put(service.getName() + innerExtension, new FactoryHolder(factoryClass, parameters));
	}

	/**
	 * Used for debug output.
	 * 
	 * @param o
	 *            output.
	 */
	private static void out(Object o) {
		// System.out.println("[MetaFactory] "+o);
	}

	public static void debugDumpAliasMap() {
		Set keys = aliases.keySet();
		for (String key : keys) {
			System.out.println(key + " = " + aliases.get(key));
		}
	}

	public static void addAliasResolver(AliasResolver resolver) {
		synchronized (resolverList) {
			for (int i = 0; i < resolverList.size(); i++) {
				AliasResolver someResolver = resolverList.get(i);
				if (resolver.getPriority() < someResolver.getPriority()) {
					resolverList.add(i, resolver);
					return;
				}
			}
			resolverList.add(resolver);
		}
	}

	public static List getAliasResolverList() {
		synchronized (resolverList) {
			ArrayList ret = new ArrayList();
			ret.addAll(resolverList);
			return ret;
		}
	}

	/**
	 * Adds a new conflict resolver to be used whenever onthefly impl lookup returns multiple candidates.
	 * @param otfCR
	 */
	public static void addOnTheFlyConflictResolver(OnTheFlyConflictResolver otfCR){
		otfConflictResolvers.add(otfCR);
	}
	
	/**
	 * Factory configuration holder.
	 * 
	 * @author Alexandr Bolbat
	 *
	 * @param 
	 */
	private static class FactoryHolder {

		/**
		 * Factory class.
		 */
		private final Class> factoryClass;

		/**
		 * Factory parameters.
		 */
		private final Map parameters;

		/**
		 * Default constructor.
		 * 
		 * @param aFactoryClass
		 *            factory class
		 * @param aParameters
		 *            factory parameters, can be null
		 */
		protected FactoryHolder(final Class> aFactoryClass, final Map aParameters) {
			if (aFactoryClass == null)
				throw new IllegalArgumentException("aFactoryClass argument is null.");

			this.factoryClass = aFactoryClass;
			this.parameters = aParameters;
		}

		public Class> getFactoryClass() {
			return factoryClass;
		}

		public Map getParameters() {
			return parameters;
		}

		@Override
		public String toString() {
			StringBuilder builder = new StringBuilder();
			builder.append("FactoryHolder [factoryClass=");
			builder.append(factoryClass);
			builder.append(", parameters=");
			builder.append(parameters);
			builder.append("]");
			return builder.toString();
		}

	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy