2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.openecomp.policy.drools.protocol.coders;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
29 import org.openecomp.policy.common.logging.eelf.MessageCodes;
30 import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
31 import org.openecomp.policy.common.logging.flexlogger.Logger;
32 import org.openecomp.policy.drools.controller.DroolsController;
33 import org.openecomp.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
34 import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomGsonCoder;
35 import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomJacksonCoder;
36 import org.openecomp.policy.drools.utils.Pair;
39 * Coder (Encoder/Decoder) of Events.
41 public interface EventProtocolCoder {
43 public static class CoderFilters {
48 protected String factClass;
51 * filters to apply to the selection of the decodedClass;
53 protected JsonProtocolFilter filter;
58 protected int modelClassLoaderHash;
64 * @param codedClass coder class
65 * @param filter filters to apply
67 public CoderFilters(String codedClass, JsonProtocolFilter filter, int modelClassLoaderHash) {
68 this.factClass = codedClass;
70 this.modelClassLoaderHash = modelClassLoaderHash;
74 * @return the codedClass
76 public String getCodedClass() {
81 * @param codedClass the decodedClass to set
83 public void setCodedClass(String codedClass) {
84 this.factClass = codedClass;
90 public synchronized JsonProtocolFilter getFilter() {
95 * @param filter the filter to set
97 public synchronized void setFilter(JsonProtocolFilter filter) {
101 public int getModelClassLoaderHash() {
102 return modelClassLoaderHash;
105 public void setFromClassLoaderHash(int fromClassLoaderHash) {
106 this.modelClassLoaderHash = fromClassLoaderHash;
110 public String toString() {
111 StringBuilder builder = new StringBuilder();
112 builder.append("CoderFilters [factClass=").append(factClass).append(", filter=").append(filter)
113 .append(", modelClassLoaderHash=").append(modelClassLoaderHash).append("]");
114 return builder.toString();
120 * Adds a Decoder class to decode the protocol over this topic
122 * @param groupId of the controller
123 * @param artifactId of the controller
124 * @param topic the topic
125 * @param eventClass the event class
126 * @param protocolFilter filters to selectively choose a particular decoder
127 * when there are multiples
129 * @throw IllegalArgumentException if an invalid parameter is passed
131 public void addDecoder(String groupId, String artifactId,
134 JsonProtocolFilter protocolFilter,
135 CustomGsonCoder customGsonCoder,
136 CustomJacksonCoder customJacksonCoder,
137 int modelClassLoaderHash)
138 throws IllegalArgumentException;
141 * removes all decoders associated with the controller id
142 * @param groupId of the controller
143 * @param artifactId of the controller
144 * @param topic of the controller
146 * @throws IllegalArgumentException if invalid arguments have been provided
148 void removeEncoders(String groupId, String artifactId, String topic) throws IllegalArgumentException;
151 * removes decoders associated with the controller id and topic
152 * @param groupId of the controller
153 * @param artifactId of the controller
154 * @param topic the topic
156 * @throws IllegalArgumentException if invalid arguments have been provided
158 public void removeDecoders(String groupId, String artifactId, String topic) throws IllegalArgumentException;
161 * Given a controller id and a topic, it gives back its filters
163 * @param groupId of the controller
164 * @param artifactId of the controller
165 * @param topic the topic
167 * return list of decoders
169 * @throw IllegalArgumentException if an invalid parameter is passed
171 public List<CoderFilters> getDecoderFilters(String groupId, String artifactId, String topic)
172 throws IllegalArgumentException;
176 * Given a controller id and a topic, it gives back the decoding configuration
178 * @param groupId of the controller
179 * @param artifactId of the controller
180 * @param topic the topic
182 * return decoding toolset
184 * @throw IllegalArgumentException if an invalid parameter is passed
186 public ProtocolCoderToolset getDecoders(String groupId, String artifactId, String topic)
187 throws IllegalArgumentException;
190 * Given a controller id and a topic, it gives back all the decoding configurations
192 * @param groupId of the controller
193 * @param artifactId of the controller
194 * @param topic the topic
196 * return decoding toolset
198 * @throw IllegalArgumentException if an invalid parameter is passed
200 public List<ProtocolCoderToolset> getDecoders(String groupId, String artifactId)
201 throws IllegalArgumentException;
205 * gets all decoders associated with the group and artifact ids
206 * @param groupId of the controller
207 * @param artifactId of the controller
209 * @throws IllegalArgumentException if invalid arguments have been provided
211 public List<CoderFilters> getDecoderFilters(String groupId, String artifactId) throws IllegalArgumentException;
215 * Given a controller id and a topic, it gives back the classes that implements the encoding
217 * @param groupId of the controller
218 * @param artifactId of the controller
219 * @param topic the topic
221 * return list of decoders
223 * @throw IllegalArgumentException if an invalid parameter is passed
225 public List<CoderFilters> getEncoderFilters(String groupId, String artifactId, String topic)
226 throws IllegalArgumentException;
229 * gets all encoders associated with the group and artifact ids
230 * @param groupId of the controller
231 * @param artifactId of the controller
233 * @throws IllegalArgumentException if invalid arguments have been provided
235 public List<CoderFilters> getEncoderFilters(String groupId, String artifactId) throws IllegalArgumentException;
238 * Given a controller id, a topic, and a classname, it gives back the classes that implements the decoding
240 * @param groupId of the controller
241 * @param artifactId of the controller
242 * @param topic the topic
243 * @param classname classname
245 * return list of decoders
247 * @throw IllegalArgumentException if an invalid parameter is passed
249 public CoderFilters getDecoderFilters(String groupId, String artifactId, String topic, String classname)
250 throws IllegalArgumentException;
253 * is there a decoder supported for the controller id and topic
255 * @param groupId of the controller
256 * @param artifactId of the controller
257 * @param topic protocol
258 * @return true if supported
260 public boolean isDecodingSupported(String groupId, String artifactId, String topic);
263 * Adds a Encoder class to encode the protocol over this topic
265 * @param groupId of the controller
266 * @param artifactId of the controller
267 * @param topic the topic
268 * @param eventClass the event class
269 * @param protocolFilter filters to selectively choose a particular decoder
270 * when there are multiples
272 * @throw IllegalArgumentException if an invalid parameter is passed
274 public void addEncoder(String groupId, String artifactId, String topic,
276 JsonProtocolFilter protocolFilter,
277 CustomGsonCoder customGsonCoder,
278 CustomJacksonCoder customJacksonCoder,
279 int modelClassLoaderHash)
280 throws IllegalArgumentException;
283 * is there an encoder supported for the controller id and topic
285 * @param groupId of the controller
286 * @param artifactId of the controller
287 * @param topic protocol
288 * @return true if supported
290 public boolean isEncodingSupported(String groupId, String artifactId, String topic);
293 * get encoder based on coordinates and classname
295 * @param groupId of the controller
296 * @param artifactId of the controller
297 * @param topic protocol
298 * @param json event string
300 * @throws IllegalArgumentException invalid arguments passed in
302 public CoderFilters getEncoderFilters(String groupId, String artifactId, String topic, String classname)
303 throws IllegalArgumentException;
306 * get encoder based on topic and encoded class
309 * @param encodedClass encoded class
311 * @throws IllegalArgumentException invalid arguments passed in
313 public List<CoderFilters> getReverseEncoderFilters(String topic, String encodedClass)
314 throws IllegalArgumentException;
317 * gets the identifier of the creator of the encoder
320 * @param encodedClass encoded class
321 * @return a drools controller
322 * @throws IllegalArgumentException invalid arguments passed in
324 public DroolsController getDroolsController(String topic, Object encodedClass)
325 throws IllegalArgumentException;
328 * gets the identifier of the creator of the encoder
331 * @param encodedClass encoded class
332 * @return list of drools controllers
333 * @throws IllegalArgumentException invalid arguments passed in
335 public List<DroolsController> getDroolsControllers(String topic, Object encodedClass)
336 throws IllegalArgumentException;
339 * decode topic's stringified event (json) to corresponding Event Object.
341 * @param groupId of the controller
342 * @param artifactId of the controller
343 * @param topic protocol
344 * @param json event string
346 * @throws IllegalArgumentException invalid arguments passed in
347 * @throws UnsupportedOperationException if the operation is not supported
348 * @throws IllegalStateException if the system is in an illegal state
350 public Object decode(String groupId, String artifactId, String topic, String json)
351 throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException;
354 * encodes topic's stringified event (json) to corresponding Event Object.
356 * @param groupId of the controller
357 * @param artifactId of the controller
358 * @param topic protocol
359 * @param event Object
361 * @throws IllegalArgumentException invalid arguments passed in
363 public String encode(String groupId, String artifactId, String topic, Object event)
364 throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;
367 * encodes topic's stringified event (json) to corresponding Event Object.
370 * @param event event object
372 * @throws IllegalArgumentException invalid arguments passed in
373 * @throws UnsupportedOperationException operation cannot be performed
375 public String encode(String topic, Object event)
376 throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;
379 * encodes topic's stringified event (json) to corresponding Event Object.
382 * @param event event object
383 * @param droolsController
385 * @throws IllegalArgumentException invalid arguments passed in
386 * @throws UnsupportedOperationException operation cannot be performed
388 public String encode(String topic, Object event, DroolsController droolsController)
389 throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;
392 * singleton reference to the global event protocol coder
394 public static EventProtocolCoder manager = new MultiplexorEventProtocolCoder();
398 * Protocol Coder that does its best attempt to decode/encode, selecting the best
399 * class and best fitted json parsing tools.
401 class MultiplexorEventProtocolCoder implements EventProtocolCoder {
402 // get an instance of logger
403 private static Logger logger = FlexLogger.getLogger(MultiplexorEventProtocolCoder.class);
407 protected EventProtocolDecoder decoders = new EventProtocolDecoder();
412 protected EventProtocolEncoder encoders = new EventProtocolEncoder();
419 public void addDecoder(String groupId, String artifactId, String topic,
421 JsonProtocolFilter protocolFilter,
422 CustomGsonCoder customGsonCoder,
423 CustomJacksonCoder customJacksonCoder,
424 int modelClassLoaderHash)
425 throws IllegalArgumentException {
426 logger.info("ADD-DECODER: " + groupId + ":" + artifactId + ":" +
427 topic + ":" + eventClass + ":" +
428 protocolFilter + ":" + customGsonCoder +
429 ":" + customJacksonCoder + ":" + modelClassLoaderHash +
431 this.decoders.add(groupId, artifactId, topic, eventClass, protocolFilter,
432 customGsonCoder, customJacksonCoder, modelClassLoaderHash);
439 public void addEncoder(String groupId, String artifactId, String topic,
441 JsonProtocolFilter protocolFilter,
442 CustomGsonCoder customGsonCoder,
443 CustomJacksonCoder customJacksonCoder,
444 int modelClassLoaderHash)
445 throws IllegalArgumentException {
446 logger.info("ADD-ENCODER: " + groupId + ":" + artifactId + ":" +
447 topic + ":" + eventClass + ":" +
448 protocolFilter + ":" + customGsonCoder +
449 ":" + customJacksonCoder + ":" + modelClassLoaderHash +
451 this.encoders.add(groupId, artifactId, topic, eventClass, protocolFilter,
452 customGsonCoder, customJacksonCoder, modelClassLoaderHash);
459 public void removeDecoders(String groupId, String artifactId, String topic)
460 throws IllegalArgumentException {
461 logger.info("REMOVE-DECODER: " + groupId + ":" + artifactId + ":" +
462 topic + " FROM " + this);
463 this.decoders.remove(groupId, artifactId, topic);
470 public void removeEncoders(String groupId, String artifactId, String topic)
471 throws IllegalArgumentException {
472 logger.info("REMOVE-ENCODER: " + groupId + ":" + artifactId + ":" +
473 topic + " FROM " + this);
474 this.encoders.remove(groupId, artifactId, topic);
481 public boolean isDecodingSupported(String groupId, String artifactId, String topic) {
482 return this.decoders.isCodingSupported(groupId, artifactId, topic);
489 public boolean isEncodingSupported(String groupId, String artifactId, String topic) {
490 return this.encoders.isCodingSupported(groupId, artifactId, topic);
497 public Object decode(String groupId, String artifactId, String topic, String json)
498 throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException {
499 logger.info("DECODE: " + groupId + ":" + artifactId + ":" +
500 topic + ":" + json + " WITH " + this);
501 return this.decoders.decode(groupId, artifactId, topic, json);
508 public String encode(String groupId, String artifactId, String topic, Object event)
509 throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException {
510 logger.info("ENCODE: " + groupId + ":" + artifactId + ":" +
511 topic + ":" + event + " WITH " + this);
512 return this.encoders.encode(groupId, artifactId, topic, event);
519 public String encode(String topic, Object event)
520 throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException {
521 logger.info("ENCODE: " + topic + ":" + event + " WITH " + this);
522 return this.encoders.encode(topic, event);
529 public String encode(String topic, Object event, DroolsController droolsController)
530 throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException {
531 logger.info("ENCODE: " + topic + ":" + event + ":" + droolsController + " WITH " + this);
532 return this.encoders.encode(topic, event, droolsController);
539 public List<CoderFilters> getDecoderFilters(String groupId, String artifactId, String topic)
540 throws IllegalArgumentException {
542 return this.decoders.getFilters(groupId, artifactId, topic);
549 public ProtocolCoderToolset getDecoders(String groupId, String artifactId, String topic)
550 throws IllegalArgumentException {
552 Pair<ProtocolCoderToolset,ProtocolCoderToolset> decoderToolsets = this.decoders.getCoders(groupId, artifactId, topic);
553 if (decoderToolsets == null)
554 throw new IllegalArgumentException("Decoders not found for " + groupId + ":" + artifactId + ":" + topic);
556 return decoderToolsets.first();
563 public List<CoderFilters> getEncoderFilters(String groupId, String artifactId, String topic)
564 throws IllegalArgumentException {
566 return this.encoders.getFilters(groupId, artifactId, topic);
573 public CoderFilters getDecoderFilters(String groupId, String artifactId, String topic, String classname)
574 throws IllegalArgumentException {
576 return this.decoders.getFilters(groupId, artifactId, topic, classname);
583 public CoderFilters getEncoderFilters(String groupId, String artifactId, String topic, String classname)
584 throws IllegalArgumentException {
586 return this.encoders.getFilters(groupId, artifactId, topic, classname);
593 public List<CoderFilters> getReverseEncoderFilters(String topic, String encodedClass) throws IllegalArgumentException {
594 return this.encoders.getReverseFilters(topic, encodedClass);
598 * get all deocders by maven coordinates and topic
600 * @param groupId group id
601 * @param artifactId artifact id
603 * @return list of decoders
604 * @throws IllegalArgumentException if invalid input
607 public List<ProtocolCoderToolset> getDecoders(String groupId, String artifactId)
608 throws IllegalArgumentException {
610 List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> decoderToolsets = this.decoders.getCoders(groupId, artifactId);
611 if (decoderToolsets == null)
612 throw new IllegalArgumentException("Decoders not found for " + groupId + ":" + artifactId);
614 List<ProtocolCoderToolset> parser1CoderToolset = new ArrayList<>();
615 for (Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderToolsetPair : decoderToolsets) {
616 parser1CoderToolset.add(coderToolsetPair.first());
619 return parser1CoderToolset;
626 public List<CoderFilters> getDecoderFilters(String groupId, String artifactId) throws IllegalArgumentException {
627 return this.decoders.getFilters(groupId, artifactId);
635 public List<CoderFilters> getEncoderFilters(String groupId, String artifactId) throws IllegalArgumentException {
636 return this.encoders.getFilters(groupId, artifactId);
643 public DroolsController getDroolsController(String topic, Object encodedClass) throws IllegalArgumentException {
644 return this.encoders.getDroolsController(topic, encodedClass);
651 public List<DroolsController> getDroolsControllers(String topic, Object encodedClass) throws IllegalArgumentException {
652 return this.encoders.getDroolsControllers(topic, encodedClass);
659 public String toString() {
660 StringBuilder builder = new StringBuilder();
661 builder.append("MultiplexorEventProtocolCoder [decoders=").append(decoders).append(", encoders=")
662 .append(encoders).append("]");
663 return builder.toString();
668 * This protocol Coder that does its best attempt to decode/encode, selecting the best
669 * class and best fitted json parsing tools.
671 abstract class GenericEventProtocolCoder {
672 private static Logger logger = FlexLogger.getLogger(GenericEventProtocolCoder.class);
675 * Mapping topic:controller-id -> <protocol-decoder-toolset-pair>
676 * where protocol-coder-toolset-pair contains both a jackson-protocol-coder-toolset
677 * and a gson-protocol-coder-toolset. The first value of the pair will the
678 * protocol coder toolset most likely to be successful with the encoding or decoding,
679 * and consequently the second value will be the less likely.
681 protected final HashMap<String, Pair<ProtocolCoderToolset,ProtocolCoderToolset>> coders =
682 new HashMap<String, Pair<ProtocolCoderToolset,ProtocolCoderToolset>>();
685 * Mapping topic + classname -> Protocol Set
687 protected final HashMap<String, List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>> reverseCoders =
688 new HashMap<String, List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>>();
690 protected boolean multipleToolsetRetries = false;
692 GenericEventProtocolCoder(boolean multipleToolsetRetries) {
693 this.multipleToolsetRetries = multipleToolsetRetries;
699 * @param groupId of the controller
700 * @param artifactId of the controller
701 * @param topic the topic
702 * @param eventClass the event class
703 * @param protocolFilter filters to selectively choose a particular decoder
704 * when there are multiples
706 * @throw IllegalArgumentException if an invalid parameter is passed
708 public void add(String groupId, String artifactId,
711 JsonProtocolFilter protocolFilter,
712 CustomGsonCoder customGsonCoder,
713 CustomJacksonCoder customJacksonCoder,
714 int modelClassLoaderHash)
715 throws IllegalArgumentException {
716 if (groupId == null || groupId.isEmpty()) {
717 throw new IllegalArgumentException("Invalid group id");
720 if (artifactId == null || artifactId.isEmpty()) {
721 throw new IllegalArgumentException("Invalid artifact id");
724 if (topic == null || topic.isEmpty()) {
725 throw new IllegalArgumentException("Invalid Topic");
728 if (eventClass == null) {
729 throw new IllegalArgumentException("Invalid Event Class");
732 String key = this.codersKey(groupId, artifactId, topic);
733 String reverseKey = this.reverseCodersKey(topic, eventClass);
736 if (coders.containsKey(key)) {
737 Pair<ProtocolCoderToolset, ProtocolCoderToolset> toolsets = coders.get(key);
739 if (logger.isInfoEnabled())
740 logger.info("ADDING CODER TO EXISTING: " + toolsets + " for " + key);
742 toolsets.first().addCoder(eventClass, protocolFilter, modelClassLoaderHash);
743 toolsets.second().addCoder(eventClass, protocolFilter, modelClassLoaderHash);
745 if (!reverseCoders.containsKey(reverseKey)) {
746 if (logger.isInfoEnabled())
747 logger.info("Multiple coder classes case: " + toolsets.first() +
748 " for " + reverseKey + " - " + key);
750 List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> reverseMappings =
751 new ArrayList<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>();
752 reverseMappings.add(toolsets);
753 reverseCoders.put(reverseKey, reverseMappings);
758 GsonProtocolCoderToolset gsonCoderTools =
759 new GsonProtocolCoderToolset
762 eventClass, protocolFilter,
764 modelClassLoaderHash);
766 JacksonProtocolCoderToolset jacksonCoderTools =
767 new JacksonProtocolCoderToolset
770 eventClass, protocolFilter,
772 modelClassLoaderHash);
774 // Use Gson as the first priority encoding/decoding toolset, and Jackson
775 // as second. This is because it has been observed that they can diverge
776 // somewhat in the encoding/decoding data types, which can produce json
777 // that may result incompatible with what some network elements are
778 // expecting. As decoding takes place, this element will reconfigure
779 // itself to set the jackson one as the favoured one first, if errors
780 // are detected in the gson encoding
782 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools =
783 new Pair<ProtocolCoderToolset,ProtocolCoderToolset>(gsonCoderTools,
786 logger.info("ADDED TOOLSET: " + key + " : " +
787 coderTools + ":" + this);
789 coders.put(key, coderTools);
791 if (reverseCoders.containsKey(reverseKey)) {
792 // There is another controller (different group id/artifact id/topic)
793 // that shares the class and the topic.
795 List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> toolsets =
796 reverseCoders.get(reverseKey);
797 boolean present = false;
798 for (Pair<ProtocolCoderToolset,ProtocolCoderToolset> parserSet: toolsets) {
800 present = parserSet.first().getControllerId().equals(key);
803 logger.error("UNEXPECTED TOOLSET REVERSE MAPPING FOUND: " + parserSet.first() +
804 " for " + reverseKey + " - " + key);
811 logger.info("ADDING TOOLSET REVERSE MAPPING: " + reverseKey + " : " +
812 toolsets + ":" + coderTools + ":" + this);
813 toolsets.add(coderTools);
816 List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> toolsets =
817 new ArrayList<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>();
818 logger.info("ADDING TOOLSET REVERSE MAPPING: " + reverseKey + " : " +
819 toolsets + ":" + coderTools + ":" + this);
820 toolsets.add(coderTools);
821 reverseCoders.put(reverseKey, toolsets);
828 * produces key for indexing toolset entries
830 * @param group group id
831 * @param artifactId artifact id
835 protected String codersKey(String groupId, String artifactId, String topic) {
836 return groupId + ":" + artifactId + ":" + topic;
840 * produces a key for the reverse index
843 * @param eventClass coded class
844 * @return reverse index key
846 protected String reverseCodersKey(String topic, String eventClass) {
847 return topic + ":" + eventClass;
853 * @param groupId group id
854 * @param artifactId artifact id
856 * @throws IllegalArgumentException if invalid input
858 public void remove(String groupId, String artifactId, String topic)
859 throws IllegalArgumentException {
861 if (groupId == null || groupId.isEmpty()) {
862 throw new IllegalArgumentException("Invalid group id");
865 if (artifactId == null || artifactId.isEmpty()) {
866 throw new IllegalArgumentException("Invalid artifact id");
869 if (topic == null || topic.isEmpty()) {
870 throw new IllegalArgumentException("Invalid Topic");
873 String key = this.codersKey(groupId, artifactId, topic);
876 if (coders.containsKey(key)) {
877 Pair<ProtocolCoderToolset, ProtocolCoderToolset> p = coders.remove(key);
878 logger.info("REMOVED TOOLSET: " + key + " : " + p + " FROM " +
879 coders + " : " + this);
881 for (CoderFilters codeFilter : p.first().getCoders()) {
882 String className = codeFilter.getCodedClass();
883 String reverseKey = this.reverseCodersKey(topic, className);
884 if (this.reverseCoders.containsKey(reverseKey) ) {
885 List<Pair<ProtocolCoderToolset, ProtocolCoderToolset>> toolsets =
886 this.reverseCoders.get(reverseKey);
887 Iterator<Pair<ProtocolCoderToolset, ProtocolCoderToolset>> toolsetsIter =
889 while (toolsetsIter.hasNext()) {
890 Pair<ProtocolCoderToolset, ProtocolCoderToolset> toolset = toolsetsIter.next();
891 if (toolset.first().getControllerId().equals(key)) {
892 logger.info("REMOVED CODER FROM REVERSE MAPPING of TOOLSET: " + reverseKey + " : " + toolset + " FROM " +
894 toolsetsIter.remove();
898 if (this.reverseCoders.get(reverseKey).isEmpty()) {
899 logger.info("REMOVE FULL REVERSE MAPPING of TOOLSET: " + reverseKey + " FROM " +
901 this.reverseCoders.remove(reverseKey);
910 * does it support coding?
912 * @param groupId group id
913 * @param artifactId artifact id
915 * @return true if its is codable
917 public boolean isCodingSupported(String groupId, String artifactId, String topic) {
919 if (groupId == null || groupId.isEmpty()) {
920 throw new IllegalArgumentException("Invalid group id");
923 if (artifactId == null || artifactId.isEmpty()) {
924 throw new IllegalArgumentException("Invalid artifact id");
927 if (topic == null || topic.isEmpty())
930 String key = this.codersKey(groupId, artifactId, topic);
932 return (coders.containsKey(key));
937 * decode a json string into an Object
939 * @param groupId group id
940 * @param artifactId artifact id
942 * @param json json string to convert to object
943 * @return the decoded object
944 * @throws IllegalArgumentException if invalid argument is provided
945 * @throws UnsupportedOperationException if the operation cannot be performed
947 public Object decode(String groupId, String artifactId, String topic, String json)
948 throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException {
950 if (!isCodingSupported(groupId, artifactId, topic)) {
951 throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic) + " for encoding");
954 String key = this.codersKey(groupId, artifactId, topic);
955 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
957 Object event = coderTools.first().decode(json);
960 } catch (Exception e) {
961 // TODO Auto-generated catch block
962 logger.warn("Can't decode @ " + this);
965 if (multipleToolsetRetries) {
966 // try the less favored toolset
968 Object event = coderTools.second().decode(json);
970 // change the priority of the toolset
972 ProtocolCoderToolset first = coderTools.first();
973 ProtocolCoderToolset second = coderTools.second();
974 coderTools.first(second);
975 coderTools.second(first);
980 } catch (Exception e2) {
981 // TODO Auto-generated catch block
982 e2.printStackTrace();
983 throw new UnsupportedOperationException(e2);
987 throw new UnsupportedOperationException("Cannot decode neither with gson or jackson");
991 * encode an object into a json string
993 * @param groupId group id
994 * @param artifactId artifact id
996 * @param event object to convert to string
997 * @return the json string
998 * @throws IllegalArgumentException if invalid argument is provided
999 * @throws UnsupportedOperationException if the operation cannot be performed
1001 public String encode(String groupId, String artifactId, String topic, Object event)
1002 throws IllegalArgumentException, UnsupportedOperationException {
1004 if (!isCodingSupported(groupId, artifactId, topic)) {
1005 throw new IllegalArgumentException
1006 ("Unsupported:" + codersKey(groupId, artifactId, topic));
1009 if (event == null) {
1010 throw new IllegalArgumentException("Unsupported topic:" + topic);
1013 // reuse the decoder set, since there must be affinity in the model
1014 String key = this.codersKey(groupId, artifactId, topic);
1015 return this.encodeInternal(key, event);
1019 * encode an object into a json string
1021 * @param key identifier
1022 * @param event object to convert to string
1023 * @return the json string
1024 * @throws IllegalArgumentException if invalid argument is provided
1025 * @throws UnsupportedOperationException if the operation cannot be performed
1027 protected String encodeInternal(String key, Object event)
1028 throws IllegalArgumentException, UnsupportedOperationException {
1030 logger.debug("ENCODE: " + key + ":" + event + this);
1032 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
1034 String json = coderTools.first().encode(event);
1035 if (json != null && !json.isEmpty())
1037 } catch (Exception e) {
1038 logger.error(MessageCodes.EXCEPTION_ERROR, e, "FIRST-ENCODE-INTERNAL: " +
1039 key + ":" + event, this.toString());
1042 if (multipleToolsetRetries) {
1043 // try the less favored toolset
1045 String json = coderTools.second().encode(event);
1047 // change the priority of the toolset
1048 synchronized(this) {
1049 ProtocolCoderToolset first = coderTools.first();
1050 ProtocolCoderToolset second = coderTools.second();
1051 coderTools.first(second);
1052 coderTools.second(first);
1057 } catch (Exception e2) {
1058 // TODO Auto-generated catch block
1059 logger.error(MessageCodes.EXCEPTION_ERROR, e2, "SECOND-ENCODE-INTERNAL: " +
1060 key + ":" + event, this.toString());
1061 throw new UnsupportedOperationException(e2);
1065 throw new UnsupportedOperationException("Cannot decode neither with gson or jackson");
1069 * encode an object into a json string
1071 * @param topic topic
1072 * @param encodedClass object to convert to string
1073 * @return the json string
1074 * @throws IllegalArgumentException if invalid argument is provided
1075 * @throws UnsupportedOperationException if the operation cannot be performed
1077 public String encode(String topic, Object encodedClass)
1078 throws IllegalArgumentException, IllegalArgumentException, UnsupportedOperationException {
1080 if (encodedClass == null) {
1081 throw new IllegalArgumentException("Invalid encoded class");
1084 if (topic == null || topic.isEmpty()) {
1085 throw new IllegalArgumentException("Invalid topic");
1088 logger.info("ENCODE: " + topic + ":" +
1089 encodedClass.getClass().getCanonicalName() + ":" +
1092 List<DroolsController> droolsControllers = droolsCreators(topic, encodedClass);
1093 if (droolsControllers.size() > 1) {
1095 logger.warn("MULTIPLE DROOLS CONTROLLERS FOUND for: " + topic + ":" +
1096 encodedClass.getClass().getCanonicalName() + ":" +
1097 droolsControllers + " IN " + this);
1101 String key = codersKey(droolsControllers.get(0).getGroupId(), droolsControllers.get(0).getArtifactId(), topic);
1102 return this.encodeInternal(key, encodedClass);
1106 * encode an object into a json string
1108 * @param topic topic
1109 * @param encodedClass object to convert to string
1110 * @return the json string
1111 * @throws IllegalArgumentException if invalid argument is provided
1112 * @throws UnsupportedOperationException if the operation cannot be performed
1114 public String encode(String topic, Object encodedClass, DroolsController droolsController)
1115 throws IllegalArgumentException, IllegalArgumentException, UnsupportedOperationException {
1117 if (encodedClass == null) {
1118 throw new IllegalArgumentException("Invalid encoded class");
1121 if (topic == null || topic.isEmpty()) {
1122 throw new IllegalArgumentException("Invalid topic");
1125 logger.info("ENCODE: " + topic + ":" +
1126 encodedClass.getClass().getCanonicalName() + ":" +
1127 encodedClass + ":" + droolsController);
1129 String key = codersKey(droolsController.getGroupId(), droolsController.getArtifactId(), topic);
1130 return this.encodeInternal(key, encodedClass);
1135 * @param encodedClass
1138 * @throws IllegalStateException
1139 * @throws IllegalArgumentException
1141 protected List<DroolsController> droolsCreators(String topic, Object encodedClass)
1142 throws IllegalStateException, IllegalArgumentException {
1144 List<DroolsController> droolsControllers = new ArrayList<DroolsController>();
1146 String reverseKey = this.reverseCodersKey(topic, encodedClass.getClass().getCanonicalName());
1147 if (!this.reverseCoders.containsKey(reverseKey)) {
1148 logger.warn("NO MAPPING for REVERSE KEY: " + topic + ":" +
1149 encodedClass.getClass().getCanonicalName() + ":" +
1150 encodedClass + ":" + reverseKey + " : " + this);
1151 return droolsControllers;
1154 List<Pair<ProtocolCoderToolset, ProtocolCoderToolset>>
1155 toolsets = this.reverseCoders.get(reverseKey);
1157 // There must be multiple toolset pairs associated with <topic,classname> reverseKey
1158 // case 2 different controllers use the same models and register the same encoder for
1159 // the same topic. This is assumed not to occur often but for the purpose of encoding
1160 // but there should be no side-effects. Ownership is crosscheck against classname and
1161 // classloader reference.
1163 if (toolsets == null || toolsets.isEmpty()) {
1164 logger.warn("ENCODE: " + topic + ":" +
1165 encodedClass.getClass().getCanonicalName() + ":" +
1166 encodedClass + " ENCODER NOT FOUND");
1167 throw new IllegalStateException("No Encoders toolsets available for topic "+ topic +
1168 " encoder " + encodedClass.getClass().getCanonicalName());
1171 for (Pair<ProtocolCoderToolset, ProtocolCoderToolset> encoderSet : toolsets) {
1172 // figure out the right toolset
1173 String groupId = encoderSet.first().getGroupId();
1174 String artifactId = encoderSet.first().getArtifactId();
1175 List<CoderFilters> coders = encoderSet.first().getCoders();
1176 for (CoderFilters coder : coders) {
1177 if (coder.getCodedClass().equals(encodedClass.getClass().getCanonicalName())) {
1178 DroolsController droolsController =
1179 DroolsController.factory.get(groupId, artifactId, "");
1180 if (droolsController.ownsCoder(encodedClass.getClass(), coder.getModelClassLoaderHash())) {
1181 droolsControllers.add(droolsController);
1187 if (droolsControllers.isEmpty()) {
1188 throw new IllegalStateException("No Encoders toolsets available for topic "+ topic +
1189 " : encoder " + encodedClass.getClass().getCanonicalName());
1191 return droolsControllers;
1196 * get all filters by maven coordinates and topic
1198 * @param groupId group id
1199 * @param artifactId artifact id
1200 * @param topic topic
1201 * @return list of coders
1202 * @throws IllegalArgumentException if invalid input
1204 public List<CoderFilters> getFilters(String groupId, String artifactId, String topic)
1205 throws IllegalArgumentException {
1207 if (!isCodingSupported(groupId, artifactId, topic)) {
1208 throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic));
1211 String key = this.codersKey(groupId, artifactId, topic);
1212 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
1213 return coderTools.first().getCoders();
1217 * get all coders by maven coordinates and topic
1219 * @param groupId group id
1220 * @param artifactId artifact id
1221 * @param topic topic
1222 * @return list of coders
1223 * @throws IllegalArgumentException if invalid input
1225 public Pair<ProtocolCoderToolset,ProtocolCoderToolset> getCoders(String groupId, String artifactId, String topic)
1226 throws IllegalArgumentException {
1228 if (!isCodingSupported(groupId, artifactId, topic)) {
1229 throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic));
1232 String key = this.codersKey(groupId, artifactId, topic);
1233 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
1238 * get all coders by maven coordinates and topic
1240 * @param groupId group id
1241 * @param artifactId artifact id
1242 * @return list of coders
1243 * @throws IllegalArgumentException if invalid input
1245 public List<CoderFilters> getFilters(String groupId, String artifactId)
1246 throws IllegalArgumentException {
1248 if (groupId == null || groupId.isEmpty()) {
1249 throw new IllegalArgumentException("Invalid group id");
1252 if (artifactId == null || artifactId.isEmpty()) {
1253 throw new IllegalArgumentException("Invalid artifact id");
1256 String key = this.codersKey(groupId, artifactId, "");
1258 List<CoderFilters> codersFilters = new ArrayList<CoderFilters>();
1259 for (Map.Entry<String, Pair<ProtocolCoderToolset,ProtocolCoderToolset>> entry : coders.entrySet()) {
1260 if (entry.getKey().startsWith(key)) {
1261 codersFilters.addAll(entry.getValue().first().getCoders());
1265 return codersFilters;
1269 * get all coders by maven coordinates and topic
1271 * @param groupId group id
1272 * @param artifactId artifact id
1273 * @return list of coders
1274 * @throws IllegalArgumentException if invalid input
1276 public List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> getCoders(String groupId, String artifactId)
1277 throws IllegalArgumentException {
1279 if (groupId == null || groupId.isEmpty()) {
1280 throw new IllegalArgumentException("Invalid group id");
1283 if (artifactId == null || artifactId.isEmpty()) {
1284 throw new IllegalArgumentException("Invalid artifact id");
1287 String key = this.codersKey(groupId, artifactId, "");
1289 List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> coderToolset = new ArrayList<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>();
1290 for (Map.Entry<String, Pair<ProtocolCoderToolset,ProtocolCoderToolset>> entry : coders.entrySet()) {
1291 if (entry.getKey().startsWith(key)) {
1292 coderToolset.add(entry.getValue());
1296 return coderToolset;
1301 * get all filters by maven coordinates, topic, and classname
1303 * @param groupId group id
1304 * @param artifactId artifact id
1305 * @param topic topic
1307 * @return list of coders
1308 * @throws IllegalArgumentException if invalid input
1310 public CoderFilters getFilters(String groupId, String artifactId, String topic, String classname)
1311 throws IllegalArgumentException {
1313 if (!isCodingSupported(groupId, artifactId, topic)) {
1314 throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic));
1317 if (classname == null || classname.isEmpty()) {
1318 throw new IllegalArgumentException("classname must be provided");
1321 String key = this.codersKey(groupId, artifactId, topic);
1322 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
1323 return coderTools.first().getCoder(classname);
1327 * get coded based on class and topic
1332 * @throws IllegalArgumentException
1334 public List<CoderFilters> getReverseFilters(String topic, String codedClass)
1335 throws IllegalArgumentException {
1337 if (topic == null || topic.isEmpty()) {
1338 throw new IllegalArgumentException("Unsupported");
1341 if (codedClass == null) {
1342 throw new IllegalArgumentException("class must be provided");
1345 String key = this.reverseCodersKey(topic, codedClass);
1346 List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> toolsets = this.reverseCoders.get(key);
1347 if (toolsets == null)
1348 throw new IllegalArgumentException("No Coder found for " + key);
1351 List<CoderFilters> coders = new ArrayList<CoderFilters>();
1352 for (Pair<ProtocolCoderToolset,ProtocolCoderToolset> toolset: toolsets) {
1353 coders.addAll(toolset.first().getCoders());
1360 * returns group and artifact id of the creator of the encoder
1365 * @throws IllegalArgumentException
1367 DroolsController getDroolsController(String topic, Object fact)
1368 throws IllegalArgumentException {
1370 if (topic == null || topic.isEmpty()) {
1371 throw new IllegalArgumentException("Unsupported");
1375 throw new IllegalArgumentException("class must be provided");
1378 List<DroolsController> droolsControllers = droolsCreators(topic, fact);
1379 if (droolsControllers.size() > 1) {
1381 logger.warn("MULTIPLE DROOLS CONTROLLERS FOUND for: " + topic + ":" +
1382 fact.getClass().getCanonicalName() + ":" +
1383 droolsControllers + " IN " + this);
1386 return droolsControllers.get(0);
1390 * returns group and artifact id of the creator of the encoder
1395 * @throws IllegalArgumentException
1397 List<DroolsController> getDroolsControllers(String topic, Object fact)
1398 throws IllegalArgumentException {
1400 if (topic == null || topic.isEmpty()) {
1401 throw new IllegalArgumentException("Unsupported");
1405 throw new IllegalArgumentException("class must be provided");
1408 List<DroolsController> droolsControllers = droolsCreators(topic, fact);
1409 if (droolsControllers.size() > 1) {
1411 logger.warn("MULTIPLE DROOLS CONTROLLERS FOUND for: " + topic + ":" +
1412 fact.getClass().getCanonicalName() + ":" +
1413 droolsControllers + " IN " + this);
1416 return droolsControllers;
1420 public String toString() {
1421 StringBuilder builder = new StringBuilder();
1422 builder.append("GenericEventProtocolCoder [coders=").append(coders.keySet()).append(", reverseCoders=")
1423 .append(reverseCoders.keySet()).append("]");
1424 return builder.toString();
1428 class EventProtocolDecoder extends GenericEventProtocolCoder {
1430 public EventProtocolDecoder(){super(false);}
1433 public String toString() {
1434 StringBuilder builder = new StringBuilder();
1435 builder.append("EventProtocolDecoder [toString()=").append(super.toString()).append("]");
1436 return builder.toString();
1441 class EventProtocolEncoder extends GenericEventProtocolCoder {
1443 public EventProtocolEncoder(){super(false);}
1446 public String toString() {
1447 StringBuilder builder = new StringBuilder();
1448 builder.append("EventProtocolEncoder [toString()=").append(super.toString()).append("]");
1449 return builder.toString();