Now more testing.
  */
 public class Id<T> implements Comparable<Id<T>> {
 
-    private long id;
+    private String id;
 
     /**
      * Constructs the id.
      * 
      * @param aId
      *            Integer id.
+     * @throws NullPointerException
+     *             in case the id is null.
      */
-    public Id(long aId) {
+    public Id(String aId) {
+        if (aId == null) {
+            throw new NullPointerException("id is null");
+        }
         id = aId;
     }
 
     /**
      * @return The underlying id.
      */
-    public long getId() {
+    public String getId() {
         return id;
     }
 
     @Override
     public int hashCode() {
-        return ((Long) id).hashCode();
+        return id.hashCode();
     }
 
     @Override
 
     @Override
     public String toString() {
-        return id + "";
+        return id;
     }
 
     @Override
     public int compareTo(Id<T> aId) {
-        return ((Long) id).compareTo((Long) aId.getId());
+        return id.compareTo(aId.getId());
     }
 }
 
 
     @Test
     public void testGetSet() {
-        Id<IdTest> id = new Id<IdTest>(100L);
-        assertEquals(100L, id.getId());
+        Id<IdTest> id = new Id<IdTest>("hello");
+        assertEquals("hello", id.getId());
     }
 
     @Test
     public void testEqualsHashCodeCompare() {
-        Id<IdTest> id1 = new Id<IdTest>(100L);
-        Id<IdTest> id2 = new Id<IdTest>(200L);
-        Id<IdTest> id3 = new Id<IdTest>(100L);
+        Id<IdTest> id1 = new Id<IdTest>("a");
+        Id<IdTest> id2 = new Id<IdTest>("b");
+        Id<IdTest> id3 = new Id<IdTest>("a");
         assertEquals(id1, id3);
         assertFalse(id1.equals(id2));
         assertFalse(id1.equals(null));
-        assertFalse(id1.equals("hello"));
+        assertFalse(id1.equals("a"));
         assertEquals(id1.hashCode(), id3.hashCode());
 
         assertTrue(id1.compareTo(id2) < 0);
         assertTrue(id2.compareTo(id1) > 0);
         assertEquals(0, id1.compareTo(id3));
     }
+
+    @Test(expected = NullPointerException.class)
+    public void testNullNotAccepted() {
+        Id<IdTest> id = new Id<IdTest>(null);
+    }
 }
 
  */
 package org.wamblee.xmlrouter.config;
 
-import java.util.Map;
+import java.util.List;
 
 import org.wamblee.xmlrouter.common.Id;
 
  * @param <T>
  *            Type for which ids are generated.
  */
-public interface Config<T> {
+public interface Config<T> extends Identifiable<Config> {
 
     /**
-     * Adds a item
+     * Adds an item. No item with the same id may exist.
      * 
      * @param aT
      *            item
-     * @return Unique id.
      */
-    Id<T> add(T aT);
+    void add(T aT);
 
     /**
      * Removes the item with a given id.
     boolean remove(Id<T> aId);
 
     /**
-     * @return All available ids.
+     * @return All available items.
      */
-    Map<Id<T>, T> map();
+    List<T> values();
 }
\ No newline at end of file
 
  * @author Erik Brakkee
  * 
  */
-public interface DocumentType {
+public interface DocumentType extends Identifiable<DocumentType> {
 
     /**
      * Symbolic name for the document type.
 
  * @author Erik Brakkee
  * 
  */
-public interface Filter {
+public interface Filter extends Identifiable<Filter> {
 
     /**
      * Determines if a given document will be processed or not.
 
--- /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.config;
+
+import org.wamblee.xmlrouter.common.Id;
+
+/**
+ * Classes implementing this interface must provide a unique id to identify
+ * their contents and behavior. If the content or behavior of an object changes,
+ * then a different id should be returned. Conversely, it is required for the id
+ * to keep as constant as possible. Also, a given object should return the same
+ * id throughout its lifecycle (from the moment it's {@link #getId()} method is
+ * called until the moment it can no longer be referenced.
+ * 
+ * @author Erik Brakkee
+ * 
+ */
+public interface Identifiable<T> {
+
+    /**
+     * Returns the unique id for the object.
+     * 
+     * @return Unique id.
+     */
+    Id<T> getId();
+}
 
  * 
  * @author Erik Brakkee
  */
-public interface RouterConfig {
+public interface RouterConfig extends Identifiable<RouterConfig> {
 
     /**
      * @return Document types.
 
      *            configuration.
      * @return Id of the applied configuration.
      */
-    Id<RouterConfig> apply(RouterConfig aConfig, Id<RouterConfig> aOldConfig);
+    void apply(RouterConfig aConfig, Id<RouterConfig> aOldConfig);
 
     /**
      * Clears the configuration for a given id.
 
  * @author Erik Brakkee
  * 
  */
-public interface Transformation {
-
-    /**
-     * @return Name for the transformation.
-     */
-    String getName();
+public interface Transformation extends Identifiable<Transformation> {
 
     /**
      * From type that can be transformed.
 
  */
 package org.wamblee.xmlrouter.impl;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.Config;
 
 public class CompositeConfig<T> implements ExtendedConfig<T> {
 
-    private Map<Id<T>, T> configs;
+    private Id<Config> id;
+    private List<T> configs;
 
-    public CompositeConfig() {
-        configs = new LinkedHashMap<Id<T>, T>();
+    public CompositeConfig(Id<Config> aId) {
+        id = aId;
+        configs = new ArrayList<T>();
+    }
+
+    @Override
+    public Id<Config> getId() {
+        // TODO test id.
+        return id;
     }
 
     public void add(Config<T> aConfig) {
-        for (Id<T> id : aConfig.map().keySet()) {
-            configs.put(id, aConfig.map().get(id));
+        // TODO check duplicate config.
+        for (T item : aConfig.values()) {
+            configs.add(item);
         }
     }
 
     @Override
-    public Map<Id<T>, T> map() {
+    public List<T> values() {
         return configs;
     }
 
         return false;
     }
 
-    private void notSupported() {
-        throw new RuntimeException("readonly instance");
-    }
-
     @Override
-    public Id<T> add(T aT) {
+    public void add(T aT) {
         notSupported();
-        return null;
+    }
+
+    private void notSupported() {
+        throw new RuntimeException("readonly instance");
     }
 }
 
 
 import java.util.Collection;
 
+import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.Config;
 import org.wamblee.xmlrouter.config.DocumentType;
 import org.wamblee.xmlrouter.config.Filter;
 import org.wamblee.xmlrouter.config.RouterConfig;
 import org.wamblee.xmlrouter.config.Transformation;
 
+// TODO test this class.
 public class CompositeRouterConfig implements ExtendedRouterConfig {
 
+    private Id<RouterConfig> id;
     private CompositeConfig<DocumentType> documentTypes;
     private CompositeConfig<Transformation> transformations;
     private CompositeConfig<Filter> filters;
 
-    public CompositeRouterConfig(Collection<RouterConfig> aConfigs) {
-        documentTypes = new CompositeConfig<DocumentType>();
-        transformations = new CompositeConfig<Transformation>();
-        filters = new CompositeConfig<Filter>();
+    public CompositeRouterConfig(Id<RouterConfig> aId,
+        Collection<RouterConfig> aConfigs) {
+        id = aId;
+        documentTypes = new CompositeConfig<DocumentType>(new Id<Config>(
+            "documentTypes"));
+        transformations = new CompositeConfig<Transformation>(new Id<Config>(
+            "transformations"));
+        filters = new CompositeConfig<Filter>(new Id<Config>("filters"));
         for (RouterConfig config : aConfigs) {
             documentTypes.add(config.documentTypeConfig());
             transformations.add(config.transformationConfig());
         }
     }
 
+    // TODO test id.
+
+    @Override
+    public Id<RouterConfig> getId() {
+        return id;
+    }
+
     @Override
     public Config<DocumentType> documentTypeConfig() {
         return documentTypes;
 
  */
 package org.wamblee.xmlrouter.impl;
 
+import java.util.ArrayList;
 import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.Iterator;
+import java.util.List;
 
 import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.Config;
+import org.wamblee.xmlrouter.config.Identifiable;
 
 /**
  * Default implementation of the {@link Config} interface.
  * 
  * @param <T>
  */
-public abstract class ConfigImpl<T> implements ExtendedConfig<T> {
+public abstract class ConfigImpl<T extends Identifiable> implements
+    ExtendedConfig<T> {
 
-    private boolean dirty;
-    private AtomicLong next;
-    private Map<Id<T>, T> registered;
+    private Id<Config> id;
+    private List<T> registered;
 
     /**
      * Constructs the object.
      */
-    public ConfigImpl(AtomicLong aNext) {
-        dirty = false;
-        next = aNext;
-        registered = new LinkedHashMap<Id<T>, T>();
+    public ConfigImpl(Id<Config> aId) {
+        // TODO test for null.
+        id = aId;
+        registered = new ArrayList<T>();
+    }
+
+    @Override
+    public Id<Config> getId() {
+        return id;
     }
 
     /*
      * @see org.wamblee.xmlrouter.config.Config#add(T)
      */
     @Override
-    public synchronized Id<T> add(T aT) {
+    public synchronized void add(T aT) {
+        // TODO test duplicate ids.
         notNull(aT);
-        long seqno = next.incrementAndGet();
-        Id<T> id = new Id<T>(seqno);
-        registered.put(id, wrap(id, aT));
-        dirty = true;
-        return id;
+        registered.add(wrap(aT));
     }
 
     /**
      * This is called to wrap the given object by a safer version.
      * 
-     * @param aId
-     *            Id.
      * @param aT
      *            Object to wrap.
      * @return Wrapped object.
      */
-    public abstract T wrap(Id<T> aId, T aT);
+    public abstract T wrap(T aT);
 
     /*
      * (non-Javadoc)
     @Override
     public synchronized boolean remove(Id<T> aId) {
         notNull(aId);
-        dirty = true;
-        return registered.remove(aId) != null;
+        Iterator<T> i = registered.iterator();
+        while (i.hasNext()) {
+            T t = i.next();
+            if (t.getId().equals(aId)) {
+                i.remove();
+                return true;
+            }
+        }
+        return false;
     }
 
     @Override
-    public Map<Id<T>, T> map() {
-        return Collections.unmodifiableMap(registered);
+    public List<T> values() {
+        return Collections.unmodifiableList(registered);
     }
 
     private void notNull(T aT) {
 
  * 
  */
 public enum Constants {
-    UNKNOWN_DOCUMENT_TYPE, UNKNOWN_DESTINATION_NAME, UNKNOWN_NAME
+    UNKNOWN_DOCUMENT_TYPE, UNKNOWN_DESTINATION_NAME, UNKNOWN_NAME, UNKNOWN_ID
 }
 
 
 import javax.xml.transform.dom.DOMSource;
 
-import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.DocumentType;
 
 /**
  * @author Erik Brakkee
  * 
  */
-public class RobustDocumentType implements DocumentType {
+public class RobustDocumentType extends RobustIdentifiable<DocumentType>
+    implements DocumentType {
 
     private static final Logger LOGGER = Logger
         .getLogger(RobustDocumentType.class.getName());
 
-    private Id<DocumentType> id;
     private DocumentType type;
 
     /**
      * @param aType
      *            Document type to wrap.
      */
-    public RobustDocumentType(Id<DocumentType> aId, DocumentType aType) {
-        id = aId;
+    public RobustDocumentType(DocumentType aType) {
+        super(aType);
         type = aType;
     }
 
         try {
             String name = type.getName();
             if (name == null) {
-                LOGGER.log(Level.WARNING, "Document type " + id +
+                LOGGER.log(Level.WARNING, "Document type " + getId() +
                     " returned null for name");
                 return Constants.UNKNOWN_DOCUMENT_TYPE.toString();
             }
             return name;
         } catch (Exception e) {
-            LOGGER.log(Level.WARNING, "Document type " + id +
+            LOGGER.log(Level.WARNING, "Document type " + getId() +
                 " threw exception", e);
             return Constants.UNKNOWN_DOCUMENT_TYPE.toString();
         }
         try {
             return type.isInstance(aSource);
         } catch (Exception e) {
-            LOGGER.log(Level.WARNING, "Document type " + id +
+            LOGGER.log(Level.WARNING, "Document type " + getId() +
                 " threw exception", e);
             return false;
         }
         try {
             return type.validate(aSource);
         } catch (Exception e) {
-            LOGGER.log(Level.WARNING, "Document type " + id +
+            LOGGER.log(Level.WARNING, "Document type " + getId() +
                 " threw exception", e);
             return false;
         }
 
 
 import javax.xml.transform.dom.DOMSource;
 
-import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.Filter;
 
 /**
  * @author Erik Brakkee
  * 
  */
-public class RobustFilter implements Filter {
+public class RobustFilter extends RobustIdentifiable<Filter> implements Filter {
 
     private static final Logger LOGGER = Logger.getLogger(RobustFilter.class
         .getName());
 
-    private Id<Filter> id;
     private Filter filter;
 
     /**
      * @param aFilter
      *            Filter to wrap.
      */
-    public RobustFilter(Id<Filter> aId, Filter aFilter) {
-        id = aId;
+    public RobustFilter(Filter aFilter) {
+        super(aFilter);
         filter = aFilter;
     }
 
         try {
             return filter.isAllowed(aDocumentType, aSource);
         } catch (Exception e) {
-            LOGGER.log(Level.WARNING, "Filter " + id +
+            LOGGER.log(Level.WARNING, "Filter " + getId() +
                 " threw exception, assuming filter returns true", e);
             return true;
         }
 
--- /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.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.wamblee.xmlrouter.common.Id;
+import org.wamblee.xmlrouter.config.Identifiable;
+
+/**
+ * Robust identifiable provides robustness for identifiable objects.
+ * 
+ * @author Erik Brakkee
+ * 
+ * @param <T>
+ */
+public class RobustIdentifiable<T> implements Identifiable<T> {
+    private static final Logger LOGGER = Logger
+        .getLogger(RobustIdentifiable.class.getName());
+
+    private Id<T> id;
+
+    // TODO test this class.
+    // TODO test that id is constant even though delegated changes its id.
+
+    public RobustIdentifiable(Identifiable<T> aIdentifiable) {
+        // TODO test id is null
+        // TODO getId() throws exception
+        try {
+            id = aIdentifiable.getId();
+            if (id == null) {
+                id = new Id<T>(Constants.UNKNOWN_ID.toString());
+                throw new RuntimeException(
+                    "Temporary to catch nulls during refactoring");
+            }
+        } catch (Exception e) {
+            LOGGER
+                .log(Level.WARNING, "Identifiable getId() threw exception", e);
+        }
+
+    }
+
+    @Override
+    public Id<T> getId() {
+        return id;
+    }
+
+    // TODO test equals, hashcode.
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object aObj) {
+        if (aObj == null) {
+            return false;
+        }
+        if (!getClass().isInstance(aObj)) {
+            return false;
+        }
+        RobustIdentifiable<T> obj = (RobustIdentifiable<T>) aObj;
+        return id.equals(obj.getId());
+    }
+}
 
 import javax.xml.transform.dom.DOMSource;
 
 import org.wamblee.xml.XMLDocument;
-import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.Transformation;
 
 /**
  * @author Erik Brakkee
  * 
  */
-public class RobustTransformation implements Transformation {
+public class RobustTransformation extends RobustIdentifiable<Transformation>
+    implements Transformation {
 
     private static final Logger LOGGER = Logger
         .getLogger(RobustTransformation.class.getName());
 
-    private Id<Transformation> id;
     private Transformation transformation;
 
     /**
      * @param aTransformation
      *            Wrapped transformation.
      */
-    public RobustTransformation(Id<Transformation> aId,
-        Transformation aTransformation) {
-        id = aId;
+    public RobustTransformation(Transformation aTransformation) {
+        super(aTransformation);
         transformation = aTransformation;
     }
 
-    @Override
-    public String getName() {
-        try {
-            String name = transformation.getName();
-            if (name == null) {
-                logTypeReturnedNull("from");
-                return Constants.UNKNOWN_DOCUMENT_TYPE.toString();
-            }
-            return name;
-        } catch (Exception e) {
-            logNameThrewException(e);
-            return Constants.UNKNOWN_DOCUMENT_TYPE.toString();
-        }
-    }
-
     @Override
     public String getFromType() {
         try {
 
     private void logTranformationThrewException(DOMSource aEvent, Exception aE) {
         LOGGER.log(Level.WARNING,
-            "transformation " + id + " threw exception for event " +
+            "transformation " + getId() + " threw exception for event " +
                 new XMLDocument(aEvent).print(true), aE);
     }
 
     private void logTransformationReturnedNull(DOMSource aEvent) {
-        LOGGER.log(Level.WARNING, "transformation " + id +
+        LOGGER.log(Level.WARNING, "transformation " + getId() +
             " returned null for event " + new XMLDocument(aEvent).print(true));
     }
 
 
  */
 package org.wamblee.xmlrouter.impl;
 
-import java.util.concurrent.atomic.AtomicLong;
-
 import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.Config;
 import org.wamblee.xmlrouter.config.DocumentType;
 import org.wamblee.xmlrouter.config.Filter;
+import org.wamblee.xmlrouter.config.RouterConfig;
 import org.wamblee.xmlrouter.config.Transformation;
 
 /**
  * @author Erik Brakkee
  */
 public class SingleRouterConfig implements ExtendedRouterConfig {
-    private AtomicLong sequenceNumbers;
+    private Id<RouterConfig> id;
     private ExtendedConfig<DocumentType> documentTypes;
     private ExtendedConfig<Transformation> transformations;
     private ExtendedConfig<Filter> filters;
      * @param aSequenceNumberGenerator
      *            Sequence number generator to use.
      */
-    public SingleRouterConfig(AtomicLong aSequenceNumberGenerator) {
-        sequenceNumbers = aSequenceNumberGenerator;
-        documentTypes = new ConfigImpl<DocumentType>(sequenceNumbers) {
+    public SingleRouterConfig(Id<RouterConfig> aId) {
+        id = aId;
+        documentTypes = new ConfigImpl<DocumentType>(new Id<Config>(
+            "documentTypes")) {
             @Override
-            public DocumentType wrap(Id<DocumentType> aId, DocumentType aT) {
-                return new RobustDocumentType(aId, aT);
+            public DocumentType wrap(DocumentType aT) {
+                return new RobustDocumentType(aT);
             }
         };
-        transformations = new ConfigImpl<Transformation>(sequenceNumbers) {
+        transformations = new ConfigImpl<Transformation>(new Id<Config>(
+            "transformations")) {
             @Override
-            public Transformation wrap(Id<Transformation> aId,
-                Transformation aTransformation) {
-                return new RobustTransformation(aId, aTransformation);
+            public Transformation wrap(Transformation aTransformation) {
+                return new RobustTransformation(aTransformation);
             }
         };
-        filters = new ConfigImpl<Filter>(sequenceNumbers) {
+        filters = new ConfigImpl<Filter>(new Id<Config>("filters")) {
             @Override
-            public Filter wrap(Id<Filter> aId, Filter aFilter) {
-                return new RobustFilter(aId, aFilter);
+            public Filter wrap(Filter aFilter) {
+                return new RobustFilter(aFilter);
             }
         };
     }
 
+    // TODO test getId.
+    @Override
+    public Id<RouterConfig> getId() {
+        return id;
+    }
+
     @Override
     public Config<DocumentType> documentTypeConfig() {
         return documentTypes;
 
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Set;
 
-import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.Transformation;
 
 /**
  */
 public class TransformationPaths {
 
-    private Map<Id<Transformation>, Transformation> transformations;
+    private Collection<Transformation> transformations;
     private List<String> vertices;
     private TransformationPath[][] matrix;
 
-    private Map<String, List<TransformationPath>> sequences;
-
     /**
      * Construct the transformations.
      */
-    public TransformationPaths(
-        Map<Id<Transformation>, Transformation> aTransformations) {
+    public TransformationPaths(Collection<Transformation> aTransformations) {
         transformations = aTransformations;
         vertices = new ArrayList<String>();
         matrix = new TransformationPath[0][0];
 
         // Obtain possible starting points.
         Set<String> v = new HashSet<String>();
-        for (Transformation transformation : transformations.values()) {
+        for (Transformation transformation : transformations) {
             v.add(transformation.getFromType());
             v.add(transformation.getToType());
         }
         for (int i = 0; i < nvertices; i++) {
             matrix[i][i] = new TransformationPath();
         }
-        for (Transformation transformation : transformations.values()) {
+        for (Transformation transformation : transformations) {
             int from = vertices.indexOf(transformation.getFromType());
             int to = vertices.indexOf(transformation.getToType());
             TransformationPath path = new TransformationPath(transformation);
 
     private void publishImpl(String aSource, DOMSource aEvent) {
         long time = clock.currentTimeMillis();
 
-        Id<DOMSource> id = new Id<DOMSource>(nextEventId.getAndIncrement());
+        Id<DOMSource> id = new Id<DOMSource>(nextEventId.getAndIncrement() + "");
         List<String> types = determineDocumentTypes(aEvent);
         EventInfo info = new EventInfo(time, aSource, id, types, aEvent);
 
                         // allow the event.
                         boolean result = destination.receive(transformed);
                         listener.delivered(aInfo, ts, destinationId.getId(),
-                            destination.getName(), result);
+                            result);
                         delivered = delivered || result;
 
                     }
 
     private boolean isAllowedByFilters(String aType, DOMSource aEvent) {
         boolean allowed = true;
-        for (Filter filter : config.getRouterConfig().filterConfig().map()
-            .values()) {
+        for (Filter filter : config.getRouterConfig().filterConfig().values()) {
             if (!filter.isAllowed(aType, aEvent)) {
                 allowed = false;
             }
     private List<String> determineDocumentTypes(DOMSource aEvent) {
         List<String> res = new ArrayList<String>();
         for (DocumentType type : config.getRouterConfig().documentTypeConfig()
-            .map().values()) {
+            .values()) {
             if (type.isInstance(aEvent)) {
                 res.add(type.getName());
             }
         return res;
     }
 
-    private void logEvent(String aMessage, String aSource, DOMSource aEvent) {
-        LOGGER.log(Level.WARNING,
-            aMessage + ": " + eventToString(aSource, aEvent));
-    }
-
     private String eventToString(String aSource, DOMSource aEvent) {
         return "source '" + aSource + "': Event: '" +
             new XMLDocument(aEvent).print(true) + "'";
     public Id<Destination> registerDestination(Destination aDestination) {
         notNull("destination", aDestination);
         long seqno = sequenceNumbers.getAndIncrement();
-        Id<Destination> id = new Id<Destination>(seqno);
+        Id<Destination> id = new Id<Destination>(seqno + "");
         destinations.put(id, new RobustDestination(id, aDestination));
         return id;
     }
 
  */
 package org.wamblee.xmlrouter.impl;
 
+import java.util.UUID;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.wamblee.xmlrouter.common.Id;
     public XMLRouterConfigService(XMLRouterConfiguration aConfig) {
         sequence = new AtomicLong(1L);
         config = aConfig;
-        routerConfigs = new ConfigImpl<RouterConfig>(sequence) {
-            public RouterConfig wrap(Id<RouterConfig> aId, RouterConfig aT) {
+        routerConfigs = new ConfigImpl<RouterConfig>(new Id<Config>("config")) {
+            public RouterConfig wrap(RouterConfig aT) {
                 return aT;
             }
         };
 
     @Override
     public RouterConfig emptyConfig() {
-        return new SingleRouterConfig(sequence);
+        // TODO check and document API impacts.
+        String id = UUID.randomUUID().toString();
+        return new SingleRouterConfig(new Id<RouterConfig>(id));
     }
 
     @Override
-    public Id<RouterConfig> apply(RouterConfig aConfig,
-        Id<RouterConfig> aOldConfig) {
+    public void apply(RouterConfig aConfig, Id<RouterConfig> aOldConfig) {
         if (aOldConfig != null) {
             routerConfigs.remove(aOldConfig);
         }
-        Id<RouterConfig> id = routerConfigs.add(aConfig);
+        routerConfigs.add(aConfig);
         update();
-        return id;
     }
 
     @Override
 
     private void update() {
         ExtendedRouterConfig newconfig = new CompositeRouterConfig(
-            routerConfigs.map().values());
+            new Id<RouterConfig>("routerconfig"), routerConfigs.values());
         config.setRouterConfig(newconfig);
     }
 
 
 import java.util.ArrayList;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
+import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.RouterConfig;
 
 /**
     public XMLRouterConfigurationImpl(ExtendedRouterConfig aConfig) {
         config = aConfig;
         transformations = new TransformationPaths(config.transformationConfig()
-            .map());
+            .values());
     }
 
     public XMLRouterConfigurationImpl() {
-        this(new CompositeRouterConfig(new ArrayList<RouterConfig>()));
+        this(new CompositeRouterConfig(new Id<RouterConfig>("routerconfig"),
+            new ArrayList<RouterConfig>()));
     }
 
     @Override
     public void setRouterConfig(ExtendedRouterConfig aConfig) {
 
         TransformationPaths newTransformations = new TransformationPaths(
-            aConfig.transformationConfig().map());
+            aConfig.transformationConfig().values());
 
         wlock.lock();
         try {
 
 import org.junit.Before;
 import org.junit.Test;
 import org.wamblee.xmlrouter.common.Id;
+import org.wamblee.xmlrouter.config.Config;
+import org.wamblee.xmlrouter.config.Identifiable;
 
 public class ConfigImplTest {
 
-    private static interface MyType {
+    private static interface MyType extends Identifiable {
 
     }
 
     private static class MyTypeWrapper implements MyType {
-        private Id<MyType> id;
         private MyType type;
 
-        public MyTypeWrapper(Id<MyType> aId, MyType aType) {
-            id = aId;
+        public MyTypeWrapper(MyType aType) {
             type = aType;
         }
 
         public MyType getType() {
             return type;
         }
+
+        @Override
+        public Id getId() {
+            return type.getId();
+        }
     }
 
     private AtomicLong sequence;
     @Before
     public void setUp() {
         sequence = new AtomicLong(1L);
-        config = new ConfigImpl<MyType>(sequence) {
+        config = new ConfigImpl<MyType>(new Id<Config>("mytype")) {
             @Override
-            public MyType wrap(Id<MyType> aId, MyType aT) {
-                return new MyTypeWrapper(aId, aT);
+            public MyType wrap(MyType aT) {
+                return new MyTypeWrapper(aT);
             }
         };
     }
     @Test
     public void testAdd() {
         MyType type1 = mock(MyType.class);
+        when(type1.getId()).thenReturn(new Id("type1"));
 
-        Id<MyType> id1 = config.add(type1);
+        config.add(type1);
 
-        assertNotNull(id1);
-        assertEquals(1, config.map().size());
-        assertTrue(config.map().get(id1) instanceof MyTypeWrapper);
-        assertSame(type1, ((MyTypeWrapper) config.map().get(id1)).getType());
+        assertEquals(1, config.values().size());
+        assertTrue(config.values().get(0) instanceof MyTypeWrapper);
+        assertSame(type1, ((MyTypeWrapper) config.values().get(0)).getType());
 
         // add another one.
         MyType type2 = mock(MyType.class);
-        Id<MyType> id2 = config.add(type2);
-        assertNotNull(id2);
-        assertEquals(2, config.map().size());
-        assertFalse(id1.equals(id2));
+        when(type2.getId()).thenReturn(new Id("type2"));
+        config.add(type2);
+
+        assertEquals(2, config.values().size());
     }
 
     @Test
     public void testRemove() {
         MyType type1 = mock(MyType.class);
-        Id<MyType> id1 = config.add(type1);
+        when(type1.getId()).thenReturn(new Id("type1"));
+
+        config.add(type1);
 
-        assertNotNull(id1);
-        assertEquals(1, config.map().size());
+        assertEquals(1, config.values().size());
 
-        config.remove(id1);
-        assertTrue(config.map().isEmpty());
+        assertTrue(config.remove(new Id("type1")));
+        assertTrue(config.values().isEmpty());
     }
 
     @Test(expected = UnsupportedOperationException.class)
     public void testUnmodifiable() {
-        config.map().put(new Id<MyType>(100L), mock(MyType.class));
+        config.values().add(mock(MyType.class));
     }
 }
 
     @Before
     public void setUp() {
         destination = mock(Destination.class);
-        robust = new RobustDestination(new Id<Destination>(100), destination);
+        robust = new RobustDestination(new Id<Destination>("100"), destination);
         source = mock(DOMSource.class);
     }
 
 
 
 import org.junit.Before;
 import org.junit.Test;
-import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.DocumentType;
 
 public class RobustDocumentTypeTest {
     @Before
     public void setUp() {
         documentType = mock(DocumentType.class);
-        robust = new RobustDocumentType(new Id<DocumentType>(10), documentType);
+        robust = new RobustDocumentType(documentType);
         source = mock(DOMSource.class);
     }
 
 
 
 import org.junit.Before;
 import org.junit.Test;
-import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.Filter;
 
 public class RobustFilterTest {
     @Before
     public void setUp() {
         filter = mock(Filter.class);
-        robust = new RobustFilter(new Id<Filter>(10), filter);
+        robust = new RobustFilter(filter);
         source = mock(DOMSource.class);
     }
 
 
 
 import org.junit.Before;
 import org.junit.Test;
-import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.Transformation;
 
 public class RobustTransformationTest {
     @Before
     public void setUp() {
         transformation = mock(Transformation.class);
-        robust = new RobustTransformation(new Id<Transformation>(100),
-            transformation);
+        robust = new RobustTransformation(transformation);
         source = mock(DOMSource.class);
         resSource = mock(DOMSource.class);
     }
 
 import static junit.framework.Assert.*;
 import static org.mockito.Mockito.*;
 
-import java.util.concurrent.atomic.AtomicLong;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.DocumentType;
 import org.wamblee.xmlrouter.config.Filter;
+import org.wamblee.xmlrouter.config.RouterConfig;
 import org.wamblee.xmlrouter.config.Transformation;
 
 public class SingleRouterConfigTest {
 
-    private AtomicLong sequence;
     private ExtendedRouterConfig config;
 
     @Before
     public void setUp() {
-        sequence = new AtomicLong(1L);
-        config = new SingleRouterConfig(sequence);
+        config = new SingleRouterConfig(new Id<RouterConfig>("routerconfig"));
     }
 
     @Test
     public void testDocumentType() {
         DocumentType type1 = mock(DocumentType.class);
+        when(type1.getId()).thenReturn(new Id<DocumentType>("type1"));
         DocumentType type2 = mock(DocumentType.class);
+        when(type1.getId()).thenReturn(new Id<DocumentType>("type2"));
 
-        Id<DocumentType> id1 = config.documentTypeConfig().add(type1);
-
-        Id<DocumentType> id2 = config.documentTypeConfig().add(type2);
-        assertFalse(id1.equals(id2));
-
-        assertEquals(2, config.documentTypeConfig().map().size());
-        assertTrue(config.documentTypeConfig().map().get(id1) instanceof RobustDocumentType);
+        config.documentTypeConfig().add(type1);
+        config.documentTypeConfig().add(type2);
 
+        assertEquals(2, config.documentTypeConfig().values().size());
+        assertTrue(config.documentTypeConfig().values().get(0) instanceof RobustDocumentType);
     }
 
     @Test
     public void testTransformation() {
         Transformation transformation1 = mock(Transformation.class);
+        when(transformation1.getId()).thenReturn(new Id<Transformation>("t1"));
         Transformation transformation2 = mock(Transformation.class);
+        when(transformation1.getId()).thenReturn(new Id<Transformation>("t2"));
 
-        Id<Transformation> id1 = config.transformationConfig().add(
-            transformation1);
+        config.transformationConfig().add(transformation1);
 
-        Id<Transformation> id2 = config.transformationConfig().add(
-            transformation2);
-        assertFalse(id1.equals(id2));
+        config.transformationConfig().add(transformation2);
 
-        assertEquals(2, config.transformationConfig().map().size());
-        assertTrue(config.transformationConfig().map().get(id1) instanceof RobustTransformation);
+        assertEquals(2, config.transformationConfig().values().size());
+        assertTrue(config.transformationConfig().values().get(0) instanceof RobustTransformation);
     }
 
     @Test
     public void testFilter() {
         Filter filter1 = mock(Filter.class);
+        when(filter1.getId()).thenReturn(new Id<Filter>("f1"));
         Filter filter2 = mock(Filter.class);
+        when(filter1.getId()).thenReturn(new Id<Filter>("f2"));
 
-        Id<Filter> id1 = config.filterConfig().add(filter1);
+        config.filterConfig().add(filter1);
 
-        Id<Filter> id2 = config.filterConfig().add(filter2);
-        assertFalse(id1.equals(id2));
+        config.filterConfig().add(filter2);
 
-        assertEquals(2, config.filterConfig().map().size());
-        assertTrue(config.filterConfig().map().get(id1) instanceof RobustFilter);
+        assertEquals(2, config.filterConfig().values().size());
+        assertTrue(config.filterConfig().values().get(0) instanceof RobustFilter);
     }
 }
 
 
 import static junit.framework.Assert.*;
 
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.List;
 
 import javax.xml.transform.dom.DOMSource;
 
         }
 
         @Override
-        public String getName() {
-            return "myname";
+        public Id<Transformation> getId() {
+            return new Id<Transformation>("myname");
         }
 
         @Override
 
     private TransformationPaths transformations;
 
-    private Map<Id<Transformation>, Transformation> createTransformations(
-        long aStartId, Transformation... aTransformations) {
-        Map<Id<Transformation>, Transformation> res = new LinkedHashMap<Id<Transformation>, Transformation>();
+    private List<Transformation> createTransformations(long aStartId,
+        Transformation... aTransformations) {
+        List<Transformation> res = new ArrayList<Transformation>();
 
-        long id = aStartId;
         for (Transformation t : aTransformations) {
-            res.put(new Id<Transformation>(id++), t);
+            res.add(t);
         }
         return res;
     }
     @Test
     public void testWithoutTransformations() {
         transformations = new TransformationPaths(
-            new HashMap<Id<Transformation>, Transformation>());
+            new ArrayList<Transformation>());
         Collection<String> res = transformations.getPossibleTargetTypes("a");
         assertEquals(1, res.size());
 
 
 import org.junit.Before;
 import org.junit.Test;
 import org.wamblee.general.SystemClock;
+import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.DocumentType;
 import org.wamblee.xmlrouter.config.RouterConfig;
 import org.wamblee.xmlrouter.config.Transformation;
     public void testOneTransformationOneDestination() {
         RouterConfig routerConfig = registerDocumentType("any");
         Transformation transformation = mock(Transformation.class);
-        when(transformation.getName()).thenReturn("trans");
+        when(transformation.getId())
+            .thenReturn(new Id<Transformation>("trans"));
         when(transformation.getFromType()).thenReturn("any");
         when(transformation.getToType()).thenReturn("bla");
         when(transformation.transform(same(source1))).thenReturn(source2);
         when(destination.receive(any(DOMSource.class))).thenReturn(true);
         routerService.publish("bla", source1);
         verify(listener).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
+            anyListOf(Transformation.class), anyString(), eq(true));
 
         verify(transformation).transform(source1);
         verify(destination).receive(same(source2));
 
 
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.concurrent.atomic.AtomicLong;
 import java.util.logging.Level;
 
 import javax.xml.transform.dom.DOMSource;
 import org.wamblee.xmlrouter.common.Id;
 import org.wamblee.xmlrouter.config.DocumentType;
 import org.wamblee.xmlrouter.config.Filter;
+import org.wamblee.xmlrouter.config.RouterConfig;
 import org.wamblee.xmlrouter.config.Transformation;
 import org.wamblee.xmlrouter.listener.EventInfo;
 import org.wamblee.xmlrouter.listener.EventListener;
 
     @Before
     public void setUp() {
-        routerConfig = new SingleRouterConfig(new AtomicLong(1L));
+        routerConfig = new SingleRouterConfig(new Id<RouterConfig>(
+            "routerconfig"));
         config = new XMLRouterConfigurationImpl(routerConfig);
         EventListener logListener = new LoggingEventListener(Level.INFO);
         listener = spy(logListener);
 
         router.publish("any", source1);
         verify(listener).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
+            anyListOf(Transformation.class), anyString(), eq(true));
         verify(destinationSpy).receive(same(source1));
 
         // Unregister the destination.
         DocumentType type = mock(DocumentType.class);
         when(type.isInstance(any(DOMSource.class))).thenReturn(true);
         when(type.getName()).thenReturn(aType);
-        Id<DocumentType> typeId = routerConfig.documentTypeConfig().add(type);
+        routerConfig.documentTypeConfig().add(type);
     }
 
     private void registerDocumentType(String aType, DOMSource aSource) {
         DocumentType type = mock(DocumentType.class);
         when(type.isInstance(same(aSource))).thenReturn(true);
         when(type.getName()).thenReturn(aType);
-        Id<DocumentType> typeId = routerConfig.documentTypeConfig().add(type);
+        routerConfig.documentTypeConfig().add(type);
     }
 
     private Destination registerDestination(boolean aResult, String... types) {
 
         router.publish("any", source1);
         verify(listener).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
+            anyListOf(Transformation.class), anyString(), eq(true));
 
         verify(destinationSpy2).receive(same(source1));
 
             .registerDestination(destinationSpy2);
         router.publish("any", source1);
         verify(listener).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
+            anyListOf(Transformation.class), anyString(), eq(true));
 
         verify(destinationSpy, never()).receive(same(source1));
         verify(destinationSpy2).receive(same(source1));
             .registerDestination(destinationSpy2);
         router.publish("any", source1);
         verify(listener).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
+            anyListOf(Transformation.class), anyString(), eq(true));
 
         verify(destinationSpy, never()).receive(same(source1));
         verify(destinationSpy2).receive(same(source1));
     public void testOneTransformationOneDestination() {
         registerDocumentType("any");
         Transformation transformation = mock(Transformation.class);
-        when(transformation.getName()).thenReturn("trans");
+        when(transformation.getId())
+            .thenReturn(new Id<Transformation>("trans"));
         when(transformation.getFromType()).thenReturn("any");
         when(transformation.getToType()).thenReturn("bla");
         when(transformation.transform(same(source1))).thenReturn(source2);
         when(destination.receive(any(DOMSource.class))).thenReturn(true);
         router.publish("bla", source1);
         verify(listener).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
+            anyListOf(Transformation.class), anyString(), eq(true));
 
         verify(transformation).transform(source1);
         verify(destination).receive(same(source2));
     public void testMisbehavingTransformationOneDestination() {
         registerDocumentType("any");
         Transformation transformation = mock(Transformation.class);
-        when(transformation.getName()).thenReturn("trans");
+        when(transformation.getId())
+            .thenReturn(new Id<Transformation>("trans"));
         when(transformation.getFromType()).thenReturn("any");
         when(transformation.getToType()).thenReturn("bla");
         doThrow(new RuntimeException("x")).when(transformation).transform(
     private Transformation createTransformation(String aFrom, String aTo,
         DOMSource aSource, DOMSource aTarget) {
         Transformation transformation = mock(Transformation.class);
-        when(transformation.getName()).thenReturn("trans");
+        when(transformation.getId())
+            .thenReturn(new Id<Transformation>("trans"));
         when(transformation.getFromType()).thenReturn(aFrom);
         when(transformation.getToType()).thenReturn(aTo);
         when(transformation.transform(same(aSource))).thenReturn(aTarget);
             .thenReturn(Arrays.asList("bla", "bla2"));
 
         reset(transformation);
-        when(transformation.getName()).thenReturn("trans");
+        when(transformation.getId())
+            .thenReturn(new Id<Transformation>("trans"));
         when(transformation.getFromType()).thenReturn("any");
         when(transformation.getToType()).thenReturn("bla");
         when(transformation.transform(same(source1))).thenReturn(null);
         when(destination.receive(any(DOMSource.class))).thenReturn(true);
         router.publish("bla", source1);
         verify(listener).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
+            anyListOf(Transformation.class), anyString(), eq(true));
 
         verify(transformation).transform(source1);
         verify(transformation2).transform(source1);
 
         router.publish("source", source1);
         verify(listener, times(2)).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
+            anyListOf(Transformation.class), anyString(), eq(true));
 
         verify(dest1).receive(same(source1));
         verify(dest2).receive(same(source1));
 
         router.publish("source", source1);
         verify(listener, times(2)).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
+            anyListOf(Transformation.class), anyString(), eq(true));
 
         verify(dest).receive(same(source1));
         verify(dest).receive(same(source2));
 
         router.publish("source", source1);
         verify(listener).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(true));
+            anyListOf(Transformation.class), anyString(), eq(true));
 
         verify(dest).receive(same(source3));
     }
         router.publish("source", source1);
 
         verify(listener).delivered(any(EventInfo.class),
-            anyListOf(Transformation.class), anyLong(), anyString(), eq(false));
+            anyListOf(Transformation.class), anyString(), eq(false));
 
     }
 }
 
     @Override
     @ReadLock
     public void delivered(EventInfo aInfo, List<Transformation> aSequence,
-        long aDestinationId, String aDestinationName, boolean aSuccessFlag) {
+        String aDestinationId, boolean aSuccessFlag) {
         for (EventListener logger : loggers) {
             try {
-                logger.delivered(aInfo, aSequence, aDestinationId,
-                    aDestinationName, aSuccessFlag);
+                logger
+                    .delivered(aInfo, aSequence, aDestinationId, aSuccessFlag);
             } catch (Exception e) {
                 LOGGER.log(Level.WARNING, "Logger threw exception", e);
             }
 
      *            Sequence of transformations performed.
      * @param aDestinationId
      *            Id of the destination the event was delivered to.
-     * @param aDestinationName
-     *            Destination name.
      * @param aSuccessFlag
      *            Whether or not event delivery succeeded.
      */
     void delivered(EventInfo aInfo, List<Transformation> aSequence,
-        long aDestinationId, String aDestinationName, boolean aSuccessFlag);
+        String aDestinationId, boolean aSuccessFlag);
 
     /**
      * Called when an event could not be delivered to any destination.
 
 
     @Override
     public void delivered(EventInfo aEvent, List<Transformation> aSequence,
-        long aDestinationId, String aDestinationName, boolean aSuccessFlag) {
+        String aDestinationId, boolean aSuccessFlag) {
         if (LOGGER.isLoggable(level)) {
-            LOGGER
-                .log(level, "event delivered: " + aEvent + ", sequence '" +
-                    getSequenceString(aSequence) + "', destinationId " +
-                    aDestinationId + ", destinationName '" + aDestinationName +
-                    "'");
+            LOGGER.log(level, "event delivered: " + aEvent + ", sequence '" +
+                getSequenceString(aSequence) + "', destinationId " +
+                aDestinationId + "'");
         }
     }
 
                 buf.append(", ");
             }
             Transformation transformation = aSequence.get(i);
-            buf.append(transformation.getName());
+            buf.append(transformation.getId());
             buf.append("(");
             buf.append(transformation.getFromType());
             buf.append("->");
 
 
 public class CompositeEventListenerTest {
 
-    private static final String DESTINATION_NAME = "dest";
-    private static final long DESTINATION_ID = 12L;
+    private static final String DESTINATION_ID = "destid";
     private CompositeEventListener composite;
 
     private EventInfo source;
     public void testNoListeners() {
         // verify no exceptions occur.
         composite.delivered(mock(EventInfo.class), getTransformations(),
-            DESTINATION_ID, DESTINATION_NAME, true);
+            DESTINATION_ID, true);
         composite.notDelivered(mock(EventInfo.class));
     }
 
     }
 
     private void invokeDelivered() {
-        composite.delivered(source, getTransformations(), DESTINATION_ID,
-            DESTINATION_NAME, true);
+        composite.delivered(source, getTransformations(), DESTINATION_ID, true);
     }
 
     private void invokeNotDelivered() {
 
     private void checkInvokeDelivered(EventListener listener) {
         verify(listener).delivered(same(source), eq(getTransformations()),
-            eq(DESTINATION_ID), eq(DESTINATION_NAME), eq(true));
+            eq(DESTINATION_ID), eq(true));
     }
 
     @Test