--- /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 java.util.Collection;
+
+import org.wamblee.xmlrouter.common.Id;
+
+/**
+ * Basic configuration interface for managing a set of configuration items of a
+ * given type with unique ids.
+ *
+ * @author Erik Brakkee
+ *
+ * @param <T>
+ * Type for which ids are generated.
+ */
+public interface Config<T> {
+
+ /**
+ * Adds a item
+ *
+ * @param aT
+ * item
+ * @return Unique id.
+ */
+ Id<T> add(T aT);
+
+ /**
+ * Removes the item with a given id.
+ *
+ * @param aId
+ * Item id.
+ * @return true iff the item was removed.
+ */
+ boolean remove(Id<T> aId);
+
+ /**
+ * @return All available ids.
+ */
+ Collection<Id<T>> ids();
+
+ /**
+ * Gets the item for the given id.
+ *
+ * @param aId
+ * Item id.
+ * @return Item, or null if not found.
+ */
+ T get(Id<T> aId);
+
+}
\ No newline at end of file
* 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 javax.xml.transform.dom.DOMSource;
+/**
+ * Represents a type of document with methods to check whether it is an instance
+ * of the type and to validate it.
+ *
+ * @author Erik Brakkee
+ *
+ */
public interface DocumentType {
-
+
/**
- * Symbolic name for the document type.
- * @return Name.
+ * Symbolic name for the document type.
+ *
+ * @return Name.
*/
String getName();
/**
- * Checks if a document is of the given type.
- * @param aSource Document
- * @return True iff the document is of the given type.
+ * Checks if a document is of the given type.
+ *
+ * @param aSource
+ * Document
+ * @return True iff the document is of the given type.
*/
boolean isInstance(DOMSource aSource);
-
+
/**
- * Validates the document. Implementations that do not validate should simply
- * return true always.
- * @param aSource Document.
- * @return True iff the document is valid.
+ * Validates the document. Implementations that do not validate should
+ * simply return true always.
+ *
+ * @param aSource
+ * Document.
+ * @return True iff the document is valid.
*/
boolean validate(DOMSource aSource);
}
* 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 javax.xml.transform.dom.DOMSource;
+/**
+ * Represents a custom filter that is used to determine whether or not a certain
+ * event is allowed or not.
+ *
+ * @author Erik Brakkee
+ *
+ */
public interface Filter {
/**
- * Determines if a given document will be processed or not.
- * @param aSource Source document.
+ * Determines if a given document will be processed or not.
+ *
+ * @param aSource
+ * Source document.
* @return
*/
boolean isAllowed(String aDocumentType, DOMSource aSource);
*/
package org.wamblee.xmlrouter.config;
-import java.util.Collection;
-
-import org.wamblee.xmlrouter.common.Id;
/**
* Configuration API for the XML router.
// Documents
- Id<DocumentType> addDocumentType(DocumentType aType);
-
- void removeDocumentType(Id<DocumentType> aId);
-
- Collection<Id<DocumentType>> getDocumentTypes();
-
- DocumentType getDocumentType(Id<DocumentType> aId);
+ Config<DocumentType> getDocumentTypeConfig();
// Transformations
- Id<Transformation> addTransformation(Transformation aTransformation);
-
- void removeTransformation(Id<Transformation> aId);
-
- Collection<Id<Transformation>> getTransformations();
-
- Transformation getTransformation(Id<Transformation> aId);
+ Config<Transformation> getTransformationConfig();
// Filters
- Id<Filter> addFilter(Filter aFilter);
-
- void removeFilter(Id<Filter> aId);
-
- Collection<Id<Filter>> getFilters();
-
- Filter getFilter(Id<Filter> aId);
+ Config<Filter> getFilterConfig();
}
--- /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;
+
+/**
+ * Router configuration service that provides atomic configuration of the
+ * router. This is the entry point for configuring the router.
+ *
+ * @author Erik Brakkee
+ */
+public interface RouterConfigService {
+
+ /**
+ * @return New empty configuration.
+ */
+ RouterConfig emptyConfig();
+
+ /**
+ * Applies a given configuration.
+ *
+ * @param aConfig
+ * Configuration to use.
+ * @param aOldConfig
+ * Id of the configuration to replace or null if this is a new
+ * configuration.
+ * @return Id of the applied configuration.
+ */
+ Id<RouterConfig> apply(RouterConfig aConfig, Id<RouterConfig> aOldConfig);
+
+ /**
+ * Clears the configuration for a given id.
+ *
+ * @param aConfig
+ * Configuration id.
+ */
+ void clear(Id<RouterConfig> aConfig);
+}
* 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 javax.xml.transform.dom.DOMSource;
+/**
+ * Represents a transformation of a give docuemnt type.
+ *
+ * @author Erik Brakkee
+ *
+ */
public interface Transformation {
-
+
/**
* @return Name for the transformation.
*/
- String getName();
+ String getName();
/**
* From type that can be transformed.
--- /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.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.wamblee.xmlrouter.common.Id;
+import org.wamblee.xmlrouter.config.Config;
+
+/**
+ * Default implementation of the {@link Config} interface.
+ *
+ * @author Erik Brakkee
+ *
+ * @param <T>
+ */
+public abstract class ConfigImpl<T> implements Config<T> {
+
+ private AtomicLong next;
+ private Map<Id<T>, T> registered;
+
+ /**
+ * Constructs the object.
+ */
+ public ConfigImpl() {
+ next = new AtomicLong(1);
+ registered = new LinkedHashMap<Id<T>, T>();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.xmlrouter.config.Config#add(T)
+ */
+ @Override
+ public Id<T> add(T aT) {
+ notNull(aT);
+ long seqno = next.incrementAndGet();
+ Id<T> id = new Id<T>(seqno);
+ registered.put(id, wrap(id, aT));
+ return id;
+ }
+
+ public abstract T wrap(Id<T> aId, T aT);
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.wamblee.xmlrouter.config.Config#remove(org.wamblee.xmlrouter.common
+ * .Id)
+ */
+ @Override
+ public boolean remove(Id<T> aId) {
+ notNull(aId);
+ return registered.remove(aId) != null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.wamblee.xmlrouter.config.Config#ids()
+ */
+ @Override
+ public Collection<Id<T>> ids() {
+ return Collections.unmodifiableCollection(registered.keySet());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.wamblee.xmlrouter.config.Config#get(org.wamblee.xmlrouter.common.Id)
+ */
+ @Override
+ public T get(Id<T> aId) {
+ notNull(aId);
+ return registered.get(aId);
+ }
+
+ private void notNull(T aT) {
+ if (aT == null) {
+ throw new NullPointerException("Object is null");
+ }
+ }
+
+ private void notNull(Id<T> aId) {
+ if (aId == null) {
+ throw new NullPointerException("Id is null");
+ }
+ }
+}
* 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;
+/**
+ * Constants used by the router for error situations.
+ *
+ * @author Erik Brakkee
+ *
+ */
public enum Constants {
UNKNOWN_DOCUMENT_TYPE, UNKNOWN_DESTINATION_NAME, UNKNOWN_NAME
}
--- /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 javax.xml.transform.dom.DOMSource;
+
+import org.wamblee.xmlrouter.common.Id;
+import org.wamblee.xmlrouter.config.DocumentType;
+
+/**
+ * Robust document type provides robustness towards externally provided document
+ * types.
+ *
+ * @author Erik Brakkee
+ *
+ */
+public class RobustDocumentType implements DocumentType {
+
+ private static final Logger LOGGER = Logger
+ .getLogger(RobustDocumentType.class.getName());
+
+ private Id<DocumentType> id;
+ private DocumentType type;
+
+ /**
+ * Constructs the wrapper.
+ *
+ * @param aId
+ * Id.
+ * @param aType
+ * Document type to wrap.
+ */
+ public RobustDocumentType(Id<DocumentType> aId, DocumentType aType) {
+ id = aId;
+ type = aType;
+ }
+
+ @Override
+ public String getName() {
+ try {
+ String name = type.getName();
+ if (name == null) {
+ LOGGER.log(Level.WARNING, "Document type " + id +
+ " returned null for name");
+ return Constants.UNKNOWN_DOCUMENT_TYPE.toString();
+ }
+ return name;
+ } catch (Exception e) {
+ LOGGER.log(Level.WARNING, "Document type " + id +
+ " threw exception", e);
+ return Constants.UNKNOWN_DOCUMENT_TYPE.toString();
+ }
+ }
+
+ @Override
+ public boolean isInstance(DOMSource aSource) {
+ try {
+ return type.isInstance(aSource);
+ } catch (Exception e) {
+ LOGGER.log(Level.WARNING, "Document type " + id +
+ " threw exception", e);
+ return false;
+ }
+ }
+
+ @Override
+ public boolean validate(DOMSource aSource) {
+ try {
+ return type.validate(aSource);
+ } catch (Exception e) {
+ LOGGER.log(Level.WARNING, "Document type " + id +
+ " threw exception", e);
+ return false;
+ }
+ }
+}
* 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 org.wamblee.xmlrouter.common.Id;
import org.wamblee.xmlrouter.config.Filter;
+/**
+ * This class provides robustness towards externally supplied filters.
+ *
+ * @author Erik Brakkee
+ *
+ */
public class RobustFilter implements Filter {
private static final Logger LOGGER = Logger.getLogger(RobustFilter.class
private Id<Filter> id;
private Filter filter;
+ /**
+ * Constructs the wrapper.
+ *
+ * @param aId
+ * Id.
+ * @param aFilter
+ * Filter to wrap.
+ */
public RobustFilter(Id<Filter> aId, Filter aFilter) {
id = aId;
filter = aFilter;
* 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 org.wamblee.xmlrouter.common.Id;
import org.wamblee.xmlrouter.config.Transformation;
+/**
+ * This class provides robustness towards externally provided transformations.
+ *
+ * @author Erik Brakkee
+ *
+ */
public class RobustTransformation implements Transformation {
private static final Logger LOGGER = Logger
private Id<Transformation> id;
private Transformation transformation;
+ /**
+ * Constructs the wrapper.
+ *
+ * @param aId
+ * Unique id.
+ * @param aTransformation
+ * Wrapped transformation.
+ */
public RobustTransformation(Id<Transformation> aId,
Transformation aTransformation) {
id = aId;
transformation = aTransformation;
}
-
+
@Override
public String getName() {
try {
* 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.ArrayList;
import org.wamblee.xmlrouter.config.Transformation;
+/**
+ * Transformation path from a source document to a destination.
+ *
+ * @author Erik Brakkee
+ *
+ */
public class TransformationPath {
private List<Transformation> transformations;
+ /**
+ * Constructs empty path.
+ */
public TransformationPath() {
transformations = new ArrayList<Transformation>();
}
+ /**
+ * Constructs path with single transformation.
+ *
+ * @param aTransformation
+ * Single transformation.
+ */
public TransformationPath(Transformation aTransformation) {
this();
transformations.add(aTransformation);
}
+ /**
+ * Constructs path with list of transformations.
+ *
+ * @param aTransformations
+ * List of transformations.
+ */
public TransformationPath(List<Transformation> aTransformations) {
this();
transformations.addAll(aTransformations);
}
+ /**
+ * Appends a transormation path to the current path.
+ *
+ * @param aSequence
+ * Transformation sequence to append.
+ * @return Appended transformations equence.
+ * @throws Runtime
+ * exception if the appended transformation would not be valid.
+ */
public TransformationPath appendPath(TransformationPath aSequence) {
if (transformations.isEmpty()) {
return new TransformationPath(aSequence.transformations);
return new TransformationPath(t);
}
+ /**
+ * @return Number of transformations.
+ */
public int size() {
return transformations.size();
}
+ /**
+ * @return From type of the path or null if the sequence is empty.
+ */
public String getFromType() {
if (transformations.isEmpty()) {
return null;
return transformations.get(0).getFromType();
}
+ /**
+ * @return To type of the path or null if the sequence is empty.
+ */
public String getToType() {
if (transformations.isEmpty()) {
return null;
return transformations.get(transformations.size() - 1).getToType();
}
+ /**
+ * @return The transformations.
+ */
public List<Transformation> getTransformations() {
return transformations;
}
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashSet;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
import org.wamblee.xmlrouter.common.Id;
+import org.wamblee.xmlrouter.config.Config;
import org.wamblee.xmlrouter.config.Transformation;
+/**
+ * This class manages transformations and computes the shortest transformations
+ * paths based on the provided transformations.
+ *
+ * @author Erik Brakkee
+ *
+ */
public class Transformations {
- private AtomicLong sequenceNumber;
- private Map<Id<Transformation>, Transformation> transformations;
+ private Config<Transformation> transformations;
private List<String> vertices;
private TransformationPath[][] matrix;
private Map<String, List<TransformationPath>> sequences;
+ /**
+ * Construct the transformations.
+ */
public Transformations() {
- sequenceNumber = new AtomicLong(1);
- transformations = new LinkedHashMap<Id<Transformation>, Transformation>();
+ transformations = new ConfigImpl<Transformation>() {
+ @Override
+ public Transformation wrap(Id<Transformation> aId,
+ Transformation aType) {
+ return new RobustTransformation(aId, aType);
+ }
+ };
vertices = new ArrayList<String>();
matrix = new TransformationPath[0][0];
}
+ public Config<Transformation> getTransformationConfig() {
+ return new Config<Transformation>() {
+ @Override
+ public Id<Transformation> add(Transformation aT) {
+ return addTransformation(aT);
+ }
+
+ @Override
+ public Transformation get(Id<Transformation> aId) {
+ return transformations.get(aId);
+ }
+
+ @Override
+ public Collection<Id<Transformation>> ids() {
+ return transformations.ids();
+ }
+
+ @Override
+ public boolean remove(Id<Transformation> aId) {
+ return transformations.remove(aId);
+ }
+ };
+ }
+
+ /**
+ * Adds a transformation. Leads to recomputation of shortest paths.
+ *
+ * @param aTransformation
+ * Transformation to add.
+ * @return Id of the transformation.
+ */
public Id<Transformation> addTransformation(Transformation aTransformation) {
- long seqno = sequenceNumber.getAndIncrement();
- Id<Transformation> id = new Id<Transformation>(seqno);
- transformations.put(id, new RobustTransformation(id, aTransformation));
+ Id<Transformation> id = transformations.add(aTransformation);
computeTransformationSequences();
return id;
}
+ /**
+ * Gets the possible target types based on an input type.
+ *
+ * @param aType
+ * Input type.
+ * @return Possible target types.
+ */
public Collection<String> getPossibleTargetTypes(String aType) {
int index = vertices.indexOf(aType);
Set<String> res = new HashSet<String>();
return matrix[i][j];
}
+ /**
+ * Computest the transformation sequences using Floyd's algorithm.
+ */
private void computeTransformationSequences() {
vertices = new ArrayList<String>();
// Obtain possible starting points.
Set<String> v = new HashSet<String>();
- for (Transformation transformation : transformations.values()) {
+ for (Id<Transformation> id : transformations.ids()) {
+ Transformation transformation = transformations.get(id);
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 (Id<Transformation> id : transformations.ids()) {
+ Transformation transformation = transformations.get(id);
int from = vertices.indexOf(transformation.getFromType());
int to = vertices.indexOf(transformation.getToType());
TransformationPath path = new TransformationPath(transformation);
.size();
}
+ /**
+ * Removes a transformation.
+ *
+ * @param aId
+ * Id of the transformation.
+ */
public void removeTransformation(Id<Transformation> aId) {
transformations.remove(aId);
computeTransformationSequences();
}
- public Collection<Id<Transformation>> getTransformations() {
- return Collections.unmodifiableCollection(transformations.keySet());
- }
-
- public Transformation getTransformation(Id<Transformation> aId) {
- return transformations.get(aId);
- }
-
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import org.wamblee.general.Clock;
import org.wamblee.xml.XMLDocument;
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.subscribe.Destination;
import org.wamblee.xmlrouter.subscribe.DestinationRegistry;
-// TODO concurrency.
-
+/**
+ * The XML Router.
+ *
+ * @author Erik Brakkee
+ *
+ */
public class XMLRouter implements RouterConfig, Gateway, DestinationRegistry {
private static final Logger LOGGER = Logger.getLogger(XMLRouter.class
.getName());
+ private AtomicLong sequenceNumbers;
private EventListener listener;
private Clock clock;
private AtomicLong nextEventId;
- private AtomicLong sequenceNumbers;
- private Map<Id<DocumentType>, DocumentType> documentTypes;
+
+ private Config<DocumentType> documentTypes;
private Transformations transformations;
- private Map<Id<Filter>, Filter> filters;
+ private Config<Filter> filters;
private Map<Id<Destination>, Destination> destinations;
public XMLRouter(Clock aClock, EventListener aListener) {
+ sequenceNumbers = new AtomicLong(1);
listener = aListener;
clock = aClock;
nextEventId = new AtomicLong(clock.currentTimeMillis());
- sequenceNumbers = new AtomicLong(1);
- documentTypes = new LinkedHashMap<Id<DocumentType>, DocumentType>();
+ documentTypes = new ConfigImpl<DocumentType>() {
+ @Override
+ public DocumentType wrap(Id<DocumentType> aId, DocumentType aType) {
+ return new RobustDocumentType(aId, aType);
+ }
+ };
transformations = new Transformations();
- filters = new LinkedHashMap<Id<Filter>, Filter>();
+ filters = new ConfigImpl<Filter>() {
+ @Override
+ public Filter wrap(Id<Filter> aId, Filter aFilter) {
+ return new RobustFilter(aId, aFilter);
+ }
+ };
destinations = new LinkedHashMap<Id<Destination>, Destination>();
}
@Override
- public Id<DocumentType> addDocumentType(DocumentType aType) {
- long seqno = sequenceNumbers.getAndIncrement();
- documentTypes.put(new Id<DocumentType>(seqno), aType);
- return new Id<DocumentType>(seqno);
- }
-
- @Override
- public void removeDocumentType(Id<DocumentType> aId) {
- documentTypes.remove(aId);
- }
-
- @Override
- public Collection<Id<DocumentType>> getDocumentTypes() {
- return Collections.unmodifiableCollection(documentTypes.keySet());
- }
-
- @Override
- public DocumentType getDocumentType(Id<DocumentType> aId) {
- return documentTypes.get(aId);
- }
-
- @Override
- public Id<Transformation> addTransformation(Transformation aTransformation) {
- return transformations.addTransformation(aTransformation);
- }
-
- @Override
- public void removeTransformation(Id<Transformation> aId) {
- transformations.removeTransformation(aId);
- }
-
- @Override
- public Collection<Id<Transformation>> getTransformations() {
- return transformations.getTransformations();
- }
-
- @Override
- public Transformation getTransformation(Id<Transformation> aId) {
- return transformations.getTransformation(aId);
- }
-
- @Override
- public Id<Filter> addFilter(Filter aFilter) {
- long seqno = sequenceNumbers.getAndIncrement();
- filters.put(new Id<Filter>(seqno), aFilter);
- return new Id<Filter>(seqno);
- }
-
- @Override
- public void removeFilter(Id<Filter> aId) {
- filters.remove(aId);
+ public Config<DocumentType> getDocumentTypeConfig() {
+ return documentTypes;
}
@Override
- public Collection<Id<Filter>> getFilters() {
- return Collections.unmodifiableCollection(filters.keySet());
+ public Config<Transformation> getTransformationConfig() {
+ return transformations.getTransformationConfig();
}
@Override
- public Filter getFilter(Id<Filter> aId) {
- return filters.get(aId);
+ public Config<Filter> getFilterConfig() {
+ return filters;
}
@Override
private boolean isAllowedByFilters(String aType, DOMSource aEvent) {
boolean allowed = true;
- for (Filter filter : filters.values()) {
+ for (Id<Filter> id : filters.ids()) {
+ Filter filter = filters.get(id);
if (!filter.isAllowed(aType, aEvent)) {
allowed = false;
}
private List<String> determineDocumentTypes(DOMSource aEvent) {
List<String> res = new ArrayList<String>();
- for (DocumentType type : documentTypes.values()) {
+ for (Id<DocumentType> id : documentTypes.ids()) {
+ DocumentType type = documentTypes.get(id);
if (type.isInstance(aEvent)) {
res.add(type.getName());
}
--- /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 static junit.framework.Assert.*;
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.*;
+
+import javax.xml.transform.dom.DOMSource;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.wamblee.xmlrouter.common.Id;
+import org.wamblee.xmlrouter.config.DocumentType;
+
+public class RobustDocumentTypeTest {
+
+ private DocumentType documentType;
+ private DocumentType robust;
+ private DOMSource source;
+
+ @Before
+ public void setUp() {
+ documentType = mock(DocumentType.class);
+ robust = new RobustDocumentType(new Id<DocumentType>(10), documentType);
+ source = mock(DOMSource.class);
+ }
+
+ @Test
+ public void testNoEzception() {
+ when(documentType.isInstance(any(DOMSource.class))).thenReturn(true);
+ when(documentType.getName()).thenReturn("hello");
+ assertTrue(robust.isInstance(source));
+ assertEquals("hello", robust.getName());
+
+ verify(documentType).isInstance(same(source));
+
+ reset(documentType);
+ when(documentType.isInstance(any(DOMSource.class))).thenReturn(false);
+ assertFalse(robust.isInstance(source));
+ verify(documentType).isInstance(same(source));
+ }
+
+ @Test
+ public void testExceptionInIsInstance() {
+ doThrow(new RuntimeException("bla")).when(documentType).isInstance(
+ any(DOMSource.class));
+ assertFalse(robust.isInstance(source));
+ verify(documentType).isInstance(same(source));
+ }
+
+ @Test
+ public void testExceptionInValidate() {
+ doThrow(new RuntimeException("bla")).when(documentType).validate(
+ any(DOMSource.class));
+ assertFalse(robust.validate(source));
+ verify(documentType).validate(same(source));
+ }
+
+ @Test
+ public void testExceptionInGetName() {
+ doThrow(new RuntimeException("bla")).when(documentType).getName();
+ assertEquals(Constants.UNKNOWN_DOCUMENT_TYPE.toString(),
+ robust.getName());
+ }
+
+ @Test
+ public void testGetNameReturnsNull() {
+ when(documentType.getName()).thenReturn(null);
+ assertEquals(Constants.UNKNOWN_DOCUMENT_TYPE.toString(),
+ robust.getName());
+ }
+}
import org.wamblee.general.SystemClock;
import org.wamblee.xmlrouter.common.Id;
import org.wamblee.xmlrouter.config.DocumentType;
+import org.wamblee.xmlrouter.config.Filter;
import org.wamblee.xmlrouter.config.Transformation;
import org.wamblee.xmlrouter.listener.EventInfo;
import org.wamblee.xmlrouter.listener.EventListener;
verify(listener).notDelivered(any(EventInfo.class));
}
+ @Test
+ public void testMisBehavingDocumentType() {
+ DocumentType type = mock(DocumentType.class);
+ doThrow(new RuntimeException("x")).when(type).isInstance(
+ any(DOMSource.class));
+ router.getDocumentTypeConfig().add(type);
+ router.publish("xx", mock(DOMSource.class));
+ verify(listener).notDelivered(any(EventInfo.class));
+ // no exception should occur.
+ }
+
+ @Test
+ public void testMisBehavingFilter() {
+ registerDocumentType("any");
+ Filter filter = mock(Filter.class);
+ doThrow(new RuntimeException("x")).when(filter).isAllowed(anyString(),
+ any(DOMSource.class));
+ router.getFilterConfig().add(filter);
+ router.publish("xx", mock(DOMSource.class));
+ verify(listener).notDelivered(any(EventInfo.class));
+ // no exception should occur.
+ }
+
@Test
public void testOneDestinationNoTransformationSuccess() {
destinationSpy = registerDestination(true, "any");
DocumentType type = mock(DocumentType.class);
when(type.isInstance(any(DOMSource.class))).thenReturn(true);
when(type.getName()).thenReturn(aType);
- Id<DocumentType> typeId = router.addDocumentType(type);
+ Id<DocumentType> typeId = router.getDocumentTypeConfig().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 = router.addDocumentType(type);
+ Id<DocumentType> typeId = router.getDocumentTypeConfig().add(type);
}
private Destination registerDestination(boolean aResult, String... types) {
when(transformation.getFromType()).thenReturn("any");
when(transformation.getToType()).thenReturn("bla");
when(transformation.transform(same(source1))).thenReturn(source2);
- router.addTransformation(transformation);
+ router.getTransformationConfig().add(transformation);
Destination destination = mock(Destination.class);
when(
verify(listener).notDelivered(any(EventInfo.class));
}
+ @Test
+ public void testMisbehavingTransformationOneDestination() {
+ registerDocumentType("any");
+ Transformation transformation = mock(Transformation.class);
+ when(transformation.getName()).thenReturn("trans");
+ when(transformation.getFromType()).thenReturn("any");
+ when(transformation.getToType()).thenReturn("bla");
+ doThrow(new RuntimeException("x")).when(transformation).transform(
+ same(source1));
+ router.getTransformationConfig().add(transformation);
+
+ Destination destination = mock(Destination.class);
+ when(
+ destination.chooseFromTargetTypes((Collection<String>) anyObject()))
+ .thenReturn(Arrays.asList("bla"));
+
+ router.registerDestination(destination);
+
+ when(destination.receive(any(DOMSource.class))).thenReturn(true);
+ router.publish("bla", source1);
+ verify(listener).notDelivered(any(EventInfo.class));
+ }
+
private Transformation createTransformation(String aFrom, String aTo,
DOMSource aSource, DOMSource aTarget) {
Transformation transformation = mock(Transformation.class);
Transformation transformation = createTransformation("any", "bla",
source1, null);
- router.addTransformation(transformation);
+ router.getTransformationConfig().add(transformation);
Destination destination = mock(Destination.class);
when(
Transformation transformation2 = createTransformation("any", "bla2",
source1, source2);
- router.addTransformation(transformation2);
+ router.getTransformationConfig().add(transformation2);
when(
destination.chooseFromTargetTypes((Collection<String>) anyObject()))
.thenReturn(Arrays.asList("bla", "bla2"));
registerDocumentType("other", source2);
Transformation transformation = createTransformation("any", "other",
source1, source2);
- router.addTransformation(transformation);
+ router.getTransformationConfig().add(transformation);
router.publish("source", source1);
verify(listener, times(2)).delivered(any(EventInfo.class),
Transformation t1 = createTransformation("any", "intermediate",
source1, source2);
- router.addTransformation(t1);
+ router.getTransformationConfig().add(t1);
Transformation t2 = createTransformation("intermediate", "other",
source2, source3);
- router.addTransformation(t2);
+ router.getTransformationConfig().add(t2);
router.publish("source", source1);
verify(listener).delivered(any(EventInfo.class),