This provides more logical behavior in the api becuase the ids are not modified.
* 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.
*
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;
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()));
}
}
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());
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.
*
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
public static final class DocumentConfig extends ConfigImpl<DocumentType> {
public DocumentConfig(Id<Config> aId) {
- super(aId);
+ super(DocumentType.class, aId);
}
public DocumentConfig(DocumentConfig aConfig) {
@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) {
@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) {
@Override
public Filter wrap(String aPrefix, Filter aFilter) {
- return new RobustFilter(aPrefix, aFilter);
+ return new RobustFilter("", aFilter);
}
}
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
import static junit.framework.Assert.*;
+import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
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
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);
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;
@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);
// 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) {
public static final class MyTypeConfig extends ConfigImpl<MyType> {
public MyTypeConfig(Id<Config> aId) {
- super(aId);
+ super(MyType.class, aId);
}
public MyTypeConfig(MyTypeConfig aConfig) {
@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());