package com.idega.repository.data; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.idega.util.ArrayUtil; import com.idega.util.datastructures.HashMatrix; /** * <p>Title: idegaWeb</p> * <p>Description: </p> * <p>Copyright: Copyright (c) 2003</p> * <p>Company: idega Software</p> * @author <a href="thomas@idega.is">Thomas Hilbig</a> * @version 1.0 * Created on Jun 14, 2004 */ public class ImplementorRepository implements Singleton { private static Instantiator instantiator = new Instantiator() { @Override public Object getInstance() { return new ImplementorRepository(); } }; private static final String GENERAL = "general"; static public ImplementorRepository getInstance() { return (ImplementorRepository) SingletonRepository.getRepository().getInstance(ImplementorRepository.class, instantiator); } private HashMatrix<String, String, List<String>> interfaceCallerImplementor = null; protected ImplementorRepository(){ // should not be initialized by constructor } public <T, C, I extends T> void addImplementorForCaller(Class<T> interfaceClass, Class<C> callerClass, Class<I> implementorClass) { if (this.interfaceCallerImplementor == null) { this.interfaceCallerImplementor = new HashMatrix<String, String, List<String>>(); } String interfaceClassName = interfaceClass.getName(); String callerClassName = (callerClass == null) ? GENERAL : callerClass.getName(); String implementorClassName = implementorClass.getName(); if (this.interfaceCallerImplementor.containsKey(interfaceClassName, callerClassName)) { List<String> implementorNames = this.interfaceCallerImplementor.get(interfaceClassName, callerClassName); if (implementorNames.contains(implementorClassName)) { // already added return; } // add the name to the existing list implementorNames.add(implementorClassName); } else{ // new entry List<String> implementorNames = new ArrayList<String>(1); implementorNames.add(implementorClassName); this.interfaceCallerImplementor.put(interfaceClassName, callerClassName, implementorNames); } } public <T, I extends T> void addImplementor(Class<T> interfaceClass, Class<I> implementationClass) { addImplementorForCaller(interfaceClass, null, implementationClass); } public <T, I extends T, C> I newInstance(Class<T> interfaceClass, Class<C> callerClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException { List<Class<I>> implementors = getValidImplementorClasses(interfaceClass, callerClass); // get the first one if (implementors == null) { throw new ClassNotFoundException("[ImplementorRepository] ImImplementor for interface " + interfaceClass.getName() + "could not be found"); } Class<I> implementorClass = implementors.get(0); return implementorClass.newInstance(); } public <T, I extends T, C> I newInstanceOrNull(Class<T> interfaceClass, Class<C> callerClass) { try { return newInstance(interfaceClass, callerClass); } catch (ClassNotFoundException e) { return null; } catch (InstantiationException e) { return null; } catch (IllegalAccessException e) { return null; } } public <T, I extends T> List<I> newInstances(Class<T> interfaceClass, Class<?> callerClass) { List<Class<I>> implementors = getValidImplementorClasses(interfaceClass, callerClass); List<I> instances = null; if (implementors == null) { // return empty list return new ArrayList<I>(0); } instances = new ArrayList<I>(implementors.size()); for (Iterator<Class<I>> iterator = implementors.iterator(); iterator.hasNext();) { Class<I> aClass = iterator.next(); try { I object = aClass.newInstance(); instances.add(object); } catch (InstantiationException e) { // ignore } catch (IllegalAccessException e) { // ignore } } return instances; } public <T, I extends T, C> Class<I> getAnyClassImpl(Class<T> interfaceClass, Class<C> callerClass) { List<Class<I>> validClasses = getValidImplementorClasses(interfaceClass, callerClass); if (validClasses == null || validClasses.isEmpty()) { return null; } return validClasses.get(0); } /** * * @param interfaceClass * @param callerClass * @return null or a non-empty list */ private <T, C> List<String> getImplementorNames(Class<T> interfaceClass, Class<C> callerClass) { if (this.interfaceCallerImplementor == null) { return null; } String interfaceClassName = interfaceClass.getName(); String callerClassName = callerClass.getName(); if (! this.interfaceCallerImplementor.containsKey(interfaceClassName, callerClassName)) { callerClassName = GENERAL; } List<String> implementors = this.interfaceCallerImplementor.get(interfaceClassName, callerClassName); if (implementors == null || implementors.isEmpty()) { return null; } return implementors; } public <T, I extends T, C> List<Class<I>> getValidImplementorClasses(Class<T> interfaceClass, Class<C> callerClass) { List<String> names = getImplementorNames(interfaceClass, callerClass); if (names == null) { return null; } List<Class<I>> classes = new ArrayList<Class<I>>(names.size()); for (Iterator<String> iterator = names.iterator(); iterator.hasNext();) { String name = iterator.next(); try { Class<I> implementorClass = RefactorClassRegistry.forName(name); classes.add(implementorClass); } catch (ClassNotFoundException e) { // do nothing, not very likely that a class is registered but doesn't exist e.printStackTrace(); } } if (classes.isEmpty()) { return null; } return classes; } /** * Checks if the caller class is considered to be of the specified type. * Use that method only for interfaces that are used as flags like Clonable. * If that method returns true it doesn't mean that you can cast an instance of * the callerClass to the specified class. * If you are going to perform a cast use the instanceOf check. * @param interfaceClass * @param callerClass * @return true if the callerClass is considered to be of the specified type. */ public <T, I extends T, C> boolean isTypeOf(Class<T> interfaceClass, Class<C> callerClass) { // first part: // does the same like "instanceOf" // // get all super classes and check for the interface List<Class<?>> classes = new ArrayList<Class<?>>(); Class<?> superClass = callerClass; while (superClass != null) { Class<?>[] interfaces = superClass.getInterfaces(); if (ArrayUtil.contains(interfaces,interfaceClass)) { // if the method is left at the place a cast could be done return true; } classes.add(superClass); superClass = superClass.getSuperclass(); } // second part: // not found? check if there are some registered implementors that are considered as interface implementors // Important note: You can't cast the caller to that type! You can only check if that class is of that type. List<Class<I>> implementorClasses = getValidImplementorClasses(interfaceClass, callerClass); if (implementorClasses == null) { return false; } for (Iterator<Class<I>> iterator = implementorClasses.iterator(); iterator.hasNext();) { Class<I> implementor = iterator.next(); if (classes.contains(implementor)) { return true; } } return false; } }