/**
* JBoss, Home of Professional Open Source
* Copyright ${year}, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.arquillian.rusheye.parser;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import javassist.util.proxy.MethodHandler;
import javassist.util.proxy.ProxyFactory;
import javassist.util.proxy.ProxyObject;
import org.arquillian.rusheye.suite.Configuration;
import org.arquillian.rusheye.suite.Mask;
import org.arquillian.rusheye.suite.Perception;
public class ConfigurationCompiler extends Configuration {
private static final Configuration DEFAULT_CONFIGURATION = new DefaultConfiguration();
private Deque<Configuration> customConfigurations = new LinkedList<Configuration>();
{
customConfigurations.push(DEFAULT_CONFIGURATION);
}
@SuppressWarnings("unchecked")
public static <T extends Configuration> T wrap(final T configuration, final Configuration... configurations) {
ProxyFactory f = new ProxyFactory();
f.setSuperclass(configuration.getClass());
Class<?> c = f.createClass();
T proxy;
try {
proxy = (T) c.newInstance();
} catch (Exception e) {
throw new IllegalStateException(e);
}
((ProxyObject) proxy).setHandler(new MethodHandler() {
Object instance = configuration;
ConfigurationCompiler configurationCompiler = new ConfigurationCompiler();
{
for (Configuration conf : configurations) {
configurationCompiler.pushConfiguration(conf);
}
configurationCompiler.pushConfiguration(configuration);
}
@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
final Class<?> declaringClass = thisMethod.getDeclaringClass();
if (declaringClass == Configuration.class) {
Method wrappedMethod = ConfigurationCompiler.class.getMethod(thisMethod.getName(),
thisMethod.getParameterTypes());
return wrappedMethod.invoke(configurationCompiler, args);
}
return thisMethod.invoke(instance, args);
}
});
return proxy;
}
public void pushConfiguration(Configuration configuration) {
customConfigurations.push(configuration);
}
@Override
public Perception getPerception() {
return new PerceptionCompiler().getCompiledPerception();
}
@Override
public void setPerception(Perception value) {
throw new UnsupportedOperationException();
}
@Override
public List<Mask> getMasks() {
List<Mask> masks = new LinkedList<Mask>();
for (Configuration configuration : customConfigurations) {
if (configuration.getMasks() != null && !configuration.getMasks().isEmpty()) {
masks.addAll(configuration.getMasks());
}
}
return masks;
}
public class PerceptionCompiler implements MethodHandler {
public Perception getCompiledPerception() {
ProxyFactory f = new ProxyFactory();
f.setSuperclass(Perception.class);
Class<?> c = f.createClass();
Perception perception;
try {
perception = (Perception) c.newInstance();
} catch (Exception e) {
throw new IllegalStateException(e);
}
((ProxyObject) perception).setHandler(this);
return perception;
}
@Override
public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
final String methodName = thisMethod.getName();
final Class<?> declaringClass = thisMethod.getDeclaringClass();
if (declaringClass == Perception.class) {
if (methodName.startsWith("getGlobalDifferencePixelAmount")
|| methodName.startsWith("getGlobalDifferencePercentage")) {
Object result = proceed.invoke(self, args);
return result;
} else if (methodName.startsWith("get")) {
Object result = evaluate(thisMethod, args);
return result;
}
}
throw new UnsupportedOperationException();
}
Object evaluate(Method thisMethod, Object[] args) throws Throwable {
for (Configuration configuration : customConfigurations) {
Perception perception = configuration.getPerception();
if (perception != null) {
Object result;
try {
result = thisMethod.invoke(perception, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
if (result != null) {
return result;
}
}
}
return null;
}
}
}