From f52ab4e6600ff9882e76f7fafa7949a4d240f8ad Mon Sep 17 00:00:00 2001 From: Christian Wulf <chw@informatik.uni-kiel.de> Date: Wed, 27 Aug 2014 13:02:31 +0200 Subject: [PATCH] added port type validation concept --- .../framework/core/AbstractStage.java | 6 +- .../framework/core/ConsumerStage.java | 4 +- .../framework/core/StageWithPort.java | 1 + .../framework/core/pipe/IPipe.java | 1 + .../stage/CollectorSink.java | 8 +- .../stage/PortTypeConfiguration.java | 19 +++ .../stage/StartTimestampFilter.java | 4 +- .../stage/StopTimestampFilter.java | 2 +- .../runtime/typeCheck/ConnectionTypeTest.java | 109 ++++++++++++++++++ submodules/JCTools | 2 +- 10 files changed, 146 insertions(+), 10 deletions(-) create mode 100644 src/main/java/teetime/variant/methodcallWithPorts/stage/PortTypeConfiguration.java create mode 100644 src/test/java/teetime/variant/methodcallWithPorts/runtime/typeCheck/ConnectionTypeTest.java diff --git a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/AbstractStage.java b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/AbstractStage.java index ad33e815..80bfd8df 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/AbstractStage.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/AbstractStage.java @@ -18,7 +18,7 @@ public abstract class AbstractStage implements StageWithPort { /** * A unique logger instance per stage instance */ - protected final Logger logger; // BETTER use SLF4J as interface and logback as impl + protected final Logger logger; private StageWithPort parentStage; @@ -131,14 +131,14 @@ public abstract class AbstractStage implements StageWithPort { protected <T> InputPort<T> createInputPort() { InputPort<T> inputPort = new InputPort<T>(this); - // inputPort.setType(type); // TODO set type for input port + // inputPort.setType(portType); this.inputPortList.add(inputPort); return inputPort; } protected <T> OutputPort<T> createOutputPort() { OutputPort<T> outputPort = new OutputPort<T>(); - // outputPort.setType(type); // TODO set type for output port + // outputPort.setType(portType); this.outputPortList.add(outputPort); return outputPort; } diff --git a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/ConsumerStage.java b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/ConsumerStage.java index 046395a5..f64c50f3 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/ConsumerStage.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/ConsumerStage.java @@ -10,7 +10,7 @@ public abstract class ConsumerStage<I> extends AbstractStage { @Override public void executeWithPorts() { - I element = this.inputPort.receive(); + I element = this.getInputPort().receive(); boolean isReschedulable = this.determineReschedulability(); this.setReschedulable(isReschedulable); @@ -24,7 +24,7 @@ public abstract class ConsumerStage<I> extends AbstractStage { } protected boolean determineReschedulability() { - return this.inputPort.getPipe().size() > 0; + return this.getInputPort().getPipe().size() > 0; } protected abstract void execute(I element); diff --git a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/StageWithPort.java b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/StageWithPort.java index 15733038..9753bcdf 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/StageWithPort.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/StageWithPort.java @@ -23,6 +23,7 @@ public interface StageWithPort { */ boolean isReschedulable(); + // BETTER remove this method since it will be replaced by onTerminating() void onIsPipelineHead(); void onSignal(Signal signal, InputPort<?> inputPort); diff --git a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/IPipe.java b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/IPipe.java index 0bedb314..a5f25199 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/IPipe.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/framework/core/pipe/IPipe.java @@ -26,6 +26,7 @@ public interface IPipe<T> { void setSignal(Signal signal); + // BETTER change signature to allow {OutputPort<T>, OutputPort<A0 extends T>, OutputPort<A1 extends T>, ...} void connectPorts(OutputPort<T> sourcePort, InputPort<T> targetPort); } diff --git a/src/main/java/teetime/variant/methodcallWithPorts/stage/CollectorSink.java b/src/main/java/teetime/variant/methodcallWithPorts/stage/CollectorSink.java index 82f2ec8d..6af3d421 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/stage/CollectorSink.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/stage/CollectorSink.java @@ -21,11 +21,17 @@ import teetime.variant.methodcallWithPorts.framework.core.ConsumerStage; /** * @author Christian Wulf - * + * * @since 1.10 */ public class CollectorSink<T> extends ConsumerStage<T> { + // private final InputPort<T> inputPort = this.createInputPort(); + // + // public final InputPort<T> getInputPort() { + // return this.inputPort; + // } + private final List<T> elements; private final int threshold; diff --git a/src/main/java/teetime/variant/methodcallWithPorts/stage/PortTypeConfiguration.java b/src/main/java/teetime/variant/methodcallWithPorts/stage/PortTypeConfiguration.java new file mode 100644 index 00000000..59790ddd --- /dev/null +++ b/src/main/java/teetime/variant/methodcallWithPorts/stage/PortTypeConfiguration.java @@ -0,0 +1,19 @@ +package teetime.variant.methodcallWithPorts.stage; + +import teetime.variant.explicitScheduling.examples.throughput.TimestampObject; + +public class PortTypeConfiguration { + + public static <T> void setPortTypes(final ObjectProducer<T> stage, final Class<T> clazz) { + stage.getOutputPort().setType(clazz); + } + + public static <T> void setPortTypes(final CollectorSink<T> stage, final Class<T> clazz) { + stage.getInputPort().setType(clazz); + } + + public static <T> void setPortTypes(final StartTimestampFilter stage) { + stage.getInputPort().setType(TimestampObject.class); + stage.getOutputPort().setType(TimestampObject.class); + } +} diff --git a/src/main/java/teetime/variant/methodcallWithPorts/stage/StartTimestampFilter.java b/src/main/java/teetime/variant/methodcallWithPorts/stage/StartTimestampFilter.java index 2b10cdf3..0ba688d7 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/stage/StartTimestampFilter.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/stage/StartTimestampFilter.java @@ -21,7 +21,7 @@ import teetime.variant.methodcallWithPorts.framework.core.OutputPort; /** * @author Christian Wulf - * + * * @since 1.10 */ public class StartTimestampFilter extends ConsumerStage<TimestampObject> { @@ -35,6 +35,6 @@ public class StartTimestampFilter extends ConsumerStage<TimestampObject> { } public OutputPort<TimestampObject> getOutputPort() { - return outputPort; + return this.outputPort; } } diff --git a/src/main/java/teetime/variant/methodcallWithPorts/stage/StopTimestampFilter.java b/src/main/java/teetime/variant/methodcallWithPorts/stage/StopTimestampFilter.java index 220780e7..c8454c2f 100644 --- a/src/main/java/teetime/variant/methodcallWithPorts/stage/StopTimestampFilter.java +++ b/src/main/java/teetime/variant/methodcallWithPorts/stage/StopTimestampFilter.java @@ -21,7 +21,7 @@ import teetime.variant.methodcallWithPorts.framework.core.OutputPort; /** * @author Christian Wulf - * + * * @since 1.10 */ public class StopTimestampFilter extends ConsumerStage<TimestampObject> { diff --git a/src/test/java/teetime/variant/methodcallWithPorts/runtime/typeCheck/ConnectionTypeTest.java b/src/test/java/teetime/variant/methodcallWithPorts/runtime/typeCheck/ConnectionTypeTest.java new file mode 100644 index 00000000..25719d73 --- /dev/null +++ b/src/test/java/teetime/variant/methodcallWithPorts/runtime/typeCheck/ConnectionTypeTest.java @@ -0,0 +1,109 @@ +package teetime.variant.methodcallWithPorts.runtime.typeCheck; + +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; +import teetime.variant.methodcallWithPorts.stage.ObjectProducer; +import teetime.variant.methodcallWithPorts.stage.PortTypeConfiguration; +import teetime.variant.methodcallWithPorts.stage.StartTimestampFilter; +import teetime.variant.methodcallWithPorts.stage.StopTimestampFilter; +import teetime.variant.methodcallWithPorts.stage.basic.Sink; + +public class ConnectionTypeTest { + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void testDynamicPortConnection() throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, + IllegalArgumentException, InvocationTargetException, ClassNotFoundException { + ConstructorClosure<TimestampObject> constructorClosure = new ConstructorClosure<TimestampObject>() { + @Override + public TimestampObject create() { + return new TimestampObject(); + } + + }; + + Constructor<ObjectProducer> constructor = ObjectProducer.class.getConstructor(long.class, ConstructorClosure.class); + + ObjectProducer objectProducer = constructor.newInstance(1, constructorClosure); + StartTimestampFilter startTimestampFilter = StartTimestampFilter.class.newInstance(); + StopTimestampFilter stopTimestampFilter = StopTimestampFilter.class.newInstance(); + Sink sink = Sink.class.newInstance(); + + PipeFactory pipeFactory = new PipeFactory(); + + IPipe pipe = pipeFactory.create(ThreadCommunication.INTRA); + pipe.connectPorts(objectProducer.getOutputPort(), startTimestampFilter.getInputPort()); + pipe = pipeFactory.create(ThreadCommunication.INTRA); + pipe.connectPorts(startTimestampFilter.getOutputPort(), stopTimestampFilter.getInputPort()); + 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 + // 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 + // } + // + // 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(); + } + + System.out.println(objectProducer.getOutputPort().getType()); + PortTypeConfiguration.setPortTypes(objectProducer, Class.forName("teetime.variant.explicitScheduling.examples.throughput.TimestampObject")); + System.out.println(objectProducer.getOutputPort().getType()); + } +} diff --git a/submodules/JCTools b/submodules/JCTools index 88e1e25f..75998aa2 160000 --- a/submodules/JCTools +++ b/submodules/JCTools @@ -1 +1 @@ -Subproject commit 88e1e25f9519b250258c7e5ada30935975ab2d10 +Subproject commit 75998aa20b7ec897ec321c1f94192de888f2dc6e -- GitLab