26885132dfbb08281b67c2d13db52c0cacb9af26
[so.git] / bpmn / MSOCoreBPMN / src / main / java / org / openecomp / mso / bpmn / core / plugins / LoggingAndURNMappingPlugin.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.mso.bpmn.core.plugins;
22
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.concurrent.ConcurrentHashMap;
27
28 import org.camunda.bpm.engine.delegate.DelegateExecution;
29 import org.camunda.bpm.engine.delegate.ExecutionListener;
30 import org.camunda.bpm.engine.impl.bpmn.parser.AbstractBpmnParseListener;
31 import org.camunda.bpm.engine.impl.bpmn.parser.BpmnParseListener;
32 import org.camunda.bpm.engine.impl.cfg.AbstractProcessEnginePlugin;
33 import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
34 import org.camunda.bpm.engine.impl.context.Context;
35 import org.camunda.bpm.engine.impl.interceptor.Command;
36 import org.camunda.bpm.engine.impl.interceptor.CommandContext;
37 import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity;
38 import org.camunda.bpm.engine.impl.pvm.process.ActivityImpl;
39 import org.camunda.bpm.engine.impl.pvm.process.ScopeImpl;
40 import org.camunda.bpm.engine.impl.pvm.process.TransitionImpl;
41 import org.camunda.bpm.engine.impl.util.xml.Element;
42 import org.camunda.bpm.engine.impl.variable.VariableDeclaration;
43
44 import org.openecomp.mso.bpmn.core.BPMNLogger;
45 import org.openecomp.mso.bpmn.core.PropertyConfiguration;
46 import org.openecomp.mso.bpmn.core.mybatis.CustomMyBatisSessionFactory;
47 import org.openecomp.mso.bpmn.core.mybatis.URNMapping;
48 import org.openecomp.mso.logger.MessageEnum;
49 import org.openecomp.mso.logger.MsoLogger;
50
51 /**
52  * Plugin for MSO logging and URN mapping.
53  */
54 public class LoggingAndURNMappingPlugin extends AbstractProcessEnginePlugin {
55         private static MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);
56         private static final String FSPROPKEY = "URNMapping.FileSystemLoading.Enabled";
57
58         @Override
59         public void preInit(
60                         ProcessEngineConfigurationImpl processEngineConfiguration) {
61                 List<BpmnParseListener> preParseListeners = processEngineConfiguration
62                                 .getCustomPreBPMNParseListeners();
63                 if (preParseListeners == null) {
64                         preParseListeners = new ArrayList<BpmnParseListener>();
65                         processEngineConfiguration.setCustomPreBPMNParseListeners(preParseListeners);
66                 }
67                 preParseListeners.add(new LoggingParseListener());
68         }
69         
70         /**
71          * Called when a process flow is parsed so we can inject listeners.
72          */
73         public static class LoggingParseListener extends AbstractBpmnParseListener {
74                 private void injectLogExecutionListener(ActivityImpl activity) {
75                         activity.addListener(
76                                         ExecutionListener.EVENTNAME_END,
77                                         new LoggingExecutionListener("END"));
78
79                         activity.addListener(
80                                         ExecutionListener.EVENTNAME_START,
81                                         new LoggingExecutionListener("START"));
82
83                         activity.addListener(
84                                         ExecutionListener.EVENTNAME_TAKE,
85                                         new LoggingExecutionListener("TAKE"));
86                 }
87
88                 public void parseProcess(Element processElement, ProcessDefinitionEntity processDefinition) {
89                 }
90
91                 public void parseStartEvent(Element startEventElement, ScopeImpl scope, ActivityImpl startEventActivity) {
92                         // Inject these listeners only on the main start event for the flow, not on any embedded subflow start events
93                         if (scope instanceof ProcessDefinitionEntity) {
94                                 startEventActivity.addListener(ExecutionListener.EVENTNAME_START, new URNMappingInitializerListener("START"));
95                                 startEventActivity.addListener(ExecutionListener.EVENTNAME_START, new LoggingInitializerListener("START"));
96                         }
97
98                         injectLogExecutionListener(startEventActivity);
99                 }
100
101                 public void parseServiceTask(Element serviceTaskElement, ScopeImpl scope, ActivityImpl activity) {
102                         injectLogExecutionListener(activity);
103                 }
104
105                 public void parseExclusiveGateway(Element exclusiveGwElement, ScopeImpl scope, ActivityImpl activity) {
106                         injectLogExecutionListener(activity);
107                 }
108
109                 public void parseInclusiveGateway(Element inclusiveGwElement, ScopeImpl scope, ActivityImpl activity) {
110                         injectLogExecutionListener(activity);
111                 }
112
113                 public void parseParallelGateway(Element parallelGwElement, ScopeImpl scope, ActivityImpl activity) {
114                         injectLogExecutionListener(activity);
115                 }
116
117                 public void parseScriptTask(Element scriptTaskElement, ScopeImpl scope, ActivityImpl activity) {
118                         injectLogExecutionListener(activity);
119                 }
120
121                 public void parseBusinessRuleTask(Element businessRuleTaskElement, ScopeImpl scope, ActivityImpl activity) {
122                         injectLogExecutionListener(activity);
123                 }
124
125                 public void parseTask(Element taskElement, ScopeImpl scope, ActivityImpl activity) {
126                         injectLogExecutionListener(activity);
127                 }
128
129                 public void parseManualTask(Element manualTaskElement, ScopeImpl scope, ActivityImpl activity) {
130                         injectLogExecutionListener(activity);
131                 }
132
133                 public void parseUserTask(Element userTaskElement, ScopeImpl scope, ActivityImpl activity) {
134                         injectLogExecutionListener(activity);
135                 }
136
137                 public void parseEndEvent(Element endEventElement, ScopeImpl scope, ActivityImpl activity) {
138                         injectLogExecutionListener(activity);
139                 }
140
141                 public void parseBoundaryTimerEventDefinition(Element timerEventDefinition, boolean interrupting, ActivityImpl timerActivity) {
142                         injectLogExecutionListener(timerActivity);
143                 }
144
145                 public void parseBoundaryErrorEventDefinition(Element errorEventDefinition, boolean interrupting, ActivityImpl activity, ActivityImpl nestedErrorEventActivity) {
146                         injectLogExecutionListener(activity);
147                 }
148
149                 public void parseSubProcess(Element subProcessElement, ScopeImpl scope, ActivityImpl activity) {
150                         injectLogExecutionListener(activity);
151                 }
152
153                 public void parseCallActivity(Element callActivityElement, ScopeImpl scope, ActivityImpl activity) {
154                         injectLogExecutionListener(activity);
155                 }
156
157                 public void parseProperty(Element propertyElement, VariableDeclaration variableDeclaration, ActivityImpl activity) {
158                         injectLogExecutionListener(activity);
159                 }
160
161                 public void parseSequenceFlow(Element sequenceFlowElement, ScopeImpl scopeElement, TransitionImpl transition) {
162                         //injectLogExecutionListener(activity);
163                 }
164
165                 public void parseSendTask(Element sendTaskElement, ScopeImpl scope, ActivityImpl activity) {
166                         injectLogExecutionListener(activity);
167                 }
168
169                 public void parseMultiInstanceLoopCharacteristics(Element activityElement, Element multiInstanceLoopCharacteristicsElement, ActivityImpl activity) {
170                         injectLogExecutionListener(activity);
171                 }
172
173                 public void parseIntermediateTimerEventDefinition(Element timerEventDefinition, ActivityImpl timerActivity) {
174                         injectLogExecutionListener(timerActivity);
175                 }
176
177                 public void parseRootElement(Element rootElement, List<ProcessDefinitionEntity> processDefinitions) {
178                         //injectLogExecutionListener(activity);
179                 }
180
181                 public void parseReceiveTask(Element receiveTaskElement, ScopeImpl scope, ActivityImpl activity) {
182                         injectLogExecutionListener(activity);
183                 }
184
185                 public void parseIntermediateSignalCatchEventDefinition(Element signalEventDefinition, ActivityImpl signalActivity) {
186                         injectLogExecutionListener(signalActivity);
187                 }
188
189                 public void parseBoundarySignalEventDefinition(Element signalEventDefinition, boolean interrupting, ActivityImpl signalActivity) {
190                         injectLogExecutionListener(signalActivity);
191                 }
192
193                 public void parseEventBasedGateway(Element eventBasedGwElement, ScopeImpl scope, ActivityImpl activity) {
194                         injectLogExecutionListener(activity);
195                 }
196
197                 public void parseTransaction(Element transactionElement, ScopeImpl scope, ActivityImpl activity) {
198                         injectLogExecutionListener(activity);
199                 }
200
201                 public void parseCompensateEventDefinition(Element compensateEventDefinition, ActivityImpl compensationActivity) {
202                         injectLogExecutionListener(compensationActivity);
203                 }
204
205                 public void parseIntermediateThrowEvent(Element intermediateEventElement, ScopeImpl scope, ActivityImpl activity) {
206                         injectLogExecutionListener(activity);
207                 }
208
209                 public void parseIntermediateCatchEvent(Element intermediateEventElement, ScopeImpl scope, ActivityImpl activity) {
210                         injectLogExecutionListener(activity);
211                 }
212
213                 public void parseBoundaryEvent(Element boundaryEventElement, ScopeImpl scopeElement, ActivityImpl nestedActivity) {
214                         injectLogExecutionListener(nestedActivity);
215                 }
216
217                 public void parseIntermediateMessageCatchEventDefinition(Element messageEventDefinition, ActivityImpl nestedActivity) {
218                         injectLogExecutionListener(nestedActivity);
219                 }
220
221                 public void parseBoundaryMessageEventDefinition(Element element, boolean interrupting, ActivityImpl messageActivity) {
222                         injectLogExecutionListener(messageActivity);
223                 }
224         }
225
226         /**
227          * Initializes URN mapping variables on process entry.
228          */
229         public static class URNMappingInitializerListener implements ExecutionListener {
230                 private String event;
231
232                 public URNMappingInitializerListener(String eventData) {
233                         this.event = eventData;
234                 }
235
236                 public String getEvent() {
237                         return event;
238                 }
239
240                 public void notify(DelegateExecution execution) throws Exception {
241                         ProcessEngineConfigurationImpl processEngineConfiguration =
242                                 Context.getProcessEngineConfiguration();
243                         loadURNProperties(execution, processEngineConfiguration);
244                 }
245
246                 private void loadURNProperties(DelegateExecution execution,
247                                 ProcessEngineConfigurationImpl processEngineConfiguration) {
248                         Map<String,String> bpmnProps = PropertyConfiguration.getInstance().getProperties("mso.bpmn.properties");
249                         if (bpmnProps == null) {
250                                 LOGGER.debug("Unable to load mso.bpmn.properties; loading URN Mapping from DB");
251                                 
252                                 LOGGER.error (MessageEnum.BPMN_GENERAL_EXCEPTION, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, 
253                                         "Unable to load mso.bpmn.properties; loading URN Mapping from DB");
254                                 
255                                 loadFromDB(execution, processEngineConfiguration);
256                         } else {
257                                 String fsEnabled = bpmnProps.get(FSPROPKEY);
258                                 if (fsEnabled != null) {
259                                         if (Boolean.parseBoolean(fsEnabled)) {
260                                                 LOGGER.debug("File system loading is enabled; loading URN properties from File system");
261                                                 LOGGER.info(MessageEnum.BPMN_GENERAL_INFO,  "BPMN",  "File system loading is enabled; loading URN properties from File System");
262                                                 loadFromFileSystem(execution);
263                                         } else {
264                                                 LOGGER.debug("File system loading is disabled; loading URN properties from DB");
265                                                 LOGGER.info (MessageEnum.BPMN_GENERAL_INFO, "BPMN", "File system loading is disabled; loading URN properties from DB");
266                                                 
267                                                 loadFromDB(execution, processEngineConfiguration);
268                                         }
269                                 } else {
270                                         
271                                         LOGGER.error (MessageEnum.BPMN_GENERAL_EXCEPTION, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, 
272                                                 "Unable to retrieve URNMapping.FileSystemLoading.Enabled from mso.bpmn.properties; loading URN Mapping from DB");
273                                         
274                                         loadFromDB(execution, processEngineConfiguration);
275                                 }
276                         }
277                 }
278
279                 private void loadFromFileSystem(DelegateExecution execution) {
280                         PropertyConfiguration propertyConfiguration = PropertyConfiguration.getInstance();
281                         Map<String,String> props = propertyConfiguration.getProperties("mso.bpmn.urn.properties");
282                         for (String key : props.keySet()) {
283                                 String varName = URNMapping.createIdentifierFromURN(key);
284                                 String varValue = props.get(key);
285                                 execution.setVariable(varName, varValue);
286                         }
287                 }
288
289                 private void loadFromDB(DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) {
290                         Command<List<URNMapping>> command = new Command<List<URNMapping>>() {
291                                 @SuppressWarnings("unchecked")
292                                 public List<URNMapping> execute(CommandContext commandContext) {
293                                         return (List<URNMapping>) commandContext.getDbSqlSession().selectList(
294                                                 "mso.urnMapping.selectAll", null);
295                                 }
296                         };
297
298                         CustomMyBatisSessionFactory sessionFactory = new CustomMyBatisSessionFactory();
299                         sessionFactory.initFromProcessEngineConfiguration(processEngineConfiguration,
300                                 "customMyBatisConfiguration.xml");
301
302                         List<URNMapping> mappings = sessionFactory.getCommandExecutorTxRequired().execute(command);
303
304                         if (mappings != null && mappings.size() > 0) {
305                                 for (URNMapping mapping : mappings) {
306                                         String varName = URNMapping.createIdentifierFromURN(mapping.getName());
307                                         String varValue = mapping.getValue();
308
309                                         LOGGER.debug("URN Mapping = '" + mapping.getName()
310                                                 + "', setting variable '" + varName + "' to '" + varValue + "'");
311
312                                         execution.setVariable(varName, varValue);
313                                 }
314                         }
315                 }
316         }
317
318         /**
319          * Sets the isDebugLogEnabled variable on process entry.
320          */
321         public static class LoggingInitializerListener implements ExecutionListener {
322                 private String event;
323
324                 public LoggingInitializerListener(String eventData) {
325                         this.event = eventData;
326                 }
327
328                 public String getEvent() {
329                         return event;
330                 }
331
332                 public void notify(DelegateExecution execution) throws Exception {
333                         String processKey = execution.getProcessEngineServices().getRepositoryService()
334                                 .getProcessDefinition(execution.getProcessDefinitionId()).getKey();
335
336                         // If a "true" value is already injected, e.g. from a top-level flow, it SHOULD NOT be
337                         // overridden by the value in the URN mapping. This allows a top-level flow and all
338                         // invoked subflows to be debugged by turning on the debug flag for just the top-level
339                         // flow, assuming the isDebugEnabled flag variable is passed from the top-level flow to
340                         // its subflows.
341
342                         // If a "false" value is already injected, e.g. from a top-level flow, it SHOULD be
343                         // overridden by the value in the URN mapping.  This allows a subflow to be debugged
344                         // without turning on the the debug flag for the top-level flow.
345
346                         String injectedValue = (String) execution.getVariable("isDebugLogEnabled");
347                         String urnValue = "true".equals(execution.getVariable("URN_log_debug_" + processKey)) ? "true" : "false";
348
349                         if ("true".equals(injectedValue)) {
350                                 LOGGER.debug("Setting isDebugLogEnabled to \"" + injectedValue + "\" for process: " + processKey + " (injected value)");
351                                 execution.setVariable("isDebugLogEnabled", injectedValue);
352                         } else {
353                                 LOGGER.debug("Setting isDebugLogEnabled to \"" + urnValue + "\" for process: " + processKey + " (from URN mapping)");
354                                 execution.setVariable("isDebugLogEnabled", urnValue);
355                         }
356                 }
357         }
358         
359         /**
360          * Logs details about the current activity.
361          */
362         public static class LoggingExecutionListener implements ExecutionListener {
363                 private static MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);
364                 private static ConcurrentHashMap<String, Long> startTimes = new ConcurrentHashMap<String, Long>();
365
366                 private String event;
367
368                 public LoggingExecutionListener(String event) {
369                         this.event = event;
370                 }
371
372                 public String getEvent() {
373                         return event;
374                 }
375
376                 public void notify(DelegateExecution execution) throws Exception {
377                         BPMNLogger.debug(
378                                 (String) execution.getVariable("isDebugLogEnabled"),
379                                 "Logging for activity---------------:" + event + ":"
380                                                 + execution.getCurrentActivityName()
381                                                 + ", processDefinitionId="
382                                                 + execution.getProcessDefinitionId() + ", activtyId="
383                                                 + execution.getCurrentActivityId() + ", activtyName='"
384                                                 + execution.getCurrentActivityName() + "'"
385                                                 + ", processInstanceId="
386                                                 + execution.getProcessInstanceId() + ", businessKey="
387                                                 + execution.getProcessBusinessKey() + ", executionId="
388                                                 + execution.getId());
389
390                         if (!isBlank(execution.getCurrentActivityName())) {
391                                 try {
392                                         String id = execution.getId();
393                                         if ("START".equals(event) && id != null ) {
394                                                 startTimes.put(id, (Long)System.currentTimeMillis());
395                                         } else if ("END".equals(event) && id != null) {
396                                                 String prefix = (String) execution.getVariable("prefix");
397
398                                                 if (prefix != null ) {
399                                                         MsoLogger.setServiceName("MSO." + prefix.substring(0,prefix.length()-1));
400                                                 }
401
402                                                 String requestId = (String) execution.getVariable("mso-request-id");
403                                                 String svcid = (String) execution.getVariable("mso-service-instance-id");
404                                                 MsoLogger.setLogContext(requestId, svcid);
405                                                 long startTime = startTimes.remove(id);
406
407                                                 if (startTime != 0) {
408                                                         
409                                                         LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, 
410                                                                         event + ": " + execution.getCurrentActivityName(), "BPMN", execution.getCurrentActivityName(), null);
411                                                         
412                                                 }
413                                         }
414                                 } catch(Exception e) {
415                                         LOGGER.debug("Exception at notify: " + e);
416                                 }
417                         }
418                 }
419
420                 private boolean isBlank(Object object) {
421                         return object == null || object.toString().trim().equals("");
422                 }
423         }
424 }