From 7d7d583192d7d2285993c05278a52c0014167401 Mon Sep 17 00:00:00 2001 From: Tony Tkacik Date: Tue, 28 May 2013 13:26:05 +0200 Subject: [PATCH] Added extensible implementation of Transformators - set of generic Transformers - factories responsible for producing outputs based on input objects - Ideal for development of translation layers between protocol specific objects and abstract transfer objects such as Actions in SAL. Signed-off-by: Tony Tkacik --- opendaylight/commons/concepts/pom.xml | 50 ++++++ .../concepts/tranform/Acceptor.java | 20 +++ .../tranform/AggregateTransformer.java | 22 +++ .../CompositeClassBasedTransformer.java | 121 ++++++++++++++ .../CompositeConditionalTransformer.java | 157 ++++++++++++++++++ .../tranform/InputClassBasedTransformer.java | 38 +++++ .../tranform/RuleBasedTransformer.java | 42 +++++ .../SimpleConditionalTransformer.java | 38 +++++ .../concepts/tranform/Transformer.java | 27 +++ .../distribution/opendaylight/pom.xml | 1 + 10 files changed, 516 insertions(+) create mode 100644 opendaylight/commons/concepts/pom.xml create mode 100644 opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/Acceptor.java create mode 100644 opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/AggregateTransformer.java create mode 100644 opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/CompositeClassBasedTransformer.java create mode 100644 opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/CompositeConditionalTransformer.java create mode 100644 opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/InputClassBasedTransformer.java create mode 100644 opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/RuleBasedTransformer.java create mode 100644 opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/SimpleConditionalTransformer.java create mode 100644 opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/Transformer.java diff --git a/opendaylight/commons/concepts/pom.xml b/opendaylight/commons/concepts/pom.xml new file mode 100644 index 0000000000..369a58af44 --- /dev/null +++ b/opendaylight/commons/concepts/pom.xml @@ -0,0 +1,50 @@ + + + 4.0.0 + + org.opendaylight.controller + commons.opendaylight + 1.4.0-SNAPSHOT + ../../commons/opendaylight + + + concepts + 0.5.0-SNAPSHOT + bundle + + + + + org.apache.felix + maven-bundle-plugin + 2.3.6 + true + + + + org.slf4j, + org.osgi.framework, + org.apache.commons.lang3.builder, + org.apache.felix.dm, + org.apache.commons.lang3.tuple, + javax.xml.bind.annotation, + javax.xml.bind.annotation.adapters + + + org.opendaylight.controller.concepts.transform + + + ${project.basedir}/META-INF + + + + + + + junit + junit + 4.8.1 + test + + + diff --git a/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/Acceptor.java b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/Acceptor.java new file mode 100644 index 0000000000..1bd78d62c7 --- /dev/null +++ b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/Acceptor.java @@ -0,0 +1,20 @@ + +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.concepts.tranform; + +public interface Acceptor { + + /** + * + * @param input + * @return true if input is accepted. + */ + boolean isAcceptable(I input); +} diff --git a/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/AggregateTransformer.java b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/AggregateTransformer.java new file mode 100644 index 0000000000..390bc0302d --- /dev/null +++ b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/AggregateTransformer.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.concepts.tranform; + +import java.util.Collection; +/** + * + * @author Tony Tkacik + * + * @param + * @param

+ */ +public interface AggregateTransformer extends Transformer { + + Collection

transformAll(Collection inputs); +} diff --git a/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/CompositeClassBasedTransformer.java b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/CompositeClassBasedTransformer.java new file mode 100644 index 0000000000..ec62feec7a --- /dev/null +++ b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/CompositeClassBasedTransformer.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.concepts.tranform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * Transformer which aggregates multiple implementations of + * {@link InputClassBasedTransformer}. + * + * The transformation process is driven by {@link Class} of input. The selection + * of used {@link InputClassBasedTransformer} is done by using the {@link Class} + * of input as a key to select the transformer. + * + * This approach provides quick resolution of transformer, but does not support + * registering a super type of input to provide transformation support for all + * subclasses, one must register a new instance of transformer for each valid + * input class. + * + * If you need more flexible selection of transformation consider using + * {@link CompositeConditionalTransformer} which is slower but most flexible or + * {@link RuleBasedTransformer} which provides declarative approach for + * transformation. + * + * See {@link #transform(Object)} for more information about tranformation + * process. + * + * @author Tony Tkacik + * + * @param + * Input super-type + * @param

+ * Product + */ +public abstract class CompositeClassBasedTransformer implements + InputClassBasedTransformer, + AggregateTransformer { + + private Map, InputClassBasedTransformer> transformers = new ConcurrentHashMap, InputClassBasedTransformer>(); + + /** + * Transforms an input into instance of Product class. + * + * The final registered transformer is the one which match following + * condition: + * + * input.getClass() == transformer.getInputClass() + * + * This means that transformers are not resolved by class hierarchy, only + * selected based on final class of the input. If you need more flexible + * selection of transformation consider using + * {@link CompositeConditionalTransformer} which is slower but more + * flexible. + * + */ + @Override + public P transform(I input) { + @SuppressWarnings("unchecked") + InputClassBasedTransformer transformer = (InputClassBasedTransformer) transformers + .get(input.getClass()); + if (transformer == null) + throw new IllegalArgumentException("Transformation of: " + input + + " is not supported"); + return transformer.transform(input); + } + + /** + * Registers a new transformer. + * + * The transformer is registered for class returned by + * {@link InputClassBasedTransformer#getInputClass()}. Only one transformer + * can be registered for particular input class. + * + */ + public void addTransformer( + InputClassBasedTransformer transformer) + throws IllegalStateException { + if (transformer == null) + throw new IllegalArgumentException("Transformer should not be null"); + if (transformer.getInputClass() == null) + throw new IllegalArgumentException( + "Transformer should specify input class."); + transformers.put(transformer.getInputClass(), transformer); + } + + /** + * Removes an registered transformer. + * + * Note: Removal is currently unsupported. + * + * @param transformer + * Tranformer to be removed. + * @throws IllegalArgumentException + * If the provided transformer is null or is not registered. + */ + public void removeTransformer( + InputClassBasedTransformer transformer) + throws IllegalArgumentException { + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Override + public Collection

transformAll(Collection inputs) { + Collection

ret = new ArrayList

(); + for (I i : inputs) { + ret.add(transform(i)); + } + return ret; + } + +} diff --git a/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/CompositeConditionalTransformer.java b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/CompositeConditionalTransformer.java new file mode 100644 index 0000000000..a31d896372 --- /dev/null +++ b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/CompositeConditionalTransformer.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.concepts.tranform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Set; +import java.util.TreeSet; + +/** + * Composite transformer which aggregates multiple implementation and selects + * the one which accepts the input. + * + * + * @author Tony Tkacik + * + * @param + * Input class for transformation + * @param

+ * Product of transformation + */ +public class CompositeConditionalTransformer implements + SimpleConditionalTransformer, + AggregateTransformer { + + private final Comparator> comparator = new Comparator>() { + + @Override + public int compare(TransformerWithPriority o1, + TransformerWithPriority o2) { + return Integer.compare(o1.priority, o2.priority); + } + + }; + private final Set> transformers; + + public CompositeConditionalTransformer() { + // FIXME: Add Ordering + transformers = new TreeSet>(comparator); + } + + @Override + public boolean isAcceptable(I input) { + for (SimpleConditionalTransformer trans : transformers) { + if (trans.isAcceptable(input)) { + return true; + } + } + return false; + } + + @Override + public P transform(I input) { + for (SimpleConditionalTransformer trans : transformers) { + if (trans.isAcceptable(input)) { + return trans.transform(input); + } + } + throw new IllegalStateException( + "Transformer for provided input is not available."); + } + + public void addTransformer(SimpleConditionalTransformer transformer, + int priority) throws IllegalStateException { + if (transformer == null) { + throw new IllegalArgumentException( + "transformer should not be null."); + } + TransformerWithPriority withPriority = new TransformerWithPriority( + transformer, priority); + if (false == transformers.add(withPriority)) { + throw new IllegalStateException("transformer " + transformer + + "already registered"); + } + } + + public void removeTransformer(SimpleConditionalTransformer transformer) + throws IllegalArgumentException { + if (transformer == null) { + throw new IllegalArgumentException( + "transformer should not be null."); + } + if (false == transformers.remove(transformer)) { + throw new IllegalStateException("transformer " + transformer + + "already registered"); + } + } + + @Override + public Collection

transformAll(Collection inputs) { + Collection

ret = new ArrayList

(); + for (I i : inputs) { + ret.add(transform(i)); + } + return ret; + } + + private static class TransformerWithPriority implements + SimpleConditionalTransformer { + final int priority; + final SimpleConditionalTransformer transformer; + + public TransformerWithPriority( + SimpleConditionalTransformer transformer, int priority) { + this.priority = priority; + this.transformer = transformer; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((transformer == null) ? 0 : transformer.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TransformerWithPriority other = (TransformerWithPriority) obj; + if (transformer == null) { + if (other.transformer != null) + return false; + } else if (!transformer.equals(other.transformer)) + return false; + return true; + } + + @Override + public boolean isAcceptable(I input) { + return transformer.isAcceptable(input); + } + + @Override + public P transform(I input) { + return transformer.transform(input); + } + + + + + + } +} diff --git a/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/InputClassBasedTransformer.java b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/InputClassBasedTransformer.java new file mode 100644 index 0000000000..1b8d1f0466 --- /dev/null +++ b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/InputClassBasedTransformer.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.concepts.tranform; + +/** + * Input class based transformer + * + * {@link Transformer} which accepts / transforms only specific classes of + * input, and is useful if the selection of transformer should be based on the + * class of the input and there is one-to-one mapping between input class and + * transformer. + * + * + * @author Tony Tkacik + * + * @param + * Common supertype of input + * @param + * Concrete type of input + * @param

+ * Product + */ +public interface InputClassBasedTransformer extends + Transformer { + + /** + * Returns an {@link Class} of input which is acceptable for transformation. + * + * @return {@link Class} of input which is acceptable for transformation. + */ + Class getInputClass(); +} diff --git a/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/RuleBasedTransformer.java b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/RuleBasedTransformer.java new file mode 100644 index 0000000000..3f21e5aafa --- /dev/null +++ b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/RuleBasedTransformer.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.concepts.tranform; + +import java.util.Set; + +/** + * Transformer with set of acceptance rules + * + * The transformer provides a set of {@link Acceptor}s, which could be used to + * verify if the input will produce result using the transformer. + * + * The transormer is able to produce result if ANY of associated + * {@link Acceptor}s accepted result. + * + * @author Tony Tkacik + * + * @param + * Input class for transformation + * @param

+ * Product of transformation + */ +public interface RuleBasedTransformer extends Transformer { + + /** + * Set of {@link Acceptor}, which could be used to verify if the input is + * usable by transformer. + * + * The transformer is able to produce result if ANY of associated + * {@link Acceptor}s accepted result. + * + * @return Set of input acceptance rules associated to this transformer. + */ + Set> getRules(); + +} diff --git a/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/SimpleConditionalTransformer.java b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/SimpleConditionalTransformer.java new file mode 100644 index 0000000000..5a9b555ac6 --- /dev/null +++ b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/SimpleConditionalTransformer.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.concepts.tranform; + +/** + * Simple condition-based transformer + * + * The transformer provides {@link #isAcceptable(Object)} method, + * which could be used to query transformer if the input will produce + * result. + * + * This interface is simplified version of {@link RuleBasedTransformer} - does not + * provide decoupling of Acceptance rule from transformer, and should be used only + * for simple use-cases. + * + * @author Tony Tkacik + * + * @param Input class for transformation + * @param

Product of transformation + */ +public interface SimpleConditionalTransformer extends Transformer, Acceptor { + + + /** + * Checks if the input is acceptable + * for processing by the transformer. + * + * @return true it the input is acceptable for processing by transformer. + */ + @Override + public boolean isAcceptable(I input); +} diff --git a/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/Transformer.java b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/Transformer.java new file mode 100644 index 0000000000..58fe0e1eb6 --- /dev/null +++ b/opendaylight/commons/concepts/src/main/java/org/opendaylight/controller/concepts/tranform/Transformer.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.concepts.tranform; + +/** + * Factory which produces product based on input object + * + * @author Tony Tkacik + * + * @param Input + * @param

Product + */ +public interface Transformer { + /** + * Transforms input into instance of product. + * + * @param input Input which drives transformation + * @return Instance of product which was created from supplied input. + */ + P transform(I input); +} diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index ddc24b3965..86725e9d05 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -97,6 +97,7 @@ ../../samples/simpleforwarding ../../samples/loadbalancer ../../samples/northbound/loadbalancer + ../../commons/concepts -- 2.36.6