Fix sonar issues in drools-pdp
[policy/drools-pdp.git] / policy-management / src / main / java / org / onap / policy / drools / protocol / coders / GsonProtocolCoderToolset.java
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2019 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.onap.policy.drools.protocol.coders;
22
23 import com.fasterxml.jackson.annotation.JsonIgnore;
24 import com.google.gson.Gson;
25 import com.google.gson.GsonBuilder;
26 import com.google.gson.JsonDeserializationContext;
27 import com.google.gson.JsonDeserializer;
28 import com.google.gson.JsonElement;
29 import com.google.gson.JsonPrimitive;
30 import com.google.gson.JsonSerializationContext;
31 import com.google.gson.JsonSerializer;
32 import java.lang.reflect.Field;
33 import java.lang.reflect.Method;
34 import java.lang.reflect.Type;
35 import java.time.Instant;
36 import java.time.ZonedDateTime;
37 import java.time.format.DateTimeFormatter;
38 import org.onap.policy.common.gson.annotation.GsonJsonIgnore;
39 import org.onap.policy.drools.controller.DroolsController;
40 import org.onap.policy.drools.controller.DroolsControllerConstants;
41 import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * Tools used for encoding/decoding using GSON.
47  */
48 class GsonProtocolCoderToolset extends ProtocolCoderToolset {
49     private static final String FETCH_CLASS_EX_MSG = "cannot fetch application class ";
50
51     /**
52      * Logger.
53      */
54     private static final Logger logger = LoggerFactory.getLogger(GsonProtocolCoderToolset.class);
55
56     /**
57      * Formatter for JSON encoding/decoding.
58      */
59     @JsonIgnore
60     @GsonJsonIgnore
61     public static final DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSxxx");
62
63     @JsonIgnore
64     @GsonJsonIgnore
65     public static final DateTimeFormatter zuluFormat = DateTimeFormatter.ISO_INSTANT;
66
67     /**
68      * Adapter for ZonedDateTime.
69      */
70     public static class GsonUtcAdapter implements JsonSerializer<ZonedDateTime>, JsonDeserializer<ZonedDateTime> {
71         @Override
72         public ZonedDateTime deserialize(JsonElement element, Type type,
73                 JsonDeserializationContext context) {
74             try {
75                 return ZonedDateTime.parse(element.getAsString(), format);
76             } catch (final Exception e) {
77                 logger.info("GsonUTCAdapter: cannot parse {} because of {}", element, e.getMessage(), e);
78             }
79             return null;
80         }
81
82         @Override
83         public JsonElement serialize(ZonedDateTime datetime, Type type,
84                 JsonSerializationContext context) {
85             return new JsonPrimitive(datetime.format(format));
86         }
87     }
88
89     public static class GsonInstantAdapter implements JsonSerializer<Instant>, JsonDeserializer<Instant> {
90
91         @Override
92         public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) {
93             return Instant.ofEpochMilli(json.getAsLong());
94         }
95
96         @Override
97         public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) {
98             return new JsonPrimitive(src.toEpochMilli());
99         }
100
101     }
102
103
104     /**
105      * decoder.
106      */
107     @JsonIgnore
108     @GsonJsonIgnore
109     protected final Gson decoder = new GsonBuilder().disableHtmlEscaping()
110         .registerTypeAdapter(ZonedDateTime.class, new GsonUtcAdapter())
111         .registerTypeAdapter(Instant.class, new GsonInstantAdapter()).create();
112
113     /**
114      * encoder.
115      */
116     @JsonIgnore
117     @GsonJsonIgnore
118     protected final Gson encoder = new GsonBuilder().disableHtmlEscaping()
119         .registerTypeAdapter(ZonedDateTime.class, new GsonUtcAdapter())
120         .registerTypeAdapter(Instant.class, new GsonInstantAdapter()).create();
121
122     /**
123      * Toolset to encode/decode tools associated with a topic.
124      *
125      * @param eventProtocolParams parameter object for event encoder
126      * @param controllerId controller id
127      */
128     public GsonProtocolCoderToolset(EventProtocolParams eventProtocolParams, String controllerId) {
129         super(eventProtocolParams, controllerId);
130     }
131
132     /**
133      * gets the Gson decoder.
134      *
135      * @return the Gson decoder
136      */
137     @JsonIgnore
138     @GsonJsonIgnore
139     protected Gson getDecoder() {
140         return this.decoder;
141     }
142
143     /**
144      * gets the Gson encoder.
145      *
146      * @return the Gson encoder
147      */
148     @JsonIgnore
149     @GsonJsonIgnore
150     protected Gson getEncoder() {
151         return this.encoder;
152     }
153
154     /**
155      * {@inheritDoc}.
156      */
157     @Override
158     public Object decode(String json) {
159
160         final DroolsController droolsController =
161                         DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, "");
162         if (droolsController == null) {
163             logger.warn("{}: no drools-controller to process {}", this, json);
164             throw new IllegalStateException("no drools-controller to process event");
165         }
166
167         final CoderFilters decoderFilter = this.filter(json);
168         if (decoderFilter == null) {
169             logger.debug("{}: no decoder to process {}", this, json);
170             throw new UnsupportedOperationException("no decoder to process event");
171         }
172
173         Class<?> decoderClass;
174         try {
175             decoderClass = droolsController.fetchModelClass(decoderFilter.getCodedClass());
176             if (decoderClass == null) {
177                 logger.warn("{}: cannot fetch application class {}", this, decoderFilter.getCodedClass());
178                 throw new IllegalStateException(
179                         FETCH_CLASS_EX_MSG + decoderFilter.getCodedClass());
180             }
181         } catch (final Exception e) {
182             logger.warn("{}: cannot fetch application class {} because of {}", this,
183                     decoderFilter.getCodedClass(), e.getMessage());
184             throw new UnsupportedOperationException(
185                     FETCH_CLASS_EX_MSG + decoderFilter.getCodedClass(), e);
186         }
187
188         if (this.customCoder != null) {
189             try {
190                 final Class<?> gsonClassContainer =
191                         droolsController.fetchModelClass(this.customCoder.getClassContainer());
192                 final Field gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField);
193                 final Object gsonObject = gsonField.get(null);
194                 final Method fromJsonMethod = gsonObject.getClass().getDeclaredMethod("fromJson",
195                         new Class[] {String.class, Class.class});
196                 return fromJsonMethod.invoke(gsonObject, json, decoderClass);
197             } catch (final Exception e) {
198                 logger.warn("{}: cannot fetch application class {} because of {}", this,
199                         decoderFilter.getCodedClass(), e.getMessage());
200                 throw new UnsupportedOperationException(
201                         FETCH_CLASS_EX_MSG + decoderFilter.getCodedClass(), e);
202             }
203         } else {
204             try {
205                 return this.decoder.fromJson(json, decoderClass);
206             } catch (final Exception e) {
207                 logger.warn("{} cannot decode {} into {} because of {}", this, json, decoderClass.getName(),
208                         e.getMessage(), e);
209                 throw new UnsupportedOperationException(
210                         "cannont decode into " + decoderFilter.getCodedClass(), e);
211             }
212         }
213     }
214
215     /**
216      * {@inheritDoc}.
217      */
218     @Override
219     public String encode(Object event) {
220
221         if (this.customCoder != null) {
222             try {
223                 final DroolsController droolsController =
224                                 DroolsControllerConstants.getFactory().get(this.groupId, this.artifactId, null);
225                 final Class<?> gsonClassContainer =
226                         droolsController.fetchModelClass(this.customCoder.getClassContainer());
227                 final Field gsonField = gsonClassContainer.getField(this.customCoder.staticCoderField);
228                 final Object gsonObject = gsonField.get(null);
229                 final Method toJsonMethod =
230                         gsonObject.getClass().getDeclaredMethod("toJson", new Class[] {Object.class});
231                 return (String) toJsonMethod.invoke(gsonObject, event);
232             } catch (final Exception e) {
233                 logger.warn("{} cannot custom-encode {} because of {}", this, event, e.getMessage(), e);
234                 throw new UnsupportedOperationException("event cannot be encoded", e);
235             }
236         } else {
237             try {
238                 return this.encoder.toJson(event);
239             } catch (final Exception e) {
240                 logger.warn("{} cannot encode {} because of {}", this, event, e.getMessage(), e);
241                 throw new UnsupportedOperationException("event cannot be encoded", e);
242             }
243         }
244     }
245
246     @Override
247     public String toString() {
248         final StringBuilder builder = new StringBuilder();
249         builder.append("GsonProtocolCoderToolset [toString()=").append(super.toString()).append("]");
250         return builder.toString();
251     }
252 }