2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.mso.bpmn.core.plugins;
23 import java.util.ArrayList;
24 import java.util.List;
26 import java.util.concurrent.ConcurrentHashMap;
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;
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;
52 * Plugin for MSO logging and URN mapping.
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";
60 ProcessEngineConfigurationImpl processEngineConfiguration) {
61 List<BpmnParseListener> preParseListeners = processEngineConfiguration
62 .getCustomPreBPMNParseListeners();
63 if (preParseListeners == null) {
64 preParseListeners = new ArrayList<>();
65 processEngineConfiguration.setCustomPreBPMNParseListeners(preParseListeners);
67 preParseListeners.add(new LoggingParseListener());
71 * Called when a process flow is parsed so we can inject listeners.
73 public static class LoggingParseListener extends AbstractBpmnParseListener {
74 private void injectLogExecutionListener(ActivityImpl activity) {
76 ExecutionListener.EVENTNAME_END,
77 new LoggingExecutionListener("END"));
80 ExecutionListener.EVENTNAME_START,
81 new LoggingExecutionListener("START"));
84 ExecutionListener.EVENTNAME_TAKE,
85 new LoggingExecutionListener("TAKE"));
89 public void parseProcess(Element processElement, ProcessDefinitionEntity processDefinition) {
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"));
100 injectLogExecutionListener(startEventActivity);
104 public void parseServiceTask(Element serviceTaskElement, ScopeImpl scope, ActivityImpl activity) {
105 injectLogExecutionListener(activity);
109 public void parseExclusiveGateway(Element exclusiveGwElement, ScopeImpl scope, ActivityImpl activity) {
110 injectLogExecutionListener(activity);
114 public void parseInclusiveGateway(Element inclusiveGwElement, ScopeImpl scope, ActivityImpl activity) {
115 injectLogExecutionListener(activity);
119 public void parseParallelGateway(Element parallelGwElement, ScopeImpl scope, ActivityImpl activity) {
120 injectLogExecutionListener(activity);
124 public void parseScriptTask(Element scriptTaskElement, ScopeImpl scope, ActivityImpl activity) {
125 injectLogExecutionListener(activity);
129 public void parseBusinessRuleTask(Element businessRuleTaskElement, ScopeImpl scope, ActivityImpl activity) {
130 injectLogExecutionListener(activity);
134 public void parseTask(Element taskElement, ScopeImpl scope, ActivityImpl activity) {
135 injectLogExecutionListener(activity);
139 public void parseManualTask(Element manualTaskElement, ScopeImpl scope, ActivityImpl activity) {
140 injectLogExecutionListener(activity);
144 public void parseUserTask(Element userTaskElement, ScopeImpl scope, ActivityImpl activity) {
145 injectLogExecutionListener(activity);
149 public void parseEndEvent(Element endEventElement, ScopeImpl scope, ActivityImpl activity) {
150 injectLogExecutionListener(activity);
154 public void parseBoundaryTimerEventDefinition(Element timerEventDefinition, boolean interrupting, ActivityImpl timerActivity) {
155 injectLogExecutionListener(timerActivity);
159 public void parseBoundaryErrorEventDefinition(Element errorEventDefinition, boolean interrupting, ActivityImpl activity, ActivityImpl nestedErrorEventActivity) {
160 injectLogExecutionListener(activity);
164 public void parseSubProcess(Element subProcessElement, ScopeImpl scope, ActivityImpl activity) {
165 injectLogExecutionListener(activity);
169 public void parseCallActivity(Element callActivityElement, ScopeImpl scope, ActivityImpl activity) {
170 injectLogExecutionListener(activity);
174 public void parseProperty(Element propertyElement, VariableDeclaration variableDeclaration, ActivityImpl activity) {
175 injectLogExecutionListener(activity);
179 public void parseSequenceFlow(Element sequenceFlowElement, ScopeImpl scopeElement, TransitionImpl transition) {
180 //injectLogExecutionListener(activity);
184 public void parseSendTask(Element sendTaskElement, ScopeImpl scope, ActivityImpl activity) {
185 injectLogExecutionListener(activity);
189 public void parseMultiInstanceLoopCharacteristics(Element activityElement, Element multiInstanceLoopCharacteristicsElement, ActivityImpl activity) {
190 injectLogExecutionListener(activity);
194 public void parseIntermediateTimerEventDefinition(Element timerEventDefinition, ActivityImpl timerActivity) {
195 injectLogExecutionListener(timerActivity);
199 public void parseRootElement(Element rootElement, List<ProcessDefinitionEntity> processDefinitions) {
200 //injectLogExecutionListener(activity);
204 public void parseReceiveTask(Element receiveTaskElement, ScopeImpl scope, ActivityImpl activity) {
205 injectLogExecutionListener(activity);
209 public void parseIntermediateSignalCatchEventDefinition(Element signalEventDefinition, ActivityImpl signalActivity) {
210 injectLogExecutionListener(signalActivity);
214 public void parseBoundarySignalEventDefinition(Element signalEventDefinition, boolean interrupting, ActivityImpl signalActivity) {
215 injectLogExecutionListener(signalActivity);
219 public void parseEventBasedGateway(Element eventBasedGwElement, ScopeImpl scope, ActivityImpl activity) {
220 injectLogExecutionListener(activity);
224 public void parseTransaction(Element transactionElement, ScopeImpl scope, ActivityImpl activity) {
225 injectLogExecutionListener(activity);
229 public void parseCompensateEventDefinition(Element compensateEventDefinition, ActivityImpl compensationActivity) {
230 injectLogExecutionListener(compensationActivity);
234 public void parseIntermediateThrowEvent(Element intermediateEventElement, ScopeImpl scope, ActivityImpl activity) {
235 injectLogExecutionListener(activity);
239 public void parseIntermediateCatchEvent(Element intermediateEventElement, ScopeImpl scope, ActivityImpl activity) {
240 injectLogExecutionListener(activity);
244 public void parseBoundaryEvent(Element boundaryEventElement, ScopeImpl scopeElement, ActivityImpl nestedActivity) {
245 injectLogExecutionListener(nestedActivity);
249 public void parseIntermediateMessageCatchEventDefinition(Element messageEventDefinition, ActivityImpl nestedActivity) {
250 injectLogExecutionListener(nestedActivity);
254 public void parseBoundaryMessageEventDefinition(Element element, boolean interrupting, ActivityImpl messageActivity) {
255 injectLogExecutionListener(messageActivity);
260 * Initializes URN mapping variables on process entry.
262 public static class URNMappingInitializerListener implements ExecutionListener {
263 private String event;
265 public URNMappingInitializerListener(String eventData) {
266 this.event = eventData;
269 public String getEvent() {
274 public void notify(DelegateExecution execution) throws Exception {
275 ProcessEngineConfigurationImpl processEngineConfiguration =
276 Context.getProcessEngineConfiguration();
277 loadURNProperties(execution, processEngineConfiguration);
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");
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");
289 loadFromDB(execution, processEngineConfiguration);
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);
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");
301 loadFromDB(execution, processEngineConfiguration);
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");
308 loadFromDB(execution, processEngineConfiguration);
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);
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);
332 CustomMyBatisSessionFactory sessionFactory = new CustomMyBatisSessionFactory();
333 sessionFactory.initFromProcessEngineConfiguration(processEngineConfiguration,
334 "customMyBatisConfiguration.xml");
336 List<URNMapping> mappings = sessionFactory.getCommandExecutorTxRequired().execute(command);
338 if (mappings != null && !mappings.isEmpty()) {
339 for (URNMapping mapping : mappings) {
340 String varName = URNMapping.createIdentifierFromURN(mapping.getName());
341 String varValue = mapping.getValue();
343 LOGGER.debug("URN Mapping = '" + mapping.getName()
344 + "', setting variable '" + varName + "' to '" + varValue + "'");
346 execution.setVariable(varName, varValue);
353 * Sets the isDebugLogEnabled variable on process entry.
355 public static class LoggingInitializerListener implements ExecutionListener {
356 private String event;
358 public LoggingInitializerListener(String eventData) {
359 this.event = eventData;
362 public String getEvent() {
367 public void notify(DelegateExecution execution) throws Exception {
368 String processKey = execution.getProcessEngineServices().getRepositoryService()
369 .getProcessDefinition(execution.getProcessDefinitionId()).getKey();
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
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.
381 String injectedValue = (String) execution.getVariable("isDebugLogEnabled");
382 String urnValue = "true".equals(execution.getVariable("URN_log_debug_" + processKey)) ? "true" : "false";
384 if ("true".equals(injectedValue)) {
385 LOGGER.debug("Setting isDebugLogEnabled to \"" + injectedValue + "\" for process: " + processKey + " (injected value)");
386 execution.setVariable("isDebugLogEnabled", injectedValue);
388 LOGGER.debug("Setting isDebugLogEnabled to \"" + urnValue + "\" for process: " + processKey + " (from URN mapping)");
389 execution.setVariable("isDebugLogEnabled", urnValue);
395 * Logs details about the current activity.
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<>();
401 private String event;
403 public LoggingExecutionListener(String event) {
407 public String getEvent() {
411 public void notify(DelegateExecution execution) throws Exception {
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());
425 if (!isBlank(execution.getCurrentActivityName())) {
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");
433 if (prefix != null ) {
434 MsoLogger.setServiceName("MSO." + prefix.substring(0,prefix.length()-1));
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);
442 if (startTime != 0) {
444 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
445 event + ": " + execution.getCurrentActivityName(), "BPMN", execution.getCurrentActivityName(), null);
449 } catch(Exception e) {
450 LOGGER.debug("Exception at notify: " + e);
455 private boolean isBlank(Object object) {
456 return object == null || "".equals(object.toString().trim());