aboutsummaryrefslogtreecommitdiffstats
path: root/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders
diff options
context:
space:
mode:
Diffstat (limited to 'policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders')
-rw-r--r--policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/EventProtocolCoder.java1451
-rw-r--r--policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/JsonProtocolFilter.java304
-rw-r--r--policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/ProtocolCoderToolset.java668
-rw-r--r--policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/TopicCoderFilterConfiguration.java309
4 files changed, 2732 insertions, 0 deletions
diff --git a/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/EventProtocolCoder.java b/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/EventProtocolCoder.java
new file mode 100644
index 00000000..8f8a4ba7
--- /dev/null
+++ b/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/EventProtocolCoder.java
@@ -0,0 +1,1451 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * policy-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.drools.protocol.coders;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.openecomp.policy.common.logging.eelf.MessageCodes;
+import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
+import org.openecomp.policy.common.logging.flexlogger.Logger;
+import org.openecomp.policy.drools.controller.DroolsController;
+import org.openecomp.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
+import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomGsonCoder;
+import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomJacksonCoder;
+import org.openecomp.policy.drools.utils.Pair;
+
+/**
+ * Coder (Encoder/Decoder) of Events.
+ */
+public interface EventProtocolCoder {
+
+ public static class CoderFilters {
+
+ /**
+ * coder class
+ */
+ protected String factClass;
+
+ /**
+ * filters to apply to the selection of the decodedClass;
+ */
+ protected JsonProtocolFilter filter;
+
+ /**
+ * classloader hash
+ */
+ protected int modelClassLoaderHash;
+
+
+ /**
+ * constructor
+ *
+ * @param codedClass coder class
+ * @param filter filters to apply
+ */
+ public CoderFilters(String codedClass, JsonProtocolFilter filter, int modelClassLoaderHash) {
+ this.factClass = codedClass;
+ this.filter = filter;
+ this.modelClassLoaderHash = modelClassLoaderHash;
+ }
+
+ /**
+ * @return the codedClass
+ */
+ public String getCodedClass() {
+ return factClass;
+ }
+
+ /**
+ * @param codedClass the decodedClass to set
+ */
+ public void setCodedClass(String codedClass) {
+ this.factClass = codedClass;
+ }
+
+ /**
+ * @return the filter
+ */
+ public synchronized JsonProtocolFilter getFilter() {
+ return filter;
+ }
+
+ /**
+ * @param filter the filter to set
+ */
+ public synchronized void setFilter(JsonProtocolFilter filter) {
+ this.filter = filter;
+ }
+
+ public int getModelClassLoaderHash() {
+ return modelClassLoaderHash;
+ }
+
+ public void setFromClassLoaderHash(int fromClassLoaderHash) {
+ this.modelClassLoaderHash = fromClassLoaderHash;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("CoderFilters [factClass=").append(factClass).append(", filter=").append(filter)
+ .append(", modelClassLoaderHash=").append(modelClassLoaderHash).append("]");
+ return builder.toString();
+ }
+
+ }
+
+ /**
+ * Adds a Decoder class to decode the protocol over this topic
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic the topic
+ * @param eventClass the event class
+ * @param protocolFilter filters to selectively choose a particular decoder
+ * when there are multiples
+ *
+ * @throw IllegalArgumentException if an invalid parameter is passed
+ */
+ public void addDecoder(String groupId, String artifactId,
+ String topic,
+ String eventClass,
+ JsonProtocolFilter protocolFilter,
+ CustomGsonCoder customGsonCoder,
+ CustomJacksonCoder customJacksonCoder,
+ int modelClassLoaderHash)
+ throws IllegalArgumentException;
+
+ /**
+ * removes all decoders associated with the controller id
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic of the controller
+ *
+ * @throws IllegalArgumentException if invalid arguments have been provided
+ */
+ void removeEncoders(String groupId, String artifactId, String topic) throws IllegalArgumentException;
+
+ /**
+ * removes decoders associated with the controller id and topic
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic the topic
+ *
+ * @throws IllegalArgumentException if invalid arguments have been provided
+ */
+ public void removeDecoders(String groupId, String artifactId, String topic) throws IllegalArgumentException;
+
+ /**
+ * Given a controller id and a topic, it gives back its filters
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic the topic
+ *
+ * return list of decoders
+ *
+ * @throw IllegalArgumentException if an invalid parameter is passed
+ */
+ public List<CoderFilters> getDecoderFilters(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException;
+
+
+ /**
+ * Given a controller id and a topic, it gives back the decoding configuration
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic the topic
+ *
+ * return decoding toolset
+ *
+ * @throw IllegalArgumentException if an invalid parameter is passed
+ */
+ public ProtocolCoderToolset getDecoders(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException;
+
+ /**
+ * Given a controller id and a topic, it gives back all the decoding configurations
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic the topic
+ *
+ * return decoding toolset
+ *
+ * @throw IllegalArgumentException if an invalid parameter is passed
+ */
+ public List<ProtocolCoderToolset> getDecoders(String groupId, String artifactId)
+ throws IllegalArgumentException;
+
+
+ /**
+ * gets all decoders associated with the group and artifact ids
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ *
+ * @throws IllegalArgumentException if invalid arguments have been provided
+ */
+ public List<CoderFilters> getDecoderFilters(String groupId, String artifactId) throws IllegalArgumentException;
+
+
+ /**
+ * Given a controller id and a topic, it gives back the classes that implements the encoding
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic the topic
+ *
+ * return list of decoders
+ *
+ * @throw IllegalArgumentException if an invalid parameter is passed
+ */
+ public List<CoderFilters> getEncoderFilters(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException;
+
+ /**
+ * gets all encoders associated with the group and artifact ids
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ *
+ * @throws IllegalArgumentException if invalid arguments have been provided
+ */
+ public List<CoderFilters> getEncoderFilters(String groupId, String artifactId) throws IllegalArgumentException;
+
+ /**
+ * Given a controller id, a topic, and a classname, it gives back the classes that implements the decoding
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic the topic
+ * @param classname classname
+ *
+ * return list of decoders
+ *
+ * @throw IllegalArgumentException if an invalid parameter is passed
+ */
+ public CoderFilters getDecoderFilters(String groupId, String artifactId, String topic, String classname)
+ throws IllegalArgumentException;
+
+ /**
+ * is there a decoder supported for the controller id and topic
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic protocol
+ * @return true if supported
+ */
+ public boolean isDecodingSupported(String groupId, String artifactId, String topic);
+
+ /**
+ * Adds a Encoder class to encode the protocol over this topic
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic the topic
+ * @param eventClass the event class
+ * @param protocolFilter filters to selectively choose a particular decoder
+ * when there are multiples
+ *
+ * @throw IllegalArgumentException if an invalid parameter is passed
+ */
+ public void addEncoder(String groupId, String artifactId, String topic,
+ String eventClass,
+ JsonProtocolFilter protocolFilter,
+ CustomGsonCoder customGsonCoder,
+ CustomJacksonCoder customJacksonCoder,
+ int modelClassLoaderHash)
+ throws IllegalArgumentException;
+
+ /**
+ * is there an encoder supported for the controller id and topic
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic protocol
+ * @return true if supported
+ */
+ public boolean isEncodingSupported(String groupId, String artifactId, String topic);
+
+ /**
+ * get encoder based on coordinates and classname
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic protocol
+ * @param json event string
+ * @return
+ * @throws IllegalArgumentException invalid arguments passed in
+ */
+ public CoderFilters getEncoderFilters(String groupId, String artifactId, String topic, String classname)
+ throws IllegalArgumentException;
+
+ /**
+ * get encoder based on topic and encoded class
+ *
+ * @param topic topic
+ * @param encodedClass encoded class
+ * @return
+ * @throws IllegalArgumentException invalid arguments passed in
+ */
+ public List<CoderFilters> getReverseEncoderFilters(String topic, String encodedClass)
+ throws IllegalArgumentException;
+
+ /**
+ * gets the identifier of the creator of the encoder
+ *
+ * @param topic topic
+ * @param encodedClass encoded class
+ * @return a drools controller
+ * @throws IllegalArgumentException invalid arguments passed in
+ */
+ public DroolsController getDroolsController(String topic, Object encodedClass)
+ throws IllegalArgumentException;
+
+ /**
+ * gets the identifier of the creator of the encoder
+ *
+ * @param topic topic
+ * @param encodedClass encoded class
+ * @return list of drools controllers
+ * @throws IllegalArgumentException invalid arguments passed in
+ */
+ public List<DroolsController> getDroolsControllers(String topic, Object encodedClass)
+ throws IllegalArgumentException;
+
+ /**
+ * decode topic's stringified event (json) to corresponding Event Object.
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic protocol
+ * @param json event string
+ * @return
+ * @throws IllegalArgumentException invalid arguments passed in
+ * @throws UnsupportedOperationException if the operation is not supported
+ * @throws IllegalStateException if the system is in an illegal state
+ */
+ public Object decode(String groupId, String artifactId, String topic, String json)
+ throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException;
+
+ /**
+ * encodes topic's stringified event (json) to corresponding Event Object.
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic protocol
+ * @param event Object
+ *
+ * @throws IllegalArgumentException invalid arguments passed in
+ */
+ public String encode(String groupId, String artifactId, String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;
+
+ /**
+ * encodes topic's stringified event (json) to corresponding Event Object.
+ *
+ * @param topic topic
+ * @param event event object
+ *
+ * @throws IllegalArgumentException invalid arguments passed in
+ * @throws UnsupportedOperationException operation cannot be performed
+ */
+ public String encode(String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;
+
+ /**
+ * encodes topic's stringified event (json) to corresponding Event Object.
+ *
+ * @param topic topic
+ * @param event event object
+ * @param droolsController
+ *
+ * @throws IllegalArgumentException invalid arguments passed in
+ * @throws UnsupportedOperationException operation cannot be performed
+ */
+ public String encode(String topic, Object event, DroolsController droolsController)
+ throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;
+
+ /**
+ * singleton reference to the global event protocol coder
+ */
+ public static EventProtocolCoder manager = new MultiplexorEventProtocolCoder();
+}
+
+/**
+ * Protocol Coder that does its best attempt to decode/encode, selecting the best
+ * class and best fitted json parsing tools.
+ */
+class MultiplexorEventProtocolCoder implements EventProtocolCoder {
+ // get an instance of logger
+ private static Logger logger = FlexLogger.getLogger(MultiplexorEventProtocolCoder.class);
+ /**
+ * Decoders
+ */
+ protected EventProtocolDecoder decoders = new EventProtocolDecoder();
+
+ /**
+ * Encoders
+ */
+ protected EventProtocolEncoder encoders = new EventProtocolEncoder();
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addDecoder(String groupId, String artifactId, String topic,
+ String eventClass,
+ JsonProtocolFilter protocolFilter,
+ CustomGsonCoder customGsonCoder,
+ CustomJacksonCoder customJacksonCoder,
+ int modelClassLoaderHash)
+ throws IllegalArgumentException {
+ logger.info("ADD-DECODER: " + groupId + ":" + artifactId + ":" +
+ topic + ":" + eventClass + ":" +
+ protocolFilter + ":" + customGsonCoder +
+ ":" + customJacksonCoder + ":" + modelClassLoaderHash +
+ " INTO " + this);
+ this.decoders.add(groupId, artifactId, topic, eventClass, protocolFilter,
+ customGsonCoder, customJacksonCoder, modelClassLoaderHash);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void addEncoder(String groupId, String artifactId, String topic,
+ String eventClass,
+ JsonProtocolFilter protocolFilter,
+ CustomGsonCoder customGsonCoder,
+ CustomJacksonCoder customJacksonCoder,
+ int modelClassLoaderHash)
+ throws IllegalArgumentException {
+ logger.info("ADD-ENCODER: " + groupId + ":" + artifactId + ":" +
+ topic + ":" + eventClass + ":" +
+ protocolFilter + ":" + customGsonCoder +
+ ":" + customJacksonCoder + ":" + modelClassLoaderHash +
+ " INTO " + this);
+ this.encoders.add(groupId, artifactId, topic, eventClass, protocolFilter,
+ customGsonCoder, customJacksonCoder, modelClassLoaderHash);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeDecoders(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException {
+ logger.info("REMOVE-DECODER: " + groupId + ":" + artifactId + ":" +
+ topic + " FROM " + this);
+ this.decoders.remove(groupId, artifactId, topic);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeEncoders(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException {
+ logger.info("REMOVE-ENCODER: " + groupId + ":" + artifactId + ":" +
+ topic + " FROM " + this);
+ this.encoders.remove(groupId, artifactId, topic);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isDecodingSupported(String groupId, String artifactId, String topic) {
+ return this.decoders.isCodingSupported(groupId, artifactId, topic);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isEncodingSupported(String groupId, String artifactId, String topic) {
+ return this.encoders.isCodingSupported(groupId, artifactId, topic);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object decode(String groupId, String artifactId, String topic, String json)
+ throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException {
+ logger.info("DECODE: " + groupId + ":" + artifactId + ":" +
+ topic + ":" + json + " WITH " + this);
+ return this.decoders.decode(groupId, artifactId, topic, json);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String encode(String groupId, String artifactId, String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException {
+ logger.info("ENCODE: " + groupId + ":" + artifactId + ":" +
+ topic + ":" + event + " WITH " + this);
+ return this.encoders.encode(groupId, artifactId, topic, event);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String encode(String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException {
+ logger.info("ENCODE: " + topic + ":" + event + " WITH " + this);
+ return this.encoders.encode(topic, event);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String encode(String topic, Object event, DroolsController droolsController)
+ throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException {
+ logger.info("ENCODE: " + topic + ":" + event + ":" + droolsController + " WITH " + this);
+ return this.encoders.encode(topic, event, droolsController);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<CoderFilters> getDecoderFilters(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException {
+
+ return this.decoders.getFilters(groupId, artifactId, topic);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ProtocolCoderToolset getDecoders(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException {
+
+ Pair<ProtocolCoderToolset,ProtocolCoderToolset> decoderToolsets = this.decoders.getCoders(groupId, artifactId, topic);
+ if (decoderToolsets == null)
+ throw new IllegalArgumentException("Decoders not found for " + groupId + ":" + artifactId + ":" + topic);
+
+ return decoderToolsets.first();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<CoderFilters> getEncoderFilters(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException {
+
+ return this.encoders.getFilters(groupId, artifactId, topic);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CoderFilters getDecoderFilters(String groupId, String artifactId, String topic, String classname)
+ throws IllegalArgumentException {
+
+ return this.decoders.getFilters(groupId, artifactId, topic, classname);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CoderFilters getEncoderFilters(String groupId, String artifactId, String topic, String classname)
+ throws IllegalArgumentException {
+
+ return this.encoders.getFilters(groupId, artifactId, topic, classname);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<CoderFilters> getReverseEncoderFilters(String topic, String encodedClass) throws IllegalArgumentException {
+ return this.encoders.getReverseFilters(topic, encodedClass);
+ }
+
+ /**
+ * get all deocders by maven coordinates and topic
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ *
+ * @return list of decoders
+ * @throws IllegalArgumentException if invalid input
+ */
+ @Override
+ public List<ProtocolCoderToolset> getDecoders(String groupId, String artifactId)
+ throws IllegalArgumentException {
+
+ List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> decoderToolsets = this.decoders.getCoders(groupId, artifactId);
+ if (decoderToolsets == null)
+ throw new IllegalArgumentException("Decoders not found for " + groupId + ":" + artifactId);
+
+ List<ProtocolCoderToolset> parser1CoderToolset = new ArrayList<>();
+ for (Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderToolsetPair : decoderToolsets) {
+ parser1CoderToolset.add(coderToolsetPair.first());
+ }
+
+ return parser1CoderToolset;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<CoderFilters> getDecoderFilters(String groupId, String artifactId) throws IllegalArgumentException {
+ return this.decoders.getFilters(groupId, artifactId);
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<CoderFilters> getEncoderFilters(String groupId, String artifactId) throws IllegalArgumentException {
+ return this.encoders.getFilters(groupId, artifactId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DroolsController getDroolsController(String topic, Object encodedClass) throws IllegalArgumentException {
+ return this.encoders.getDroolsController(topic, encodedClass);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<DroolsController> getDroolsControllers(String topic, Object encodedClass) throws IllegalArgumentException {
+ return this.encoders.getDroolsControllers(topic, encodedClass);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("MultiplexorEventProtocolCoder [decoders=").append(decoders).append(", encoders=")
+ .append(encoders).append("]");
+ return builder.toString();
+ }
+}
+
+/**
+ * This protocol Coder that does its best attempt to decode/encode, selecting the best
+ * class and best fitted json parsing tools.
+ */
+abstract class GenericEventProtocolCoder {
+ private static Logger logger = FlexLogger.getLogger(GenericEventProtocolCoder.class);
+
+ /**
+ * Mapping topic:controller-id -> <protocol-decoder-toolset-pair>
+ * where protocol-coder-toolset-pair contains both a jackson-protocol-coder-toolset
+ * and a gson-protocol-coder-toolset. The first value of the pair will the
+ * protocol coder toolset most likely to be successful with the encoding or decoding,
+ * and consequently the second value will be the less likely.
+ */
+ protected final HashMap<String, Pair<ProtocolCoderToolset,ProtocolCoderToolset>> coders =
+ new HashMap<String, Pair<ProtocolCoderToolset,ProtocolCoderToolset>>();
+
+ /**
+ * Mapping topic + classname -> Protocol Set
+ */
+ protected final HashMap<String, List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>> reverseCoders =
+ new HashMap<String, List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>>();
+
+ protected boolean multipleToolsetRetries = false;
+
+ GenericEventProtocolCoder(boolean multipleToolsetRetries) {
+ this.multipleToolsetRetries = multipleToolsetRetries;
+ }
+
+ /**
+ * Index a new coder
+ *
+ * @param groupId of the controller
+ * @param artifactId of the controller
+ * @param topic the topic
+ * @param eventClass the event class
+ * @param protocolFilter filters to selectively choose a particular decoder
+ * when there are multiples
+ *
+ * @throw IllegalArgumentException if an invalid parameter is passed
+ */
+ public void add(String groupId, String artifactId,
+ String topic,
+ String eventClass,
+ JsonProtocolFilter protocolFilter,
+ CustomGsonCoder customGsonCoder,
+ CustomJacksonCoder customJacksonCoder,
+ int modelClassLoaderHash)
+ throws IllegalArgumentException {
+ if (groupId == null || groupId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid group id");
+ }
+
+ if (artifactId == null || artifactId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid artifact id");
+ }
+
+ if (topic == null || topic.isEmpty()) {
+ throw new IllegalArgumentException("Invalid Topic");
+ }
+
+ if (eventClass == null) {
+ throw new IllegalArgumentException("Invalid Event Class");
+ }
+
+ String key = this.codersKey(groupId, artifactId, topic);
+ String reverseKey = this.reverseCodersKey(topic, eventClass);
+
+ synchronized(this) {
+ if (coders.containsKey(key)) {
+ Pair<ProtocolCoderToolset, ProtocolCoderToolset> toolsets = coders.get(key);
+
+ if (logger.isInfoEnabled())
+ logger.info("ADDING CODER TO EXISTING: " + toolsets + " for " + key);
+
+ toolsets.first().addCoder(eventClass, protocolFilter, modelClassLoaderHash);
+ toolsets.second().addCoder(eventClass, protocolFilter, modelClassLoaderHash);
+
+ if (!reverseCoders.containsKey(reverseKey)) {
+ if (logger.isInfoEnabled())
+ logger.info("Multiple coder classes case: " + toolsets.first() +
+ " for " + reverseKey + " - " + key);
+
+ List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> reverseMappings =
+ new ArrayList<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>();
+ reverseMappings.add(toolsets);
+ reverseCoders.put(reverseKey, reverseMappings);
+ }
+ return;
+ }
+
+ GsonProtocolCoderToolset gsonCoderTools =
+ new GsonProtocolCoderToolset
+ (topic, key,
+ groupId, artifactId,
+ eventClass, protocolFilter,
+ customGsonCoder,
+ modelClassLoaderHash);
+
+ JacksonProtocolCoderToolset jacksonCoderTools =
+ new JacksonProtocolCoderToolset
+ (topic, key,
+ groupId, artifactId,
+ eventClass, protocolFilter,
+ customJacksonCoder,
+ modelClassLoaderHash);
+
+ // Use Gson as the first priority encoding/decoding toolset, and Jackson
+ // as second. This is because it has been observed that they can diverge
+ // somewhat in the encoding/decoding data types, which can produce json
+ // that may result incompatible with what some network elements are
+ // expecting. As decoding takes place, this element will reconfigure
+ // itself to set the jackson one as the favoured one first, if errors
+ // are detected in the gson encoding
+
+ Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools =
+ new Pair<ProtocolCoderToolset,ProtocolCoderToolset>(gsonCoderTools,
+ jacksonCoderTools);
+
+ logger.info("ADDED TOOLSET: " + key + " : " +
+ coderTools + ":" + this);
+
+ coders.put(key, coderTools);
+
+ if (reverseCoders.containsKey(reverseKey)) {
+ // There is another controller (different group id/artifact id/topic)
+ // that shares the class and the topic.
+
+ List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> toolsets =
+ reverseCoders.get(reverseKey);
+ boolean present = false;
+ for (Pair<ProtocolCoderToolset,ProtocolCoderToolset> parserSet: toolsets) {
+ // just doublecheck
+ present = parserSet.first().getControllerId().equals(key);
+ if (present) {
+ /* anomaly */
+ logger.error("UNEXPECTED TOOLSET REVERSE MAPPING FOUND: " + parserSet.first() +
+ " for " + reverseKey + " - " + key);
+ }
+ }
+
+ if (present) {
+ return;
+ } else {
+ logger.info("ADDING TOOLSET REVERSE MAPPING: " + reverseKey + " : " +
+ toolsets + ":" + coderTools + ":" + this);
+ toolsets.add(coderTools);
+ }
+ } else {
+ List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> toolsets =
+ new ArrayList<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>();
+ logger.info("ADDING TOOLSET REVERSE MAPPING: " + reverseKey + " : " +
+ toolsets + ":" + coderTools + ":" + this);
+ toolsets.add(coderTools);
+ reverseCoders.put(reverseKey, toolsets);
+ }
+
+ }
+ }
+
+ /**
+ * produces key for indexing toolset entries
+ *
+ * @param group group id
+ * @param artifactId artifact id
+ * @param topic topic
+ * @return index key
+ */
+ protected String codersKey(String groupId, String artifactId, String topic) {
+ return groupId + ":" + artifactId + ":" + topic;
+ }
+
+ /**
+ * produces a key for the reverse index
+ *
+ * @param topic topic
+ * @param eventClass coded class
+ * @return reverse index key
+ */
+ protected String reverseCodersKey(String topic, String eventClass) {
+ return topic + ":" + eventClass;
+ }
+
+ /**
+ * remove coder
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ * @param topic topic
+ * @throws IllegalArgumentException if invalid input
+ */
+ public void remove(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException {
+
+ if (groupId == null || groupId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid group id");
+ }
+
+ if (artifactId == null || artifactId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid artifact id");
+ }
+
+ if (topic == null || topic.isEmpty()) {
+ throw new IllegalArgumentException("Invalid Topic");
+ }
+
+ String key = this.codersKey(groupId, artifactId, topic);
+
+ synchronized(this) {
+ if (coders.containsKey(key)) {
+ Pair<ProtocolCoderToolset, ProtocolCoderToolset> p = coders.remove(key);
+ logger.info("REMOVED TOOLSET: " + key + " : " + p + " FROM " +
+ coders + " : " + this);
+
+ for (CoderFilters codeFilter : p.first().getCoders()) {
+ String className = codeFilter.getCodedClass();
+ String reverseKey = this.reverseCodersKey(topic, className);
+ if (this.reverseCoders.containsKey(reverseKey) ) {
+ List<Pair<ProtocolCoderToolset, ProtocolCoderToolset>> toolsets =
+ this.reverseCoders.get(reverseKey);
+ Iterator<Pair<ProtocolCoderToolset, ProtocolCoderToolset>> toolsetsIter =
+ toolsets.iterator();
+ while (toolsetsIter.hasNext()) {
+ Pair<ProtocolCoderToolset, ProtocolCoderToolset> toolset = toolsetsIter.next();
+ if (toolset.first().getControllerId().equals(key)) {
+ logger.info("REMOVED CODER FROM REVERSE MAPPING of TOOLSET: " + reverseKey + " : " + toolset + " FROM " +
+ reverseCoders);
+ toolsetsIter.remove();
+ }
+ }
+
+ if (this.reverseCoders.get(reverseKey).isEmpty()) {
+ logger.info("REMOVE FULL REVERSE MAPPING of TOOLSET: " + reverseKey + " FROM " +
+ reverseCoders);
+ this.reverseCoders.remove(reverseKey);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * does it support coding?
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ * @param topic topic
+ * @return true if its is codable
+ */
+ public boolean isCodingSupported(String groupId, String artifactId, String topic) {
+
+ if (groupId == null || groupId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid group id");
+ }
+
+ if (artifactId == null || artifactId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid artifact id");
+ }
+
+ if (topic == null || topic.isEmpty())
+ return false;
+
+ String key = this.codersKey(groupId, artifactId, topic);
+ synchronized(this) {
+ return (coders.containsKey(key));
+ }
+ }
+
+ /**
+ * decode a json string into an Object
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ * @param topic topic
+ * @param json json string to convert to object
+ * @return the decoded object
+ * @throws IllegalArgumentException if invalid argument is provided
+ * @throws UnsupportedOperationException if the operation cannot be performed
+ */
+ public Object decode(String groupId, String artifactId, String topic, String json)
+ throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException {
+
+ if (!isCodingSupported(groupId, artifactId, topic)) {
+ throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic) + " for encoding");
+ }
+
+ String key = this.codersKey(groupId, artifactId, topic);
+ Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
+ try {
+ Object event = coderTools.first().decode(json);
+ if (event != null)
+ return event;
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ logger.warn("Can't decode @ " + this);
+ }
+
+ if (multipleToolsetRetries) {
+ // try the less favored toolset
+ try {
+ Object event = coderTools.second().decode(json);
+ if (event != null) {
+ // change the priority of the toolset
+ synchronized(this) {
+ ProtocolCoderToolset first = coderTools.first();
+ ProtocolCoderToolset second = coderTools.second();
+ coderTools.first(second);
+ coderTools.second(first);
+ }
+
+ return event;
+ }
+ } catch (Exception e2) {
+ // TODO Auto-generated catch block
+ e2.printStackTrace();
+ throw new UnsupportedOperationException(e2);
+ }
+ }
+
+ throw new UnsupportedOperationException("Cannot decode neither with gson or jackson");
+ }
+
+ /**
+ * encode an object into a json string
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ * @param topic topic
+ * @param event object to convert to string
+ * @return the json string
+ * @throws IllegalArgumentException if invalid argument is provided
+ * @throws UnsupportedOperationException if the operation cannot be performed
+ */
+ public String encode(String groupId, String artifactId, String topic, Object event)
+ throws IllegalArgumentException, UnsupportedOperationException {
+
+ if (!isCodingSupported(groupId, artifactId, topic)) {
+ throw new IllegalArgumentException
+ ("Unsupported:" + codersKey(groupId, artifactId, topic));
+ }
+
+ if (event == null) {
+ throw new IllegalArgumentException("Unsupported topic:" + topic);
+ }
+
+ // reuse the decoder set, since there must be affinity in the model
+ String key = this.codersKey(groupId, artifactId, topic);
+ return this.encodeInternal(key, event);
+ }
+
+ /**
+ * encode an object into a json string
+ *
+ * @param key identifier
+ * @param event object to convert to string
+ * @return the json string
+ * @throws IllegalArgumentException if invalid argument is provided
+ * @throws UnsupportedOperationException if the operation cannot be performed
+ */
+ protected String encodeInternal(String key, Object event)
+ throws IllegalArgumentException, UnsupportedOperationException {
+
+ logger.debug("ENCODE: " + key + ":" + event + this);
+
+ Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
+ try {
+ String json = coderTools.first().encode(event);
+ if (json != null && !json.isEmpty())
+ return json;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "FIRST-ENCODE-INTERNAL: " +
+ key + ":" + event, this.toString());
+ }
+
+ if (multipleToolsetRetries) {
+ // try the less favored toolset
+ try {
+ String json = coderTools.second().encode(event);
+ if (json != null) {
+ // change the priority of the toolset
+ synchronized(this) {
+ ProtocolCoderToolset first = coderTools.first();
+ ProtocolCoderToolset second = coderTools.second();
+ coderTools.first(second);
+ coderTools.second(first);
+ }
+
+ return json;
+ }
+ } catch (Exception e2) {
+ // TODO Auto-generated catch block
+ logger.error(MessageCodes.EXCEPTION_ERROR, e2, "SECOND-ENCODE-INTERNAL: " +
+ key + ":" + event, this.toString());
+ throw new UnsupportedOperationException(e2);
+ }
+ }
+
+ throw new UnsupportedOperationException("Cannot decode neither with gson or jackson");
+ }
+
+ /**
+ * encode an object into a json string
+ *
+ * @param topic topic
+ * @param encodedClass object to convert to string
+ * @return the json string
+ * @throws IllegalArgumentException if invalid argument is provided
+ * @throws UnsupportedOperationException if the operation cannot be performed
+ */
+ public String encode(String topic, Object encodedClass)
+ throws IllegalArgumentException, IllegalArgumentException, UnsupportedOperationException {
+
+ if (encodedClass == null) {
+ throw new IllegalArgumentException("Invalid encoded class");
+ }
+
+ if (topic == null || topic.isEmpty()) {
+ throw new IllegalArgumentException("Invalid topic");
+ }
+
+ logger.info("ENCODE: " + topic + ":" +
+ encodedClass.getClass().getCanonicalName() + ":" +
+ encodedClass);
+
+ List<DroolsController> droolsControllers = droolsCreators(topic, encodedClass);
+ if (droolsControllers.size() > 1) {
+ // unexpected
+ logger.warn("MULTIPLE DROOLS CONTROLLERS FOUND for: " + topic + ":" +
+ encodedClass.getClass().getCanonicalName() + ":" +
+ droolsControllers + " IN " + this);
+ // continue
+ }
+
+ String key = codersKey(droolsControllers.get(0).getGroupId(), droolsControllers.get(0).getArtifactId(), topic);
+ return this.encodeInternal(key, encodedClass);
+ }
+
+ /**
+ * encode an object into a json string
+ *
+ * @param topic topic
+ * @param encodedClass object to convert to string
+ * @return the json string
+ * @throws IllegalArgumentException if invalid argument is provided
+ * @throws UnsupportedOperationException if the operation cannot be performed
+ */
+ public String encode(String topic, Object encodedClass, DroolsController droolsController)
+ throws IllegalArgumentException, IllegalArgumentException, UnsupportedOperationException {
+
+ if (encodedClass == null) {
+ throw new IllegalArgumentException("Invalid encoded class");
+ }
+
+ if (topic == null || topic.isEmpty()) {
+ throw new IllegalArgumentException("Invalid topic");
+ }
+
+ logger.info("ENCODE: " + topic + ":" +
+ encodedClass.getClass().getCanonicalName() + ":" +
+ encodedClass + ":" + droolsController);
+
+ String key = codersKey(droolsController.getGroupId(), droolsController.getArtifactId(), topic);
+ return this.encodeInternal(key, encodedClass);
+ }
+
+ /**
+ * @param topic
+ * @param encodedClass
+ * @param reverseKey
+ * @return
+ * @throws IllegalStateException
+ * @throws IllegalArgumentException
+ */
+ protected List<DroolsController> droolsCreators(String topic, Object encodedClass)
+ throws IllegalStateException, IllegalArgumentException {
+
+ List<DroolsController> droolsControllers = new ArrayList<DroolsController>();
+
+ String reverseKey = this.reverseCodersKey(topic, encodedClass.getClass().getCanonicalName());
+ if (!this.reverseCoders.containsKey(reverseKey)) {
+ logger.warn("NO MAPPING for REVERSE KEY: " + topic + ":" +
+ encodedClass.getClass().getCanonicalName() + ":" +
+ encodedClass + ":" + reverseKey + " : " + this);
+ return droolsControllers;
+ }
+
+ List<Pair<ProtocolCoderToolset, ProtocolCoderToolset>>
+ toolsets = this.reverseCoders.get(reverseKey);
+
+ // There must be multiple toolset pairs associated with <topic,classname> reverseKey
+ // case 2 different controllers use the same models and register the same encoder for
+ // the same topic. This is assumed not to occur often but for the purpose of encoding
+ // but there should be no side-effects. Ownership is crosscheck against classname and
+ // classloader reference.
+
+ if (toolsets == null || toolsets.isEmpty()) {
+ logger.warn("ENCODE: " + topic + ":" +
+ encodedClass.getClass().getCanonicalName() + ":" +
+ encodedClass + " ENCODER NOT FOUND");
+ throw new IllegalStateException("No Encoders toolsets available for topic "+ topic +
+ " encoder " + encodedClass.getClass().getCanonicalName());
+ }
+
+ for (Pair<ProtocolCoderToolset, ProtocolCoderToolset> encoderSet : toolsets) {
+ // figure out the right toolset
+ String groupId = encoderSet.first().getGroupId();
+ String artifactId = encoderSet.first().getArtifactId();
+ List<CoderFilters> coders = encoderSet.first().getCoders();
+ for (CoderFilters coder : coders) {
+ if (coder.getCodedClass().equals(encodedClass.getClass().getCanonicalName())) {
+ DroolsController droolsController =
+ DroolsController.factory.get(groupId, artifactId, "");
+ if (droolsController.ownsCoder(encodedClass.getClass(), coder.getModelClassLoaderHash())) {
+ droolsControllers.add(droolsController);
+ }
+ }
+ }
+ }
+
+ if (droolsControllers.isEmpty()) {
+ throw new IllegalStateException("No Encoders toolsets available for topic "+ topic +
+ " : encoder " + encodedClass.getClass().getCanonicalName());
+ }
+ return droolsControllers;
+ }
+
+
+ /**
+ * get all filters by maven coordinates and topic
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ * @param topic topic
+ * @return list of coders
+ * @throws IllegalArgumentException if invalid input
+ */
+ public List<CoderFilters> getFilters(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException {
+
+ if (!isCodingSupported(groupId, artifactId, topic)) {
+ throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic));
+ }
+
+ String key = this.codersKey(groupId, artifactId, topic);
+ Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
+ return coderTools.first().getCoders();
+ }
+
+ /**
+ * get all coders by maven coordinates and topic
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ * @param topic topic
+ * @return list of coders
+ * @throws IllegalArgumentException if invalid input
+ */
+ public Pair<ProtocolCoderToolset,ProtocolCoderToolset> getCoders(String groupId, String artifactId, String topic)
+ throws IllegalArgumentException {
+
+ if (!isCodingSupported(groupId, artifactId, topic)) {
+ throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic));
+ }
+
+ String key = this.codersKey(groupId, artifactId, topic);
+ Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
+ return coderTools;
+ }
+
+ /**
+ * get all coders by maven coordinates and topic
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ * @return list of coders
+ * @throws IllegalArgumentException if invalid input
+ */
+ public List<CoderFilters> getFilters(String groupId, String artifactId)
+ throws IllegalArgumentException {
+
+ if (groupId == null || groupId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid group id");
+ }
+
+ if (artifactId == null || artifactId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid artifact id");
+ }
+
+ String key = this.codersKey(groupId, artifactId, "");
+
+ List<CoderFilters> codersFilters = new ArrayList<CoderFilters>();
+ for (Map.Entry<String, Pair<ProtocolCoderToolset,ProtocolCoderToolset>> entry : coders.entrySet()) {
+ if (entry.getKey().startsWith(key)) {
+ codersFilters.addAll(entry.getValue().first().getCoders());
+ }
+ }
+
+ return codersFilters;
+ }
+
+ /**
+ * get all coders by maven coordinates and topic
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ * @return list of coders
+ * @throws IllegalArgumentException if invalid input
+ */
+ public List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> getCoders(String groupId, String artifactId)
+ throws IllegalArgumentException {
+
+ if (groupId == null || groupId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid group id");
+ }
+
+ if (artifactId == null || artifactId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid artifact id");
+ }
+
+ String key = this.codersKey(groupId, artifactId, "");
+
+ List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> coderToolset = new ArrayList<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>();
+ for (Map.Entry<String, Pair<ProtocolCoderToolset,ProtocolCoderToolset>> entry : coders.entrySet()) {
+ if (entry.getKey().startsWith(key)) {
+ coderToolset.add(entry.getValue());
+ }
+ }
+
+ return coderToolset;
+ }
+
+
+ /**
+ * get all filters by maven coordinates, topic, and classname
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ * @param topic topic
+ * @param classname
+ * @return list of coders
+ * @throws IllegalArgumentException if invalid input
+ */
+ public CoderFilters getFilters(String groupId, String artifactId, String topic, String classname)
+ throws IllegalArgumentException {
+
+ if (!isCodingSupported(groupId, artifactId, topic)) {
+ throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic));
+ }
+
+ if (classname == null || classname.isEmpty()) {
+ throw new IllegalArgumentException("classname must be provided");
+ }
+
+ String key = this.codersKey(groupId, artifactId, topic);
+ Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
+ return coderTools.first().getCoder(classname);
+ }
+
+ /**
+ * get coded based on class and topic
+ *
+ * @param topic
+ * @param codedClass
+ * @return
+ * @throws IllegalArgumentException
+ */
+ public List<CoderFilters> getReverseFilters(String topic, String codedClass)
+ throws IllegalArgumentException {
+
+ if (topic == null || topic.isEmpty()) {
+ throw new IllegalArgumentException("Unsupported");
+ }
+
+ if (codedClass == null) {
+ throw new IllegalArgumentException("class must be provided");
+ }
+
+ String key = this.reverseCodersKey(topic, codedClass);
+ List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> toolsets = this.reverseCoders.get(key);
+ if (toolsets == null)
+ throw new IllegalArgumentException("No Coder found for " + key);
+
+
+ List<CoderFilters> coders = new ArrayList<CoderFilters>();
+ for (Pair<ProtocolCoderToolset,ProtocolCoderToolset> toolset: toolsets) {
+ coders.addAll(toolset.first().getCoders());
+ }
+
+ return coders;
+ }
+
+ /**
+ * returns group and artifact id of the creator of the encoder
+ *
+ * @param topic
+ * @param fact
+ * @return
+ * @throws IllegalArgumentException
+ */
+ DroolsController getDroolsController(String topic, Object fact)
+ throws IllegalArgumentException {
+
+ if (topic == null || topic.isEmpty()) {
+ throw new IllegalArgumentException("Unsupported");
+ }
+
+ if (fact == null) {
+ throw new IllegalArgumentException("class must be provided");
+ }
+
+ List<DroolsController> droolsControllers = droolsCreators(topic, fact);
+ if (droolsControllers.size() > 1) {
+ // unexpected
+ logger.warn("MULTIPLE DROOLS CONTROLLERS FOUND for: " + topic + ":" +
+ fact.getClass().getCanonicalName() + ":" +
+ droolsControllers + " IN " + this);
+ // continue
+ }
+ return droolsControllers.get(0);
+ }
+
+ /**
+ * returns group and artifact id of the creator of the encoder
+ *
+ * @param topic
+ * @param fact
+ * @return
+ * @throws IllegalArgumentException
+ */
+ List<DroolsController> getDroolsControllers(String topic, Object fact)
+ throws IllegalArgumentException {
+
+ if (topic == null || topic.isEmpty()) {
+ throw new IllegalArgumentException("Unsupported");
+ }
+
+ if (fact == null) {
+ throw new IllegalArgumentException("class must be provided");
+ }
+
+ List<DroolsController> droolsControllers = droolsCreators(topic, fact);
+ if (droolsControllers.size() > 1) {
+ // unexpected
+ logger.warn("MULTIPLE DROOLS CONTROLLERS FOUND for: " + topic + ":" +
+ fact.getClass().getCanonicalName() + ":" +
+ droolsControllers + " IN " + this);
+ // continue
+ }
+ return droolsControllers;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("GenericEventProtocolCoder [coders=").append(coders.keySet()).append(", reverseCoders=")
+ .append(reverseCoders.keySet()).append("]");
+ return builder.toString();
+ }
+}
+
+class EventProtocolDecoder extends GenericEventProtocolCoder {
+
+ public EventProtocolDecoder(){super(false);}
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("EventProtocolDecoder [toString()=").append(super.toString()).append("]");
+ return builder.toString();
+ }
+
+}
+
+class EventProtocolEncoder extends GenericEventProtocolCoder {
+
+ public EventProtocolEncoder(){super(false);}
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("EventProtocolEncoder [toString()=").append(super.toString()).append("]");
+ return builder.toString();
+ }
+} \ No newline at end of file
diff --git a/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/JsonProtocolFilter.java b/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/JsonProtocolFilter.java
new file mode 100644
index 00000000..a2ce3123
--- /dev/null
+++ b/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/JsonProtocolFilter.java
@@ -0,0 +1,304 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * policy-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.drools.protocol.coders;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openecomp.policy.drools.utils.Pair;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+/**
+ * JSON Protocol Filter. Evaluates an JSON string and evaluates if it
+ * passes its filters.
+ */
+public class JsonProtocolFilter {
+
+ /**
+ * Helper class to collect Filter information
+ */
+ public static class FilterRule {
+ /**
+ * Field name
+ */
+ protected String name;
+
+ /**
+ * Field Value regex
+ */
+ protected String regex;
+
+ /**
+ * Filter Constructor
+ *
+ * @param name field name
+ * @param regex field regex value
+ */
+ public FilterRule(String name, String regex) {
+ this.name = name;
+ this.regex = regex;
+ }
+
+ /**
+ * Default constructor (for serialization only)
+ */
+ public FilterRule() {
+ super();
+ }
+
+ /**
+ * gets name
+ *
+ * @return
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * gets regex
+ *
+ * @return
+ */
+ public String getRegex() {
+ return regex;
+ }
+
+ /**
+ * sets field name
+ * @param name field name
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * sets regex name
+ * @param regex
+ */
+ public void setRegex(String regex) {
+ this.regex = regex;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Filter [name=").append(name).append(", regex=").append(regex).append("]");
+ return builder.toString();
+ }
+ }
+
+ /**
+ * all the filters to be applied
+ */
+ protected List<FilterRule> rules = new ArrayList<FilterRule>();
+
+ /**
+ *
+ * @param rawFilters raw filter initialization
+ *
+ * @throws IllegalArgumentException an invalid input has been provided
+ */
+ public static JsonProtocolFilter fromRawFilters(List<Pair<String, String>> rawFilters)
+ throws IllegalArgumentException {
+
+ if (rawFilters == null) {
+ throw new IllegalArgumentException("No raw filters provided");
+ }
+
+ List<FilterRule> filters = new ArrayList<FilterRule>();
+ for (Pair<String, String> filterPair: rawFilters) {
+ if (filterPair.first() == null || filterPair.first().isEmpty()) {
+ // TODO: warn
+ continue;
+ }
+
+ filters.add(new FilterRule(filterPair.first(), filterPair.second()));
+ }
+ return new JsonProtocolFilter(filters);
+ }
+
+ /**
+ * Create a Protocol Filter
+ *
+ * @throws IllegalArgumentException an invalid input has been provided
+ */
+ public JsonProtocolFilter() throws IllegalArgumentException {}
+
+ /**
+ *
+ * @param rawFilters raw filter initialization
+ *
+ * @throws IllegalArgumentException an invalid input has been provided
+ */
+ public JsonProtocolFilter(List<FilterRule> filters) throws IllegalArgumentException {
+ this.rules = filters;
+ }
+
+ /**
+ * are there any filters?
+ *
+ * @return true if there are filters, false otherwise
+ */
+ public boolean isRules() {
+ return !this.rules.isEmpty();
+ }
+
+ /**
+ * accept a JSON string as conformant it if passes all filters
+ *
+ * @param json json is a JSON object
+ * @return true if json string is conformant
+ *
+ * @throws IllegalArgumentException an invalid input has been provided
+ */
+ public synchronized boolean accept(JsonElement json) throws IllegalArgumentException {
+ if (json == null) {
+ throw new IllegalArgumentException("no JSON provided");
+ }
+
+ if (rules.isEmpty()) {
+ return true;
+ }
+
+ try {
+ if (json == null || !json.isJsonObject()) {
+ return false;
+ }
+
+ JsonObject event = json.getAsJsonObject();
+ for (FilterRule filter: rules) {
+ if (filter.regex == null ||
+ filter.regex.isEmpty() ||
+ filter.regex.equals(".*")) {
+
+ // Only check for presence
+ if (!event.has(filter.name)) {
+ return false;
+ }
+ } else {
+ JsonElement field = event.get(filter.name);
+ if (field == null) {
+ return false;
+ }
+
+ String fieldValue = field.getAsString();
+ if (!fieldValue.matches(filter.regex)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * accept a JSON string as conformant it if passes all filters
+ *
+ * @param json json string
+ * @return true if json string is conformant
+ *
+ * @throws IllegalArgumentException an invalid input has been provided
+ */
+ public synchronized boolean accept(String json) throws IllegalArgumentException {
+ if (json == null || json.isEmpty()) {
+ throw new IllegalArgumentException("no JSON provided");
+ }
+
+ if (rules.isEmpty()) {
+ return true;
+ }
+
+ try {
+ JsonElement element = new JsonParser().parse(json);
+ if (element == null || !element.isJsonObject()) {
+ return false;
+ }
+
+ return this.accept(element.getAsJsonObject());
+ } catch (IllegalArgumentException ile) {
+ throw ile;
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public List<FilterRule> getRules() {
+ return rules;
+ }
+
+ public synchronized void setRules(List<FilterRule> rulesFilters) {
+ this.rules = rulesFilters;
+ }
+
+ public synchronized void deleteRules(String name) {
+ for (FilterRule rule : new ArrayList<>(this.rules)) {
+ if (rule.name.equals(name)) {
+ this.rules.remove(rule);
+ }
+ }
+ }
+
+ public List<FilterRule> getRules(String name) {
+ ArrayList<FilterRule> temp = new ArrayList<>();
+ for (FilterRule rule : new ArrayList<>(this.rules)) {
+ if (rule.name.equals(name)) {
+ temp.add(rule);
+ }
+ }
+ return temp;
+ }
+
+ public synchronized void deleteRule(String name, String regex) {
+ for (FilterRule rule : new ArrayList<>(this.rules)) {
+ if (rule.name.equals(name) && rule.regex.equals(regex)) {
+ this.rules.remove(rule);
+ }
+ }
+ }
+
+ public synchronized void addRule(String name, String regex) {
+ for (FilterRule rule : new ArrayList<>(this.rules)) {
+ if (rule.name.equals(name) && rule.regex.equals(regex)) {
+ return;
+ }
+ }
+
+ this.rules.add(new FilterRule(name,regex));
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("JsonProtocolFilter [rules=").append(rules).append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/ProtocolCoderToolset.java b/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/ProtocolCoderToolset.java
new file mode 100644
index 00000000..9e079ff5
--- /dev/null
+++ b/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/ProtocolCoderToolset.java
@@ -0,0 +1,668 @@
+package org.openecomp.policy.drools.protocol.coders;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.time.Instant;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.openecomp.policy.common.logging.eelf.MessageCodes;
+import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
+import org.openecomp.policy.common.logging.flexlogger.Logger;
+import org.openecomp.policy.drools.controller.DroolsController;
+import org.openecomp.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
+import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomCoder;
+import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomGsonCoder;
+import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomJacksonCoder;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+/**
+ * Protocol Coding/Decoding Toolset
+ */
+public abstract class ProtocolCoderToolset {
+
+ /**
+ * topic
+ */
+ protected final String topic;
+
+ /**
+ * controller id
+ */
+ protected final String controllerId;
+
+ /**
+ * group id
+ */
+ protected final String groupId;
+
+ /**
+ * artifact id
+ */
+ protected final String artifactId;
+
+ /**
+ * Protocols and associated Filters
+ */
+ protected final List<CoderFilters> coders = new ArrayList<CoderFilters>();
+
+ /**
+ * Tree model (instead of class model) generic parsing to be able to inspect elements
+ */
+ protected JsonParser filteringParser = new JsonParser();
+
+ /**
+ * custom coder
+ */
+ protected CustomCoder customCoder;
+
+ /**
+ * Constructor
+ *
+ * @param topic the topic
+ * @param controllerId the controller id
+ * @param codedClass the decoded class
+ * @param filters list of filters that apply to the
+ * selection of this decodedClass in case of multiplicity
+ * @throws IllegalArgumentException if invalid data has been passed in
+ */
+ public ProtocolCoderToolset(String topic,
+ String controllerId,
+ String groupId,
+ String artifactId,
+ String codedClass,
+ JsonProtocolFilter filters,
+ CustomCoder customCoder,
+ int modelClassLoaderHash)
+ throws IllegalArgumentException {
+
+ if (topic == null || controllerId == null ||
+ groupId == null || artifactId == null ||
+ codedClass == null || filters == null ||
+ topic.isEmpty() || controllerId.isEmpty()) {
+ // TODO
+ throw new IllegalArgumentException("Invalid input");
+ }
+
+ this.topic = topic;
+ this.controllerId = controllerId;
+ this.groupId = groupId;
+ this.artifactId = artifactId;
+ this.coders.add(new CoderFilters(codedClass, filters, modelClassLoaderHash));
+ this.customCoder = customCoder;
+ }
+
+ /**
+ * gets the coder + filters associated with this class name
+ *
+ * @param classname class name
+ * @return the decoder filters or null if not found
+ */
+ public CoderFilters getCoder(String classname) {
+ for (CoderFilters decoder: this.coders) {
+ if (decoder.factClass.equals(classname)) {
+ return decoder;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * get all coder filters in use
+ *
+ * @return coder filters
+ */
+ public List<CoderFilters> getCoders() {
+ return this.coders;
+ }
+
+ /**
+ * add coder or replace it exists
+ *
+ * @param eventClass decoder
+ * @param filter filter
+ */
+ public void addCoder(String eventClass, JsonProtocolFilter filter, int modelClassLoaderHash) {
+ synchronized(this) {
+ for (CoderFilters coder: this.coders) {
+ if (coder.factClass.equals(eventClass)) {
+ // this is a better check than checking pointers, just
+ // in case classloader is different and this is just an update
+ coder.factClass = eventClass;
+ coder.filter = filter;
+ coder.modelClassLoaderHash = modelClassLoaderHash;
+ return;
+ }
+ }
+ }
+
+ this.coders.add(new CoderFilters(eventClass, filter, modelClassLoaderHash));
+ }
+
+ /**
+ * remove coder
+ *
+ * @param eventClass decoder
+ * @param filter filter
+ */
+ public void removeCoders(String eventClass) {
+ synchronized(this) {
+ Iterator<CoderFilters> codersIt = this.coders.iterator();
+ while (codersIt.hasNext()) {
+ CoderFilters coder = codersIt.next();
+ if (coder.factClass.equals(eventClass)) {
+ codersIt.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * gets the topic
+ *
+ * @return the topic
+ */
+ public String getTopic() {return topic;}
+
+ /**
+ * gets the controller id
+ *
+ * @return the controller id
+ */
+ public String getControllerId() {return controllerId;}
+
+ /**
+ * @return the groupId
+ */
+ public String getGroupId() {
+ return groupId;
+ }
+
+ /**
+ * @return the artifactId
+ */
+ public String getArtifactId() {
+ return artifactId;
+ }
+
+ /**
+ * @return the customCoder
+ */
+ public CustomCoder getCustomCoder() {
+ return customCoder;
+ }
+
+ /**
+ * @param customCoder the customCoder to set
+ */
+ public void setCustomCoder(CustomCoder customCoder) {
+ this.customCoder = customCoder;
+ }
+
+ /**
+ * performs filtering on a json string
+ *
+ * @param json json string
+ * @return the decoder that passes the filter, otherwise null
+ * @throws UnsupportedOperationException can't filter
+ * @throws IllegalArgumentException invalid input
+ */
+ protected CoderFilters filter(String json)
+ throws UnsupportedOperationException, IllegalArgumentException, IllegalStateException {
+
+
+ // 1. Get list of decoding classes for this controller Id and topic
+ // 2. If there are no classes, return error
+ // 3. Otherwise, from the available classes for decoding, pick the first one that
+ // passes the filters
+
+ // Don't parse if it is not necessary
+
+ if (this.coders.isEmpty()) {
+ // TODO this is an error
+ throw new IllegalStateException("No coders available");
+ }
+
+ if (this.coders.size() == 1) {
+ JsonProtocolFilter filter = this.coders.get(0).getFilter();
+ if (!filter.isRules()) {
+ return this.coders.get(0);
+ }
+ }
+
+ JsonElement event;
+ try {
+ event = this.filteringParser.parse(json);
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ throw new UnsupportedOperationException(e);
+ }
+
+ for (CoderFilters decoder: this.coders) {
+ try {
+ boolean accepted = decoder.getFilter().accept(event);
+ if (accepted) {
+ return decoder;
+ }
+ } catch (Exception e) {
+ // TODO: handle exception
+ e.printStackTrace();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Decode json into a POJO object
+ * @param json json string
+ *
+ * @return a POJO object for the json string
+ * @throws IllegalArgumentException if an invalid parameter has been received
+ * @throws UnsupportedOperationException if parsing into POJO is not possible
+ */
+ public abstract Object decode(String json)
+ throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException;
+
+ /**
+ * Encodes a POJO object into a JSON String
+ *
+ * @param event JSON POJO event to be converted to String
+ * @return JSON string version of POJO object
+ * @throws IllegalArgumentException if an invalid parameter has been received
+ * @throws UnsupportedOperationException if parsing into POJO is not possible
+ */
+ public abstract String encode(Object event)
+ throws IllegalArgumentException, UnsupportedOperationException;
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("ProtocolCoderToolset [topic=").append(topic).append(", controllerId=").append(controllerId)
+ .append(", groupId=").append(groupId).append(", artifactId=").append(artifactId).append(", coders=")
+ .append(coders).append(", filteringParser=").append(filteringParser).append(", customCoder=")
+ .append(customCoder).append("]");
+ return builder.toString();
+ }
+}
+
+/**
+ * Tools used for encoding/decoding using Jackson
+ */
+class JacksonProtocolCoderToolset extends ProtocolCoderToolset {
+ private static Logger logger = FlexLogger.getLogger(JacksonProtocolCoderToolset.class);
+ /**
+ * decoder
+ */
+ @JsonIgnore
+ protected final ObjectMapper decoder = new ObjectMapper();
+
+ /**
+ * encoder
+ */
+ @JsonIgnore
+ protected final ObjectMapper encoder = new ObjectMapper();
+
+ /**
+ * Toolset to encode/decode tools associated with a topic
+ *
+ * @param topic topic
+ * @param decodedClass decoded class of an event
+ * @param filter
+ */
+ public JacksonProtocolCoderToolset(String topic, String controllerId,
+ String groupId, String artifactId,
+ String decodedClass,
+ JsonProtocolFilter filter,
+ CustomJacksonCoder customJacksonCoder,
+ int modelClassLoaderHash) {
+ super(topic, controllerId, groupId, artifactId, decodedClass, filter, customJacksonCoder, modelClassLoaderHash);
+ decoder.registerModule(new JavaTimeModule());
+ decoder.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
+ false);
+ }
+
+ /**
+ * gets the Jackson decoder
+ *
+ * @return the Jackson decoder
+ */
+ @JsonIgnore
+ protected ObjectMapper getDecoder() {return decoder;}
+
+ /**
+ * gets the Jackson encoder
+ *
+ * @return the Jackson encoder
+ */
+ @JsonIgnore
+ protected ObjectMapper getEncoder() {return encoder;}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object decode(String json)
+ throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException {
+
+ // 0. Use custom coder if available
+
+ if (this.customCoder != null) {
+ throw new UnsupportedOperationException
+ ("Jackon Custom Decoder is not supported at this time");
+ }
+
+ DroolsController droolsController =
+ DroolsController.factory.get(groupId, artifactId, "");
+ if (droolsController == null) {
+ String error = "NO-DROOLS-CONTROLLER for: " + json + " IN " + this;
+ logger.warn(error);
+ throw new IllegalStateException(error);
+ }
+
+ CoderFilters decoderFilter = filter(json);
+ if (decoderFilter == null) {
+ String error = "NO-DECODER for: " + json + " IN " + this;
+ logger.warn(error);
+ throw new UnsupportedOperationException(error);
+ }
+
+ Class<?> decoderClass;
+ try {
+ decoderClass =
+ droolsController.fetchModelClass(decoderFilter.getCodedClass());
+ if (decoderClass == null) {
+ String error = "DECODE-ERROR FETCHING MODEL CLASS: " + ":" + json + ":" + this;
+ logger.error(error);
+ throw new IllegalStateException(error);
+ }
+ } catch (Exception e) {
+ String error = "DECODE-ERROR FETCHING MODEL CLASS: "+ e.getMessage() + ":" + json + ":" + this;
+ logger.warn(MessageCodes.EXCEPTION_ERROR, e, error);
+ throw new UnsupportedOperationException(error, e);
+ }
+
+
+ try {
+ Object fact = this.decoder.readValue(json, decoderClass);
+ return fact;
+ } catch (Exception e) {
+ String error = "DECODE-ERROR FROM PDP-D FRAMEWORK: "+ json + ":" + e.getMessage() + ":" + this;
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, error);
+ throw new UnsupportedOperationException(error, e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String encode(Object event)
+ throws IllegalArgumentException, UnsupportedOperationException {
+
+ // 0. Use custom coder if available
+
+ if (this.customCoder != null) {
+ throw new UnsupportedOperationException
+ ("Jackon Custom Encoder is not supported at this time");
+ }
+
+ try {
+ String encodedEvent = this.encoder.writeValueAsString(event);
+ return encodedEvent;
+ } catch (JsonProcessingException e) {
+ String error = "ENCODE-ERROR: "+ event + " IN " + this;
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, error);
+ throw new UnsupportedOperationException(error, e);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("JacksonProtocolCoderToolset [toString()=").append(super.toString()).append("]");
+ return builder.toString();
+ }
+
+}
+
+/**
+ * Tools used for encoding/decoding using Jackson
+ */
+class GsonProtocolCoderToolset extends ProtocolCoderToolset {
+
+ private static Logger logger = FlexLogger.getLogger(GsonProtocolCoderToolset.class);
+ /**
+ * Formatter for JSON encoding/decoding
+ */
+ @JsonIgnore
+ public static DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSxxx");
+
+ @JsonIgnore
+ public static DateTimeFormatter zuluFormat = DateTimeFormatter.ISO_INSTANT;
+
+ /**
+ * Adapter for ZonedDateTime
+ */
+
+ public static class GsonUTCAdapter implements JsonSerializer<ZonedDateTime>, JsonDeserializer<ZonedDateTime> {
+
+ public ZonedDateTime deserialize(JsonElement element, Type type, JsonDeserializationContext context)
+ throws JsonParseException {
+ try {
+ return ZonedDateTime.parse(element.getAsString(), format);
+ } catch (Exception e) {
+ System.err.println(e);
+ }
+ return null;
+ }
+
+ public JsonElement serialize(ZonedDateTime datetime, Type type, JsonSerializationContext context) {
+ return new JsonPrimitive(datetime.format(format));
+ }
+ }
+
+ public static class GsonInstantAdapter implements JsonSerializer<Instant>, JsonDeserializer<Instant> {
+
+ @Override
+ public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+ throws JsonParseException {
+ return Instant.ofEpochMilli(json.getAsLong());
+ }
+
+ @Override
+ public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) {
+ return new JsonPrimitive(src.toEpochMilli());
+ }
+
+ }
+
+
+ /**
+ * decoder
+ */
+ @JsonIgnore
+ protected final Gson decoder = new GsonBuilder().disableHtmlEscaping().
+ registerTypeAdapter(ZonedDateTime.class, new GsonUTCAdapter()).
+ create();
+
+ /**
+ * encoder
+ */
+ @JsonIgnore
+ protected final Gson encoder = new GsonBuilder().disableHtmlEscaping().
+ registerTypeAdapter(ZonedDateTime.class, new GsonUTCAdapter()).
+ create();
+
+ /**
+ * Toolset to encode/decode tools associated with a topic
+ *
+ * @param topic topic
+ * @param decodedClass decoded class of an event
+ * @param filter
+ */
+ public GsonProtocolCoderToolset(String topic, String controllerId,
+ String groupId, String artifactId,
+ String decodedClass,
+ JsonProtocolFilter filter,
+ CustomGsonCoder customGsonCoder,
+ int modelClassLoaderHash) {
+ super(topic, controllerId, groupId, artifactId, decodedClass, filter, customGsonCoder, modelClassLoaderHash);
+ }
+
+ /**
+ * gets the Gson decoder
+ *
+ * @return the Gson decoder
+ */
+ @JsonIgnore
+ protected Gson getDecoder() {return decoder;}
+
+ /**
+ * gets the Gson encoder
+ *
+ * @return the Gson encoder
+ */
+ @JsonIgnore
+ protected Gson getEncoder() {return encoder;}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object decode(String json)
+ throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException {
+
+ DroolsController droolsController =
+ DroolsController.factory.get(groupId, artifactId, "");
+ if (droolsController == null) {
+ String error = "NO-DROOLS-CONTROLLER for: " + json + " IN " + this;
+ logger.warn(error);
+ throw new IllegalStateException(error);
+ }
+
+ CoderFilters decoderFilter = filter(json);
+ if (decoderFilter == null) {
+ String error = "NO-DECODER for: " + json + " IN " + this;
+ logger.warn(error);
+ throw new UnsupportedOperationException(error);
+ }
+
+ Class<?> decoderClass;
+ try {
+ decoderClass =
+ droolsController.fetchModelClass(decoderFilter.getCodedClass());
+ if (decoderClass == null) {
+ String error = "DECODE-ERROR FETCHING MODEL CLASS: " + ":" + json + ":" + this;
+ logger.error(error);
+ throw new IllegalStateException(error);
+ }
+ } catch (Exception e) {
+ String error = "DECODE-ERROR FETCHING MODEL CLASS: "+ e.getMessage() + ":" + json + ":" + this;
+ logger.warn(MessageCodes.EXCEPTION_ERROR, e, error);
+ throw new UnsupportedOperationException(error, e);
+ }
+
+ if (this.customCoder != null) {
+ try {
+ Class<?> gsonClassContainer =
+ droolsController.fetchModelClass(this.customCoder.getClassContainer());
+ Field gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField);
+ Object gsonObject = gsonField.get(null);
+ Method fromJsonMethod = gsonObject.getClass().
+ getDeclaredMethod
+ ("fromJson", new Class[]{String.class, Class.class});
+ Object fact = fromJsonMethod.invoke(gsonObject, json, decoderClass);
+ return fact;
+ } catch (NoSuchFieldException | SecurityException | IllegalAccessException |
+ NoSuchMethodException | InvocationTargetException e) {
+ String error = "DECODE-ERROR-FROM-CUSTOM-CODER: " + e.getMessage() + ":" + json + ":" + this;
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, error);
+ throw new UnsupportedOperationException(error, e);
+ }
+ } else {
+ try {
+ Object fact = this.decoder.fromJson(json, decoderClass);
+ return fact;
+ } catch (Exception e) {
+ String error = "DECODE-ERROR FROM PDP-D FRAMEWORK: "+ json + ":" + e.getMessage() + ":" + this;
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, error);
+ throw new UnsupportedOperationException(error, e);
+ }
+ }
+ }
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String encode(Object event)
+ throws IllegalArgumentException, UnsupportedOperationException {
+
+ DroolsController droolsController =
+ DroolsController.factory.get(groupId, artifactId, "");
+ if (droolsController == null) {
+ String error = "NO-DROOLS-CONTROLLER for: " + event + " IN " + this;
+ logger.warn(error);
+ throw new IllegalStateException(error);
+ }
+
+ if (this.customCoder != null) {
+ try {
+ Class<?> gsonClassContainer =
+ droolsController.fetchModelClass(this.customCoder.getClassContainer());
+ Field gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField);
+ Object gsonObject = gsonField.get(null);
+ Method toJsonMethod = gsonObject.getClass().
+ getDeclaredMethod
+ ("toJson", new Class[]{Object.class});
+ String encodedJson = (String) toJsonMethod.invoke(gsonObject, event);
+ return encodedJson;
+ } catch (NoSuchFieldException | SecurityException | IllegalAccessException |
+ NoSuchMethodException | InvocationTargetException e) {
+ String error = "DECODE-ERROR-FROM-CUSTOM-CODER: " + e.getMessage() + ":" + event + ":" + this;
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, error);
+ throw new UnsupportedOperationException(error, e);
+ }
+ } else {
+ try {
+ String encodedEvent = this.encoder.toJson(event);
+ return encodedEvent;
+ } catch (Exception e) {
+ String error = "ENCODE-ERROR: "+ event + " IN " + this;
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, error);
+ throw new UnsupportedOperationException(error, e);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("GsonProtocolCoderToolset [toString()=").append(super.toString()).append("]");
+ return builder.toString();
+ }
+}
diff --git a/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/TopicCoderFilterConfiguration.java b/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/TopicCoderFilterConfiguration.java
new file mode 100644
index 00000000..3c112573
--- /dev/null
+++ b/policy-management/src/main/java/org/openecomp/policy/drools/protocol/coders/TopicCoderFilterConfiguration.java
@@ -0,0 +1,309 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * policy-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.drools.protocol.coders;
+
+import java.util.List;
+
+public class TopicCoderFilterConfiguration {
+
+ /**
+ * Custom coder, contains class and static field to access parser that the controller
+ * desires to use instead of the framework provided parser
+ */
+ public static abstract class CustomCoder {
+ protected String className;
+ protected String staticCoderField;
+
+ /**
+ * create custom coder from raw string in the following format
+ * (typically embedded in a property file):
+ *
+ * Note this is to support decoding/encoding of partial structures that are
+ * only known by the model.
+ *
+ * @param rawCustomCoder with format: <class-containing-custom-coder>,<static-coder-field>
+ */
+ public CustomCoder(String rawCustomCoder) throws IllegalArgumentException {
+ if (rawCustomCoder != null && !rawCustomCoder.isEmpty()) {
+
+ this.className = rawCustomCoder.substring(0,rawCustomCoder.indexOf(","));
+ if (this.className == null || this.className.isEmpty()) {
+ throw new IllegalArgumentException("No classname to create CustomCoder cannot be created");
+ }
+
+ this.staticCoderField = rawCustomCoder.substring(rawCustomCoder.indexOf(",")+1);
+ if (this.staticCoderField == null || this.staticCoderField.isEmpty()) {
+ throw new IllegalArgumentException
+ ("No staticCoderField to create CustomCoder cannot be created for class " +
+ className);
+ }
+
+ }
+ }
+ /**
+ * @param classContainer
+ * @param staticCoderField
+ */
+ public CustomCoder(String className, String staticCoderField) throws IllegalArgumentException {
+ if (className == null || className.isEmpty()) {
+ throw new IllegalArgumentException("No classname to create CustomCoder cannot be created");
+ }
+
+ if (staticCoderField == null || staticCoderField.isEmpty()) {
+ throw new IllegalArgumentException
+ ("No staticCoderField to create CustomCoder cannot be created for class " +
+ className);
+ }
+
+ this.className = className;
+ this.staticCoderField = staticCoderField;
+ }
+
+ /**
+ * @return the className
+ */
+ public String getClassContainer() {
+ return className;
+ }
+
+ /**
+ * @param className the className to set
+ */
+ public void setClassContainer(String className) {
+ this.className = className;
+ }
+
+ /**
+ * @return the staticCoderField
+ */
+ public String getStaticCoderField() {
+ return staticCoderField;
+ }
+
+ /**
+ * @param staticCoderField the staticGson to set
+ */
+ public void setStaticCoderField(String staticCoderField) {
+ this.staticCoderField = staticCoderField;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("CustomCoder [className=").append(className).append(", staticCoderField=")
+ .append(staticCoderField).append("]");
+ return builder.toString();
+ }
+ }
+
+ public static class CustomGsonCoder extends CustomCoder {
+
+ public CustomGsonCoder(String className, String staticCoderField) {
+ super(className, staticCoderField);
+ }
+
+ public CustomGsonCoder(String customGson) throws IllegalArgumentException {
+ super(customGson);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("CustomGsonCoder [toString()=").append(super.toString()).append("]");
+ return builder.toString();
+ }
+
+ }
+
+ public static class CustomJacksonCoder extends CustomCoder {
+
+ public CustomJacksonCoder(String className, String staticCoderField) {
+ super(className, staticCoderField);
+ }
+
+ public CustomJacksonCoder(String customJackson) throws IllegalArgumentException {
+ super(customJackson);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("CustomJacksonCoder [toString()=").append(super.toString()).append("]");
+ return builder.toString();
+ }
+
+ }
+
+ /**
+ * Coder/Decoder class and Filter container. The decoder class is potential,
+ * in order to be operational needs to be fetched from an available
+ * class loader.
+ *
+ */
+ public static class PotentialCoderFilter {
+
+ /**
+ * decoder class (pending from being able to be fetched and found
+ * in some class loader)
+ */
+ protected String codedClass;
+
+ /**
+ * filters to apply to the selection of the decodedClass;
+ */
+ protected JsonProtocolFilter filter;
+
+ /**
+ * constructor
+ *
+ * @param codedClass decoder class
+ * @param filter filters to apply
+ */
+ public PotentialCoderFilter(String codedClass, JsonProtocolFilter filter) {
+ this.codedClass = codedClass;
+ this.filter = filter;
+ }
+
+ /**
+ * @return the decodedClass
+ */
+ public String getCodedClass() {
+ return codedClass;
+ }
+
+ /**
+ * @param decodedClass the decodedClass to set
+ */
+ public void setCodedClass(String decodedClass) {
+ this.codedClass = decodedClass;
+ }
+
+ /**
+ * @return the filter
+ */
+ public JsonProtocolFilter getFilter() {
+ return filter;
+ }
+
+ /**
+ * @param filter the filter to set
+ */
+ public void setFilter(JsonProtocolFilter filter) {
+ this.filter = filter;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("PotentialCoderFilter [codedClass=").append(codedClass).append(", filter=").append(filter)
+ .append("]");
+ return builder.toString();
+ }
+ }
+
+ /**
+ * the source topic
+ */
+ protected final String topic;
+
+ /**
+ * List of decoder -> filters
+ */
+ protected final List<PotentialCoderFilter> coderFilters;
+
+ /**
+ * custom gson coder that this controller prefers to use instead of the framework ones
+ */
+ protected CustomGsonCoder customGsonCoder;
+
+ /**
+ * custom jackson coder that this controller prefers to use instead of the framework ones
+ */
+ protected CustomJacksonCoder customJacksonCoder;
+
+ /**
+ * Constructor
+ *
+ * @param decoderFilters list of decoders and associated filters
+ * @param topic the topic
+ */
+ public TopicCoderFilterConfiguration(String topic, List<PotentialCoderFilter> decoderFilters,
+ CustomGsonCoder customGsonCoder,
+ CustomJacksonCoder customJacksonCoder) {
+ this.coderFilters = decoderFilters;
+ this.topic = topic;
+ this.customGsonCoder = customGsonCoder;
+ this.customJacksonCoder = customJacksonCoder;
+ }
+
+ /**
+ * @return the topic
+ */
+ public String getTopic() {
+ return topic;
+ }
+
+ /**
+ * @return the decoderFilters
+ */
+ public List<PotentialCoderFilter> getCoderFilters() {
+ return coderFilters;
+ }
+
+ /**
+ * @return the customGsonCoder
+ */
+ public CustomGsonCoder getCustomGsonCoder() {
+ return customGsonCoder;
+ }
+
+ /**
+ * @param customGsonCoder the customGsonCoder to set
+ */
+ public void setCustomGsonCoder(CustomGsonCoder customGsonCoder) {
+ this.customGsonCoder = customGsonCoder;
+ }
+
+ /**
+ * @return the customJacksonCoder
+ */
+ public CustomJacksonCoder getCustomJacksonCoder() {
+ return customJacksonCoder;
+ }
+
+ /**
+ * @param customJacksonCoder the customJacksonCoder to set
+ */
+ public void setCustomJacksonCoder(CustomJacksonCoder customJacksonCoder) {
+ this.customJacksonCoder = customJacksonCoder;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("TopicCoderFilterConfiguration [topic=").append(topic).append(", coderFilters=")
+ .append(coderFilters).append(", customGsonCoder=").append(customGsonCoder)
+ .append(", customJacksonCoder=").append(customJacksonCoder).append("]");
+ return builder.toString();
+ }
+
+
+}