id prefixes are now done at the very last moment instead of when an item is added.
authorErik Brakkee <erik@brakkee.org>
Tue, 9 Aug 2011 15:23:15 +0000 (17:23 +0200)
committerErik Brakkee <erik@brakkee.org>
Tue, 9 Aug 2011 15:23:15 +0000 (17:23 +0200)
This provides more logical behavior in the api becuase the ids are not modified.

config/src/main/java/org/wamblee/xmlrouter/config/Config.java
impl/src/main/java/org/wamblee/xmlrouter/impl/CompositeConfig.java
impl/src/main/java/org/wamblee/xmlrouter/impl/CompositeRouterConfig.java
impl/src/main/java/org/wamblee/xmlrouter/impl/ConfigImpl.java
impl/src/main/java/org/wamblee/xmlrouter/impl/IdentifiablePrefixProxyFactory.java [new file with mode: 0644]
impl/src/main/java/org/wamblee/xmlrouter/impl/SingleRouterConfig.java
impl/src/main/java/org/wamblee/xmlrouter/impl/XMLRouterConfigService.java
impl/src/test/java/org/wamblee/xmlrouter/impl/CompositeConfigTest.java
impl/src/test/java/org/wamblee/xmlrouter/impl/ConfigImplTest.java

index baa4c8b4d72d0f6d2c38bba418ba7f354882721c..aa5c5409851fbcb6a155ee18a5c046de2f1be1e2 100644 (file)
@@ -29,6 +29,12 @@ import org.wamblee.xmlrouter.common.Id;
  *            Type for which ids are generated.
  */
 public interface Config<T extends Identifiable> extends Identifiable<Config> {
+
+    /**
+     * @return The type of contained object.
+     */
+    Class<T> getType();
+
     /**
      * Adds an item. No item with the same id may exist.
      * 
index c9e250e49824fa44272aa3f1addd919f74871c09..0c6100dc3fc82c2c9a4484bc2af21e258e84d7a0 100644 (file)
@@ -39,16 +39,24 @@ public class CompositeConfig<T extends Identifiable<T>> implements
 
     private static final Id<Config> ID = new Id<Config>("compositeconfig");
     private static final String READ_ONLY_INSTANCE = "read only instance";
+
+    private Class<T> type;
     private Set<Id<Config>> ids;
     private List<Id<T>> valueIds;
     private List<T> values;
 
-    public CompositeConfig() {
+    public CompositeConfig(Class<T> aType) {
+        type = aType;
         ids = new HashSet<Id<Config>>();
         valueIds = new ArrayList<Id<T>>();
         values = new ArrayList<T>();
     }
 
+    @Override
+    public Class<T> getType() {
+        return type;
+    }
+
     @Override
     public Id<Config> getId() {
         return ID;
@@ -60,17 +68,22 @@ public class CompositeConfig<T extends Identifiable<T>> implements
             throw new ConfigException("duplicate id '" +
                 aConfig.getId().toString() + "'");
         }
+        String prefix = aConfig.getId().getId() + ".";
         for (T item : aConfig.values()) {
-            if (valueIds.contains(item.getId())) {
+            Id<T> newId = new Id<T>(prefix + item.getId());
+            if (valueIds.contains(newId)) {
                 throw new ConfigException("duplicate id '" +
                     item.getId().toString() + "'");
             }
         }
 
         ids.add(aConfig.getId());
+
         for (T item : aConfig.values()) {
-            valueIds.add(item.getId());
-            values.add(item);
+            Id<T> newId = new Id<T>(prefix + item.getId());
+            valueIds.add(newId);
+            values.add(IdentifiablePrefixProxyFactory.getProxy(prefix, item,
+                Identifiable.class, aConfig.getType()));
         }
     }
 
index eabbf3e4e45debbe88782c0072b40de4d83fdcad..fa01c064af7773dfdd60d0ebf02fb3299bb6664b 100644 (file)
@@ -34,9 +34,10 @@ public class CompositeRouterConfig implements ExtendedRouterConfig {
 
     public CompositeRouterConfig(Id<RouterConfig> aId,
         Collection<RouterConfig> aConfigs) {
-        documentTypes = new CompositeConfig<DocumentType>();
-        transformations = new CompositeConfig<Transformation>();
-        filters = new CompositeConfig<Filter>();
+        documentTypes = new CompositeConfig<DocumentType>(DocumentType.class);
+        transformations = new CompositeConfig<Transformation>(
+            Transformation.class);
+        filters = new CompositeConfig<Filter>(Filter.class);
         for (RouterConfig config : aConfigs) {
             documentTypes.addConfig(config.documentTypeConfig());
             transformations.addConfig(config.transformationConfig());
index 8088be30e31df69d8bf87280f68d7bfef94bbf42..0e1da0be84853fb6b7690d5ddecfef1f1bd3c3ed 100644 (file)
@@ -37,18 +37,26 @@ import org.wamblee.xmlrouter.config.Identifiable;
 public abstract class ConfigImpl<T extends Identifiable<T>> implements
     ExtendedConfig<T> {
 
+    private Class<T> type;
     private Id<Config> id;
     private Map<Id<T>, T> registered;
 
     /**
      * Constructs the object.
      */
-    public ConfigImpl(Id<Config> aId) {
+    public ConfigImpl(Class<T> aType, Id<Config> aId) {
+        notNull("type", aType);
         notNull("id", aId);
+        type = aType;
         id = aId;
         registered = new HashMap<Id<T>, T>();
     }
 
+    @Override
+    public Class<T> getType() {
+        return type;
+    }
+
     /**
      * Copies the config object.
      * 
diff --git a/impl/src/main/java/org/wamblee/xmlrouter/impl/IdentifiablePrefixProxyFactory.java b/impl/src/main/java/org/wamblee/xmlrouter/impl/IdentifiablePrefixProxyFactory.java
new file mode 100644 (file)
index 0000000..c787c7b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2005-2011 the original author or authors.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wamblee.xmlrouter.impl;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+import org.wamblee.xmlrouter.common.Id;
+import org.wamblee.xmlrouter.config.Identifiable;
+
+/**
+ * This proxy factory creates proxies for identifiable objects that add a prefix
+ * to the ids.
+ * 
+ * @author Erik Brakkee
+ * 
+ * @param <T>
+ */
+public class IdentifiablePrefixProxyFactory<T> {
+
+    public static final class IdPrefixInvocationHandler<T> implements
+        InvocationHandler {
+
+        private String prefix;
+        private T service;
+
+        public IdPrefixInvocationHandler(String aPrefix, T aService) {
+            prefix = aPrefix;
+            service = aService;
+        }
+
+        @Override
+        public Object invoke(Object aProxy, final Method aMethod,
+            final Object[] aArgs) throws Throwable {
+            try {
+                if (aMethod.getDeclaringClass().equals(Identifiable.class)) {
+                    if (!aMethod.getName().equals("getId")) {
+                        throw new RuntimeException(
+                            "Programming error, Identifiable interface was modified");
+                    }
+                    Id id = (Id) aMethod.invoke(service, aArgs);
+                    return new Id(prefix + id.getId());
+                }
+                return aMethod.invoke(service, aArgs);
+            } catch (InvocationTargetException e) {
+                throw e.getCause();
+            }
+        }
+    }
+
+    public static <T> T getProxy(String aPrefix, T aService,
+        Class... aInterfaces) {
+        InvocationHandler handler = new IdPrefixInvocationHandler<T>(aPrefix,
+            aService);
+        Class proxyClass = Proxy.getProxyClass(aService.getClass()
+            .getClassLoader(), aInterfaces);
+        T proxy;
+        try {
+            proxy = (T) proxyClass.getConstructor(
+                new Class[] { InvocationHandler.class }).newInstance(
+                new Object[] { handler });
+            return proxy;
+        } catch (Exception e) {
+            throw new RuntimeException("Could not create proxy for " +
+                aService.getClass().getName(), e);
+        }
+    }
+}
index deb38f6656fcd39ea9f3bf37e4768b23a94431cb..4ecaad4a35d633679620f791426242f868784b35 100644 (file)
@@ -34,7 +34,7 @@ public class SingleRouterConfig implements ExtendedRouterConfig {
 
     public static final class DocumentConfig extends ConfigImpl<DocumentType> {
         public DocumentConfig(Id<Config> aId) {
-            super(aId);
+            super(DocumentType.class, aId);
         }
 
         public DocumentConfig(DocumentConfig aConfig) {
@@ -43,14 +43,14 @@ public class SingleRouterConfig implements ExtendedRouterConfig {
 
         @Override
         public DocumentType wrap(String aPrefix, DocumentType aT) {
-            return new RobustDocumentType(aPrefix, aT);
+            return new RobustDocumentType("", aT);
         }
     }
 
     public static final class TransformationConfig extends
         ConfigImpl<Transformation> {
         public TransformationConfig(Id<Config> aId) {
-            super(aId);
+            super(Transformation.class, aId);
         }
 
         public TransformationConfig(TransformationConfig aConfig) {
@@ -60,13 +60,13 @@ public class SingleRouterConfig implements ExtendedRouterConfig {
         @Override
         public Transformation wrap(String aPrefix,
             Transformation aTransformation) {
-            return new RobustTransformation(aPrefix, aTransformation);
+            return new RobustTransformation("", aTransformation);
         }
     }
 
     public static final class FilterConfig extends ConfigImpl<Filter> {
         public FilterConfig(Id<Config> aId) {
-            super(aId);
+            super(Filter.class, aId);
         }
 
         public FilterConfig(FilterConfig aConfig) {
@@ -75,7 +75,7 @@ public class SingleRouterConfig implements ExtendedRouterConfig {
 
         @Override
         public Filter wrap(String aPrefix, Filter aFilter) {
-            return new RobustFilter(aPrefix, aFilter);
+            return new RobustFilter("", aFilter);
         }
     }
 
index ff8c6de09ad0ef312229b0af0e9b14f0aaa285e0..da883d241155f18b9196c4a9c9e3c7919d9b1fde 100644 (file)
@@ -44,8 +44,8 @@ public class XMLRouterConfigService implements RouterConfigService {
         application = aApplication;
         sequence = new AtomicLong(1L);
         config = aConfig;
-        routerConfigs = new ConfigImpl<RouterConfig>(new Id<Config>(
-            aApplication)) {
+        routerConfigs = new ConfigImpl<RouterConfig>(RouterConfig.class,
+            new Id<Config>(aApplication)) {
             public RouterConfig wrap(final String aPrefix, final RouterConfig aT) {
                 return new RouterConfig() {
                     @Override
index 9905046d9463998e38f5cb5c4e92cf487b4a3a6a..cd0879d59cbcc3b98cb737bbda2c53b1ab1d8fb8 100644 (file)
@@ -17,6 +17,7 @@ package org.wamblee.xmlrouter.impl;
 
 import static junit.framework.Assert.*;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import org.junit.Test;
@@ -27,22 +28,31 @@ import org.wamblee.xmlrouter.config.Identifiable;
 
 public class CompositeConfigTest {
 
-    public static class IntClass implements Identifiable<IntClass> {
+    public static interface StringClassInterface extends
+        Identifiable<StringClassInterface> {
 
-        private int value;
+    }
+
+    public static class StringClass implements StringClassInterface {
 
-        public IntClass(int aValue) {
+        private String value;
+
+        public StringClass(String aValue) {
             value = aValue;
         }
 
+        public StringClass(int aValue) {
+            this(aValue + "");
+        }
+
         @Override
-        public Id<IntClass> getId() {
-            return new Id<IntClass>(value + "");
+        public Id<StringClassInterface> getId() {
+            return new Id<StringClassInterface>(value + "");
         }
 
         @Override
         public int hashCode() {
-            return ((Integer) value).hashCode();
+            return value.hashCode();
         }
 
         @Override
@@ -50,50 +60,52 @@ public class CompositeConfigTest {
             if (aObj == null) {
                 return false;
             }
-            if (!(aObj instanceof IntClass)) {
+            if (!(aObj instanceof StringClass)) {
                 return false;
             }
-            IntClass obj = (IntClass) aObj;
-            return value == obj.value;
+            StringClass obj = (StringClass) aObj;
+            return value.equals(obj.value);
         }
     }
 
     @Test
     public void testEmptyConfig() {
-        Config<IntClass> composite = composite();
+        Config<StringClassInterface> composite = composite();
         assertTrue(composite.values().isEmpty());
     }
 
     @Test(expected = RuntimeException.class)
     public void testAddNotAllowed() {
-        composite().add(new IntClass(10));
+        composite().add(new StringClass(10));
     }
 
     @Test(expected = RuntimeException.class)
     public void testRemoveNotAllowed() {
-        composite().remove(new Id<IntClass>("xxx"));
+        composite().remove(new Id<StringClassInterface>("xxx"));
     }
 
     @Test
     public void testAddConfig() {
-        CompositeConfig<IntClass> composite = composite();
-        Config<IntClass> c1 = new ConfigImpl(id("c1")) {
+        CompositeConfig<StringClassInterface> composite = composite();
+        Config<StringClassInterface> c1 = new ConfigImpl(
+            StringClassInterface.class, id("c1")) {
             @Override
             public Identifiable wrap(String aPrefix, Identifiable aT) {
                 return aT;
             }
         };
-        Config<IntClass> c2 = new ConfigImpl(id("c2")) {
+        Config<StringClassInterface> c2 = new ConfigImpl(
+            StringClassInterface.class, id("c2")) {
             @Override
             public Identifiable wrap(String aPrefix, Identifiable aT) {
                 return aT;
             }
         };
 
-        IntClass i1 = new IntClass(10);
-        IntClass i2 = new IntClass(20);
-        IntClass i3 = new IntClass(30);
-        IntClass i4 = new IntClass(40);
+        StringClass i1 = new StringClass(10);
+        StringClass i2 = new StringClass(20);
+        StringClass i3 = new StringClass(30);
+        StringClass i4 = new StringClass(40);
 
         c1.add(i1);
         c1.add(i2);
@@ -101,30 +113,40 @@ public class CompositeConfigTest {
         c2.add(i4);
 
         composite.addConfig(c1);
-        List<IntClass> values = composite.values();
-        assertEquals(2, values.size());
-        assertTrue(values.contains(i1));
-        assertTrue(values.contains(i2));
+        List<StringClassInterface> values = composite.values();
+        List<String> ids = new ArrayList<String>();
+        for (StringClassInterface intf : values) {
+            ids.add(intf.getId().getId());
+        }
+        assertTrue(ids.contains("c1.10"));
+        assertTrue(ids.contains("c1.20"));
 
         composite.addConfig(c2);
         values = composite.values();
         assertEquals(4, values.size());
-        assertTrue(values.contains(i1));
-        assertTrue(values.contains(i2));
-        assertTrue(values.contains(i3));
-        assertTrue(values.contains(i4));
+
+        ids = new ArrayList<String>();
+        for (StringClassInterface intf : values) {
+            ids.add(intf.getId().getId());
+        }
+        assertTrue(ids.contains("c1.10"));
+        assertTrue(ids.contains("c1.20"));
+        assertTrue(ids.contains("c2.30"));
+        assertTrue(ids.contains("c2.40"));
     }
 
     @Test(expected = ConfigException.class)
     public void testDuplicatesNotAllowed() {
-        CompositeConfig<IntClass> composite = composite();
-        Config<IntClass> c1 = new ConfigImpl(id("c1")) {
+        CompositeConfig<StringClassInterface> composite = composite();
+        Config<StringClassInterface> c1 = new ConfigImpl(
+            StringClassInterface.class, id("c1")) {
             @Override
             public Identifiable wrap(String aPrefix, Identifiable aT) {
                 return aT;
             }
         };
-        Config<IntClass> c2 = new ConfigImpl(id("c1")) {
+        Config<StringClassInterface> c2 = new ConfigImpl(
+            StringClassInterface.class, id("c1")) {
             @Override
             public Identifiable wrap(String aPrefix, Identifiable aT) {
                 return aT;
@@ -136,22 +158,24 @@ public class CompositeConfigTest {
 
     @Test
     public void testDuplicateItem() {
-        CompositeConfig<IntClass> composite = composite();
-        Config<IntClass> c1 = new ConfigImpl(id("c1")) {
+        CompositeConfig<StringClassInterface> composite = composite();
+        Config<StringClassInterface> c1 = new ConfigImpl(
+            StringClassInterface.class, id("c.x")) {
             @Override
             public Identifiable wrap(String aPrefix, Identifiable aT) {
                 return aT;
             }
         };
-        Config<IntClass> c2 = new ConfigImpl(id("c2")) {
+        Config<StringClassInterface> c2 = new ConfigImpl(
+            StringClassInterface.class, id("c")) {
             @Override
             public Identifiable wrap(String aPrefix, Identifiable aT) {
                 return aT;
             }
         };
 
-        IntClass i1 = new IntClass(10);
-        IntClass i2 = new IntClass(10);
+        StringClass i1 = new StringClass("y");
+        StringClass i2 = new StringClass("x.y");
         c1.add(i1);
         c2.add(i2);
         composite.addConfig(c1);
@@ -162,11 +186,13 @@ public class CompositeConfigTest {
             // ok.
         }
         assertEquals(1, composite.values().size());
-        assertTrue(composite.values().contains(i1));
+        assertEquals("c.x.y", composite.values().iterator().next().getId()
+            .getId());
     }
 
-    private CompositeConfig<IntClass> composite() {
-        return new CompositeConfig<IntClass>();
+    private CompositeConfig<StringClassInterface> composite() {
+        return new CompositeConfig<StringClassInterface>(
+            StringClassInterface.class);
     }
 
     private Id<Config> id(String aId) {
index aa197eaf54274e44fee6d9ba87555d0381833735..85860122b71c75bcac18fb61a6b469e000ffb780 100644 (file)
@@ -55,7 +55,7 @@ public class ConfigImplTest {
 
     public static final class MyTypeConfig extends ConfigImpl<MyType> {
         public MyTypeConfig(Id<Config> aId) {
-            super(aId);
+            super(MyType.class, aId);
         }
 
         public MyTypeConfig(MyTypeConfig aConfig) {
@@ -121,22 +121,11 @@ public class ConfigImplTest {
     @Test
     public void testEquals() {
 
-        Config<MyType> config1 = new ConfigImpl<MyType>(new Id<Config>(
-            CONFIG_TYPE)) {
-            @Override
-            public MyType wrap(String aPrefix, MyType aT) {
-                return new MyTypeWrapper(aPrefix, aT);
-            }
-        };
+        Config<MyType> config1 = new MyTypeConfig(new Id<Config>(CONFIG_TYPE));
         assertFalse(config1.equals(null));
         assertFalse(config1.equals("hello"));
-        Config<MyType> config2 = new ConfigImpl<MyType>(new Id<Config>(
-            CONFIG_TYPE)) {
-            @Override
-            public MyType wrap(String aPrefix, MyType aT) {
-                return new MyTypeWrapper(aPrefix, aT);
-            }
-        };
+        Config<MyType> config2 = new MyTypeConfig(new Id<Config>(CONFIG_TYPE));
+
         assertEquals(config1, config2);
         assertEquals(config1.hashCode(), config2.hashCode());