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