Initial OpenECOMP policy/drools-pdp commit
[policy/drools-pdp.git] / policy-management / src / main / java / org / openecomp / policy / drools / protocol / coders / EventProtocolCoder.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * policy-management
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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=========================================================
19  */
20
21 package org.openecomp.policy.drools.protocol.coders;
22
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28
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;
37
38 /**
39  * Coder (Encoder/Decoder) of Events.
40  */
41 public interface EventProtocolCoder {
42         
43         public static class CoderFilters {
44
45                 /**
46                  * coder class 
47                  */
48                 protected String factClass;
49                 
50                 /**
51                  * filters to apply to the selection of the decodedClass;
52                  */
53                 protected JsonProtocolFilter filter;
54
55                 /**
56                  * classloader hash
57                  */
58                 protected int modelClassLoaderHash;
59
60                 
61                 /**
62                  * constructor
63                  * 
64                  * @param codedClass coder class
65                  * @param filter filters to apply
66                  */
67                 public CoderFilters(String codedClass, JsonProtocolFilter filter, int modelClassLoaderHash) {
68                         this.factClass = codedClass;
69                         this.filter = filter;
70                         this.modelClassLoaderHash = modelClassLoaderHash;
71                 }
72
73                 /**
74                  * @return the codedClass
75                  */
76                 public String getCodedClass() {
77                         return factClass;
78                 }
79
80                 /**
81                  * @param codedClass the decodedClass to set
82                  */
83                 public void setCodedClass(String codedClass) {
84                         this.factClass = codedClass;
85                 }
86                 
87                 /**
88                  * @return the filter
89                  */
90                 public synchronized JsonProtocolFilter getFilter() {
91                         return filter;
92                 }
93
94                 /**
95                  * @param filter the filter to set
96                  */
97                 public synchronized void setFilter(JsonProtocolFilter filter) {
98                         this.filter = filter;
99                 }
100
101                 public int getModelClassLoaderHash() {
102                         return modelClassLoaderHash;
103                 }
104
105                 public void setFromClassLoaderHash(int fromClassLoaderHash) {
106                         this.modelClassLoaderHash = fromClassLoaderHash;
107                 }
108
109                 @Override
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();
115                 }
116
117         }
118         
119         /**
120          * Adds a Decoder class to decode the protocol over this topic
121          *  
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
128          * 
129          * @throw IllegalArgumentException if an invalid parameter is passed
130          */
131         public void addDecoder(String groupId, String artifactId, 
132                                        String topic, 
133                                        String eventClass, 
134                                        JsonProtocolFilter protocolFilter, 
135                                        CustomGsonCoder customGsonCoder,
136                                        CustomJacksonCoder customJacksonCoder,
137                                        int modelClassLoaderHash)
138                 throws IllegalArgumentException;
139
140         /**
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
145          * 
146          * @throws IllegalArgumentException if invalid arguments have been provided
147          */
148         void removeEncoders(String groupId, String artifactId, String topic) throws IllegalArgumentException;
149         
150         /**
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
155          * 
156          * @throws IllegalArgumentException if invalid arguments have been provided
157          */
158         public void removeDecoders(String groupId, String artifactId, String topic) throws IllegalArgumentException;
159         
160         /**
161          * Given a controller id and a topic, it gives back its filters
162          * 
163          * @param groupId of the controller
164          * @param artifactId of the controller
165          * @param topic the topic
166          * 
167          * return list of decoders
168          * 
169          * @throw IllegalArgumentException if an invalid parameter is passed
170          */
171         public List<CoderFilters> getDecoderFilters(String groupId, String artifactId, String topic)
172                 throws IllegalArgumentException;        
173         
174
175         /**
176          * Given a controller id and a topic, it gives back the decoding configuration
177          * 
178          * @param groupId of the controller
179          * @param artifactId of the controller
180          * @param topic the topic
181          * 
182          * return decoding toolset
183          * 
184          * @throw IllegalArgumentException if an invalid parameter is passed
185          */
186         public ProtocolCoderToolset getDecoders(String groupId, String artifactId, String topic) 
187                    throws IllegalArgumentException;
188         
189         /**
190          * Given a controller id and a topic, it gives back all the decoding configurations
191          * 
192          * @param groupId of the controller
193          * @param artifactId of the controller
194          * @param topic the topic
195          * 
196          * return decoding toolset
197          * 
198          * @throw IllegalArgumentException if an invalid parameter is passed
199          */
200         public List<ProtocolCoderToolset> getDecoders(String groupId, String artifactId)
201                    throws IllegalArgumentException;
202         
203         
204         /**
205          * gets all decoders associated with the group and artifact ids
206          * @param groupId of the controller
207          * @param artifactId of the controller
208          * 
209          * @throws IllegalArgumentException if invalid arguments have been provided
210          */
211         public List<CoderFilters> getDecoderFilters(String groupId, String artifactId) throws IllegalArgumentException;
212         
213
214         /**
215          * Given a controller id and a topic, it gives back the classes that implements the encoding
216          * 
217          * @param groupId of the controller
218          * @param artifactId of the controller
219          * @param topic the topic
220          * 
221          * return list of decoders
222          * 
223          * @throw IllegalArgumentException if an invalid parameter is passed
224          */
225         public List<CoderFilters> getEncoderFilters(String groupId, String artifactId, String topic) 
226                         throws IllegalArgumentException;
227         
228         /**
229          * gets all encoders associated with the group and artifact ids
230          * @param groupId of the controller
231          * @param artifactId of the controller
232          * 
233          * @throws IllegalArgumentException if invalid arguments have been provided
234          */
235         public List<CoderFilters> getEncoderFilters(String groupId, String artifactId) throws IllegalArgumentException;
236         
237         /**
238          * Given a controller id, a topic, and a classname, it gives back the classes that implements the decoding
239          * 
240          * @param groupId of the controller
241          * @param artifactId of the controller
242          * @param topic the topic
243          * @param classname classname
244          * 
245          * return list of decoders
246          * 
247          * @throw IllegalArgumentException if an invalid parameter is passed
248          */     
249         public CoderFilters getDecoderFilters(String groupId, String artifactId, String topic, String classname)
250                 throws IllegalArgumentException;        
251         
252         /**
253          * is there a decoder supported for the controller id and topic
254          * 
255          * @param groupId of the controller
256          * @param artifactId of the controller
257          * @param topic protocol
258          * @return true if supported
259          */
260         public boolean isDecodingSupported(String groupId, String artifactId, String topic);
261         
262         /**
263          * Adds a Encoder class to encode the protocol over this topic
264          *  
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
271          * 
272          * @throw IllegalArgumentException if an invalid parameter is passed
273          */
274         public void addEncoder(String groupId, String artifactId, String topic, 
275                                                    String eventClass, 
276                                        JsonProtocolFilter protocolFilter,
277                                        CustomGsonCoder customGsonCoder,
278                                        CustomJacksonCoder customJacksonCoder,
279                                        int modelClassLoaderHash)
280                 throws IllegalArgumentException;
281         
282         /**
283          * is there an encoder supported for the controller id and topic
284          * 
285          * @param groupId of the controller
286          * @param artifactId of the controller
287          * @param topic protocol
288          * @return true if supported
289          */
290         public boolean isEncodingSupported(String groupId, String artifactId, String topic);
291         
292         /**
293          * get encoder based on coordinates and classname
294          * 
295          * @param groupId of the controller
296          * @param artifactId of the controller
297          * @param topic protocol
298          * @param json event string
299          * @return
300          * @throws IllegalArgumentException invalid arguments passed in
301          */
302         public CoderFilters getEncoderFilters(String groupId, String artifactId, String topic, String classname)
303                         throws IllegalArgumentException;
304         
305         /**
306          * get encoder based on topic and encoded class
307          * 
308          * @param topic topic
309          * @param encodedClass encoded class
310          * @return
311          * @throws IllegalArgumentException invalid arguments passed in
312          */
313         public List<CoderFilters> getReverseEncoderFilters(String topic, String encodedClass)
314                         throws IllegalArgumentException;
315         
316         /**
317          * gets the identifier of the creator of the encoder
318          * 
319          * @param topic topic
320          * @param encodedClass encoded class
321          * @return a drools controller
322          * @throws IllegalArgumentException invalid arguments passed in
323          */
324         public DroolsController getDroolsController(String topic, Object encodedClass)
325                         throws IllegalArgumentException;
326         
327         /**
328          * gets the identifier of the creator of the encoder
329          * 
330          * @param topic topic
331          * @param encodedClass encoded class
332          * @return list of drools controllers
333          * @throws IllegalArgumentException invalid arguments passed in
334          */
335         public List<DroolsController> getDroolsControllers(String topic, Object encodedClass)
336                         throws IllegalArgumentException;
337         
338         /**
339          * decode topic's stringified event (json) to corresponding Event Object.
340          * 
341          * @param groupId of the controller
342          * @param artifactId of the controller
343          * @param topic protocol
344          * @param json event string
345          * @return
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
349          */
350         public Object decode(String groupId, String artifactId, String topic, String json) 
351                         throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException;
352
353         /**
354          * encodes topic's stringified event (json) to corresponding Event Object.
355          * 
356          * @param groupId of the controller
357          * @param artifactId of the controller
358          * @param topic protocol
359          * @param event Object
360          * 
361          * @throws IllegalArgumentException invalid arguments passed in
362          */
363         public String encode(String groupId, String artifactId, String topic, Object event) 
364                         throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;
365         
366         /**
367          * encodes topic's stringified event (json) to corresponding Event Object.
368          * 
369          * @param topic topic
370          * @param event event object
371          * 
372          * @throws IllegalArgumentException invalid arguments passed in
373          * @throws UnsupportedOperationException operation cannot be performed
374          */
375         public String encode(String topic, Object event) 
376                         throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;
377         
378         /**
379          * encodes topic's stringified event (json) to corresponding Event Object.
380          * 
381          * @param topic topic
382          * @param event event object
383          * @param droolsController 
384          * 
385          * @throws IllegalArgumentException invalid arguments passed in
386          * @throws UnsupportedOperationException operation cannot be performed
387          */
388         public String encode(String topic, Object event, DroolsController droolsController) 
389                         throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException;
390         
391         /**
392          * singleton reference to the global event protocol coder
393          */
394         public static EventProtocolCoder manager = new MultiplexorEventProtocolCoder();
395 }
396
397 /**
398  * Protocol Coder that does its best attempt to decode/encode, selecting the best
399  * class and best fitted json parsing tools.
400  */
401 class MultiplexorEventProtocolCoder implements EventProtocolCoder {
402         // get an instance of logger 
403         private static Logger  logger = FlexLogger.getLogger(MultiplexorEventProtocolCoder.class);      
404         /**
405          * Decoders
406          */
407         protected EventProtocolDecoder decoders = new EventProtocolDecoder();
408         
409         /**
410          * Encoders
411          */
412         protected EventProtocolEncoder encoders = new EventProtocolEncoder();
413         
414         
415         /**
416          * {@inheritDoc}
417          */
418         @Override
419         public void addDecoder(String groupId, String artifactId, String topic, 
420                                        String eventClass, 
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 + 
430                                           " INTO " + this);
431                 this.decoders.add(groupId, artifactId, topic, eventClass, protocolFilter, 
432                                          customGsonCoder, customJacksonCoder, modelClassLoaderHash);
433         }
434         
435         /**
436          * {@inheritDoc}
437          */
438         @Override
439         public void addEncoder(String groupId, String artifactId, String topic, 
440                                        String eventClass, 
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 +
450                                    " INTO " + this);
451                 this.encoders.add(groupId, artifactId, topic, eventClass, protocolFilter, 
452                                   customGsonCoder, customJacksonCoder, modelClassLoaderHash);
453         }
454         
455         /**
456          * {@inheritDoc}
457          */
458         @Override
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);
464         }
465         
466         /**
467          * {@inheritDoc}
468          */
469         @Override
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);
475         }
476         
477         /**
478          * {@inheritDoc}
479          */
480         @Override
481         public boolean isDecodingSupported(String groupId, String artifactId, String topic) {   
482                 return this.decoders.isCodingSupported(groupId, artifactId, topic);
483         }
484         
485         /**
486          * {@inheritDoc}
487          */
488         @Override
489         public boolean isEncodingSupported(String groupId, String artifactId, String topic) {
490                 return this.encoders.isCodingSupported(groupId, artifactId, topic);
491         }
492         
493         /**
494          * {@inheritDoc}
495          */
496         @Override
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);
502         }
503
504         /**
505          * {@inheritDoc}
506          */
507         @Override
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);
513         }
514         
515         /**
516          * {@inheritDoc}
517          */
518         @Override
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);
523         }
524         
525         /**
526          * {@inheritDoc}
527          */
528         @Override
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);
533         }
534
535         /**
536          * {@inheritDoc}
537          */
538         @Override
539         public List<CoderFilters> getDecoderFilters(String groupId, String artifactId, String topic) 
540                         throws IllegalArgumentException {
541                 
542                 return this.decoders.getFilters(groupId, artifactId, topic);
543         }
544         
545         /**
546          * {@inheritDoc}
547          */
548         @Override
549         public ProtocolCoderToolset getDecoders(String groupId, String artifactId, String topic) 
550                         throws IllegalArgumentException {
551                 
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);
555                 
556                 return decoderToolsets.first();
557         }
558         
559         /**
560          * {@inheritDoc}
561          */
562         @Override
563         public List<CoderFilters> getEncoderFilters(String groupId, String artifactId, String topic) 
564                         throws IllegalArgumentException {
565                 
566                 return this.encoders.getFilters(groupId, artifactId, topic);
567         }
568
569         /**
570          * {@inheritDoc}
571          */
572         @Override
573         public CoderFilters getDecoderFilters(String groupId, String artifactId, String topic, String classname)
574                         throws IllegalArgumentException {
575                 
576                 return this.decoders.getFilters(groupId, artifactId, topic, classname);
577         }
578         
579         /**
580          * {@inheritDoc}
581          */
582         @Override
583         public CoderFilters getEncoderFilters(String groupId, String artifactId, String topic, String classname)
584                         throws IllegalArgumentException {
585                 
586                 return this.encoders.getFilters(groupId, artifactId, topic, classname);
587         }
588         
589         /**
590          * {@inheritDoc}
591          */
592         @Override
593         public List<CoderFilters> getReverseEncoderFilters(String topic, String encodedClass) throws IllegalArgumentException {
594                 return this.encoders.getReverseFilters(topic, encodedClass);
595         }
596
597         /**
598          * get all deocders by maven coordinates and topic
599          * 
600          * @param groupId group id
601          * @param artifactId artifact id
602          * 
603          * @return list of decoders
604          * @throws IllegalArgumentException if invalid input
605          */
606         @Override
607         public List<ProtocolCoderToolset> getDecoders(String groupId, String artifactId) 
608                         throws IllegalArgumentException {
609
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);
613                 
614                 List<ProtocolCoderToolset> parser1CoderToolset = new ArrayList<>();
615                 for (Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderToolsetPair : decoderToolsets) {
616                         parser1CoderToolset.add(coderToolsetPair.first());
617                 }
618                 
619                 return parser1CoderToolset;
620         }
621         
622         /**
623          * {@inheritDoc}
624          */
625         @Override
626         public List<CoderFilters> getDecoderFilters(String groupId, String artifactId) throws IllegalArgumentException {
627                 return this.decoders.getFilters(groupId, artifactId);
628                 
629         }
630
631         /**
632          * {@inheritDoc}
633          */
634         @Override
635         public List<CoderFilters> getEncoderFilters(String groupId, String artifactId) throws IllegalArgumentException {
636                 return this.encoders.getFilters(groupId, artifactId);
637         }
638         
639         /**
640          * {@inheritDoc}
641          */
642         @Override
643         public DroolsController getDroolsController(String topic, Object encodedClass) throws IllegalArgumentException {
644                 return this.encoders.getDroolsController(topic, encodedClass);
645         }
646         
647         /**
648          * {@inheritDoc}
649          */
650         @Override
651         public List<DroolsController> getDroolsControllers(String topic, Object encodedClass) throws IllegalArgumentException {
652                 return this.encoders.getDroolsControllers(topic, encodedClass);
653         }
654
655         /**
656          * {@inheritDoc}
657          */
658         @Override
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();
664         }
665 }
666
667 /**
668  * This protocol Coder that does its best attempt to decode/encode, selecting the best
669  * class and best fitted json parsing tools.
670  */
671 abstract class GenericEventProtocolCoder  {
672         private static Logger  logger = FlexLogger.getLogger(GenericEventProtocolCoder.class);  
673         
674         /**
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.
680          */
681         protected final HashMap<String, Pair<ProtocolCoderToolset,ProtocolCoderToolset>> coders = 
682                         new HashMap<String, Pair<ProtocolCoderToolset,ProtocolCoderToolset>>();
683         
684         /**
685          * Mapping topic + classname -> Protocol Set 
686          */
687         protected final HashMap<String, List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>> reverseCoders = 
688                         new HashMap<String, List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>>();
689         
690         protected boolean multipleToolsetRetries = false;
691         
692         GenericEventProtocolCoder(boolean multipleToolsetRetries) {
693                 this.multipleToolsetRetries = multipleToolsetRetries;
694         }
695         
696         /**
697          * Index a new coder
698          *  
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
705          * 
706          * @throw IllegalArgumentException if an invalid parameter is passed
707          */
708         public void add(String groupId, String artifactId, 
709                                 String topic, 
710                                 String eventClass, 
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");
718                 }
719                 
720                 if (artifactId == null || artifactId.isEmpty()) {
721                         throw new IllegalArgumentException("Invalid artifact id");
722                 }
723                 
724                 if (topic == null || topic.isEmpty()) {
725                         throw new IllegalArgumentException("Invalid Topic");
726                 }
727                 
728                 if (eventClass == null) {
729                         throw new IllegalArgumentException("Invalid Event Class");
730                 }
731                 
732                 String key = this.codersKey(groupId, artifactId, topic);
733                 String reverseKey = this.reverseCodersKey(topic, eventClass);
734                 
735                 synchronized(this) {
736                         if (coders.containsKey(key)) {                          
737                                 Pair<ProtocolCoderToolset, ProtocolCoderToolset> toolsets = coders.get(key);
738                                 
739                                 if (logger.isInfoEnabled())
740                                         logger.info("ADDING CODER TO EXISTING: " + toolsets + " for " + key);
741                                 
742                                 toolsets.first().addCoder(eventClass, protocolFilter, modelClassLoaderHash);
743                                 toolsets.second().addCoder(eventClass, protocolFilter, modelClassLoaderHash);
744                                 
745                                 if (!reverseCoders.containsKey(reverseKey)) {
746                                         if (logger.isInfoEnabled())
747                                                 logger.info("Multiple coder classes case: " + toolsets.first() + 
748                                                                            " for " + reverseKey + " - " + key);
749                                         
750                                         List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> reverseMappings =
751                                                         new ArrayList<Pair<ProtocolCoderToolset,ProtocolCoderToolset>>();
752                                         reverseMappings.add(toolsets);
753                                         reverseCoders.put(reverseKey, reverseMappings);
754                                 }
755                                 return;
756                         }
757                 
758                         GsonProtocolCoderToolset gsonCoderTools = 
759                                                                                 new GsonProtocolCoderToolset
760                                                                                                                 (topic, key, 
761                                                                                                                  groupId, artifactId, 
762                                                                                                                  eventClass, protocolFilter,
763                                                                                                                  customGsonCoder,
764                                                                                                                  modelClassLoaderHash);
765                         
766                         JacksonProtocolCoderToolset jacksonCoderTools = 
767                                                                                 new JacksonProtocolCoderToolset
768                                                                                                                 (topic, key, 
769                                                                                                                  groupId, artifactId, 
770                                                                                                                  eventClass, protocolFilter,
771                                                                                                                  customJacksonCoder,
772                                                                                                                  modelClassLoaderHash);
773                         
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
781                         
782                         Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = 
783                                         new Pair<ProtocolCoderToolset,ProtocolCoderToolset>(gsonCoderTools, 
784                                                                                                     jacksonCoderTools);
785                         
786                         logger.info("ADDED TOOLSET: " + key + " : " + 
787                                           coderTools + ":" + this);
788                         
789                         coders.put(key, coderTools);
790                         
791                         if (reverseCoders.containsKey(reverseKey)) {
792                                 // There is another controller (different group id/artifact id/topic)
793                                 // that shares the class and the topic.
794                                 
795                                 List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> toolsets = 
796                                                                                                                         reverseCoders.get(reverseKey);
797                                 boolean present = false;
798                                 for (Pair<ProtocolCoderToolset,ProtocolCoderToolset> parserSet: toolsets) {
799                                         // just doublecheck
800                                         present = parserSet.first().getControllerId().equals(key);
801                                         if (present) {
802                                                 /* anomaly */
803                                                 logger.error("UNEXPECTED TOOLSET REVERSE MAPPING FOUND: " + parserSet.first() + 
804                                                                            " for " + reverseKey + " - " + key);
805                                         }
806                                 }
807                                 
808                                 if (present) {
809                                         return;
810                                 } else {
811                                         logger.info("ADDING TOOLSET REVERSE MAPPING: " + reverseKey + " : " + 
812                                                       toolsets + ":" + coderTools + ":" + this);
813                                         toolsets.add(coderTools);
814                                 }
815                         } else {
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);
822                         }
823                         
824                 }
825         }
826
827         /**
828          * produces key for indexing toolset entries
829          * 
830          * @param group group id
831          * @param artifactId artifact id
832          * @param topic topic
833          * @return index key
834          */
835         protected String codersKey(String groupId, String artifactId, String topic) {
836                 return groupId + ":" + artifactId + ":" + topic;
837         }
838         
839         /**
840          * produces a key for the reverse index
841          * 
842          * @param topic topic 
843          * @param eventClass coded class
844          * @return reverse index key
845          */
846         protected String reverseCodersKey(String topic, String eventClass) {
847                 return topic + ":" + eventClass;
848         }
849         
850         /**
851          * remove coder 
852          * 
853          * @param groupId group id
854          * @param artifactId artifact id
855          * @param topic topic
856          * @throws IllegalArgumentException if invalid input
857          */
858         public void remove(String groupId, String artifactId, String topic) 
859                    throws IllegalArgumentException {
860                 
861                 if (groupId == null || groupId.isEmpty()) {
862                         throw new IllegalArgumentException("Invalid group id");
863                 }
864                 
865                 if (artifactId == null || artifactId.isEmpty()) {
866                         throw new IllegalArgumentException("Invalid artifact id");
867                 }
868                 
869                 if (topic == null || topic.isEmpty()) {
870                         throw new IllegalArgumentException("Invalid Topic");
871                 }
872                 
873                 String key = this.codersKey(groupId, artifactId, topic);
874                 
875                 synchronized(this) {
876                         if (coders.containsKey(key)) {
877                                 Pair<ProtocolCoderToolset, ProtocolCoderToolset> p = coders.remove(key);
878                                 logger.info("REMOVED TOOLSET: " + key + " : " + p + " FROM " + 
879                                                   coders + " : " +  this);
880                                 
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 = 
888                                                                                                                                                                 toolsets.iterator();
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 " + 
893                                                                                           reverseCoders);
894                                                                 toolsetsIter.remove();
895                                                         }
896                                                 }
897                                                 
898                                                 if (this.reverseCoders.get(reverseKey).isEmpty()) {
899                                                         logger.info("REMOVE FULL REVERSE MAPPING of TOOLSET: " + reverseKey + " FROM " + 
900                                                                           reverseCoders);                                                       
901                                                         this.reverseCoders.remove(reverseKey);
902                                                 }
903                                         }
904                                 }
905                         }
906                 }
907         }
908
909         /**
910          * does it support coding?
911          * 
912          * @param groupId group id
913          * @param artifactId artifact id
914          * @param topic topic
915          * @return true if its is codable
916          */
917         public boolean isCodingSupported(String groupId, String artifactId, String topic) {
918                 
919                 if (groupId == null || groupId.isEmpty()) {
920                         throw new IllegalArgumentException("Invalid group id");
921                 }
922                 
923                 if (artifactId == null || artifactId.isEmpty()) {
924                         throw new IllegalArgumentException("Invalid artifact id");
925                 }
926                 
927                 if (topic == null || topic.isEmpty())
928                         return false;
929                 
930                 String key = this.codersKey(groupId, artifactId, topic);
931                 synchronized(this) {
932                         return (coders.containsKey(key));
933                 }
934         }
935         
936         /**
937          * decode a json string into an Object
938          * 
939          * @param groupId group id
940          * @param artifactId artifact id
941          * @param topic topic
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
946          */
947         public Object decode(String groupId, String artifactId, String topic, String json) 
948                         throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException {
949                 
950                 if (!isCodingSupported(groupId, artifactId, topic)) {
951                         throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic) + " for encoding");
952                 }
953                 
954                 String key = this.codersKey(groupId, artifactId, topic);
955                 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
956                 try {
957                         Object event = coderTools.first().decode(json);
958                         if (event != null)
959                                 return event;
960                 } catch (Exception e) {
961                         // TODO Auto-generated catch block
962                         logger.warn("Can't decode @ " + this);
963                 }
964                 
965                 if (multipleToolsetRetries) {
966                         // try the less favored toolset
967                         try {
968                                 Object event = coderTools.second().decode(json);
969                                 if (event != null) {
970                                         // change the priority of the toolset
971                                         synchronized(this) {
972                                                 ProtocolCoderToolset first = coderTools.first();
973                                                 ProtocolCoderToolset second = coderTools.second();
974                                                 coderTools.first(second);
975                                                 coderTools.second(first);
976                                         }
977                                         
978                                         return event;
979                                 }
980                         } catch (Exception e2) {
981                                 // TODO Auto-generated catch block
982                                 e2.printStackTrace();
983                                 throw new UnsupportedOperationException(e2);
984                         }
985                 } 
986                 
987                 throw new UnsupportedOperationException("Cannot decode neither with gson or jackson");
988         }
989
990         /**
991          * encode an object into a json string
992          * 
993          * @param groupId group id
994          * @param artifactId artifact id
995          * @param topic topic
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
1000          */
1001         public String encode(String groupId, String artifactId, String topic, Object event) 
1002                         throws IllegalArgumentException, UnsupportedOperationException {
1003                 
1004                 if (!isCodingSupported(groupId, artifactId, topic)) {
1005                         throw new IllegalArgumentException
1006                                 ("Unsupported:" + codersKey(groupId, artifactId, topic));
1007                 }
1008                 
1009                 if (event == null) {
1010                         throw new IllegalArgumentException("Unsupported topic:" + topic);
1011                 }
1012                 
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);
1016         }
1017         
1018         /**
1019          * encode an object into a json string
1020          * 
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
1026          */
1027         protected String encodeInternal(String key, Object event) 
1028                         throws IllegalArgumentException, UnsupportedOperationException {
1029                 
1030                 logger.debug("ENCODE: " + key + ":" + event + this);
1031                 
1032                 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
1033                 try {
1034                         String json = coderTools.first().encode(event);
1035                         if (json != null && !json.isEmpty())
1036                                 return json;
1037                 } catch (Exception e) {
1038                         logger.error(MessageCodes.EXCEPTION_ERROR, e, "FIRST-ENCODE-INTERNAL: " + 
1039                                        key + ":" + event, this.toString());
1040                 }
1041                 
1042                 if (multipleToolsetRetries) {
1043                         // try the less favored toolset
1044                         try {
1045                                 String json = coderTools.second().encode(event);
1046                                 if (json != null) {
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);
1053                                         }
1054                                         
1055                                         return json;
1056                                 }
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);
1062                         }
1063                 }
1064                 
1065                 throw new UnsupportedOperationException("Cannot decode neither with gson or jackson");
1066         }
1067         
1068         /**
1069          * encode an object into a json string
1070          * 
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
1076          */
1077         public String encode(String topic, Object encodedClass) 
1078                         throws IllegalArgumentException, IllegalArgumentException, UnsupportedOperationException {
1079                 
1080                 if (encodedClass == null) {
1081                         throw new IllegalArgumentException("Invalid encoded class");
1082                 }
1083                 
1084                 if (topic == null || topic.isEmpty()) {
1085                         throw new IllegalArgumentException("Invalid topic");
1086                 }
1087                 
1088                 logger.info("ENCODE: " + topic + ":" + 
1089                                   encodedClass.getClass().getCanonicalName() + ":" + 
1090                                           encodedClass);
1091                 
1092                 List<DroolsController> droolsControllers = droolsCreators(topic, encodedClass);
1093                 if (droolsControllers.size() > 1) {
1094                         // unexpected
1095                         logger.warn("MULTIPLE DROOLS CONTROLLERS FOUND for: " + topic + ":" + 
1096                               encodedClass.getClass().getCanonicalName() + ":" + 
1097                               droolsControllers + " IN " + this);               
1098                         // continue
1099                 }
1100                 
1101                 String key = codersKey(droolsControllers.get(0).getGroupId(), droolsControllers.get(0).getArtifactId(), topic);
1102                 return this.encodeInternal(key, encodedClass);
1103         }
1104         
1105         /**
1106          * encode an object into a json string
1107          * 
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
1113          */
1114         public String encode(String topic, Object encodedClass, DroolsController droolsController) 
1115                         throws IllegalArgumentException, IllegalArgumentException, UnsupportedOperationException {
1116                 
1117                 if (encodedClass == null) {
1118                         throw new IllegalArgumentException("Invalid encoded class");
1119                 }
1120                 
1121                 if (topic == null || topic.isEmpty()) {
1122                         throw new IllegalArgumentException("Invalid topic");
1123                 }
1124                 
1125                 logger.info("ENCODE: " + topic + ":" + 
1126                                   encodedClass.getClass().getCanonicalName() + ":" + 
1127                                           encodedClass + ":" + droolsController);
1128                 
1129                 String key = codersKey(droolsController.getGroupId(), droolsController.getArtifactId(), topic);
1130                 return this.encodeInternal(key, encodedClass);
1131         }
1132
1133         /**
1134          * @param topic
1135          * @param encodedClass
1136          * @param reverseKey
1137          * @return
1138          * @throws IllegalStateException
1139          * @throws IllegalArgumentException
1140          */
1141         protected List<DroolsController> droolsCreators(String topic, Object encodedClass)
1142                         throws IllegalStateException, IllegalArgumentException {
1143                 
1144                 List<DroolsController> droolsControllers = new ArrayList<DroolsController>();
1145                 
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;
1152                 }
1153                 
1154                 List<Pair<ProtocolCoderToolset, ProtocolCoderToolset>> 
1155                                         toolsets = this.reverseCoders.get(reverseKey);
1156                 
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.
1162                 
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());
1169                 }
1170                 
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);
1182                                         }
1183                                 }
1184                         }
1185                 }
1186                 
1187                 if (droolsControllers.isEmpty()) {
1188                         throw new IllegalStateException("No Encoders toolsets available for topic "+ topic +
1189                             " : encoder " + encodedClass.getClass().getCanonicalName());                                
1190                 }
1191                 return droolsControllers;
1192         }
1193
1194
1195         /**
1196          * get all filters by maven coordinates and topic
1197          * 
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
1203          */
1204         public List<CoderFilters> getFilters(String groupId, String artifactId, String topic) 
1205                         throws IllegalArgumentException {
1206                 
1207                 if (!isCodingSupported(groupId, artifactId, topic)) {
1208                         throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic));
1209                 }
1210                 
1211                 String key = this.codersKey(groupId, artifactId, topic);
1212                 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
1213                 return coderTools.first().getCoders();
1214         }
1215         
1216         /**
1217          * get all coders by maven coordinates and topic
1218          * 
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
1224          */
1225         public Pair<ProtocolCoderToolset,ProtocolCoderToolset> getCoders(String groupId, String artifactId, String topic) 
1226                         throws IllegalArgumentException {
1227                 
1228                 if (!isCodingSupported(groupId, artifactId, topic)) {
1229                         throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic));
1230                 }
1231                 
1232                 String key = this.codersKey(groupId, artifactId, topic);
1233                 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
1234                 return coderTools;
1235         }
1236         
1237         /**
1238          * get all coders by maven coordinates and topic
1239          * 
1240          * @param groupId group id
1241          * @param artifactId artifact id
1242          * @return list of coders
1243          * @throws IllegalArgumentException if invalid input
1244          */
1245         public List<CoderFilters> getFilters(String groupId, String artifactId) 
1246                         throws IllegalArgumentException {
1247                 
1248                 if (groupId == null || groupId.isEmpty()) {
1249                         throw new IllegalArgumentException("Invalid group id");
1250                 }
1251                 
1252                 if (artifactId == null || artifactId.isEmpty()) {
1253                         throw new IllegalArgumentException("Invalid artifact id");
1254                 }
1255                 
1256                 String key = this.codersKey(groupId, artifactId, "");
1257                 
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());
1262                         }
1263                 }
1264                 
1265                 return codersFilters;
1266         }
1267         
1268         /**
1269          * get all coders by maven coordinates and topic
1270          * 
1271          * @param groupId group id
1272          * @param artifactId artifact id
1273          * @return list of coders
1274          * @throws IllegalArgumentException if invalid input
1275          */
1276         public List<Pair<ProtocolCoderToolset,ProtocolCoderToolset>> getCoders(String groupId, String artifactId) 
1277                         throws IllegalArgumentException {
1278                 
1279                 if (groupId == null || groupId.isEmpty()) {
1280                         throw new IllegalArgumentException("Invalid group id");
1281                 }
1282                 
1283                 if (artifactId == null || artifactId.isEmpty()) {
1284                         throw new IllegalArgumentException("Invalid artifact id");
1285                 }
1286                 
1287                 String key = this.codersKey(groupId, artifactId, "");
1288                 
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());
1293                         }
1294                 }
1295                 
1296                 return coderToolset;
1297         }
1298
1299
1300         /**
1301          * get all filters by maven coordinates, topic, and classname
1302          * 
1303          * @param groupId group id
1304          * @param artifactId artifact id
1305          * @param topic topic
1306          * @param classname
1307          * @return list of coders
1308          * @throws IllegalArgumentException if invalid input
1309          */
1310         public CoderFilters getFilters(String groupId, String artifactId, String topic, String classname)
1311                         throws IllegalArgumentException {
1312                 
1313                 if (!isCodingSupported(groupId, artifactId, topic)) {
1314                         throw new IllegalArgumentException("Unsupported:" + codersKey(groupId, artifactId, topic));
1315                 }
1316                 
1317                 if (classname == null || classname.isEmpty()) {
1318                         throw new IllegalArgumentException("classname must be provided");
1319                 }
1320                 
1321                 String key = this.codersKey(groupId, artifactId, topic);
1322                 Pair<ProtocolCoderToolset,ProtocolCoderToolset> coderTools = coders.get(key);
1323                 return coderTools.first().getCoder(classname);
1324         }
1325         
1326         /**
1327          * get coded based on class and topic
1328          * 
1329          * @param topic
1330          * @param codedClass
1331          * @return
1332          * @throws IllegalArgumentException
1333          */
1334         public List<CoderFilters> getReverseFilters(String topic, String codedClass)
1335                         throws IllegalArgumentException {
1336                 
1337                 if (topic == null || topic.isEmpty()) {
1338                         throw new IllegalArgumentException("Unsupported");
1339                 }
1340                 
1341                 if (codedClass == null) {
1342                         throw new IllegalArgumentException("class must be provided");
1343                 }
1344                 
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);
1349                 
1350                 
1351                 List<CoderFilters> coders = new ArrayList<CoderFilters>();
1352                 for (Pair<ProtocolCoderToolset,ProtocolCoderToolset> toolset: toolsets) {
1353                         coders.addAll(toolset.first().getCoders());
1354                 }
1355                 
1356                 return coders;
1357         }
1358         
1359         /**
1360          * returns group and artifact id of the creator of the encoder
1361          * 
1362          * @param topic
1363          * @param fact
1364          * @return
1365          * @throws IllegalArgumentException
1366          */
1367         DroolsController getDroolsController(String topic, Object fact)
1368                         throws IllegalArgumentException {
1369                 
1370                 if (topic == null || topic.isEmpty()) {
1371                         throw new IllegalArgumentException("Unsupported");
1372                 }
1373                 
1374                 if (fact == null) {
1375                         throw new IllegalArgumentException("class must be provided");
1376                 }
1377                 
1378                 List<DroolsController> droolsControllers = droolsCreators(topic, fact);
1379                 if (droolsControllers.size() > 1) {
1380                         // unexpected
1381                         logger.warn("MULTIPLE DROOLS CONTROLLERS FOUND for: " + topic + ":" + 
1382                               fact.getClass().getCanonicalName() + ":" + 
1383                               droolsControllers + " IN " + this);               
1384                         // continue
1385                 }
1386                 return droolsControllers.get(0);
1387         }
1388         
1389         /**
1390          * returns group and artifact id of the creator of the encoder
1391          * 
1392          * @param topic
1393          * @param fact
1394          * @return
1395          * @throws IllegalArgumentException
1396          */
1397         List<DroolsController> getDroolsControllers(String topic, Object fact)
1398                         throws IllegalArgumentException {
1399                 
1400                 if (topic == null || topic.isEmpty()) {
1401                         throw new IllegalArgumentException("Unsupported");
1402                 }
1403                 
1404                 if (fact == null) {
1405                         throw new IllegalArgumentException("class must be provided");
1406                 }
1407                 
1408                 List<DroolsController> droolsControllers = droolsCreators(topic, fact);
1409                 if (droolsControllers.size() > 1) {
1410                         // unexpected
1411                         logger.warn("MULTIPLE DROOLS CONTROLLERS FOUND for: " + topic + ":" + 
1412                               fact.getClass().getCanonicalName() + ":" + 
1413                               droolsControllers + " IN " + this);               
1414                         // continue
1415                 }
1416                 return droolsControllers;
1417         }
1418
1419         @Override
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();
1425         }
1426 }
1427
1428 class EventProtocolDecoder extends GenericEventProtocolCoder {
1429
1430         public EventProtocolDecoder(){super(false);}
1431         
1432         @Override
1433         public String toString() {
1434                 StringBuilder builder = new StringBuilder();
1435                 builder.append("EventProtocolDecoder [toString()=").append(super.toString()).append("]");
1436                 return builder.toString();
1437         }
1438         
1439 }
1440         
1441 class EventProtocolEncoder extends GenericEventProtocolCoder {
1442         
1443         public EventProtocolEncoder(){super(false);}
1444
1445         @Override
1446         public String toString() {
1447                 StringBuilder builder = new StringBuilder();
1448                 builder.append("EventProtocolEncoder [toString()=").append(super.toString()).append("]");
1449                 return builder.toString();
1450         }
1451 }