diff options
author | Jorge Hernandez <jh1730@att.com> | 2017-10-09 08:07:36 -0500 |
---|---|---|
committer | Jorge Hernandez <jh1730@att.com> | 2017-10-09 08:07:36 -0500 |
commit | 86b60d8d28e4891259094fa1e936c6e579620b29 (patch) | |
tree | 7edb5f2a0cba0eab991db119589b24ee088d7a69 /policy-management/src/main/java | |
parent | 552048293a269ba961f526f45a89e433b7b073ea (diff) |
send messages directly through topic
This work is needed for consolidating the amsterdam templates used
both for junits and the official one from the archetype into one,
so junits can run in the official one.
This work revisits the functionality of when a drools controller
cannot be found to check state before delivering a message from
the drools application, it will use a standalone enconder
(previously configured to do so).
This was intended to work like this originally, but never tested
nor used as all deliveries are send through the controllers so
locked/alive state is checked (but there may ocassions where we
want to take this default action).
Change-Id: Ie23e4e13323f3ab9fd207f8a396c1af6564b7edf
Issue-ID: POLICY-101
Signed-off-by: Jorge Hernandez <jh1730@att.com>
Diffstat (limited to 'policy-management/src/main/java')
2 files changed, 619 insertions, 622 deletions
diff --git a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/EventProtocolCoder.java b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/EventProtocolCoder.java index 6f14076f..7f1d9b7e 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/EventProtocolCoder.java +++ b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/EventProtocolCoder.java @@ -1054,19 +1054,15 @@ abstract class GenericEventProtocolCoder { if (topic == null || topic.isEmpty()) throw new IllegalArgumentException("Invalid topic"); - List<DroolsController> droolsControllers = droolsCreators(topic, event); - - if (droolsControllers.isEmpty()) - throw new IllegalArgumentException("no drools controller has been found"); - - if (droolsControllers.size() > 1) { - logger.warn("{}: multiple drools-controller {} for {}:{} ", this, topic, - droolsControllers, event.getClass().getCanonicalName()); - // continue - } - - String key = codersKey(droolsControllers.get(0).getGroupId(), droolsControllers.get(0).getArtifactId(), topic); - return this.encodeInternal(key, event); + String reverseKey = this.reverseCodersKey(topic, event.getClass().getCanonicalName()); + if (!this.reverseCoders.containsKey(reverseKey)) + throw new IllegalArgumentException("no reverse coder has been found"); + + List<Pair<ProtocolCoderToolset, ProtocolCoderToolset>> + toolsets = this.reverseCoders.get(reverseKey); + + String key = codersKey(toolsets.get(0).first().getGroupId(), toolsets.get(0).first().getArtifactId(), topic); + return this.encodeInternal(key, event); } /** diff --git a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java index df51473d..d53ab28e 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java +++ b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java @@ -58,626 +58,627 @@ import com.google.gson.JsonSerializer; * Protocol Coding/Decoding Toolset */ public abstract class ProtocolCoderToolset { - - /** - * Logger - */ - private static Logger logger = LoggerFactory.getLogger(ProtocolCoderToolset.class); - - /** - * topic - */ - protected final String topic; - - /** - * controller id - */ - protected final String controllerId; - - /** - * group id - */ - protected final String groupId; - - /** - * artifact id - */ - protected final String artifactId; - - /** - * Protocols and associated Filters - */ - protected final List<CoderFilters> coders = new ArrayList<>(); - - /** - * Tree model (instead of class model) generic parsing to be able to inspect elements - */ - protected JsonParser filteringParser = new JsonParser(); - - /** - * custom coder - */ - protected CustomCoder customCoder; - - /** - * Constructor - * - * @param topic the topic - * @param controllerId the controller id - * @param codedClass the decoded class - * @param filters list of filters that apply to the - * selection of this decodedClass in case of multiplicity - * @throws IllegalArgumentException if invalid data has been passed in - */ - public ProtocolCoderToolset(String topic, - String controllerId, - String groupId, - String artifactId, - String codedClass, - JsonProtocolFilter filters, - CustomCoder customCoder, - int modelClassLoaderHash) - throws IllegalArgumentException { - - if (topic == null || controllerId == null || - groupId == null || artifactId == null || - codedClass == null || filters == null || - topic.isEmpty() || controllerId.isEmpty()) { - // TODO - throw new IllegalArgumentException("Invalid input"); - } - - this.topic = topic; - this.controllerId = controllerId; - this.groupId = groupId; - this.artifactId = artifactId; - this.coders.add(new CoderFilters(codedClass, filters, modelClassLoaderHash)); - this.customCoder = customCoder; - } - - /** - * gets the coder + filters associated with this class name - * - * @param classname class name - * @return the decoder filters or null if not found - */ - public CoderFilters getCoder(String classname) { - for (CoderFilters decoder: this.coders) { - if (decoder.factClass.equals(classname)) { - return decoder; - } - } - return null; - } - - /** - * get all coder filters in use - * - * @return coder filters - */ - public List<CoderFilters> getCoders() { - return this.coders; - } - - /** - * add coder or replace it exists - * - * @param eventClass decoder - * @param filter filter - */ - public void addCoder(String eventClass, JsonProtocolFilter filter, int modelClassLoaderHash) { - synchronized(this) { - for (CoderFilters coder: this.coders) { - if (coder.factClass.equals(eventClass)) { - // this is a better check than checking pointers, just - // in case classloader is different and this is just an update - coder.factClass = eventClass; - coder.filter = filter; - coder.modelClassLoaderHash = modelClassLoaderHash; - return; - } - } - } - - this.coders.add(new CoderFilters(eventClass, filter, modelClassLoaderHash)); - } - - /** - * remove coder - * - * @param eventClass decoder - * @param filter filter - */ - public void removeCoders(String eventClass) { - synchronized(this) { - Iterator<CoderFilters> codersIt = this.coders.iterator(); - while (codersIt.hasNext()) { - CoderFilters coder = codersIt.next(); - if (coder.factClass.equals(eventClass)) { - codersIt.remove(); - } - } - } - } - - /** - * gets the topic - * - * @return the topic - */ - public String getTopic() {return topic;} - - /** - * gets the controller id - * - * @return the controller id - */ - public String getControllerId() {return controllerId;} - - /** - * @return the groupId - */ - public String getGroupId() { - return groupId; - } - - /** - * @return the artifactId - */ - public String getArtifactId() { - return artifactId; - } - - /** - * @return the customCoder - */ - public CustomCoder getCustomCoder() { - return customCoder; - } - - /** - * @param customCoder the customCoder to set - */ - public void setCustomCoder(CustomCoder customCoder) { - this.customCoder = customCoder; - } - - /** - * performs filtering on a json string - * - * @param json json string - * @return the decoder that passes the filter, otherwise null - * @throws UnsupportedOperationException can't filter - * @throws IllegalArgumentException invalid input - */ - protected CoderFilters filter(String json) - throws UnsupportedOperationException, IllegalArgumentException, IllegalStateException { - - - // 1. Get list of decoding classes for this controller Id and topic - // 2. If there are no classes, return error - // 3. Otherwise, from the available classes for decoding, pick the first one that - // passes the filters - - // Don't parse if it is not necessary - - if (this.coders.isEmpty()) { - // TODO this is an error - throw new IllegalStateException("No coders available"); - } - - if (this.coders.size() == 1) { - JsonProtocolFilter filter = this.coders.get(0).getFilter(); - if (!filter.isRules()) { - return this.coders.get(0); - } - } - - JsonElement event; - try { - event = this.filteringParser.parse(json); - } catch (Exception e) { - throw new UnsupportedOperationException(e); - } - - for (CoderFilters decoder: this.coders) { - try { - boolean accepted = decoder.getFilter().accept(event); - if (accepted) { - return decoder; - } - } catch (Exception e) { - logger.info("{}: unexpected failure accepting {} because of {}", - this, event, e.getMessage(), e); - // continue - } - } - - return null; - } - - /** - * Decode json into a POJO object - * @param json json string - * - * @return a POJO object for the json string - * @throws IllegalArgumentException if an invalid parameter has been received - * @throws UnsupportedOperationException if parsing into POJO is not possible - */ - public abstract Object decode(String json) - throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException; - - /** - * Encodes a POJO object into a JSON String - * - * @param event JSON POJO event to be converted to String - * @return JSON string version of POJO object - * @throws IllegalArgumentException if an invalid parameter has been received - * @throws UnsupportedOperationException if parsing into POJO is not possible - */ - public abstract String encode(Object event) - throws IllegalArgumentException, UnsupportedOperationException; - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("ProtocolCoderToolset [topic=").append(topic).append(", controllerId=").append(controllerId) - .append(", groupId=").append(groupId).append(", artifactId=").append(artifactId).append(", coders=") - .append(coders).append(", filteringParser=").append(filteringParser).append(", customCoder=") - .append(customCoder).append("]"); - return builder.toString(); - } + + /** + * Logger + */ + private static Logger logger = LoggerFactory.getLogger(ProtocolCoderToolset.class); + + /** + * topic + */ + protected final String topic; + + /** + * controller id + */ + protected final String controllerId; + + /** + * group id + */ + protected final String groupId; + + /** + * artifact id + */ + protected final String artifactId; + + /** + * Protocols and associated Filters + */ + protected final List<CoderFilters> coders = new ArrayList<>(); + + /** + * Tree model (instead of class model) generic parsing to be able to inspect elements + */ + protected JsonParser filteringParser = new JsonParser(); + + /** + * custom coder + */ + protected CustomCoder customCoder; + + /** + * Constructor + * + * @param topic the topic + * @param controllerId the controller id + * @param codedClass the decoded class + * @param filters list of filters that apply to the selection of this decodedClass in case of + * multiplicity + * @throws IllegalArgumentException if invalid data has been passed in + */ + public ProtocolCoderToolset(String topic, String controllerId, String groupId, String artifactId, + String codedClass, JsonProtocolFilter filters, CustomCoder customCoder, + int modelClassLoaderHash) throws IllegalArgumentException { + + if (topic == null || controllerId == null || groupId == null || artifactId == null + || codedClass == null || filters == null || topic.isEmpty() || controllerId.isEmpty()) { + // TODO + throw new IllegalArgumentException("Invalid input"); + } + + this.topic = topic; + this.controllerId = controllerId; + this.groupId = groupId; + this.artifactId = artifactId; + this.coders.add(new CoderFilters(codedClass, filters, modelClassLoaderHash)); + this.customCoder = customCoder; + } + + /** + * gets the coder + filters associated with this class name + * + * @param classname class name + * @return the decoder filters or null if not found + */ + public CoderFilters getCoder(String classname) { + for (final CoderFilters decoder : this.coders) { + if (decoder.factClass.equals(classname)) { + return decoder; + } + } + return null; + } + + /** + * get all coder filters in use + * + * @return coder filters + */ + public List<CoderFilters> getCoders() { + return this.coders; + } + + /** + * add coder or replace it exists + * + * @param eventClass decoder + * @param filter filter + */ + public void addCoder(String eventClass, JsonProtocolFilter filter, int modelClassLoaderHash) { + synchronized (this) { + for (final CoderFilters coder : this.coders) { + if (coder.factClass.equals(eventClass)) { + // this is a better check than checking pointers, just + // in case classloader is different and this is just an update + coder.factClass = eventClass; + coder.filter = filter; + coder.modelClassLoaderHash = modelClassLoaderHash; + return; + } + } + } + + this.coders.add(new CoderFilters(eventClass, filter, modelClassLoaderHash)); + } + + /** + * remove coder + * + * @param eventClass decoder + * @param filter filter + */ + public void removeCoders(String eventClass) { + synchronized (this) { + final Iterator<CoderFilters> codersIt = this.coders.iterator(); + while (codersIt.hasNext()) { + final CoderFilters coder = codersIt.next(); + if (coder.factClass.equals(eventClass)) { + codersIt.remove(); + } + } + } + } + + /** + * gets the topic + * + * @return the topic + */ + public String getTopic() { + return this.topic; + } + + /** + * gets the controller id + * + * @return the controller id + */ + public String getControllerId() { + return this.controllerId; + } + + /** + * @return the groupId + */ + public String getGroupId() { + return this.groupId; + } + + /** + * @return the artifactId + */ + public String getArtifactId() { + return this.artifactId; + } + + /** + * @return the customCoder + */ + public CustomCoder getCustomCoder() { + return this.customCoder; + } + + /** + * @param customCoder the customCoder to set + */ + public void setCustomCoder(CustomCoder customCoder) { + this.customCoder = customCoder; + } + + /** + * performs filtering on a json string + * + * @param json json string + * @return the decoder that passes the filter, otherwise null + * @throws UnsupportedOperationException can't filter + * @throws IllegalArgumentException invalid input + */ + protected CoderFilters filter(String json) + throws UnsupportedOperationException, IllegalArgumentException, IllegalStateException { + + + // 1. Get list of decoding classes for this controller Id and topic + // 2. If there are no classes, return error + // 3. Otherwise, from the available classes for decoding, pick the first one that + // passes the filters + + // Don't parse if it is not necessary + + if (this.coders.isEmpty()) { + // TODO this is an error + throw new IllegalStateException("No coders available"); + } + + if (this.coders.size() == 1) { + final JsonProtocolFilter filter = this.coders.get(0).getFilter(); + if (!filter.isRules()) { + return this.coders.get(0); + } + } + + JsonElement event; + try { + event = this.filteringParser.parse(json); + } catch (final Exception e) { + throw new UnsupportedOperationException(e); + } + + for (final CoderFilters decoder : this.coders) { + try { + final boolean accepted = decoder.getFilter().accept(event); + if (accepted) { + return decoder; + } + } catch (final Exception e) { + logger.info("{}: unexpected failure accepting {} because of {}", this, event, + e.getMessage(), e); + // continue + } + } + + return null; + } + + /** + * Decode json into a POJO object + * + * @param json json string + * + * @return a POJO object for the json string + * @throws IllegalArgumentException if an invalid parameter has been received + * @throws UnsupportedOperationException if parsing into POJO is not possible + */ + public abstract Object decode(String json) + throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException; + + /** + * Encodes a POJO object into a JSON String + * + * @param event JSON POJO event to be converted to String + * @return JSON string version of POJO object + * @throws IllegalArgumentException if an invalid parameter has been received + * @throws UnsupportedOperationException if parsing into POJO is not possible + */ + public abstract String encode(Object event) + throws IllegalArgumentException, UnsupportedOperationException; + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("ProtocolCoderToolset [topic=").append(this.topic).append(", controllerId=") + .append(this.controllerId).append(", groupId=").append(this.groupId).append(", artifactId=") + .append(this.artifactId).append(", coders=").append(this.coders) + .append(", filteringParser=").append(this.filteringParser).append(", customCoder=") + .append(this.customCoder).append("]"); + return builder.toString(); + } } + /** * Tools used for encoding/decoding using Jackson */ class JacksonProtocolCoderToolset extends ProtocolCoderToolset { - private static Logger logger = LoggerFactory.getLogger(JacksonProtocolCoderToolset.class); - /** - * decoder - */ - @JsonIgnore - protected final ObjectMapper decoder = new ObjectMapper(); - - /** - * encoder - */ - @JsonIgnore - protected final ObjectMapper encoder = new ObjectMapper(); - - /** - * Toolset to encode/decode tools associated with a topic - * - * @param topic topic - * @param decodedClass decoded class of an event - * @param filter - */ - public JacksonProtocolCoderToolset(String topic, String controllerId, - String groupId, String artifactId, - String decodedClass, - JsonProtocolFilter filter, - CustomJacksonCoder customJacksonCoder, - int modelClassLoaderHash) { - super(topic, controllerId, groupId, artifactId, decodedClass, filter, customJacksonCoder, modelClassLoaderHash); - decoder.registerModule(new JavaTimeModule()); - decoder.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, - false); - } - - /** - * gets the Jackson decoder - * - * @return the Jackson decoder - */ - @JsonIgnore - protected ObjectMapper getDecoder() {return decoder;} - - /** - * gets the Jackson encoder - * - * @return the Jackson encoder - */ - @JsonIgnore - protected ObjectMapper getEncoder() {return encoder;} - - /** - * {@inheritDoc} - */ - @Override - public Object decode(String json) - throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException { - - // 0. Use custom coder if available - - if (this.customCoder != null) { - throw new UnsupportedOperationException - ("Jackon Custom Decoder is not supported at this time"); - } - - DroolsController droolsController = - DroolsController.factory.get(groupId, artifactId, ""); - if (droolsController == null) { - logger.warn("{}: no drools-controller to process {}", this, json); - throw new IllegalStateException("no drools-controller to process event"); - } - - CoderFilters decoderFilter = filter(json); - if (decoderFilter == null) { - logger.debug("{}: no decoder to process {}", this, json); - throw new UnsupportedOperationException("no decoder to process event"); - } - - Class<?> decoderClass; - try { - decoderClass = - droolsController.fetchModelClass(decoderFilter.getCodedClass()); - if (decoderClass == null) { - logger.warn("{}: cannot fetch application class {}", this, decoderFilter.getCodedClass()); - throw new IllegalStateException("cannot fetch application class " + decoderFilter.getCodedClass()); - } - } catch (Exception e) { - logger.warn("{}: cannot fetch application class {} because of {}", this, - decoderFilter.getCodedClass(), e.getMessage()); - throw new UnsupportedOperationException("cannot fetch application class " + decoderFilter.getCodedClass(), e); - } - - - try { - Object fact = this.decoder.readValue(json, decoderClass); - return fact; - } catch (Exception e) { - logger.warn("{} cannot decode {} into {} because of {}", - this, json, decoderClass.getName(), e.getMessage(), e); - throw new UnsupportedOperationException("cannont decode into " + decoderFilter.getCodedClass(), e); - } - } - - /** - * {@inheritDoc} - */ - @Override - public String encode(Object event) - throws IllegalArgumentException, UnsupportedOperationException { - - // 0. Use custom coder if available - - if (this.customCoder != null) { - throw new UnsupportedOperationException - ("Jackon Custom Encoder is not supported at this time"); - } - - try { - String encodedEvent = this.encoder.writeValueAsString(event); - return encodedEvent; - } catch (JsonProcessingException e) { - logger.error("{} cannot encode {} because of {}", this, event, e.getMessage(), e); - throw new UnsupportedOperationException("event cannot be encoded"); - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("JacksonProtocolCoderToolset [toString()=").append(super.toString()).append("]"); - return builder.toString(); - } + private static Logger logger = LoggerFactory.getLogger(JacksonProtocolCoderToolset.class); + /** + * decoder + */ + @JsonIgnore + protected final ObjectMapper decoder = new ObjectMapper(); + + /** + * encoder + */ + @JsonIgnore + protected final ObjectMapper encoder = new ObjectMapper(); + + /** + * Toolset to encode/decode tools associated with a topic + * + * @param topic topic + * @param decodedClass decoded class of an event + * @param filter + */ + public JacksonProtocolCoderToolset(String topic, String controllerId, String groupId, + String artifactId, String decodedClass, JsonProtocolFilter filter, + CustomJacksonCoder customJacksonCoder, int modelClassLoaderHash) { + super(topic, controllerId, groupId, artifactId, decodedClass, filter, customJacksonCoder, + modelClassLoaderHash); + this.decoder.registerModule(new JavaTimeModule()); + this.decoder.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + /** + * gets the Jackson decoder + * + * @return the Jackson decoder + */ + @JsonIgnore + protected ObjectMapper getDecoder() { + return this.decoder; + } + + /** + * gets the Jackson encoder + * + * @return the Jackson encoder + */ + @JsonIgnore + protected ObjectMapper getEncoder() { + return this.encoder; + } + + /** + * {@inheritDoc} + */ + @Override + public Object decode(String json) + throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException { + + // 0. Use custom coder if available + + if (this.customCoder != null) { + throw new UnsupportedOperationException( + "Jackon Custom Decoder is not supported at this time"); + } + + final DroolsController droolsController = + DroolsController.factory.get(this.groupId, this.artifactId, ""); + if (droolsController == null) { + logger.warn("{}: no drools-controller to process {}", this, json); + throw new IllegalStateException("no drools-controller to process event"); + } + + final CoderFilters decoderFilter = this.filter(json); + if (decoderFilter == null) { + logger.debug("{}: no decoder to process {}", this, json); + throw new UnsupportedOperationException("no decoder to process event"); + } + + Class<?> decoderClass; + try { + decoderClass = droolsController.fetchModelClass(decoderFilter.getCodedClass()); + if (decoderClass == null) { + logger.warn("{}: cannot fetch application class {}", this, decoderFilter.getCodedClass()); + throw new IllegalStateException( + "cannot fetch application class " + decoderFilter.getCodedClass()); + } + } catch (final Exception e) { + logger.warn("{}: cannot fetch application class {} because of {}", this, + decoderFilter.getCodedClass(), e.getMessage()); + throw new UnsupportedOperationException( + "cannot fetch application class " + decoderFilter.getCodedClass(), e); + } + + + try { + final Object fact = this.decoder.readValue(json, decoderClass); + return fact; + } catch (final Exception e) { + logger.warn("{} cannot decode {} into {} because of {}", this, json, decoderClass.getName(), + e.getMessage(), e); + throw new UnsupportedOperationException( + "cannont decode into " + decoderFilter.getCodedClass(), e); + } + } + + /** + * {@inheritDoc} + */ + @Override + public String encode(Object event) + throws IllegalArgumentException, UnsupportedOperationException { + + // 0. Use custom coder if available + + if (this.customCoder != null) { + throw new UnsupportedOperationException( + "Jackon Custom Encoder is not supported at this time"); + } + + try { + final String encodedEvent = this.encoder.writeValueAsString(event); + return encodedEvent; + } catch (final JsonProcessingException e) { + logger.error("{} cannot encode {} because of {}", this, event, e.getMessage(), e); + throw new UnsupportedOperationException("event cannot be encoded"); + } + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("JacksonProtocolCoderToolset [toString()=").append(super.toString()).append("]"); + return builder.toString(); + } } + /** * Tools used for encoding/decoding using Jackson */ class GsonProtocolCoderToolset extends ProtocolCoderToolset { - - /** - * Logger - */ - private static final Logger logger = LoggerFactory.getLogger(GsonProtocolCoderToolset.class); - - /** - * Formatter for JSON encoding/decoding - */ - @JsonIgnore - public static final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSxxx"); - - @JsonIgnore - public static final DateTimeFormatter zuluFormat = DateTimeFormatter.ISO_INSTANT; - - /** - * Adapter for ZonedDateTime - */ - public static class GsonUTCAdapter implements JsonSerializer<ZonedDateTime>, JsonDeserializer<ZonedDateTime> { - @Override - public ZonedDateTime deserialize(JsonElement element, Type type, JsonDeserializationContext context) - throws JsonParseException { - try { - return ZonedDateTime.parse(element.getAsString(), format); - } catch (Exception e) { - logger.info("GsonUTCAdapter: cannot parse {} because of {}", - element, e.getMessage(), e); - } - return null; - } - - @Override - public JsonElement serialize(ZonedDateTime datetime, Type type, JsonSerializationContext context) { - return new JsonPrimitive(datetime.format(format)); - } - } - - public static class GsonInstantAdapter implements JsonSerializer<Instant>, JsonDeserializer<Instant> { - - @Override - public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) - throws JsonParseException { - return Instant.ofEpochMilli(json.getAsLong()); - } - - @Override - public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) { - return new JsonPrimitive(src.toEpochMilli()); - } - - } - - - /** - * decoder - */ - @JsonIgnore - protected final Gson decoder = new GsonBuilder().disableHtmlEscaping(). - registerTypeAdapter(ZonedDateTime.class, new GsonUTCAdapter()). - create(); - - /** - * encoder - */ - @JsonIgnore - protected final Gson encoder = new GsonBuilder().disableHtmlEscaping(). - registerTypeAdapter(ZonedDateTime.class, new GsonUTCAdapter()). - create(); - - /** - * Toolset to encode/decode tools associated with a topic - * - * @param topic topic - * @param decodedClass decoded class of an event - * @param filter - */ - public GsonProtocolCoderToolset(String topic, String controllerId, - String groupId, String artifactId, - String decodedClass, - JsonProtocolFilter filter, - CustomGsonCoder customGsonCoder, - int modelClassLoaderHash) { - super(topic, controllerId, groupId, artifactId, decodedClass, filter, customGsonCoder, modelClassLoaderHash); - } - - /** - * gets the Gson decoder - * - * @return the Gson decoder - */ - @JsonIgnore - protected Gson getDecoder() {return decoder;} - - /** - * gets the Gson encoder - * - * @return the Gson encoder - */ - @JsonIgnore - protected Gson getEncoder() {return encoder;} - - /** - * {@inheritDoc} - */ - @Override - public Object decode(String json) - throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException { - - DroolsController droolsController = - DroolsController.factory.get(groupId, artifactId, ""); - if (droolsController == null) { - logger.warn("{}: no drools-controller to process {}", this, json); - throw new IllegalStateException("no drools-controller to process event"); - } - - CoderFilters decoderFilter = filter(json); - if (decoderFilter == null) { - logger.debug("{}: no decoder to process {}", this, json); - throw new UnsupportedOperationException("no decoder to process event"); - } - - Class<?> decoderClass; - try { - decoderClass = - droolsController.fetchModelClass(decoderFilter.getCodedClass()); - if (decoderClass == null) { - logger.warn("{}: cannot fetch application class {}", this, decoderFilter.getCodedClass()); - throw new IllegalStateException("cannot fetch application class " + decoderFilter.getCodedClass()); - } - } catch (Exception e) { - logger.warn("{}: cannot fetch application class {} because of {}", this, - decoderFilter.getCodedClass(), e.getMessage()); - throw new UnsupportedOperationException("cannot fetch application class " + decoderFilter.getCodedClass(), e); - } - - if (this.customCoder != null) { - try { - Class<?> gsonClassContainer = - droolsController.fetchModelClass(this.customCoder.getClassContainer()); - Field gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField); - Object gsonObject = gsonField.get(null); - Method fromJsonMethod = gsonObject.getClass(). - getDeclaredMethod - ("fromJson", new Class[]{String.class, Class.class}); - Object fact = fromJsonMethod.invoke(gsonObject, json, decoderClass); - return fact; - } catch (Exception e) { - logger.warn("{}: cannot fetch application class {} because of {}", this, - decoderFilter.getCodedClass(), e.getMessage()); - throw new UnsupportedOperationException("cannot fetch application class " + decoderFilter.getCodedClass(), e); - } - } else { - try { - Object fact = this.decoder.fromJson(json, decoderClass); - return fact; - } catch (Exception e) { - logger.warn("{} cannot decode {} into {} because of {}", - this, json, decoderClass.getName(), e.getMessage(), e); - throw new UnsupportedOperationException("cannont decode into " + decoderFilter.getCodedClass(), e); - } - } - } - - - - /** - * {@inheritDoc} - */ - @Override - public String encode(Object event) - throws IllegalArgumentException, UnsupportedOperationException { - - DroolsController droolsController = - DroolsController.factory.get(groupId, artifactId, null); - if (droolsController == null) { - logger.info("{}: no drools-controller to process {} (continue)", this, event); - throw new IllegalStateException("custom-coder but no drools-controller"); - } - - if (this.customCoder != null) { - try { - Class<?> gsonClassContainer = - droolsController.fetchModelClass(this.customCoder.getClassContainer()); - Field gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField); - Object gsonObject = gsonField.get(null); - Method toJsonMethod = gsonObject.getClass(). - getDeclaredMethod - ("toJson", new Class[]{Object.class}); - String encodedJson = (String) toJsonMethod.invoke(gsonObject, event); - return encodedJson; - } catch (Exception e) { - logger.warn("{} cannot custom-encode {} because of {}", this, event, e.getMessage(), e); - throw new UnsupportedOperationException("event cannot be encoded", e); - } - } else { - try { - String encodedEvent = this.encoder.toJson(event); - return encodedEvent; - } catch (Exception e) { - logger.warn("{} cannot encode {} because of {}", this, event, e.getMessage(), e); - throw new UnsupportedOperationException("event cannot be encoded", e); - } - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("GsonProtocolCoderToolset [toString()=").append(super.toString()).append("]"); - return builder.toString(); - } + + /** + * Logger + */ + private static final Logger logger = LoggerFactory.getLogger(GsonProtocolCoderToolset.class); + + /** + * Formatter for JSON encoding/decoding + */ + @JsonIgnore + public static final DateTimeFormatter format = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSxxx"); + + @JsonIgnore + public static final DateTimeFormatter zuluFormat = DateTimeFormatter.ISO_INSTANT; + + /** + * Adapter for ZonedDateTime + */ + public static class GsonUTCAdapter + implements JsonSerializer<ZonedDateTime>, JsonDeserializer<ZonedDateTime> { + @Override + public ZonedDateTime deserialize(JsonElement element, Type type, + JsonDeserializationContext context) throws JsonParseException { + try { + return ZonedDateTime.parse(element.getAsString(), format); + } catch (final Exception e) { + logger.info("GsonUTCAdapter: cannot parse {} because of {}", element, e.getMessage(), e); + } + return null; + } + + @Override + public JsonElement serialize(ZonedDateTime datetime, Type type, + JsonSerializationContext context) { + return new JsonPrimitive(datetime.format(format)); + } + } + + public static class GsonInstantAdapter + implements JsonSerializer<Instant>, JsonDeserializer<Instant> { + + @Override + public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + return Instant.ofEpochMilli(json.getAsLong()); + } + + @Override + public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src.toEpochMilli()); + } + + } + + + /** + * decoder + */ + @JsonIgnore + protected final Gson decoder = new GsonBuilder().disableHtmlEscaping() + .registerTypeAdapter(ZonedDateTime.class, new GsonUTCAdapter()).create(); + + /** + * encoder + */ + @JsonIgnore + protected final Gson encoder = new GsonBuilder().disableHtmlEscaping() + .registerTypeAdapter(ZonedDateTime.class, new GsonUTCAdapter()).create(); + + /** + * Toolset to encode/decode tools associated with a topic + * + * @param topic topic + * @param decodedClass decoded class of an event + * @param filter + */ + public GsonProtocolCoderToolset(String topic, String controllerId, String groupId, + String artifactId, String decodedClass, JsonProtocolFilter filter, + CustomGsonCoder customGsonCoder, int modelClassLoaderHash) { + super(topic, controllerId, groupId, artifactId, decodedClass, filter, customGsonCoder, + modelClassLoaderHash); + } + + /** + * gets the Gson decoder + * + * @return the Gson decoder + */ + @JsonIgnore + protected Gson getDecoder() { + return this.decoder; + } + + /** + * gets the Gson encoder + * + * @return the Gson encoder + */ + @JsonIgnore + protected Gson getEncoder() { + return this.encoder; + } + + /** + * {@inheritDoc} + */ + @Override + public Object decode(String json) + throws IllegalArgumentException, UnsupportedOperationException, IllegalStateException { + + final DroolsController droolsController = + DroolsController.factory.get(this.groupId, this.artifactId, ""); + if (droolsController == null) { + logger.warn("{}: no drools-controller to process {}", this, json); + throw new IllegalStateException("no drools-controller to process event"); + } + + final CoderFilters decoderFilter = this.filter(json); + if (decoderFilter == null) { + logger.debug("{}: no decoder to process {}", this, json); + throw new UnsupportedOperationException("no decoder to process event"); + } + + Class<?> decoderClass; + try { + decoderClass = droolsController.fetchModelClass(decoderFilter.getCodedClass()); + if (decoderClass == null) { + logger.warn("{}: cannot fetch application class {}", this, decoderFilter.getCodedClass()); + throw new IllegalStateException( + "cannot fetch application class " + decoderFilter.getCodedClass()); + } + } catch (final Exception e) { + logger.warn("{}: cannot fetch application class {} because of {}", this, + decoderFilter.getCodedClass(), e.getMessage()); + throw new UnsupportedOperationException( + "cannot fetch application class " + decoderFilter.getCodedClass(), e); + } + + if (this.customCoder != null) { + try { + final Class<?> gsonClassContainer = + droolsController.fetchModelClass(this.customCoder.getClassContainer()); + final Field gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField); + final Object gsonObject = gsonField.get(null); + final Method fromJsonMethod = gsonObject.getClass().getDeclaredMethod("fromJson", + new Class[] {String.class, Class.class}); + final Object fact = fromJsonMethod.invoke(gsonObject, json, decoderClass); + return fact; + } catch (final Exception e) { + logger.warn("{}: cannot fetch application class {} because of {}", this, + decoderFilter.getCodedClass(), e.getMessage()); + throw new UnsupportedOperationException( + "cannot fetch application class " + decoderFilter.getCodedClass(), e); + } + } else { + try { + final Object fact = this.decoder.fromJson(json, decoderClass); + return fact; + } catch (final Exception e) { + logger.warn("{} cannot decode {} into {} because of {}", this, json, decoderClass.getName(), + e.getMessage(), e); + throw new UnsupportedOperationException( + "cannont decode into " + decoderFilter.getCodedClass(), e); + } + } + } + + + + /** + * {@inheritDoc} + */ + @Override + public String encode(Object event) + throws IllegalArgumentException, UnsupportedOperationException { + + if (this.customCoder != null) { + try { + final DroolsController droolsController = + DroolsController.factory.get(this.groupId, this.artifactId, null); + final Class<?> gsonClassContainer = + droolsController.fetchModelClass(this.customCoder.getClassContainer()); + final Field gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField); + final Object gsonObject = gsonField.get(null); + final Method toJsonMethod = + gsonObject.getClass().getDeclaredMethod("toJson", new Class[] {Object.class}); + final String encodedJson = (String) toJsonMethod.invoke(gsonObject, event); + return encodedJson; + } catch (final Exception e) { + logger.warn("{} cannot custom-encode {} because of {}", this, event, e.getMessage(), e); + throw new UnsupportedOperationException("event cannot be encoded", e); + } + } else { + try { + return this.encoder.toJson(event); + } catch (final Exception e) { + logger.warn("{} cannot encode {} because of {}", this, event, e.getMessage(), e); + throw new UnsupportedOperationException("event cannot be encoded", e); + } + } + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("GsonProtocolCoderToolset [toString()=").append(super.toString()).append("]"); + return builder.toString(); + } } |