2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.drools.protocol.coders;
23 import com.google.gson.Gson;
24 import com.google.gson.GsonBuilder;
25 import com.google.gson.JsonDeserializationContext;
26 import com.google.gson.JsonDeserializer;
27 import com.google.gson.JsonElement;
28 import com.google.gson.JsonPrimitive;
29 import com.google.gson.JsonSerializationContext;
30 import com.google.gson.JsonSerializer;
31 import java.lang.reflect.Type;
32 import java.time.Instant;
33 import java.time.ZonedDateTime;
34 import java.time.format.DateTimeFormatter;
35 import lombok.ToString;
36 import org.onap.policy.common.gson.annotation.GsonJsonIgnore;
37 import org.onap.policy.drools.controller.DroolsControllerConstants;
38 import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 * Tools used for encoding/decoding using GSON.
45 @ToString(callSuper = true)
46 class GsonProtocolCoderToolset extends ProtocolCoderToolset {
47 private static final String CANNOT_FETCH_CLASS = "{}: cannot fetch application class {}";
48 private static final String FETCH_CLASS_EX_MSG = "cannot fetch application class ";
53 private static final Logger logger = LoggerFactory.getLogger(GsonProtocolCoderToolset.class);
56 * Formatter for JSON encoding/decoding.
59 public static final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSxxx");
62 public static final DateTimeFormatter zuluFormat = DateTimeFormatter.ISO_INSTANT;
65 * Adapter for ZonedDateTime.
67 public static class GsonUtcAdapter implements JsonSerializer<ZonedDateTime>, JsonDeserializer<ZonedDateTime> {
69 public ZonedDateTime deserialize(JsonElement element, Type type,
70 JsonDeserializationContext context) {
72 return ZonedDateTime.parse(element.getAsString(), format);
73 } catch (final Exception e) {
74 logger.info("GsonUTCAdapter: cannot parse {} because of {}", element, e.getMessage(), e);
80 public JsonElement serialize(ZonedDateTime datetime, Type type,
81 JsonSerializationContext context) {
82 return new JsonPrimitive(datetime.format(format));
86 public static class GsonInstantAdapter implements JsonSerializer<Instant>, JsonDeserializer<Instant> {
89 public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
90 return Instant.ofEpochMilli(json.getAsLong());
94 public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) {
95 return new JsonPrimitive(src.toEpochMilli());
105 protected final Gson decoder = new GsonBuilder().disableHtmlEscaping()
106 .registerTypeAdapter(ZonedDateTime.class, new GsonUtcAdapter())
107 .registerTypeAdapter(Instant.class, new GsonInstantAdapter()).create();
113 protected final Gson encoder = new GsonBuilder().disableHtmlEscaping()
114 .registerTypeAdapter(ZonedDateTime.class, new GsonUtcAdapter())
115 .registerTypeAdapter(Instant.class, new GsonInstantAdapter()).create();
118 * Toolset to encode/decode tools associated with a topic.
120 * @param eventProtocolParams parameter object for event encoder
121 * @param controllerId controller id
123 public GsonProtocolCoderToolset(EventProtocolParams eventProtocolParams, String controllerId) {
124 super(eventProtocolParams, controllerId);
128 * gets the Gson decoder.
130 * @return the Gson decoder
133 protected Gson getDecoder() {
138 * gets the Gson encoder.
140 * @return the Gson encoder
143 protected Gson getEncoder() {
151 public Object decode(String json) {
153 final var droolsController =
154 DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, "");
155 if (droolsController == null) {
156 logger.warn("{}: no drools-controller to process {}", this, json);
157 throw new IllegalStateException("no drools-controller to process event");
160 final CoderFilters decoderFilter = this.filter(json);
161 if (decoderFilter == null) {
162 logger.debug("{}: no decoder to process {}", this, json);
163 throw new UnsupportedOperationException("no decoder to process event");
166 Class<?> decoderClass;
168 decoderClass = droolsController.fetchModelClass(decoderFilter.getFactClass());
169 if (decoderClass == null) {
170 logger.warn(CANNOT_FETCH_CLASS, this, decoderFilter.getFactClass());
171 throw new IllegalStateException(
172 FETCH_CLASS_EX_MSG + decoderFilter.getFactClass());
174 } catch (final Exception e) {
175 logger.warn(CANNOT_FETCH_CLASS, this, decoderFilter.getFactClass());
176 throw new UnsupportedOperationException(
177 FETCH_CLASS_EX_MSG + decoderFilter.getFactClass(), e);
180 if (this.customCoder != null) {
182 final var gsonClassContainer =
183 droolsController.fetchModelClass(this.customCoder.getClassContainer());
184 final var gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField);
185 final var gsonObject = gsonField.get(null);
186 final var fromJsonMethod = gsonObject.getClass().getDeclaredMethod("fromJson",
187 String.class, Class.class);
188 return fromJsonMethod.invoke(gsonObject, json, decoderClass);
189 } catch (final Exception e) {
190 logger.warn(CANNOT_FETCH_CLASS, this, decoderFilter.getFactClass());
191 throw new UnsupportedOperationException(
192 FETCH_CLASS_EX_MSG + decoderFilter.getFactClass(), e);
196 return this.decoder.fromJson(json, decoderClass);
197 } catch (final Exception e) {
198 logger.warn("{} cannot decode {} into {}", this, json, decoderClass.getName());
199 throw new UnsupportedOperationException(
200 "cannont decode into " + decoderFilter.getFactClass(), e);
209 public String encode(Object event) {
211 if (this.customCoder != null) {
213 final var droolsController =
214 DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, null);
215 final Class<?> gsonClassContainer =
216 droolsController.fetchModelClass(this.customCoder.getClassContainer());
217 final var gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField);
218 final var gsonObject = gsonField.get(null);
219 final var toJsonMethod =
220 gsonObject.getClass().getDeclaredMethod("toJson", Object.class);
221 return (String) toJsonMethod.invoke(gsonObject, event);
222 } catch (final Exception e) {
223 logger.warn("{} cannot custom-encode {}", this, event);
224 throw new UnsupportedOperationException("event cannot be encoded", e);
228 return this.encoder.toJson(event);
229 } catch (final Exception e) {
230 logger.warn("{} cannot encode {}", this, event);
231 throw new UnsupportedOperationException("event cannot be encoded", e);