package rtt.core.testing.generation; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.SortedSet; import rtt.annotations.Node.Initialize; import rtt.annotations.processing.AnnotationProcessor; import rtt.annotations.processing.InitMember; import rtt.core.archive.input.Input; import rtt.core.exceptions.AnnotationException; import rtt.core.utils.RTTLogging; public class Executor { private static final String NO_INTERFACES = "Interfaces are not allowed for output data generation."; private static final String NO_ANONYMOUS = "Anonymous classes are not allowed for output generation."; private static final String NO_LOCALCLASS = "Local classes are currently not supported for output generation."; private static final String NO_NONSTATIC_MEMBERCLASS = "Non-static member classes are currently not supported for output generation."; private static final String NO_NODE_ANNOTATION = "The given class doesn't have a @Node annotation."; private static final String NONE_INIT_MEMBER = "Could not find a method or constructor annotated with @Node.Initialize."; private static final String NO_SINGLE_INIT_MEMBER = "Found more than one method or constructor annotated with @Node.Initialize."; private static final String PARAMETER_COUNT_ERROR = "The element which is annotated with @Node.Initialize must have $$ parameter(s)."; private static final String NO_INPUTSTREAM_PARAMETER = "The first parameter needs to be an InputStream."; private static final String NO_STRINGARRAY_PARAMETER = "The second parameter needs to be an array of strings."; private Class<?> initialObjectType = null; private InitMember<?> initialMember = null; private List<Class<? extends Throwable>> acceptedExceptions; private Initialize initAnnotation; public Executor(Class<?> initialObjectType) { checkClass(initialObjectType); SortedSet<InitMember<?>> initMembers = AnnotationProcessor.getInitMembers(initialObjectType); if (initMembers.size() == 0) { RTTLogging.throwException(new IllegalStateException(NONE_INIT_MEMBER)); } if (initMembers.size() > 1) { RTTLogging.throwException(new IllegalStateException(NO_SINGLE_INIT_MEMBER)); } this.initialObjectType = initialObjectType; initialMember = initMembers.first(); initAnnotation = initialMember.getAnnotation(); checkParameters(initialMember.getParameterTypes(), initAnnotation.withParams()); acceptedExceptions = new ArrayList<>(); for (Class<? extends Throwable> throwable : initAnnotation.acceptedExceptions()) { acceptedExceptions.add(throwable); } } private void checkClass(Class<?> initialNodeClass) { if (initialNodeClass.isInterface()) { RTTLogging.throwException(new IllegalArgumentException(NO_INTERFACES)); } if (initialNodeClass.isAnonymousClass()) { RTTLogging.throwException(new IllegalArgumentException(NO_ANONYMOUS)); } if (initialNodeClass.isLocalClass()) { RTTLogging.throwException(new IllegalArgumentException(NO_LOCALCLASS)); } if (initialNodeClass.isMemberClass() && !Modifier.isStatic(initialNodeClass.getModifiers())) { RTTLogging.throwException(new IllegalArgumentException(NO_NONSTATIC_MEMBERCLASS)); } if (!AnnotationProcessor.isNode(initialNodeClass)) { RTTLogging.throwException(new AnnotationException(NO_NODE_ANNOTATION)); } } private void checkParameters(Class<?>[] parameterTypes, boolean withParams) { int paramSize = withParams ? 2 : 1; if (parameterTypes.length != paramSize) { RTTLogging.throwException(new AnnotationException(PARAMETER_COUNT_ERROR.replace("$$", "" + paramSize))); } if (parameterTypes[0] == null || !parameterTypes[0].equals(InputStream.class)) { RTTLogging.throwException(new AnnotationException(NO_INPUTSTREAM_PARAMETER)); } if (withParams && (parameterTypes[1] == null || !parameterTypes[1].equals(String[].class))) { RTTLogging.throwException(new AnnotationException(NO_STRINGARRAY_PARAMETER)); } } public Object initialize(Input input, List<String> params) throws ReflectiveOperationException { Object initialObject = null; try (InputStream inputStream = new ByteArrayInputStream(input.getValue().getBytes())) { initialObject = initialMember.getResult(inputStream, params); } catch (IOException e) { RTTLogging.throwException( new RuntimeException("RTT could not access input stream.", e)); } return initialObject; } public boolean isAcceptedException(Throwable exception) { return acceptedExceptions.contains(exception.getClass()); } public Class<?> getInitialObjectType() { return initialObjectType; } }