diff --git a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/RunnableStage.java b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/RunnableStage.java index 54bc6088cbfde995d658db7d914cbfec629be2ff..3c61059f8366553c2df19e735d307214b354e169 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/RunnableStage.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/RunnableStage.java @@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory; import teetime.variant.methodcallWithPorts.framework.core.signal.StartingSignal; import teetime.variant.methodcallWithPorts.framework.core.signal.TerminatingSignal; import teetime.variant.methodcallWithPorts.framework.core.signal.ValidatingSignal; +import teetime.variant.methodcallWithPorts.framework.core.validation.AnalysisNotValidException; public class RunnableStage implements Runnable { @@ -26,8 +27,7 @@ public class RunnableStage implements Runnable { ValidatingSignal validatingSignal = new ValidatingSignal(); this.stage.onSignal(validatingSignal, null); if (validatingSignal.getInvalidPortConnections().size() > 0) { - // throw new RuntimeException(message); - // TODO implement what to do on validation messages + throw new AnalysisNotValidException(validatingSignal.getInvalidPortConnections()); } } diff --git a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/validation/AnalysisNotValidException.java b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/validation/AnalysisNotValidException.java new file mode 100644 index 0000000000000000000000000000000000000000..7fd84f20793d5612296af1beb035e3ebd06a52cb --- /dev/null +++ b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/validation/AnalysisNotValidException.java @@ -0,0 +1,28 @@ +package teetime.variant.methodcallWithPorts.framework.core.validation; + +import java.util.List; + +import com.google.common.base.Joiner; + +public class AnalysisNotValidException extends RuntimeException { + + private static final long serialVersionUID = 455596493924684318L; + + private final List<InvalidPortConnection> invalidPortConnections; + + public AnalysisNotValidException(final List<InvalidPortConnection> invalidPortConnections) { + super(); + this.invalidPortConnections = invalidPortConnections; + + } + + @Override + public String getMessage() { + StringBuilder builder = new StringBuilder(this.invalidPortConnections.size() * 40); + builder.append(this.invalidPortConnections.size()); + builder.append(" invalid port connections were detected.\n"); + Joiner.on("\n").appendTo(builder, this.invalidPortConnections); + return builder.toString(); + } + +} diff --git a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/validation/InvalidPortConnection.java b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/validation/InvalidPortConnection.java index 51239fedc5d763caceacdb89d34185c7a4a3dfe8..de60a0a40e9e2a9d4c0ab22adc85dbf0806fe17d 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/validation/InvalidPortConnection.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/validation/InvalidPortConnection.java @@ -6,20 +6,27 @@ import teetime.variant.methodcallWithPorts.framework.core.OutputPort; public class InvalidPortConnection { private final OutputPort<?> sourcePort; - private final InputPort<?> inputPort; + private final InputPort<?> targetPort; - public InvalidPortConnection(final OutputPort<?> sourcePort, final InputPort<?> inputPort) { + public InvalidPortConnection(final OutputPort<?> sourcePort, final InputPort<?> targetPort) { super(); this.sourcePort = sourcePort; - this.inputPort = inputPort; + this.targetPort = targetPort; } public OutputPort<?> getSourcePort() { - return sourcePort; + return this.sourcePort; } - public InputPort<?> getInputPort() { - return inputPort; + public InputPort<?> getTargetPort() { + return this.targetPort; + } + + @Override + public String toString() { + String sourcePortTypeName = (this.sourcePort.getType() == null) ? null : this.sourcePort.getType().getName(); + String targetPortTypeName = (this.targetPort.getType() == null) ? null : this.targetPort.getType().getName(); + return sourcePortTypeName + " != " + targetPortTypeName; } } diff --git a/src/test/java/teetime/variant/methodcallWithPorts/runtime/typeCheck/ConnectionTypeTest.java b/src/test/java/teetime/variant/methodcallWithPorts/runtime/typeCheck/ConnectionTypeTest.java index 25719d739103fa5b94f5cab5f27df7cbd2f9384a..bafea6a59b86a3b17f86453eebb2480822fa36de 100644 --- a/src/test/java/teetime/variant/methodcallWithPorts/runtime/typeCheck/ConnectionTypeTest.java +++ b/src/test/java/teetime/variant/methodcallWithPorts/runtime/typeCheck/ConnectionTypeTest.java @@ -1,15 +1,15 @@ package teetime.variant.methodcallWithPorts.runtime.typeCheck; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + import java.lang.reflect.Constructor; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.TypeVariable; import org.junit.Test; import teetime.util.ConstructorClosure; import teetime.variant.explicitScheduling.examples.throughput.TimestampObject; -import teetime.variant.methodcallWithPorts.framework.core.OutputPort; import teetime.variant.methodcallWithPorts.framework.core.pipe.IPipe; import teetime.variant.methodcallWithPorts.framework.core.pipe.PipeFactory; import teetime.variant.methodcallWithPorts.framework.core.pipe.PipeFactory.ThreadCommunication; @@ -21,10 +21,12 @@ import teetime.variant.methodcallWithPorts.stage.basic.Sink; public class ConnectionTypeTest { + // tests for load-time validation + @SuppressWarnings({ "unchecked", "rawtypes" }) @Test public void testDynamicPortConnection() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, - IllegalArgumentException, InvocationTargetException, ClassNotFoundException { + IllegalArgumentException, InvocationTargetException, ClassNotFoundException { ConstructorClosure<TimestampObject> constructorClosure = new ConstructorClosure<TimestampObject>() { @Override public TimestampObject create() { @@ -36,6 +38,8 @@ public class ConnectionTypeTest { Constructor<ObjectProducer> constructor = ObjectProducer.class.getConstructor(long.class, ConstructorClosure.class); ObjectProducer objectProducer = constructor.newInstance(1, constructorClosure); + // PortTypeConfiguration.setPortTypes(objectProducer, Class.forName("teetime.variant.explicitScheduling.examples.throughput.TimestampObject")); + StartTimestampFilter startTimestampFilter = StartTimestampFilter.class.newInstance(); StopTimestampFilter stopTimestampFilter = StopTimestampFilter.class.newInstance(); Sink sink = Sink.class.newInstance(); @@ -49,61 +53,38 @@ public class ConnectionTypeTest { pipe = pipeFactory.create(ThreadCommunication.INTRA); pipe.connectPorts(stopTimestampFilter.getOutputPort(), sink.getInputPort()); - /* - * requirements: - * <ul> - * <li>when selecting a stage class to create one instance, the user is prompted to declare each type argument - * <li> - * </ul> - */ - - TypeVariable<Class<ObjectProducer>>[] objectProducerTypeParameters = ObjectProducer.class.getTypeParameters(); - for (TypeVariable<Class<ObjectProducer>> typeVariable : objectProducerTypeParameters) { - System.out.println(typeVariable.getBounds()); // ->[Ljava.lang.reflect.Type;@13a65d1f - System.out.println(typeVariable.getBounds().length); // ->1 - System.out.println(typeVariable.getBounds()[0]); // ->class java.lang.Object - System.out.println(typeVariable.getName()); // ->T - System.out.println(typeVariable.getClass()); // ->class sun.reflect.generics.reflectiveObjects.TypeVariableImpl - System.out.println(typeVariable.getGenericDeclaration()); // ->class teetime.variant.methodcallWithPorts.stage.ObjectProducer - } - - // TypeVariable<?>[] objectProducerOutputPortTypeParameters = objectProducer.getOutputPort().getClass().getTypeParameters(); - // for (TypeVariable<?> typeVariable : objectProducerOutputPortTypeParameters) { - // System.out.println(typeVariable.getBounds()); // ->[Ljava.lang.reflect.Type;@20a12d8f + // TypeVariable<Class<ObjectProducer>>[] objectProducerTypeParameters = ObjectProducer.class.getTypeParameters(); + // for (TypeVariable<Class<ObjectProducer>> typeVariable : objectProducerTypeParameters) { + // System.out.println(typeVariable.getBounds()); // ->[Ljava.lang.reflect.Type;@13a65d1f // System.out.println(typeVariable.getBounds().length); // ->1 // System.out.println(typeVariable.getBounds()[0]); // ->class java.lang.Object // System.out.println(typeVariable.getName()); // ->T // System.out.println(typeVariable.getClass()); // ->class sun.reflect.generics.reflectiveObjects.TypeVariableImpl - // System.out.println(typeVariable.getGenericDeclaration()); // ->class teetime.variant.methodcallWithPorts.framework.core.OutputPort + // System.out.println(typeVariable.getGenericDeclaration()); // ->class teetime.variant.methodcallWithPorts.stage.ObjectProducer // } // - // TypeVariable<?>[] startTimestampFilterOutputPortTypeParameters = startTimestampFilter.getOutputPort().getClass().getTypeParameters(); - // for (TypeVariable<?> typeVariable : startTimestampFilterOutputPortTypeParameters) { - // System.out.println(typeVariable.getBounds()); // ->[Ljava.lang.reflect.Type;@7b365f02 - // System.out.println(typeVariable.getBounds().length); // ->1 - // System.out.println(typeVariable.getBounds()[0]); // ->class java.lang.Object - // System.out.println(typeVariable.getName()); // ->T - // System.out.println(typeVariable.getClass()); // ->class sun.reflect.generics.reflectiveObjects.TypeVariableImpl - // System.out.println(typeVariable.getGenericDeclaration()); // ->class teetime.variant.methodcallWithPorts.framework.core.OutputPort + // Class<?> currentClass = objectProducer.getClass(); + // while (currentClass.getSuperclass() != null) { // we don't want to process Object.class + // Field[] fields = currentClass.getDeclaredFields(); + // for (Field field : fields) { + // // System.out.println("Field: " + field.getType()); + // if (OutputPort.class.equals(field.getType())) { + // System.out.println("Field.name: " + field.getName()); + // System.out.println("Field.type: " + field.getType()); + // // field.getType() + // } + // } + // + // currentClass = currentClass.getSuperclass(); // } - Class<?> currentClass = objectProducer.getClass(); - while (currentClass.getSuperclass() != null) { // we don't want to process Object.class - Field[] fields = currentClass.getDeclaredFields(); - for (Field field : fields) { - // System.out.println("Field: " + field.getType()); - if (OutputPort.class.equals(field.getType())) { - System.out.println("Field.name: " + field.getName()); - System.out.println("Field.type: " + field.getType()); - // field.getType() - } - } - - currentClass = currentClass.getSuperclass(); - } + assertNull(objectProducer.getOutputPort().getType()); + PortTypeConfiguration.setPortTypes(objectProducer, Class.forName(TimestampObject.class.getName())); + assertEquals(TimestampObject.class, objectProducer.getOutputPort().getType()); - System.out.println(objectProducer.getOutputPort().getType()); - PortTypeConfiguration.setPortTypes(objectProducer, Class.forName("teetime.variant.explicitScheduling.examples.throughput.TimestampObject")); - System.out.println(objectProducer.getOutputPort().getType()); + assertNull(startTimestampFilter.getOutputPort().getType()); + PortTypeConfiguration.setPortTypes(startTimestampFilter); + assertEquals(TimestampObject.class, startTimestampFilter.getInputPort().getType()); + assertEquals(TimestampObject.class, startTimestampFilter.getOutputPort().getType()); } }