/*
* Copyright Technophobia Ltd 2012
*
* This file is part of Substeps.
*
* Substeps is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Substeps is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Substeps. If not, see <http://www.gnu.org/licenses/>.
*/
package com.technophobia.substeps.execution;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Maps;
/*
* Copyright Technophobia Ltd 2012
*
* This file is part of Substeps.
*
* Substeps is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Substeps is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Substeps. If not, see <http://www.gnu.org/licenses/>.
*/
public class ImplementationCache implements MethodExecutor {
protected final Map<Class<?>, Object> instanceMap;
public ImplementationCache() {
instanceMap = Maps.newHashMap();
}
public void addImplementationClasses(final Class<?>... implementationClasses) {
if (implementationClasses != null) {
for (final Class<?> implementationClass : implementationClasses) {
if (!instanceMap.containsKey(implementationClass)) {
instanceMap.put(implementationClass, instantiate(implementationClass));
}
}
}
}
private Object instantiate(final Class<?> implementationClass) {
try {
return implementationClass.newInstance();
} catch (final InstantiationException ex) {
throw new IllegalStateException("Could not create instance of " + implementationClass, ex);
} catch (final IllegalAccessException ex) {
throw new IllegalStateException("Could not create instance of " + implementationClass, ex);
}
}
/*
* (non-Javadoc)
*
* @see
* com.technophobia.substeps.execution.MethodExecutor#executeMethods(java
* .util.List)
*/
public void executeMethods(final List<Method> methods) throws Exception {
for (final Method method : methods) {
// TODO - curious about the findSuitableInstancesOf ? won't
// method.getDeclaringClass be ok??
for (final Object object : findSuitableInstancesOf(method.getDeclaringClass())) {
method.invoke(object);
}
}
}
private Collection<Object> findSuitableInstancesOf(final Class<?> methodClass) {
final Collection<Class<?>> suitableClassDefs = Collections2.filter(instanceMap.keySet(),
new Predicate<Class<?>>() {
public boolean apply(final Class<?> instanceClass) {
return methodClass.isAssignableFrom(instanceClass);
}
});
return Collections2.transform(suitableClassDefs, Functions.forMap(instanceMap));
}
/*
* (non-Javadoc)
*
* @see
* com.technophobia.substeps.execution.MethodExecutor#executeMethod(java
* .lang.Class, java.lang.reflect.Method, java.lang.Object[])
*/
public void executeMethod(final Class<?> targetClass, final Method targetMethod, final Object[] methodArgs)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
addImplementationClasses(targetClass);
if (methodArgs != null) {
targetMethod.invoke(instanceMap.get(targetClass), methodArgs);
} else {
targetMethod.invoke(instanceMap.get(targetClass));
}
}
@SuppressWarnings("unchecked")
public <T> T getImplementation(Class<T> implementationClass) {
addImplementationClasses(implementationClass);
return (T) instanceMap.get(implementationClass);
}
}