diff --git a/src/main/java/teetime/stage/basic/distributor/CloneStrategy.java b/src/main/java/teetime/stage/basic/distributor/CloneStrategy.java index 1264c6b81c8c187a1b9b29ff7fe4408ef0ca9bea..46ed05883ddf17bc070d585232535ac680ef26ae 100644 --- a/src/main/java/teetime/stage/basic/distributor/CloneStrategy.java +++ b/src/main/java/teetime/stage/basic/distributor/CloneStrategy.java @@ -15,6 +15,12 @@ */ package teetime.stage.basic.distributor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + import teetime.framework.OutputPort; /** @@ -26,7 +32,83 @@ public final class CloneStrategy implements IDistributorStrategy { @Override public <T> boolean distribute(final OutputPort<T>[] outputPorts, final T element) { - throw new UnsupportedOperationException(); + for (final OutputPort<T> outputPort : outputPorts) { + outputPort.send(clone(element)); + } + + return true; + } + + @SuppressWarnings("unchecked") + private static <T> T clone(final T element) { + try { + final T newInstance = (T) element.getClass().newInstance(); + + final Collection<Method> setters = findSetters(element.getClass()); + final Collection<Method> getters = findGetters(element.getClass()); + + for (Method setter : setters) { + final Method getter = findCorrespondingGetter(setter, getters); + if (getter != null) { + setter.invoke(newInstance, getter.invoke(element, new Object[0])); + } + } + + return newInstance; + } catch (InstantiationException e) { + throw new UnsupportedOperationException(); + } catch (IllegalAccessException e) { + throw new UnsupportedOperationException(); + } catch (IllegalArgumentException e) { + throw new UnsupportedOperationException(); + } catch (InvocationTargetException e) { + throw new UnsupportedOperationException(); + } + } + + private static Collection<Method> findSetters(final Class<?> clazz) { + final List<Method> methods = new ArrayList<Method>(); + + for (Method method : clazz.getMethods()) { + if (method.getReturnType() == Void.TYPE) { + if (method.getParameterCount() == 1) { + if (method.getName().matches("set[A-Z].*")) { + methods.add(method); + } + } + } + } + + return methods; + } + + private static Collection<Method> findGetters(final Class<?> clazz) { + final List<Method> methods = new ArrayList<Method>(); + + for (Method method : clazz.getMethods()) { + if (method.getReturnType() != Void.TYPE) { + if (method.getParameterCount() == 0) { + if (method.getName().matches("get[A-Z].*") || method.getName().matches("is[A-Z].*")) { + methods.add(method); + } + } + } + } + + return methods; + } + + private static Method findCorrespondingGetter(final Method setter, final Collection<Method> getters) { + final String attributeName = setter.getName().substring(3); + for (Method getter : getters) { + if (getter.getReturnType() == setter.getParameterTypes()[0]) { + if (getter.getName().matches("get" + attributeName) || getter.getName().matches("is" + attributeName)) { + return getter; + } + } + } + + return null; } } diff --git a/src/test/java/teetime/stage/basic/distributor/DistributorTest.java b/src/test/java/teetime/stage/basic/distributor/DistributorTest.java index 48521d5247774844b6b1c8c99a4a3d5f2880e80f..0b8e3cda9c42726051af85e33469fc4673147207 100644 --- a/src/test/java/teetime/stage/basic/distributor/DistributorTest.java +++ b/src/test/java/teetime/stage/basic/distributor/DistributorTest.java @@ -17,6 +17,7 @@ package teetime.stage.basic.distributor; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static org.hamcrest.collection.IsEmptyCollection.empty; import static org.junit.Assert.assertThat; @@ -105,11 +106,50 @@ public class DistributorTest { } @Test - public void cloneShouldNotWork() { + public void cloneForIntegerShouldNotWork() { distributorUnderTest.setStrategy(new CloneStrategy()); expectedException.expect(UnsupportedOperationException.class); this.distributorUnderTest.execute(1); } + @Test + public void cloneForSimpleBeanShoulWork() throws Exception { + final Distributor<SimpleBean> distributorUnderTest = new Distributor<SimpleBean>(new CloneStrategy()); + final CollectorSink<SimpleBean> collector = new CollectorSink<SimpleBean>(); + + final IPipeFactory pipeFactory = new SingleElementPipeFactory(); + pipeFactory.create(distributorUnderTest.getNewOutputPort(), collector.getInputPort()); + + distributorUnderTest.onStarting(); + + final SimpleBean originalBean = new SimpleBean(42); + distributorUnderTest.execute(originalBean); + final SimpleBean clonedBean = collector.getElements().get(0); + + assertThat(originalBean, is(not(clonedBean))); + assertThat(originalBean.getValue(), is(clonedBean.getValue())); + } + + private static class SimpleBean { + + private int value; + + @SuppressWarnings("unused") + public SimpleBean() {} + + public SimpleBean(final int value) { + this.setValue(value); + } + + public int getValue() { + return value; + } + + public void setValue(final int value) { + this.value = value; + } + + } + }