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