/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.axis2.transport.testkit.tests; import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.apache.axis2.transport.testkit.Adapter; import org.apache.commons.lang.builder.HashCodeBuilder; public class TestResource { private enum Status { UNRESOLVED, RESOLVED, SETUP, RECYCLED }; private interface Invocable { void execute(Object object) throws Exception; } private static class MethodInvocation implements Invocable { private final Method method; private final Object[] args; public MethodInvocation(Method method, Object[] args) { this.method = method; this.args = args; } public void execute(Object object) throws Exception { try { method.invoke(object, args); } catch (InvocationTargetException ex) { Throwable cause = ex.getCause(); if (cause instanceof Error) { throw (Error)cause; } else if (cause instanceof Exception) { throw (Exception)cause; } else { throw ex; } } } } private static class FieldResetter implements Invocable { private final Field field; public FieldResetter(Field field) { this.field = field; } public void execute(Object object) throws Exception { field.set(object, null); } } private final Object instance; private final Object target; private final Set<TestResource> directDependencies = new HashSet<TestResource>(); private final LinkedList<Invocable> initializers = new LinkedList<Invocable>(); private final List<Invocable> finalizers = new LinkedList<Invocable>(); private Status status = Status.UNRESOLVED; private boolean hasHashCode; private int hashCode; public TestResource(Object instance) { this.instance = instance; Object target = instance; while (target instanceof Adapter) { target = ((Adapter)target).getTarget(); } this.target = target; } public void resolve(TestResourceSet resourceSet) { if (status != Status.UNRESOLVED) { return; } for (Class<?> clazz = target.getClass(); !clazz.equals(Object.class); clazz = clazz.getSuperclass()) { for (Method method : clazz.getDeclaredMethods()) { if (method.getAnnotation(Setup.class) != null) { Type[] parameterTypes = method.getGenericParameterTypes(); Object[] args = new Object[parameterTypes.length]; for (int i=0; i<parameterTypes.length; i++) { Type parameterType = parameterTypes[i]; if (!(parameterType instanceof Class)) { throw new Error("Generic parameters not supported in " + method); } Class<?> parameterClass = (Class<?>)parameterType; if (parameterClass.isArray()) { Class<?> componentType = parameterClass.getComponentType(); TestResource[] resources = resourceSet.findResources(componentType, true); Object[] arg = (Object[])Array.newInstance(componentType, resources.length); for (int j=0; j<resources.length; j++) { TestResource resource = resources[j]; directDependencies.add(resource); arg[j] = resource.getInstance(); } args[i] = arg; } else { TestResource[] resources = resourceSet.findResources(parameterClass, true); if (resources.length == 0) { throw new Error(target.getClass().getName() + " depends on " + parameterClass.getName() + ", but none found"); } else if (resources.length > 1) { throw new Error(target.getClass().getName() + " depends on " + parameterClass.getName() + ", but multiple candidates found"); } TestResource resource = resources[0]; directDependencies.add(resource); args[i] = resource.getInstance(); } } method.setAccessible(true); initializers.addFirst(new MethodInvocation(method, args)); } else if (method.getAnnotation(TearDown.class) != null && method.getParameterTypes().length == 0) { method.setAccessible(true); finalizers.add(new MethodInvocation(method, null)); } } for (Field field : clazz.getDeclaredFields()) { if (field.getAnnotation(Transient.class) != null) { field.setAccessible(true); finalizers.add(new FieldResetter(field)); } } } status = Status.RESOLVED; } public Object getInstance() { return instance; } public Object getTarget() { return target; } public boolean hasLifecycle() { return !(initializers.isEmpty() && finalizers.isEmpty()); } public void setUp() throws Exception { if (status != Status.RESOLVED) { throw new IllegalStateException(); } for (Invocable initializer : initializers) { initializer.execute(target); } status = Status.SETUP; } public void recycle(TestResource resource) { if (status != Status.RESOLVED || resource.status != Status.SETUP || !equals(resource)) { throw new IllegalStateException(); } status = Status.SETUP; resource.status = Status.RECYCLED; } public void tearDown() throws Exception { if (status != Status.SETUP) { throw new IllegalStateException(); } for (Invocable finalizer : finalizers) { finalizer.execute(target); } status = Status.RESOLVED; } @Override public boolean equals(Object obj) { if (obj instanceof TestResource) { TestResource other = (TestResource)obj; return target == other.target && directDependencies.equals(other.directDependencies); } else { return false; } } @Override public int hashCode() { int hashCode; if (hasHashCode) { hashCode = this.hashCode; } else { hashCode = new HashCodeBuilder().append(target).append(directDependencies).toHashCode(); if (status != Status.UNRESOLVED) { this.hashCode = hashCode; } } return hashCode; } @Override public String toString() { Class<?> clazz = target.getClass(); String simpleName = clazz.getSimpleName(); if (simpleName.length() > 0) { return simpleName; } else { return "<anonymous " + clazz.getSuperclass().getSimpleName() + ">"; } } }