Consolidate PolicyRestAdapter setup
[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.utils.PolicyUtils;
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     /**
108      * getBRMSParamPolicyRuleData.
109      *
110      * @param request HttpServletRequest
111      * @param response HttpServletResponse
112      */
113     @RequestMapping(value = {"/policyController/getBRMSTemplateData.htm"}, method = {RequestMethod.POST})
114     public void getBRMSParamPolicyRuleData(HttpServletRequest request, HttpServletResponse response) {
115         try {
116             dynamicLayoutMap = new HashMap<>();
117             ObjectMapper mapper = new ObjectMapper();
118             mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
119             JsonNode root = mapper.readTree(request.getReader());
120             String rule = findRule(root.get(PolicyController.getPolicydata()).toString().replaceAll("^\"|\"$", ""));
121             generateUI(rule);
122             response.setCharacterEncoding(PolicyController.getCharacterencoding());
123             response.setContentType(PolicyController.getContenttype());
124             request.setCharacterEncoding(PolicyController.getCharacterencoding());
125
126             response.getWriter().write(new JSONObject("{policyData: " + mapper.writeValueAsString(dynamicLayoutMap)
127                 + "}").toString());
128         } catch (Exception e) {
129             policyLogger.error("Exception Occured while getting BRMS Rule data", e);
130         }
131     }
132
133     private String findRule(String ruleTemplate) {
134         List<Object> datas = commonClassDao.getDataById(BRMSParamTemplate.class, "ruleName", ruleTemplate);
135         if (CollectionUtils.isNotEmpty(datas)) {
136             return ((BRMSParamTemplate) datas.get(0)).getRule();
137         }
138         return null;
139     }
140
141     private void generateUI(String rule) {
142         if (rule == null) {
143             return;
144         }
145         try {
146             processRule(rule);
147         } catch (Exception e) {
148             policyLogger.error(XACMLErrorConstants.ERROR_SYSTEM_ERROR + e);
149         }
150
151     }
152
153     private void processRule(String rule) {
154         StringBuilder params = getParamsBuilderFromRule(rule);
155         params = new StringBuilder(
156                 params.toString().replace("declare Params", "").replace("end", "").replaceAll("\\s+", ""));
157         String[] components = params.toString().split(":");
158         String caption = "";
159         for (int i = 0; i < components.length; i++) {
160             String type;
161             if (i == 0) {
162                 caption = components[i];
163             }
164             if ("".equals(caption)) {
165                 break;
166             }
167             String nextComponent;
168             try {
169                 nextComponent = components[i + 1];
170             } catch (Exception e) {
171                 policyLogger.info("Error when procesing rule: " + e);
172                 nextComponent = components[i];
173             }
174             if (nextComponent.startsWith(string)) {
175                 type = "String";
176                 createField(caption, type);
177                 caption = nextComponent.replace(string, "");
178             } else if (nextComponent.startsWith("int")) {
179                 type = "int";
180                 createField(caption, type);
181                 caption = nextComponent.replace("int", "");
182             }
183         }
184     }
185
186     private StringBuilder getParamsBuilderFromRule(final String rule) {
187         StringBuilder params = new StringBuilder();
188         boolean flag = false;
189         boolean comment = false;
190         String[] lines = rule.split("\n");
191         for (String line : lines) {
192             if (line.isEmpty() || line.startsWith("//")) {
193                 continue;
194             }
195             if (line.startsWith("/*")) {
196                 comment = true;
197                 continue;
198             }
199             if (line.contains("//")) {
200                 line = splitSingleLineComment(line);
201             }
202             if (line.contains("/*")) {
203                 comment = true;
204                 if (line.contains("*/")) {
205                     comment = false;
206                     line = processMultiLineFullComment(line);
207                 } else {
208                     line = splitMultiLineStartComment(line);
209                 }
210             }
211             if (line.contains("*/")) {
212                 comment = false;
213                 line = processEndComment(line);
214             }
215             if (comment) {
216                 continue;
217             }
218             if (flag) {
219                 params.append(line);
220             }
221             if (line.contains("declare Params")) {
222                 params.append(line);
223                 flag = true;
224             }
225             if (line.contains("end") && flag) {
226                 break;
227             }
228         }
229         return params;
230     }
231
232     private String splitMultiLineStartComment(String line) {
233         return line.split("\\/\\*")[0];
234     }
235
236     private String splitMultiLineEndComment(String line) {
237         return line.split("\\*\\/")[1].replace("*/", "");
238     }
239
240     private String splitSingleLineComment(String line) {
241         return line.split("\\/\\/")[0];
242     }
243
244     private void createField(String caption, String type) {
245         dynamicLayoutMap.put(caption, type);
246     }
247
248     /**
249      * prePopulateBRMSParamPolicyData.
250      * When the User Click Edit or View Policy the following method will get invoked for setting the data to
251      * PolicyRestAdapter.
252      * Which is used to bind the data in GUI.
253      *
254      * @param policyAdapter PolicyRestAdapter
255      * @param entity PolicyEntity
256      */
257     public void prePopulateBRMSParamPolicyData(PolicyRestAdapter policyAdapter, PolicyEntity entity) {
258         dynamicLayoutMap = new HashMap<>();
259         if (! (policyAdapter.getPolicyData() instanceof PolicyType)) {
260             return;
261         }
262         PolicyType policy = (PolicyType) policyAdapter.getPolicyData();
263         policyAdapter.setOldPolicyFileName(policyAdapter.getPolicyName());
264         // policy name value is the policy name without any prefix and
265         // Extensions.
266         String policyNameValue =
267                 policyAdapter.getPolicyName().substring(policyAdapter.getPolicyName().indexOf("BRMS_Param_") + 11);
268         if (policyLogger.isDebugEnabled()) {
269             policyLogger
270                     .debug("Prepopulating form data for BRMS RAW Policy selected:" + policyAdapter.getPolicyName());
271         }
272         policyAdapter.setPolicyName(policyNameValue);
273         String description;
274         try {
275             description = policy.getDescription().substring(0, policy.getDescription().indexOf("@CreatedBy:"));
276         } catch (Exception e) {
277             policyLogger.info("Error getting description: " + e);
278             description = policy.getDescription();
279         }
280         policyAdapter.setPolicyDescription(description);
281         setDataAdapterFromAdviceExpressions(policy, policyAdapter);
282
283         // Generate Param UI
284         try {
285             paramUiGenerate(policyAdapter, entity);
286         } catch (Exception e) {
287             policyLogger.error(XACMLErrorConstants.ERROR_DATA_ISSUE + e.getMessage() + e);
288         }
289
290         // Get the target data under policy.
291         policyAdapter.setDynamicLayoutMap(dynamicLayoutMap);
292         if (policyAdapter.getDynamicLayoutMap().size() > 0) {
293             LinkedHashMap<String, String> drlRule = policyAdapter.getDynamicLayoutMap().keySet().stream()
294                     .collect(Collectors.toMap(String::toString,
295                         keyValue -> policyAdapter.getDynamicLayoutMap().get(keyValue), (a, b) -> b,
296                             LinkedHashMap::new));
297             policyAdapter.setRuleData(drlRule);
298         }
299         TargetType target = policy.getTarget();
300         if (target != null) {
301             setDataToAdapterFromTarget(target, policyAdapter);
302         }
303     }
304
305     private void setDataAdapterFromAdviceExpressions(PolicyType policy, PolicyRestAdapter policyAdapter) {
306         ArrayList<Object> attributeList = new ArrayList<>();
307         // Set Attributes.
308         AdviceExpressionsType expressionTypes =
309                 ((RuleType) policy.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().get(0))
310                         .getAdviceExpressions();
311         for (AdviceExpressionType adviceExpression : expressionTypes.getAdviceExpression()) {
312             for (AttributeAssignmentExpressionType attributeAssignment : adviceExpression
313                     .getAttributeAssignmentExpression()) {
314                 if (attributeAssignment.getAttributeId().startsWith("key:")) {
315                     Map<String, String> attribute = new HashMap<>();
316                     String key = attributeAssignment.getAttributeId().replace("key:", "");
317                     attribute.put("key", key);
318                     @SuppressWarnings("unchecked")
319                     JAXBElement<AttributeValueType> attributeValue =
320                             (JAXBElement<AttributeValueType>) attributeAssignment.getExpression();
321                     String value = (String) attributeValue.getValue().getContent().get(0);
322                     attribute.put("value", value);
323                     attributeList.add(attribute);
324                 } else if (attributeAssignment.getAttributeId().startsWith("dependencies:")) {
325                     ArrayList<String> dependencies = new ArrayList<>(Arrays
326                             .asList(attributeAssignment.getAttributeId().replace("dependencies:", "").split(",")));
327                     dependencies.remove("");
328                     policyAdapter.setBrmsDependency(dependencies);
329                 } else if (attributeAssignment.getAttributeId().startsWith("controller:")) {
330                     policyAdapter.setBrmsController(attributeAssignment.getAttributeId().replace("controller:", ""));
331                 }
332             }
333             policyAdapter.setAttributes(attributeList);
334         }
335     }
336
337     private void setDataToAdapterFromTarget(TargetType target, PolicyRestAdapter policyAdapter) {
338         // Under target we have AnyOFType
339         if (target.getAnyOf() == null) {
340             return;
341         }
342         target.getAnyOf().stream().map(AnyOfType::getAllOf).filter(Objects::nonNull).flatMap(Collection::stream)
343                 .forEach(allOf -> setDataToAdapterFromMatchList(allOf.getMatch(), policyAdapter));
344     }
345
346     private void setDataToAdapterFromMatchList(List<MatchType> matchList, PolicyRestAdapter policyAdapter) {
347         if (matchList == null) {
348             return;
349         }
350         for (final MatchType match : matchList) {
351             //
352             // Under the match we have attribute value and
353             // attributeDesignator. So,finally down to the actual attribute.
354             //
355             AttributeValueType attributeValue = match.getAttributeValue();
356             String value = (String) attributeValue.getContent().get(0);
357             AttributeDesignatorType designator = match.getAttributeDesignator();
358             String attributeId = designator.getAttributeId();
359             policyAdapter.setupUsingAttribute(attributeId, value);
360         }
361     }
362
363     // This method generates the UI from rule configuration
364     private void paramUiGenerate(PolicyRestAdapter policyAdapter, PolicyEntity entity) {
365         String data = entity.getConfigurationData().getConfigBody();
366         if (data == null) {
367             return;
368         }
369         StringBuilder params = new StringBuilder();
370         boolean flag = false;
371         boolean comment = false;
372         for (String line : data.split("\n")) {
373             if (line.isEmpty() || line.startsWith("//")) {
374                 continue;
375             }
376             if (line.contains(brmsTemplateVlaue)) {
377                 String value = line.substring(line.indexOf("<$%"), line.indexOf("%$>"));
378                 value = value.replace(brmsTemplateVlaue, "");
379                 policyAdapter.setRuleName(value);
380             }
381             if (line.contains("<%$Values=")) {
382                 String value = line.substring(line.indexOf("<%$"), line.indexOf("$%>"));
383                 value = value.replaceAll("<%\\$Values=", "");
384                 Arrays.stream(value.split(":\\|:")).map(keyValue -> keyValue.split(":-:"))
385                         .filter(pair -> pair.length > 0)
386                         .forEach(pair -> dynamicLayoutMap.put(pair[0], (pair.length > 1) ? pair[1] : ""));
387                 return;
388             }
389             if (line.startsWith("/*")) {
390                 comment = true;
391                 continue;
392             }
393             if ((line.contains("//")) && (!(line.contains("http://") || line.contains("https://")))) {
394                 line = splitSingleLineComment(line);
395             }
396             if (line.contains("/*")) {
397                 comment = true;
398                 if (line.contains("*/")) {
399                     comment = false;
400                     line = processMultiLineFullComment(line);
401                 } else {
402                     line = splitMultiLineStartComment(line);
403                 }
404             }
405             if (line.contains("*/")) {
406                 comment = false;
407                 line = processEndComment(line);
408             }
409             if (comment) {
410                 continue;
411             }
412             if (flag) {
413                 params.append(line);
414             }
415             if (line.contains("rule") && line.contains(".Params\"")) {
416                 params.append(line);
417                 flag = true;
418             }
419             if (line.contains("end") && flag) {
420                 break;
421             }
422         }
423         params = new StringBuilder(params.substring(params.indexOf(".Params\"") + 11));
424         params = new StringBuilder(
425                 params.toString().replaceAll("\\s+", "").replace("salience1000whenthenParamsparams=newParams();", "")
426                         .replace("insert(params);end", "").replace("params.set", ""));
427         updateCaptionToDynamicLayoutMap(params);
428     }
429
430     private void updateCaptionToDynamicLayoutMap(final StringBuilder params) {
431         String[] components = params.toString().split("\\);");
432         if (components.length > 0) {
433             for (int i = 0; i < components.length; i++) {
434                 String value;
435                 components[i] = components[i] + ")";
436                 String caption = components[i].substring(0, components[i].indexOf('('));
437                 caption = caption.substring(0, 1).toLowerCase() + caption.substring(1);
438                 if (components[i].contains("(\"")) {
439                     value = components[i].substring(components[i].indexOf("(\""), components[i].indexOf("\")"))
440                             .replace("(\"", "").replace("\")", "");
441                 } else {
442                     value = components[i].substring(components[i].indexOf('('), components[i].indexOf(')'))
443                             .replace("(", "").replace(")", "");
444                 }
445                 dynamicLayoutMap.put(caption, value);
446             }
447         }
448     }
449
450     private String processEndComment(String line) {
451         try {
452             line = splitMultiLineEndComment(line);
453         } catch (Exception e) {
454             policyLogger.info("Just for Logging" + e);
455             line = "";
456         }
457         return line;
458     }
459
460     private String processMultiLineFullComment(String line) {
461         try {
462             line = splitMultiLineStartComment(line) + splitMultiLineEndComment(line);
463         } catch (Exception e) {
464             policyLogger.info("Just for Logging" + e);
465             line = splitMultiLineStartComment(line);
466         }
467         return line;
468     }
469
470     /**
471      * setViewRule.
472      *
473      * @param request HttpServletRequest
474      * @param response HttpServletResponse
475      */
476     @SuppressWarnings("unchecked")
477     @RequestMapping(value = {"/policyController/ViewBRMSParamPolicyRule.htm"}, method = {RequestMethod.POST})
478     public void setViewRule(HttpServletRequest request, HttpServletResponse response) {
479         try {
480             ObjectMapper mapper = new ObjectMapper();
481             mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
482             JsonNode root = mapper.readTree(request.getReader());
483             PolicyRestAdapter policyData = mapper.readValue(
484                     root.get(PolicyController.getPolicydata()).get("policy").toString(), PolicyRestAdapter.class);
485             policyData.setDomainDir(
486                     root.get(PolicyController.getPolicydata()).get("model").get("name").toString().replace("\"", ""));
487             if (root.get(PolicyController.getPolicydata()).get("model").get("type").toString().replace("\"", "")
488                     .equals(PolicyController.getFile())) {
489                 policyData.setEditPolicy(true);
490             }
491
492             String body = findRule(policyData.getRuleName()) + "\n";
493             StringBuilder generatedMetadata = new StringBuilder().append(
494                     "/* Autogenerated Code Please Don't change/remove this comment section. "
495                             + "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             while (iterator.hasNext()) {
521                 // Converting the first character of the key into a lower case.
522                 String input = iterator.next();
523                 String output = Character.toLowerCase(input.charAt(0)) + (input.length() > 1 ? input.substring(1) : "");
524                 // Searching for a pattern in the String using the key.
525                 Pattern pattern = Pattern.compile("\\$\\{" + output + "\\}");
526                 Matcher matcher = pattern.matcher(body);
527                 // Replacing the value with the inputs provided by the user in the editor.
528                 body = matcher.replaceAll(copyMap.get(input));
529             }
530             response.setCharacterEncoding(PolicyUtils.CHARACTER_ENCODING);
531             response.setContentType(PolicyUtils.APPLICATION_JSON);
532             request.setCharacterEncoding(PolicyUtils.CHARACTER_ENCODING);
533
534             response.getWriter().write(new JSONObject("{policyData: " + mapper.writeValueAsString(body)
535                 + "}").toString());
536         } catch (Exception e) {
537             policyLogger.error(XACMLErrorConstants.ERROR_PROCESS_FLOW + e);
538         }
539     }
540 }