Added the "@Override" annotation above signature
[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<>();
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                 @Override
89                 public void parseProcess(Element processElement, ProcessDefinitionEntity processDefinition) {
90                 }
91
92                 @Override
93                 public void parseStartEvent(Element startEventElement, ScopeImpl scope, ActivityImpl startEventActivity) {
94                         // Inject these listeners only on the main start event for the flow, not on any embedded subflow start events
95                         if (scope instanceof ProcessDefinitionEntity) {
96                                 startEventActivity.addListener(ExecutionListener.EVENTNAME_START, new URNMappingInitializerListener("START"));
97                                 startEventActivity.addListener(ExecutionListener.EVENTNAME_START, new LoggingInitializerListener("START"));
98                         }
99
100                         injectLogExecutionListener(startEventActivity);
101                 }
102
103                 @Override
104                 public void parseServiceTask(Element serviceTaskElement, ScopeImpl scope, ActivityImpl activity) {
105                         injectLogExecutionListener(activity);
106                 }
107
108                 @Override
109                 public void parseExclusiveGateway(Element exclusiveGwElement, ScopeImpl scope, ActivityImpl activity) {
110                         injectLogExecutionListener(activity);
111                 }
112
113                 @Override
114                 public void parseInclusiveGateway(Element inclusiveGwElement, ScopeImpl scope, ActivityImpl activity) {
115                         injectLogExecutionListener(activity);
116                 }
117
118                 @Override
119                 public void parseParallelGateway(Element parallelGwElement, ScopeImpl scope, ActivityImpl activity) {
120                         injectLogExecutionListener(activity);
121                 }
122
123                 @Override
124                 public void parseScriptTask(Element scriptTaskElement, ScopeImpl scope, ActivityImpl activity) {
125                         injectLogExecutionListener(activity);
126                 }
127
128                 @Override
129                 public void parseBusinessRuleTask(Element businessRuleTaskElement, ScopeImpl scope, ActivityImpl activity) {
130                         injectLogExecutionListener(activity);
131                 }
132
133                 @Override
134                 public void parseTask(Element taskElement, ScopeImpl scope, ActivityImpl activity) {
135                         injectLogExecutionListener(activity);
136                 }
137
138                 @Override
139                 public void parseManualTask(Element manualTaskElement, ScopeImpl scope, ActivityImpl activity) {
140                         injectLogExecutionListener(activity);
141                 }
142
143                 @Override
144                 public void parseUserTask(Element userTaskElement, ScopeImpl scope, ActivityImpl activity) {
145                         injectLogExecutionListener(activity);
146                 }
147
148                 @Override
149                 public void parseEndEvent(Element endEventElement, ScopeImpl scope, ActivityImpl activity) {
150                         injectLogExecutionListener(activity);
151                 }
152
153                 @Override
154                 public void parseBoundaryTimerEventDefinition(Element timerEventDefinition, boolean interrupting, ActivityImpl timerActivity) {
155                         injectLogExecutionListener(timerActivity);
156                 }
157
158                 @Override
159                 public void parseBoundaryErrorEventDefinition(Element errorEventDefinition, boolean interrupting, ActivityImpl activity, ActivityImpl nestedErrorEventActivity) {
160                         injectLogExecutionListener(activity);
161                 }
162
163                 @Override
164                 public void parseSubProcess(Element subProcessElement, ScopeImpl scope, ActivityImpl activity) {
165                         injectLogExecutionListener(activity);
166                 }
167
168                 @Override
169                 public void parseCallActivity(Element callActivityElement, ScopeImpl scope, ActivityImpl activity) {
170                         injectLogExecutionListener(activity);
171                 }
172
173                 @Override
174                 public void parseProperty(Element propertyElement, VariableDeclaration variableDeclaration, ActivityImpl activity) {
175                         injectLogExecutionListener(activity);
176                 }
177
178                 @Override
179                 public void parseSequenceFlow(Element sequenceFlowElement, ScopeImpl scopeElement, TransitionImpl transition) {
180                         //injectLogExecutionListener(activity);
181                 }
182
183                 @Override
184                 public void parseSendTask(Element sendTaskElement, ScopeImpl scope, ActivityImpl activity) {
185                         injectLogExecutionListener(activity);
186                 }
187
188                 @Override
189                 public void parseMultiInstanceLoopCharacteristics(Element activityElement, Element multiInstanceLoopCharacteristicsElement, ActivityImpl activity) {
190                         injectLogExecutionListener(activity);
191                 }
192
193                 @Override
194                 public void parseIntermediateTimerEventDefinition(Element timerEventDefinition, ActivityImpl timerActivity) {
195                         injectLogExecutionListener(timerActivity);
196                 }
197
198                 @Override
199                 public void parseRootElement(Element rootElement, List<ProcessDefinitionEntity> processDefinitions) {
200                         //injectLogExecutionListener(activity);
201                 }
202
203                 @Override
204                 public void parseReceiveTask(Element receiveTaskElement, ScopeImpl scope, ActivityImpl activity) {
205                         injectLogExecutionListener(activity);
206                 }
207
208                 @Override
209                 public void parseIntermediateSignalCatchEventDefinition(Element signalEventDefinition, ActivityImpl signalActivity) {
210                         injectLogExecutionListener(signalActivity);
211                 }
212
213                 @Override
214                 public void parseBoundarySignalEventDefinition(Element signalEventDefinition, boolean interrupting, ActivityImpl signalActivity) {
215                         injectLogExecutionListener(signalActivity);
216                 }
217
218                 @Override
219                 public void parseEventBasedGateway(Element eventBasedGwElement, ScopeImpl scope, ActivityImpl activity) {
220                         injectLogExecutionListener(activity);
221                 }
222
223                 @Override
224                 public void parseTransaction(Element transactionElement, ScopeImpl scope, ActivityImpl activity) {
225                         injectLogExecutionListener(activity);
226                 }
227
228                 @Override
229                 public void parseCompensateEventDefinition(Element compensateEventDefinition, ActivityImpl compensationActivity) {
230                         injectLogExecutionListener(compensationActivity);
231                 }
232
233                 @Override
234                 public void parseIntermediateThrowEvent(Element intermediateEventElement, ScopeImpl scope, ActivityImpl activity) {
235                         injectLogExecutionListener(activity);
236                 }
237
238                 @Override
239                 public void parseIntermediateCatchEvent(Element intermediateEventElement, ScopeImpl scope, ActivityImpl activity) {
240                         injectLogExecutionListener(activity);
241                 }
242
243                 @Override
244                 public void parseBoundaryEvent(Element boundaryEventElement, ScopeImpl scopeElement, ActivityImpl nestedActivity) {
245                         injectLogExecutionListener(nestedActivity);
246                 }
247
248                 @Override
249                 public void parseIntermediateMessageCatchEventDefinition(Element messageEventDefinition, ActivityImpl nestedActivity) {
250                         injectLogExecutionListener(nestedActivity);
251                 }
252
253                 @Override
254                 public void parseBoundaryMessageEventDefinition(Element element, boolean interrupting, ActivityImpl messageActivity) {
255                         injectLogExecutionListener(messageActivity);
256                 }
257         }
258
259         /**
260          * Initializes URN mapping variables on process entry.
261          */
262         public static class URNMappingInitializerListener implements ExecutionListener {
263                 private String event;
264
265                 public URNMappingInitializerListener(String eventData) {
266                         this.event = eventData;
267                 }
268
269                 public String getEvent() {
270                         return event;
271                 }
272
273                 @Override
274                 public void notify(DelegateExecution execution) throws Exception {
275                         ProcessEngineConfigurationImpl processEngineConfiguration =
276                                 Context.getProcessEngineConfiguration();
277                         loadURNProperties(execution, processEngineConfiguration);
278                 }
279
280                 private void loadURNProperties(DelegateExecution execution,
281                                 ProcessEngineConfigurationImpl processEngineConfiguration) {
282                         Map<String,String> bpmnProps = PropertyConfiguration.getInstance().getProperties("mso.bpmn.properties");
283                         if (bpmnProps == null) {
284                                 LOGGER.debug("Unable to load mso.bpmn.properties; loading URN Mapping from DB");
285                                 
286                                 LOGGER.error (MessageEnum.BPMN_GENERAL_EXCEPTION, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, 
287                                         "Unable to load mso.bpmn.properties; loading URN Mapping from DB");
288                                 
289                                 loadFromDB(execution, processEngineConfiguration);
290                         } else {
291                                 String fsEnabled = bpmnProps.get(FSPROPKEY);
292                                 if (fsEnabled != null) {
293                                         if (Boolean.parseBoolean(fsEnabled)) {
294                                                 LOGGER.debug("File system loading is enabled; loading URN properties from File system");
295                                                 LOGGER.info(MessageEnum.BPMN_GENERAL_INFO,  "BPMN",  "File system loading is enabled; loading URN properties from File System");
296                                                 loadFromFileSystem(execution);
297                                         } else {
298                                                 LOGGER.debug("File system loading is disabled; loading URN properties from DB");
299                                                 LOGGER.info (MessageEnum.BPMN_GENERAL_INFO, "BPMN", "File system loading is disabled; loading URN properties from DB");
300                                                 
301                                                 loadFromDB(execution, processEngineConfiguration);
302                                         }
303                                 } else {
304                                         
305                                         LOGGER.error (MessageEnum.BPMN_GENERAL_EXCEPTION, "BPMN", MsoLogger.getServiceName(), MsoLogger.ErrorCode.UnknownError, 
306                                                 "Unable to retrieve URNMapping.FileSystemLoading.Enabled from mso.bpmn.properties; loading URN Mapping from DB");
307                                         
308                                         loadFromDB(execution, processEngineConfiguration);
309                                 }
310                         }
311                 }
312
313                 private void loadFromFileSystem(DelegateExecution execution) {
314                         PropertyConfiguration propertyConfiguration = PropertyConfiguration.getInstance();
315                         Map<String,String> props = propertyConfiguration.getProperties("mso.bpmn.urn.properties");
316                         for (String key : props.keySet()) {
317                                 String varName = URNMapping.createIdentifierFromURN(key);
318                                 String varValue = props.get(key);
319                                 execution.setVariable(varName, varValue);
320                         }
321                 }
322
323                 private void loadFromDB(DelegateExecution execution, ProcessEngineConfigurationImpl processEngineConfiguration) {
324                         Command<List<URNMapping>> command = new Command<List<URNMapping>>() {
325                                 @SuppressWarnings("unchecked")
326                                 public List<URNMapping> execute(CommandContext commandContext) {
327                                         return (List<URNMapping>) commandContext.getDbSqlSession().selectList(
328                                                 "mso.urnMapping.selectAll", null);
329                                 }
330                         };
331
332                         CustomMyBatisSessionFactory sessionFactory = new CustomMyBatisSessionFactory();
333                         sessionFactory.initFromProcessEngineConfiguration(processEngineConfiguration,
334                                 "customMyBatisConfiguration.xml");
335
336                         List<URNMapping> mappings = sessionFactory.getCommandExecutorTxRequired().execute(command);
337
338                         if (mappings != null && !mappings.isEmpty()) {
339                                 for (URNMapping mapping : mappings) {
340                                         String varName = URNMapping.createIdentifierFromURN(mapping.getName());
341                                         String varValue = mapping.getValue();
342
343                                         LOGGER.debug("URN Mapping = '" + mapping.getName()
344                                                 + "', setting variable '" + varName + "' to '" + varValue + "'");
345
346                                         execution.setVariable(varName, varValue);
347                                 }
348                         }
349                 }
350         }
351
352         /**
353          * Sets the isDebugLogEnabled variable on process entry.
354          */
355         public static class LoggingInitializerListener implements ExecutionListener {
356                 private String event;
357
358                 public LoggingInitializerListener(String eventData) {
359                         this.event = eventData;
360                 }
361
362                 public String getEvent() {
363                         return event;
364                 }
365
366                 @Override
367                 public void notify(DelegateExecution execution) throws Exception {
368                         String processKey = execution.getProcessEngineServices().getRepositoryService()
369                                 .getProcessDefinition(execution.getProcessDefinitionId()).getKey();
370
371                         // If a "true" value is already injected, e.g. from a top-level flow, it SHOULD NOT be
372                         // overridden by the value in the URN mapping. This allows a top-level flow and all
373                         // invoked subflows to be debugged by turning on the debug flag for just the top-level
374                         // flow, assuming the isDebugEnabled flag variable is passed from the top-level flow to
375                         // its subflows.
376
377                         // If a "false" value is already injected, e.g. from a top-level flow, it SHOULD be
378                         // overridden by the value in the URN mapping.  This allows a subflow to be debugged
379                         // without turning on the the debug flag for the top-level flow.
380
381                         String injectedValue = (String) execution.getVariable("isDebugLogEnabled");
382                         String urnValue = "true".equals(execution.getVariable("URN_log_debug_" + processKey)) ? "true" : "false";
383
384                         if ("true".equals(injectedValue)) {
385                                 LOGGER.debug("Setting isDebugLogEnabled to \"" + injectedValue + "\" for process: " + processKey + " (injected value)");
386                                 execution.setVariable("isDebugLogEnabled", injectedValue);
387                         } else {
388                                 LOGGER.debug("Setting isDebugLogEnabled to \"" + urnValue + "\" for process: " + processKey + " (from URN mapping)");
389                                 execution.setVariable("isDebugLogEnabled", urnValue);
390                         }
391                 }
392         }
393         
394         /**
395          * Logs details about the current activity.
396          */
397         public static class LoggingExecutionListener implements ExecutionListener {
398                 private static MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL);
399                 private static ConcurrentHashMap<String, Long> startTimes = new ConcurrentHashMap<>();
400
401                 private String event;
402
403                 public LoggingExecutionListener(String event) {
404                         this.event = event;
405                 }
406
407                 public String getEvent() {
408                         return event;
409                 }
410
411                 public void notify(DelegateExecution execution) throws Exception {
412                         BPMNLogger.debug(
413                                 (String) execution.getVariable("isDebugLogEnabled"),
414                                 "Logging for activity---------------:" + event + ":"
415                                                 + execution.getCurrentActivityName()
416                                                 + ", processDefinitionId="
417                                                 + execution.getProcessDefinitionId() + ", activtyId="
418                                                 + execution.getCurrentActivityId() + ", activtyName='"
419                                                 + execution.getCurrentActivityName() + "'"
420                                                 + ", processInstanceId="
421                                                 + execution.getProcessInstanceId() + ", businessKey="
422                                                 + execution.getProcessBusinessKey() + ", executionId="
423                                                 + execution.getId());
424
425                         if (!isBlank(execution.getCurrentActivityName())) {
426                                 try {
427                                         String id = execution.getId();
428                                         if ("START".equals(event) && id != null ) {
429                                                 startTimes.put(id, (Long)System.currentTimeMillis());
430                                         } else if ("END".equals(event) && id != null) {
431                                                 String prefix = (String) execution.getVariable("prefix");
432
433                                                 if (prefix != null ) {
434                                                         MsoLogger.setServiceName("MSO." + prefix.substring(0,prefix.length()-1));
435                                                 }
436
437                                                 String requestId = (String) execution.getVariable("mso-request-id");
438                                                 String svcid = (String) execution.getVariable("mso-service-instance-id");
439                                                 MsoLogger.setLogContext(requestId, svcid);
440                                                 long startTime = startTimes.remove(id);
441
442                                                 if (startTime != 0) {
443                                                         
444                                                         LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, 
445                                                                         event + ": " + execution.getCurrentActivityName(), "BPMN", execution.getCurrentActivityName(), null);
446                                                         
447                                                 }
448                                         }
449                                 } catch(Exception e) {
450                                         LOGGER.debug("Exception at notify: " + e);
451                                 }
452                         }
453                 }
454
455                 private boolean isBlank(Object object) {
456                         return object == null || "".equals(object.toString().trim());
457                 }
458         }
459 }