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