/******************************************************************************* * Copyright Technophobia Ltd 2012 * * This file is part of the Substeps Eclipse Plugin. * * The Substeps Eclipse Plugin is free software: you can redistribute it and/or modify * it under the terms of the Eclipse Public License v1.0. * * The Substeps Eclipse Plugin 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 * Eclipse Public License for more details. * * You should have received a copy of the Eclipse Public License * along with the Substeps Eclipse Plugin. If not, see <http://www.eclipse.org/legal/epl-v10.html>. ******************************************************************************/ package com.technophobia.substeps.classloader; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import com.technophobia.substeps.FeatureEditorPlugin; import com.technophobia.substeps.model.SubSteps.AdditionalStepImplementations; import com.technophobia.substeps.model.SubSteps.Step; import com.technophobia.substeps.model.Syntax; import com.technophobia.substeps.runner.syntax.ClassAnalyser; /** * Subclass of ClassAnalyser that handles classes that have been loaded in a * different Classloader. * * @author sforbes * */ public class ClassLoadedClassAnalyser extends ClassAnalyser { private final ClassLoader classLoader; public ClassLoadedClassAnalyser(final ClassLoader classLoader) { super(); this.classLoader = classLoader; } @Override public void analyseClass(final Class<?> loadedClass, final Syntax syntax) { try { super.analyseClass(loadedClass, syntax); } catch (final NoClassDefFoundError ex) { // If the eclipse project is not building properly, this class may // not have loaded correctly. // If that's the case, handle this gracefully, rather than breaking FeatureEditorPlugin.instance().error( "NoClassDefFoundError trying to analyse class " + loadedClass.getName()); } } @Override protected boolean isStepMethod(final Method m) { try { return m.isAnnotationPresent(getLoadedClassFor(Step.class)); } catch (final ArrayStoreException ex) { // If the eclipse project is not building properly, this class may // not have loaded correctly. // If that's the case, handle this gracefully, rather than breaking FeatureEditorPlugin.instance().error( "ArrayStoreException trying to analyse class " + m.getDeclaringClass().getName()); return false; } } @Override protected boolean hasAdditionalStepsAnnotation(final Class<?> loadedClass) { try { return loadedClass.isAnnotationPresent(getLoadedClassFor(AdditionalStepImplementations.class)); } catch (final ArrayStoreException ex) { // If the eclipse project is not building properly, this class may // not have loaded correctly. // If that's the case, handle this gracefully, rather than breaking FeatureEditorPlugin.instance() .error("ArrayStoreException trying to analyse class " + loadedClass.getName()); return false; } } @Override protected Class<?>[] getAdditionalStepClasses(final Class<?> loadedClass) { final Class<AdditionalStepImplementations> loadedAnnotationClass = getLoadedClassFor(AdditionalStepImplementations.class); final Object annotation = loadedClass.getAnnotation(loadedAnnotationClass); return valueAttributeFromObject(annotation, "value"); } @Override protected String stepValueFrom(final Method m) { final Class<Step> loadedAnnotationClass = getLoadedClassFor(Step.class); final Object annotation = m.getAnnotation(loadedAnnotationClass); return valueAttributeFromObject(annotation, "value"); } /** * Use the classloader to reload clazz * * @param clazz * The class to be reloaded in the classloader * @return The reloaded class */ @SuppressWarnings("unchecked") private <T extends Annotation> Class<T> getLoadedClassFor(final Class<T> clazz) { try { return (Class<T>) classLoader.loadClass(clazz.getName()); } catch (final ClassNotFoundException ex) { throw new IllegalStateException("Could not find class " + clazz, ex); } } /** * Reflectively gets property from object * * @param ob * The object containing the method * @param methodName * The method to be looked up * @return value of the object method */ @SuppressWarnings("unchecked") private <T> T valueAttributeFromObject(final Object ob, final String methodName) { try { return (T) ob.getClass().getMethod(methodName).invoke(ob); } catch (final Exception e) { FeatureEditorPlugin.instance().error("Could not invoke method " + methodName + " on object " + ob); return null; } } }