Fix sonar issues in dcaegen2/services/mapper
[dcaegen2/services/mapper.git] / UniversalVesAdapter / src / main / java / org / onap / universalvesadapter / utils / MapperConfigUtils.java
1 /*
2 * ============LICENSE_START=======================================================
3 * ONAP : DCAE
4 * ================================================================================
5 * Copyright 2018 TechMahindra
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 package org.onap.universalvesadapter.utils;
21
22 import java.io.IOException;
23 import java.util.Set;
24 import java.util.TreeSet;
25
26 import org.onap.universalvesadapter.exception.MapperConfigException;
27 import org.onap.universalvesadapter.mappingconfig.Entry;
28 import org.onap.universalvesadapter.mappingconfig.Evaluation;
29 import org.onap.universalvesadapter.mappingconfig.MapperConfig;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import com.fasterxml.jackson.databind.JsonNode;
34 import com.fasterxml.jackson.databind.ObjectMapper;
35
36 /**
37  * This class will be used in Future for different telemetry data:
38  * This class will be utility class to read the mapper config file and parse the
39  * config to prepare the grammar to detect the incoming json's event type.
40  * 
41  * @author kmalbari
42  *
43  */
44 public class MapperConfigUtils {
45
46         private static final Logger LOGGER = LoggerFactory.getLogger(MapperConfigUtils.class);
47     private static Set<Entry> entries = new TreeSet<>((o1, o2) -> o1.getPriority().compareTo(o2.getPriority()));
48
49     private enum JoinOperator {
50         AND("AND"), OR("OR");
51
52         private final String value;
53
54         private JoinOperator(final String value) {
55             this.value = value;
56         }
57
58         public String getValue() {
59             return value;
60         }
61     }
62
63     private enum ExpressionOperator {
64         EQUALS("EQUALS"), STARTSWITH("STARTSWITH"), ENDSWITH("ENDSWITH"), CONTAINS("CONTAINS");
65
66         private final String value;
67
68         private ExpressionOperator(final String value) {
69             this.value = value;
70         }
71
72         public String getValue() {
73             return value;
74         }
75     }
76
77     private enum DataType {
78         STRING("STRING"), DOUBLE("DOUBLE");
79
80         private final String value;
81
82         private DataType(final String value) {
83             this.value = value;
84         }
85
86         public String getValue() {
87             return value;
88         }
89     }
90
91     /**
92      * main method.
93      * 
94      * @param args
95      *            arguments
96      */
97     public static void main(String[] args) {
98
99         String mappingFile = " { " + " \"entries\": [{ " + "     \"priority\": 4, " + "     \"evaluation\": { "
100                 + "         \"operand\": \"AND\", " + "         \"field\": null, " + "         \"value\": null, "
101                 + "         \"datatype\": null, " + "         \"lhs\": { " + "             \"operand\": \"OR\", "
102                 + "             \"field\": null, " + "             \"value\": null, "
103                 + "             \"datatype\": null, " + "             \"lhs\": { "
104                 + "                 \"operand\": \"EQUALS\", " + "                 \"field\": \"domain\", "
105                 + "                 \"value\": \"snmp-heartbeat\", " + "                 \"datatype\": \"string\", "
106                 + "                 \"lhs\": null, " + "                 \"rhs\": null " + "             }, "
107                 + "             \"rhs\": { " + "                 \"operand\": \"EQUALS\", "
108                 + "                 \"field\": \"domain\", " + "                 \"value\": \"snmp-fault\", "
109                 + "                 \"datatype\": \"string\", " + "                 \"lhs\": null, "
110                 + "                 \"rhs\": null " + "             } " + "         }, " + "         \"rhs\": { "
111                 + "             \"operand\": \"EQUALS\", " + "             \"field\": \"trap version\", "
112                 + "             \"value\": \"1.2\", " + "             \"datatype\": \"float\", "
113                 + "             \"lhs\": null, " + "             \"rhs\": null " + "         } " + "     }, "
114                 + "     \"result\": \"smooks.config\" " + " }, { " + "     \"priority\": 1, "
115                 + "     \"evaluation\": { " + "         \"operand\": \"AND\", " + "         \"field\": null, "
116                 + "         \"value\": null, " + "         \"datatype\": null, " + "         \"lhs\": { "
117                 + "             \"operand\": \"OR\", " + "             \"field\": null, "
118                 + "             \"value\": null, " + "             \"datatype\": null, " + "             \"lhs\": { "
119                 + "                 \"operand\": \"EQUALS\", " + "                 \"field\": \"domain\", "
120                 + "                 \"value\": \"snmp-heartbeat\", " + "                 \"datatype\": \"string\", "
121                 + "                 \"lhs\": null, " + "                 \"rhs\": null " + "             }, "
122                 + "             \"rhs\": { " + "                 \"operand\": \"EQUALS\", "
123                 + "                 \"field\": \"domain\", " + "                 \"value\": \"snmp-fault\", "
124                 + "                 \"datatype\": \"string\", " + "                 \"lhs\": null, "
125                 + "                 \"rhs\": null " + "             } " + "         }, " + "         \"rhs\": { "
126                 + "             \"operand\": \"EQUALS\", " + "             \"field\": \"trap version\", "
127                 + "             \"value\": \"1.2\", " + "             \"datatype\": \"float\", "
128                 + "             \"lhs\": null, " + "             \"rhs\": null " + "         } " + "     }, "
129                 + "     \"result\": \"smooks.config\" " + " }, { " + "     \"priority\": 3, "
130                 + "     \"evaluation\": { " + "         \"operand\": \"AND\", " + "         \"field\": null, "
131                 + "         \"value\": null, " + "         \"datatype\": null, " + "         \"lhs\": { "
132                 + "             \"operand\": \"OR\", " + "             \"field\": null, "
133                 + "             \"value\": null, " + "             \"datatype\": null, " + "             \"lhs\": { "
134                 + "                 \"operand\": \"EQUALS\", " + "                 \"field\": \"domain\", "
135                 + "                 \"value\": \"snmp-heartbeat\", " + "                 \"datatype\": \"string\", "
136                 + "                 \"lhs\": null, " + "                 \"rhs\": null " + "             }, "
137                 + "             \"rhs\": { " + "                 \"operand\": \"EQUALS\", "
138                 + "                 \"field\": \"domain\", " + "                 \"value\": \"snmp-fault\", "
139                 + "                 \"datatype\": \"string\", " + "                 \"lhs\": null, "
140                 + "                 \"rhs\": null " + "             } " + "         }, " + "         \"rhs\": { "
141                 + "             \"operand\": \"EQUALS\", " + "             \"field\": \"trap version\", "
142                 + "             \"value\": \"1.2\", " + "             \"datatype\": \"float\", "
143                 + "             \"lhs\": null, " + "             \"rhs\": null " + "         } " + "     }, "
144                 + "     \"result\": \"smooks.config\" " + " }, { " + "     \"priority\": 2, "
145                 + "     \"evaluation\": { " + "         \"operand\": \"AND\", " + "         \"field\": null, "
146                 + "         \"value\": null, " + "         \"datatype\": null, " + "         \"lhs\": { "
147                 + "             \"operand\": \"OR\", " + "             \"field\": null, "
148                 + "             \"value\": null, " + "             \"datatype\": null, " + "             \"lhs\": { "
149                 + "                 \"operand\": \"EQUALS\", " + "                 \"field\": \"domain\", "
150                 + "                 \"value\": \"snmp-heartbeat\", " + "                 \"datatype\": \"string\", "
151                 + "                 \"lhs\": null, " + "                 \"rhs\": null " + "             }, "
152                 + "             \"rhs\": { " + "                 \"operand\": \"EQUALS\", "
153                 + "                 \"field\": \"domain\", " + "                 \"value\": \"snmp-fault\", "
154                 + "                 \"datatype\": \"string\", " + "                 \"lhs\": null, "
155                 + "                 \"rhs\": null " + "             } " + "         }, " + "         \"rhs\": { "
156                 + "             \"operand\": \"EQUALS\", " + "             \"field\": \"trap version\", "
157                 + "             \"value\": \"1.2\", " + "             \"datatype\": \"float\", "
158                 + "             \"lhs\": null, " + "             \"rhs\": null " + "         } " + "     }, "
159                 + "     \"result\": \"smooks.config\" " + " }] " + "}";
160         String incomingJsonString = "{\"domain\":\"snmp-heartbeat\",\"trap version\":1.2}";
161
162         try {
163             readMapperConfigFile(mappingFile);
164             checkIncomingJsonForMatchingDomain(incomingJsonString);
165         } catch (MapperConfigException e) {
166             LOGGER.error("Exception in mapperConfigFile reading:{}",e);
167         }
168
169     }
170
171     /**
172      * Checks incoming json to see which of the domain it mathces as per mapper
173      * config entries. If nothing matches, a default mapping will be used.
174      * 
175      * @param incomingJsonString
176      *            incoming json
177      * @throws MapperConfigException
178      *             if error occurs in operation
179      */
180     public static String checkIncomingJsonForMatchingDomain(String incomingJsonString) throws MapperConfigException {
181         ObjectMapper mapper = new ObjectMapper();
182         JsonNode actualObj = null;
183         try {
184             actualObj = mapper.readTree(incomingJsonString);
185         } catch (IOException exception) {
186             throw new MapperConfigException("Unable to read incoming json in a tree " + exception.getMessage(),
187                     exception);
188         }
189         for (Entry entry : entries) {
190
191             boolean result = false;
192             result = evaluateEntryMatch(entry.getEvaluation(), actualObj);
193             if (result) {
194                 return entry.getResult();
195             }
196         }
197         return "default";
198     }
199
200     /**
201      * Reads the mapper config file.
202      * 
203      * @param mappingFileData
204      *            string json for mapper config
205      * @throws MapperConfigException
206      *             if error in mapper config
207      */
208     public static void readMapperConfigFile(String mappingFileData) throws MapperConfigException {
209
210         ObjectMapper name = new ObjectMapper();
211         MapperConfig config = null;
212         try {
213             config = name.readValue(mappingFileData, MapperConfig.class);
214         } catch (IOException exception) {
215             throw new MapperConfigException("Unable to read config file for reason...\n " + exception.getMessage(),
216                     exception);
217         }
218         LOGGER.debug("Read config file content into :{}",config);
219         
220         if (null != config) {
221             entries.addAll(config.getEntries());
222         } else {
223             throw new MapperConfigException("Unable to generate configuration for different domains.");
224         }
225     }
226
227     /**
228      * Evaluates the passed in {@code Evaluation} instance and return boolean
229      * result.
230      * 
231      * @param evaluation
232      *            evaluation instance
233      * @param actualObj
234      *            Json node with values to compare with
235      * @return true if matches evaluation else false
236      * @throws MapperConfigException
237      *             error in evaluation
238      */
239     public static boolean evaluateEntryMatch(Evaluation evaluation, JsonNode actualObj) throws MapperConfigException {
240         if (null == evaluation) {
241             throw new MapperConfigException("Cannot have null evaluation");
242         }
243         if (null != evaluation.getOperand()) {
244
245             if (MapperConfigUtils.isValidEnum(JoinOperator.class, evaluation.getOperand())) {
246                 // if(JOIN_OPERATOR.contains(evaluation.getOperand())){
247                 switch (JoinOperator.valueOf(evaluation.getOperand())) {
248                     case AND:
249                         return evaluateEntryMatch(evaluation.getLhs(), actualObj)
250                                 && evaluateEntryMatch(evaluation.getRhs(), actualObj);
251                     case OR:
252                         return evaluateEntryMatch(evaluation.getLhs(), actualObj)
253                                 || evaluateEntryMatch(evaluation.getRhs(), actualObj);
254                     default:
255                         break;
256                 }
257             }
258
259             if (MapperConfigUtils.isValidEnum(ExpressionOperator.class, evaluation.getOperand())) {
260                 // if(EXPR_OPERATOR.contains(evaluation.getOperand())){
261
262                 // currently it is assumed field being compared is first level
263                 // child of incoming JSON structure.
264                 // If needed, can write a JsonPath implementation later
265                 String field = evaluation.getField();
266                 if (null != field && null != evaluation.getDatatype() && actualObj.has(field)) {
267                     switch (ExpressionOperator.valueOf(evaluation.getOperand())) {
268                         case EQUALS:
269                             if (MapperConfigUtils.isValidEnum(DataType.class, evaluation.getDatatype())) {
270                                 switch (DataType.valueOf(evaluation.getDatatype())) {
271                                     case STRING:
272                                         if (null != actualObj.get(field))
273                                             return actualObj.get(field).asText().equals(evaluation.getValue());
274                                         break;
275                                     case DOUBLE:
276                                         if (null != actualObj.get(field))
277                                             return actualObj.get(field).asDouble() == Double
278                                                     .valueOf(evaluation.getValue());
279                                         break;
280                                     default:
281                                         return false;
282                                 }
283                             } else
284                                 return false;
285                             break;
286                         case STARTSWITH:
287                             if (MapperConfigUtils.isValidEnum(DataType.class, evaluation.getDatatype())) {
288                                 switch (DataType.valueOf(evaluation.getDatatype())) {
289                                     case STRING:
290                                         if (null != actualObj.get(field))
291                                             return actualObj.get(field).asText().startsWith(evaluation.getValue());
292                                         break;
293                                     default:
294                                         return false;
295                                 }
296                             } else
297                                 return false;
298                             break;
299                         case ENDSWITH:
300                             if (MapperConfigUtils.isValidEnum(DataType.class, evaluation.getDatatype())) {
301                                 switch (DataType.valueOf(evaluation.getDatatype())) {
302                                     case STRING:
303                                         if (null != actualObj.get(field))
304                                             return actualObj.get(field).asText().endsWith(evaluation.getValue());
305                                         break;
306                                     default:
307                                         return false;
308                                 }
309                             } else
310                                 return false;
311                             break;
312                         case CONTAINS:
313                             if (MapperConfigUtils.isValidEnum(DataType.class, evaluation.getDatatype())) {
314                                 switch (DataType.valueOf(evaluation.getDatatype())) {
315                                     case STRING:
316                                         if (null != actualObj.get(field))
317                                             return actualObj.get(field).asText().contains(evaluation.getValue());
318                                         break;
319                                     default:
320                                         return false;
321                                 }
322                             } else
323                                 return false;
324                             break;
325                         default:
326                             return false;
327                     }
328                 }
329             }
330         } else
331             throw new MapperConfigException("Not an expected operand as per config for " + evaluation.getField());
332
333         return false;
334     }
335     /**
336      * <p>Checks if the specified name is a valid enum for the class.</p>
337      *
338      * <p>This method differs from {@link Enum#valueOf} in that checks if the name is
339      * a valid enum without needing to catch the exception.</p>
340      *
341      * @param <E> the type of the enumeration
342      * @param enumClass  the class of the enum to query, not null
343      * @param enumName   the enum name, null returns false
344      * @return true if the enum name is valid, otherwise false
345      */
346
347     public static <E extends Enum<E>> boolean isValidEnum(final Class<E> enumClass, final String enumName) {
348         if (enumName == null) {
349             return false;
350         }
351         try {
352             Enum.valueOf(enumClass, enumName);
353             return true;
354         } catch (final IllegalArgumentException ex) {
355             return false;
356         }
357     }
358
359
360 }