Controller Blueprints Nitrogen to Oxygen Migration
[ccsdk/features.git] / blueprints-processor / plugin / assignment-provider / src / main / java / org / onap / ccsdk / features / assignment / processor / DBResourceProcessor.java
1 /*\r
2  * Copyright © 2017-2018 AT&T Intellectual Property.\r
3  * Modifications Copyright © 2018 IBM.\r
4  * \r
5  * Licensed under the Apache License, Version 2.0 (the "License");\r
6  * you may not use this file except in compliance with the License.\r
7  * You may obtain a copy of the License at\r
8  * \r
9  * http://www.apache.org/licenses/LICENSE-2.0\r
10  * \r
11  * Unless required by applicable law or agreed to in writing, software\r
12  * distributed under the License is distributed on an "AS IS" BASIS,\r
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
14  * See the License for the specific language governing permissions and\r
15  * limitations under the License.\r
16  */\r
17 \r
18 package org.onap.ccsdk.features.assignment.processor;\r
19 \r
20 import java.util.HashMap;\r
21 import java.util.List;\r
22 import java.util.Map;\r
23 import org.apache.commons.collections.CollectionUtils;\r
24 import org.apache.commons.collections.MapUtils;\r
25 import org.apache.commons.lang3.StringUtils;\r
26 import org.onap.ccsdk.features.assignment.service.ConfigAssignmentUtils;\r
27 import org.onap.ccsdk.features.data.adaptor.service.ConfigResourceService;\r
28 import org.onap.ccsdk.features.model.ConfigModelConstant;\r
29 import org.onap.ccsdk.features.model.ConfigModelException;\r
30 import org.onap.ccsdk.features.model.ValidTypes;\r
31 import org.onap.ccsdk.features.model.data.ResourceAssignment;\r
32 import org.onap.ccsdk.features.model.data.dict.ResourceDefinition;\r
33 import org.onap.ccsdk.features.model.data.dict.SourcesDefinition;\r
34 import org.onap.ccsdk.features.model.service.ComponentNode;\r
35 import org.onap.ccsdk.features.model.utils.JsonUtils;\r
36 import org.onap.ccsdk.features.model.utils.ResourceAssignmentUtils;\r
37 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;\r
38 import org.onap.ccsdk.sli.core.sli.SvcLogicException;\r
39 import com.att.eelf.configuration.EELFLogger;\r
40 import com.att.eelf.configuration.EELFManager;\r
41 import com.fasterxml.jackson.databind.node.ArrayNode;\r
42 import com.fasterxml.jackson.databind.node.JsonNodeFactory;\r
43 import com.fasterxml.jackson.databind.node.ObjectNode;\r
44 \r
45 public class DBResourceProcessor implements ComponentNode {\r
46 \r
47     private static EELFLogger logger = EELFManager.getInstance().getLogger(DBResourceProcessor.class);\r
48     private ConfigResourceService configResourceService;\r
49     private Map<String, ResourceDefinition> dictionaries;\r
50 \r
51     public DBResourceProcessor(ConfigResourceService configResourceService) {\r
52         this.configResourceService = configResourceService;\r
53     }\r
54 \r
55     @Override\r
56     public Boolean preCondition(Map<String, String> inParams, SvcLogicContext ctx, Map<String, Object> componentContext)\r
57             throws SvcLogicException {\r
58         return Boolean.TRUE;\r
59     }\r
60 \r
61     @Override\r
62     public void preProcess(Map<String, String> inParams, SvcLogicContext ctx, Map<String, Object> componentContext)\r
63             throws SvcLogicException {\r
64         // Auto-generated method stub\r
65     }\r
66 \r
67     @Override\r
68     public void process(Map<String, String> inParams, SvcLogicContext ctx) throws SvcLogicException {\r
69         // Auto-generated method stub\r
70     }\r
71 \r
72     @SuppressWarnings("unchecked")\r
73     @Override\r
74     public void process(Map<String, String> inParams, SvcLogicContext ctx, Map<String, Object> componentContext)\r
75             throws SvcLogicException {\r
76         try {\r
77             List<ResourceAssignment> batchResourceAssignment =\r
78                     (List<ResourceAssignment>) componentContext.get(ConfigModelConstant.PROPERTY_RESOURCE_ASSIGNMENTS);\r
79             dictionaries =\r
80                     (Map<String, ResourceDefinition>) componentContext.get(ConfigModelConstant.PROPERTY_DICTIONARIES);\r
81 \r
82             if (CollectionUtils.isNotEmpty(batchResourceAssignment)) {\r
83                 for (ResourceAssignment resourceAssignment : batchResourceAssignment) {\r
84                     processResourceAssignment(ctx, componentContext, resourceAssignment);\r
85                 }\r
86             }\r
87         } catch (Exception e) {\r
88             throw new SvcLogicException(String.format("DBResourceProcessor Exception : (%s)", e), e);\r
89         }\r
90     }\r
91 \r
92     private void processResourceAssignment(SvcLogicContext ctx, Map<String, Object> componentContext,\r
93             ResourceAssignment resourceAssignment) throws SvcLogicException, ConfigModelException {\r
94         if (resourceAssignment != null) {\r
95             try {\r
96                 validate(resourceAssignment);\r
97 \r
98                 // Check if It has Input\r
99                 Object value = ConfigAssignmentUtils.getContextKeyValue(ctx, resourceAssignment.getName());\r
100                 if (value != null) {\r
101                     logger.info("db source template key ({}) found from input and value is ({})",\r
102                             resourceAssignment.getName(), value);\r
103                     ResourceAssignmentUtils.setResourceDataValue(componentContext, resourceAssignment, value);\r
104                     return;\r
105                 }\r
106 \r
107                 ResourceDefinition resourceDefinition = dictionaries.get(resourceAssignment.getDictionaryName());\r
108                 SourcesDefinition sourceDb = resourceDefinition.getSources().get("db");\r
109                 if (StringUtils.isBlank(sourceDb.getProperties().getQuery())) {\r
110                     throw new SvcLogicException("db query property is missing");\r
111                 }\r
112 \r
113                 String sql = sourceDb.getProperties().getQuery();\r
114                 Map<String, String> inputKeyMapping = sourceDb.getProperties().getInputKeyMapping();\r
115 \r
116                 logger.info("Db dictionary information : ({}), ({}), ({})", sql, inputKeyMapping,\r
117                         sourceDb.getProperties().getOutputKeyMapping());\r
118 \r
119                 Map<String, Object> namedParameters = populateNamedParameter(componentContext, inputKeyMapping);\r
120 \r
121                 logger.info("Parameter information : ({})", namedParameters);\r
122                 List<Map<String, Object>> rows = configResourceService.query(sql, namedParameters);\r
123                 if (rows != null && !rows.isEmpty()) {\r
124                     processDBResults(ctx, componentContext, resourceAssignment, sourceDb, rows);\r
125                 } else {\r
126                     logger.warn("Failed to get db result for dictionary name ({}) the query ({})",\r
127                             resourceAssignment.getDictionaryName(), sql);\r
128                 }\r
129 \r
130                 // Check the value has populated for mandatory case\r
131                 ResourceAssignmentUtils.assertTemplateKeyValueNotNull(componentContext, resourceAssignment);\r
132             } catch (Exception e) {\r
133                 ResourceAssignmentUtils.setFailedResourceDataValue(componentContext, resourceAssignment,\r
134                         e.getMessage());\r
135                 throw new SvcLogicException(\r
136                         String.format("Failed in template key (%s) assignments : (%s)", resourceAssignment, e), e);\r
137             }\r
138         } else {\r
139             // Do Nothing\r
140         }\r
141     }\r
142 \r
143     private void validate(ResourceAssignment resourceAssignment) throws SvcLogicException {\r
144         if (resourceAssignment == null) {\r
145             throw new SvcLogicException("resource assignment is not defined");\r
146         }\r
147 \r
148         if (StringUtils.isBlank(resourceAssignment.getName())) {\r
149             throw new SvcLogicException("resource assignment template key is not defined");\r
150         }\r
151 \r
152         if (StringUtils.isBlank(resourceAssignment.getDictionaryName())) {\r
153             throw new SvcLogicException(\r
154                     String.format("resource assignment dictionary name is not defined for template key (%s)",\r
155                             resourceAssignment.getName()));\r
156         }\r
157 \r
158         if (!ConfigModelConstant.SOURCE_DB.equalsIgnoreCase(resourceAssignment.getDictionarySource())) {\r
159             throw new SvcLogicException(String.format("resource assignment source is not db, it is (%s)",\r
160                     resourceAssignment.getDictionarySource()));\r
161         }\r
162 \r
163         ResourceDefinition resourceDefinition = dictionaries.get(resourceAssignment.getDictionaryName());\r
164         if (resourceDefinition == null) {\r
165             throw new SvcLogicException(String.format("missing resource dictionary definition for name (%s)  ",\r
166                     resourceAssignment.getDictionaryName()));\r
167         }\r
168 \r
169         if (resourceDefinition.getSources() == null || resourceDefinition.getSources().get("db") == null) {\r
170             throw new SvcLogicException(String.format("missing resource dictionary db source definition for name (%s) ",\r
171                     resourceAssignment.getDictionaryName()));\r
172         }\r
173 \r
174         SourcesDefinition sourceDb = resourceDefinition.getSources().get("db");\r
175         if (StringUtils.isBlank(sourceDb.getProperties().getQuery())) {\r
176             throw new SvcLogicException(String.format("Failed to get request Query for dictionary (%s)",\r
177                     resourceAssignment.getDictionaryName()));\r
178         }\r
179 \r
180     }\r
181 \r
182     private Map<String, Object> populateNamedParameter(Map<String, Object> componentContext,\r
183             Map<String, String> inputKeyMapping) {\r
184         Map<String, Object> namedParameters = new HashMap<>();\r
185         if (MapUtils.isNotEmpty(inputKeyMapping)) {\r
186 \r
187             for (Map.Entry<String, String> mapping : inputKeyMapping.entrySet()) {\r
188                 ResourceDefinition referenceDictionaryDefinition = dictionaries.get(mapping.getValue());\r
189                 Object expressionValue =\r
190                         ResourceAssignmentUtils.getDictionaryKeyValue(componentContext, referenceDictionaryDefinition);\r
191                 logger.trace("Reference dictionary key ({}), value ({})", mapping.getKey(), expressionValue);\r
192                 namedParameters.put(mapping.getKey(), expressionValue);\r
193             }\r
194         }\r
195         return namedParameters;\r
196     }\r
197 \r
198     @SuppressWarnings("squid:S3776")\r
199     private void processDBResults(SvcLogicContext ctx, Map<String, Object> componentContext,\r
200             ResourceAssignment resourceAssignment, SourcesDefinition sourceDb, List<Map<String, Object>> rows)\r
201             throws SvcLogicException, ConfigModelException {\r
202 \r
203         Map<String, String> outputKeyMapping = sourceDb.getProperties().getOutputKeyMapping();\r
204         String type = resourceAssignment.getProperty().getType();\r
205         String entrySchema = null;\r
206         logger.info("Response processing type({})", type);\r
207         // Primitive Types\r
208         if (ValidTypes.getPrimitivePropertType().contains(type)) {\r
209 \r
210             Map<String, Object> row = rows.get(0);\r
211             String dbColumnName = outputKeyMapping.get(resourceAssignment.getDictionaryName());\r
212             Object dbColumnValue = row.get(dbColumnName);\r
213             ResourceAssignmentUtils.setResourceDataValue(componentContext, resourceAssignment, dbColumnValue);\r
214 \r
215         } else if (ValidTypes.getListPropertType().contains(type)) {\r
216             // Array Types\r
217             if (resourceAssignment.getProperty().getEntrySchema() != null) {\r
218                 entrySchema = resourceAssignment.getProperty().getEntrySchema().getType();\r
219             }\r
220 \r
221             if (StringUtils.isNotBlank(entrySchema)) {\r
222                 ArrayNode arrayNode = JsonNodeFactory.instance.arrayNode();\r
223 \r
224                 for (Map<String, Object> row : rows) {\r
225                     if (ValidTypes.getPrimitivePropertType().contains(entrySchema)) {\r
226                         String dbColumnName = outputKeyMapping.get(resourceAssignment.getDictionaryName());\r
227                         Object dbColumnValue = row.get(dbColumnName);\r
228                         // Add Array JSON\r
229                         JsonUtils.populatePrimitiveValues(dbColumnValue, entrySchema, arrayNode);\r
230                     } else {\r
231                         ObjectNode arrayChildNode = JsonNodeFactory.instance.objectNode();\r
232                         for (Map.Entry<String, String> mapping : outputKeyMapping.entrySet()) {\r
233                             Object dbColumnValue = row.get(mapping.getKey());\r
234                             String propertyTypeForDataType =\r
235                                     ConfigAssignmentUtils.getPropertyType(ctx, entrySchema, mapping.getKey());\r
236                             JsonUtils.populatePrimitiveValues(mapping.getKey(), dbColumnValue, propertyTypeForDataType,\r
237                                     arrayChildNode);\r
238                         }\r
239                         arrayNode.add(arrayChildNode);\r
240                     }\r
241                 }\r
242                 // Set the List of Complex Values\r
243                 ResourceAssignmentUtils.setResourceDataValue(componentContext, resourceAssignment, arrayNode);\r
244             } else {\r
245                 throw new SvcLogicException(String.format("Entry schema is not defined for dictionary (%s) info",\r
246                         resourceAssignment.getDictionaryName()));\r
247             }\r
248         } else {\r
249             // Complex Types\r
250             Map<String, Object> row = rows.get(0);\r
251             ObjectNode objectNode = JsonNodeFactory.instance.objectNode();\r
252             for (Map.Entry<String, String> mapping : outputKeyMapping.entrySet()) {\r
253                 Object dbColumnValue = row.get(mapping.getKey());\r
254                 String propertyTypeForDataType = ConfigAssignmentUtils.getPropertyType(ctx, type, mapping.getKey());\r
255                 JsonUtils.populatePrimitiveValues(mapping.getKey(), dbColumnValue, propertyTypeForDataType, objectNode);\r
256             }\r
257             ResourceAssignmentUtils.setResourceDataValue(componentContext, resourceAssignment, objectNode);\r
258         }\r
259     }\r
260 \r
261     @Override\r
262     public void postProcess(Map<String, String> inParams, SvcLogicContext ctx, Map<String, Object> componentContext)\r
263             throws SvcLogicException {\r
264         // Auto-generated method stub\r
265     }\r
266 \r
267 }\r