diff options
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(); + } } |