33b78034858cb8678a493e77f99e3c196d35bab2
[policy/engine.git] / POLICY-SDK-APP / src / main / java / org / onap / policy / controller / CreateBRMSParamController.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP Policy Engine
4  * ================================================================================
5  * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6  * Modified Copyright (C) 2018 Samsung Electronics Co., Ltd.
7  * Modifications Copyright (C) 2019 Bell Canada
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.controller;
24
25 import com.fasterxml.jackson.databind.DeserializationFeature;
26 import com.fasterxml.jackson.databind.JsonNode;
27 import com.fasterxml.jackson.databind.ObjectMapper;
28
29 import java.io.PrintWriter;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collection;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.LinkedHashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.Objects;
40 import java.util.Set;
41 import java.util.regex.Matcher;
42 import java.util.regex.Pattern;
43 import java.util.stream.Collectors;
44
45 import javax.servlet.http.HttpServletRequest;
46 import javax.servlet.http.HttpServletResponse;
47 import javax.xml.bind.JAXBElement;
48
49 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType;
50 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionsType;
51 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
52 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
53 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
54 import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
55 import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
56 import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
57 import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
58 import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType;
59
60 import org.apache.commons.collections.CollectionUtils;
61 import org.json.JSONObject;
62 import org.onap.policy.common.logging.flexlogger.FlexLogger;
63 import org.onap.policy.common.logging.flexlogger.Logger;
64 import org.onap.policy.rest.adapter.PolicyRestAdapter;
65 import org.onap.policy.rest.dao.CommonClassDao;
66 import org.onap.policy.rest.jpa.BRMSParamTemplate;
67 import org.onap.policy.rest.jpa.PolicyEntity;
68 import org.onap.policy.xacml.api.XACMLErrorConstants;
69 import org.onap.portalsdk.core.controller.RestrictedBaseController;
70 import org.springframework.beans.factory.annotation.Autowired;
71 import org.springframework.stereotype.Controller;
72 import org.springframework.web.bind.annotation.RequestMapping;
73 import org.springframework.web.bind.annotation.RequestMethod;
74
75 @Controller
76 @RequestMapping("/")
77 public class CreateBRMSParamController extends RestrictedBaseController {
78
79     private static final Logger policyLogger = FlexLogger.getLogger(CreateBRMSParamController.class);
80
81     private static CommonClassDao commonClassDao;
82
83     public static CommonClassDao getCommonClassDao() {
84         return commonClassDao;
85     }
86
87     public static void setCommonClassDao(CommonClassDao commonClassDao) {
88         CreateBRMSParamController.commonClassDao = commonClassDao;
89     }
90
91     @Autowired
92     private CreateBRMSParamController(CommonClassDao commonClassDao) {
93         CreateBRMSParamController.commonClassDao = commonClassDao;
94     }
95
96     public CreateBRMSParamController() {
97         // Empty constructor
98     }
99
100     protected PolicyRestAdapter policyAdapter = null;
101
102     private HashMap<String, String> dynamicLayoutMap;
103
104     private static String brmsTemplateVlaue = "<$%BRMSParamTemplate=";
105     private static String string = "String";
106
107     @RequestMapping(value = {"/policyController/getBRMSTemplateData.htm"}, method = {RequestMethod.POST})
108     public void getBRMSParamPolicyRuleData(HttpServletRequest request, HttpServletResponse response) {
109         try {
110             dynamicLayoutMap = new HashMap<>();
111             ObjectMapper mapper = new ObjectMapper();
112             mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
113             JsonNode root = mapper.readTree(request.getReader());
114             String rule = findRule(root.get(PolicyController.getPolicydata()).toString().replaceAll("^\"|\"$", ""));
115             generateUI(rule);
116             response.setCharacterEncoding(PolicyController.getCharacterencoding());
117             response.setContentType(PolicyController.getContenttype());
118             request.setCharacterEncoding(PolicyController.getCharacterencoding());
119
120             PrintWriter out = response.getWriter();
121             String responseString = mapper.writeValueAsString(dynamicLayoutMap);
122             JSONObject j = new JSONObject("{policyData: " + responseString + "}");
123             out.write(j.toString());
124         } catch (Exception e) {
125             policyLogger.error("Exception Occured while getting BRMS Rule data", e);
126         }
127     }
128
129     private String findRule(String ruleTemplate) {
130         List<Object> datas = commonClassDao.getDataById(BRMSParamTemplate.class, "ruleName", ruleTemplate);
131         if (CollectionUtils.isNotEmpty(datas)) {
132             BRMSParamTemplate bRMSParamTemplate = (BRMSParamTemplate) datas.get(0);
133             return bRMSParamTemplate.getRule();
134         }
135         return null;
136     }
137
138     private void generateUI(String rule) {
139         if (rule == null) {
140             return;
141         }
142         try {
143             processRule(rule);
144         } catch (Exception e) {
145             policyLogger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + e);
146         }
147
148     }
149
150     private void processRule(String rule) {
151         StringBuilder params = getParamsBuilderFromRule(rule);
152         params = new StringBuilder(
153                 params.toString().replace("declare Params", "").replace("end", "").replaceAll("\\s+", ""));
154         String[] components = params.toString().split(":");
155         String caption = "";
156         for (int i = 0; i < components.length; i++) {
157             String type;
158             if (i == 0) {
159                 caption = components[i];
160             }
161             if ("".equals(caption)) {
162                 break;
163             }
164             String nextComponent;
165             try {
166                 nextComponent = components[i + 1];
167             } catch (Exception e) {
168                 policyLogger.info("Error when procesing rule: " + e);
169                 nextComponent = components[i];
170             }
171             if (nextComponent.startsWith(string)) {
172                 type = "String";
173                 createField(caption, type);
174                 caption = nextComponent.replace(string, "");
175             } else if (nextComponent.startsWith("int")) {
176                 type = "int";
177                 createField(caption, type);
178                 caption = nextComponent.replace("int", "");
179             }
180         }
181     }
182
183     private StringBuilder getParamsBuilderFromRule(final String rule) {
184         StringBuilder params = new StringBuilder();
185         boolean flag = false;
186         boolean comment = false;
187         String[] lines = rule.split("\n");
188         for (String line : lines) {
189             if (line.isEmpty() || line.startsWith("//")) {
190                 continue;
191             }
192             if (line.startsWith("/*")) {
193                 comment = true;
194                 continue;
195             }
196             if (line.contains("//")) {
197                 line = splitSingleLineComment(line);
198             }
199             if (line.contains("/*")) {
200                 comment = true;
201                 if (line.contains("*/")) {
202                     comment = false;
203                     line = processMultiLineFullComment(line);
204                 } else {
205                     line = splitMultiLineStartComment(line);
206                 }
207             }
208             if (line.contains("*/")) {
209                 comment = false;
210                 line = processEndComment(line);
211             }
212             if (comment) {
213                 continue;
214             }
215             if (flag) {
216                 params.append(line);
217             }
218             if (line.contains("declare Params")) {
219                 params.append(line);
220                 flag = true;
221             }
222             if (line.contains("end") && flag) {
223                 break;
224             }
225         }
226         return params;
227     }
228
229     private String splitMultiLineStartComment(String line) {
230         return line.split("\\/\\*")[0];
231     }
232
233     private String splitMultiLineEndComment(String line) {
234         return line.split("\\*\\/")[1].replace("*/", "");
235     }
236
237     private String splitSingleLineComment(String line) {
238         return line.split("\\/\\/")[0];
239     }
240
241     private void createField(String caption, String type) {
242         dynamicLayoutMap.put(caption, type);
243     }
244
245     /*
246      * When the User Click Edit or View Policy the following method will get invoked for setting the data to
247      * PolicyRestAdapter.
248      * Which is used to bind the data in GUI
249      */
250     public void prePopulateBRMSParamPolicyData(PolicyRestAdapter policyAdapter, PolicyEntity entity) {
251         dynamicLayoutMap = new HashMap<>();
252         if (policyAdapter.getPolicyData() instanceof PolicyType) {
253             PolicyType policy = (PolicyType) policyAdapter.getPolicyData();
254             policyAdapter.setOldPolicyFileName(policyAdapter.getPolicyName());
255             // policy name value is the policy name without any prefix and
256             // Extensions.
257             String policyNameValue =
258                     policyAdapter.getPolicyName().substring(policyAdapter.getPolicyName().indexOf("BRMS_Param_") + 11);
259             if (policyLogger.isDebugEnabled()) {
260                 policyLogger
261                         .debug("Prepopulating form data for BRMS RAW Policy selected:" + policyAdapter.getPolicyName());
262             }
263             policyAdapter.setPolicyName(policyNameValue);
264             String description;
265             try {
266                 description = policy.getDescription().substring(0, policy.getDescription().indexOf("@CreatedBy:"));
267             } catch (Exception e) {
268                 policyLogger.info("Error getting description: " + e);
269                 description = policy.getDescription();
270             }
271             policyAdapter.setPolicyDescription(description);
272             setDataAdapterFromAdviceExpressions(policy, policyAdapter);
273
274             // Generate Param UI
275             try {
276                 paramUIGenerate(policyAdapter, entity);
277             } catch (Exception e) {
278                 policyLogger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e.getMessage() + e);
279             }
280
281             // Get the target data under policy.
282             policyAdapter.setDynamicLayoutMap(dynamicLayoutMap);
283             if (policyAdapter.getDynamicLayoutMap().size() > 0) {
284                 LinkedHashMap<String, String> drlRule = policyAdapter.getDynamicLayoutMap().keySet().stream()
285                         .collect(Collectors.toMap(String::toString,
286                                 keyValue -> policyAdapter.getDynamicLayoutMap().get(keyValue), (a, b) -> b,
287                                 LinkedHashMap::new));
288                 policyAdapter.setRuleData(drlRule);
289             }
290             TargetType target = policy.getTarget();
291             if (target != null) {
292                 setDataToAdapterFromTarget(target, policyAdapter);
293             }
294         }
295     }
296
297     private void setDataAdapterFromAdviceExpressions(PolicyType policy, PolicyRestAdapter policyAdapter) {
298         ArrayList<Object> attributeList = new ArrayList<>();
299         // Set Attributes.
300         AdviceExpressionsType expressionTypes =
301                 ((RuleType) policy.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().get(0))
302                         .getAdviceExpressions();
303         for (AdviceExpressionType adviceExpression : expressionTypes.getAdviceExpression()) {
304             for (AttributeAssignmentExpressionType attributeAssignment : adviceExpression
305                     .getAttributeAssignmentExpression()) {
306                 if (attributeAssignment.getAttributeId().startsWith("key:")) {
307                     Map<String, String> attribute = new HashMap<>();
308                     String key = attributeAssignment.getAttributeId().replace("key:", "");
309                     attribute.put("key", key);
310                     @SuppressWarnings("unchecked")
311                     JAXBElement<AttributeValueType> attributeValue =
312                             (JAXBElement<AttributeValueType>) attributeAssignment.getExpression();
313                     String value = (String) attributeValue.getValue().getContent().get(0);
314                     attribute.put("value", value);
315                     attributeList.add(attribute);
316                 } else if (attributeAssignment.getAttributeId().startsWith("dependencies:")) {
317                     ArrayList<String> dependencies = new ArrayList<>(Arrays
318                             .asList(attributeAssignment.getAttributeId().replace("dependencies:", "").split(",")));
319                     dependencies.remove("");
320                     policyAdapter.setBrmsDependency(dependencies);
321                 } else if (attributeAssignment.getAttributeId().startsWith("controller:")) {
322                     policyAdapter.setBrmsController(attributeAssignment.getAttributeId().replace("controller:", ""));
323                 }
324             }
325             policyAdapter.setAttributes(attributeList);
326         }
327     }
328
329     private void setDataToAdapterFromTarget(TargetType target, PolicyRestAdapter policyAdapter) {
330         // Under target we have AnyOFType
331         List<AnyOfType> anyOfList = target.getAnyOf();
332         if (anyOfList == null) {
333             return;
334         }
335         anyOfList.stream().map(AnyOfType::getAllOf).filter(Objects::nonNull).flatMap(Collection::stream)
336                 .forEach(allOf -> setDataToAdapterFromMatchList(allOf.getMatch(), policyAdapter));
337     }
338
339     private void setDataToAdapterFromMatchList(List<MatchType> matchList, PolicyRestAdapter policyAdapter) {
340         if (matchList == null) {
341             return;
342         }
343         for (final MatchType match : matchList) {
344             //
345             // Under the match we have attribute value and
346             // attributeDesignator. So,finally down to the actual attribute.
347             //
348             AttributeValueType attributeValue = match.getAttributeValue();
349             String value = (String) attributeValue.getContent().get(0);
350             AttributeDesignatorType designator = match.getAttributeDesignator();
351             String attributeId = designator.getAttributeId();
352             if ("RiskType".equals(attributeId)) {
353                 policyAdapter.setRiskType(value);
354             }
355             if ("RiskLevel".equals(attributeId)) {
356                 policyAdapter.setRiskLevel(value);
357             }
358             if ("guard".equals(attributeId)) {
359                 policyAdapter.setGuard(value);
360             }
361             if ("TTLDate".equals(attributeId) && !value.contains("NA")) {
362                 PolicyController controller = new PolicyController();
363                 String newDate = controller.convertDate(value);
364                 policyAdapter.setTtlDate(newDate);
365             }
366         }
367     }
368
369     // This method generates the UI from rule configuration
370     private void paramUIGenerate(PolicyRestAdapter policyAdapter, PolicyEntity entity) {
371         String data = entity.getConfigurationData().getConfigBody();
372         if (data == null) {
373             return;
374         }
375         StringBuilder params = new StringBuilder();
376         boolean flag = false;
377         boolean comment = false;
378         for (String line : data.split("\n")) {
379             if (line.isEmpty() || line.startsWith("//")) {
380                 continue;
381             }
382             if (line.contains(brmsTemplateVlaue)) {
383                 String value = line.substring(line.indexOf("<$%"), line.indexOf("%$>"));
384                 value = value.replace(brmsTemplateVlaue, "");
385                 policyAdapter.setRuleName(value);
386             }
387             if (line.contains("<%$Values=")) {
388                 String value = line.substring(line.indexOf("<%$"), line.indexOf("$%>"));
389                 value = value.replaceAll("<%\\$Values=", "");
390                 Arrays.stream(value.split(":\\|:")).map(keyValue -> keyValue.split(":-:"))
391                         .filter(pair -> pair.length > 0)
392                         .forEach(pair -> dynamicLayoutMap.put(pair[0], (pair.length > 1) ? pair[1] : ""));
393                 return;
394             }
395             if (line.startsWith("/*")) {
396                 comment = true;
397                 continue;
398             }
399             if ((line.contains("//")) && (!(line.contains("http://") || line.contains("https://")))) {
400                 line = splitSingleLineComment(line);
401             }
402             if (line.contains("/*")) {
403                 comment = true;
404                 if (line.contains("*/")) {
405                     comment = false;
406                     line = processMultiLineFullComment(line);
407                 } else {
408                     line = splitMultiLineStartComment(line);
409                 }
410             }
411             if (line.contains("*/")) {
412                 comment = false;
413                 line = processEndComment(line);
414             }
415             if (comment) {
416                 continue;
417             }
418             if (flag) {
419                 params.append(line);
420             }
421             if (line.contains("rule") && line.contains(".Params\"")) {
422                 params.append(line);
423                 flag = true;
424             }
425             if (line.contains("end") && flag) {
426                 break;
427             }
428         }
429         params = new StringBuilder(params.substring(params.indexOf(".Params\"") + 11));
430         params = new StringBuilder(
431                 params.toString().replaceAll("\\s+", "").replace("salience1000whenthenParamsparams=newParams();", "")
432                         .replace("insert(params);end", "").replace("params.set", ""));
433         updateCaptionToDynamicLayoutMap(params);
434     }
435
436     private void updateCaptionToDynamicLayoutMap(final StringBuilder params) {
437         String[] components = params.toString().split("\\);");
438         if (components.length > 0) {
439             for (int i = 0; i < components.length; i++) {
440                 String value;
441                 components[i] = components[i] + ")";
442                 String caption = components[i].substring(0, components[i].indexOf('('));
443                 caption = caption.substring(0, 1).toLowerCase() + caption.substring(1);
444                 if (components[i].contains("(\"")) {
445                     value = components[i].substring(components[i].indexOf("(\""), components[i].indexOf("\")"))
446                             .replace("(\"", "").replace("\")", "");
447                 } else {
448                     value = components[i].substring(components[i].indexOf('('), components[i].indexOf(')'))
449                             .replace("(", "").replace(")", "");
450                 }
451                 dynamicLayoutMap.put(caption, value);
452             }
453         }
454     }
455
456     private String processEndComment(String line) {
457         try {
458             line = splitMultiLineEndComment(line);
459         } catch (Exception e) {
460             policyLogger.info("Just for Logging" + e);
461             line = "";
462         }
463         return line;
464     }
465
466     private String processMultiLineFullComment(String line) {
467         try {
468             line = splitMultiLineStartComment(line) + splitMultiLineEndComment(line);
469         } catch (Exception e) {
470             policyLogger.info("Just for Logging" + e);
471             line = splitMultiLineStartComment(line);
472         }
473         return line;
474     }
475
476     // set View Rule
477     @SuppressWarnings("unchecked")
478     @RequestMapping(value = {"/policyController/ViewBRMSParamPolicyRule.htm"}, method = {RequestMethod.POST})
479     public void setViewRule(HttpServletRequest request, HttpServletResponse response) {
480         try {
481             ObjectMapper mapper = new ObjectMapper();
482             mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
483             JsonNode root = mapper.readTree(request.getReader());
484             PolicyRestAdapter policyData = mapper.readValue(
485                     root.get(PolicyController.getPolicydata()).get("policy").toString(), PolicyRestAdapter.class);
486             policyData.setDomainDir(
487                     root.get(PolicyController.getPolicydata()).get("model").get("name").toString().replace("\"", ""));
488             if (root.get(PolicyController.getPolicydata()).get("model").get("type").toString().replace("\"", "")
489                     .equals(PolicyController.getFile())) {
490                 policyData.setEditPolicy(true);
491             }
492
493             String body = findRule(policyData.getRuleName()) + "\n";
494             StringBuilder generatedMetadata = new StringBuilder().append(
495                     "/* Autogenerated Code Please Don't change/remove this comment section. This is for the UI purpose. \n\t ")
496                     .append(brmsTemplateVlaue).append(policyData.getRuleName()).append("%$> \n */ \n");
497
498             if (policyData.getDynamicLayoutMap().size() > 0) {
499                 generatedMetadata.append("/* <%$Values=");
500                 for (Entry<?, ?> entry : policyData.getRuleData().entrySet()) {
501                     String uiKey = (String) entry.getKey();
502                     if (!"templateName".equals(uiKey)) {
503                         generatedMetadata.append(uiKey).append(":-:").append(entry.getValue()).append(":|:");
504                     }
505                 }
506                 generatedMetadata.append("$%> \n*/ \n");
507             }
508             policyLogger.info("Metadata generated with :" + generatedMetadata.toString());
509             body = generatedMetadata.toString() + body;
510             // Expand the body.
511             Map<String, String> copyMap =
512                     new HashMap<>((Map<? extends String, ? extends String>) policyData.getRuleData());
513             copyMap.put("policyName",
514                     policyData.getDomainDir().replace("\\", ".") + ".Config_BRMS_Param_" + policyData.getPolicyName());
515             copyMap.put("policyScope", policyData.getDomainDir().replace("\\", "."));
516             copyMap.put("policyVersion", "1");
517             // Finding all the keys in the Map data-structure.
518             Set<String> keySet = copyMap.keySet();
519             Iterator<String> iterator = keySet.iterator();
520             Pattern p;
521             Matcher m;
522             while (iterator.hasNext()) {
523                 // Converting the first character of the key into a lower case.
524                 String input = iterator.next();
525                 String output = Character.toLowerCase(input.charAt(0)) + (input.length() > 1 ? input.substring(1) : "");
526                 // Searching for a pattern in the String using the key.
527                 p = Pattern.compile("\\$\\{" + output + "\\}");
528                 m = p.matcher(body);
529                 // Replacing the value with the inputs provided by the user in the editor.
530                 body = m.replaceAll(copyMap.get(input));
531             }
532             response.setCharacterEncoding("UTF-8");
533             response.setContentType("application / json");
534             request.setCharacterEncoding("UTF-8");
535
536             PrintWriter out = response.getWriter();
537             String responseString = mapper.writeValueAsString(body);
538             JSONObject j = new JSONObject("{policyData: " + responseString + "}");
539             out.write(j.toString());
540         } catch (Exception e) {
541             policyLogger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + e);
542         }
543     }
544 }