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<BpmnParseListener>();
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"));
88 public void parseProcess(Element processElement, ProcessDefinitionEntity processDefinition) {
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"));
98 injectLogExecutionListener(startEventActivity);
101 public void parseServiceTask(Element serviceTaskElement, ScopeImpl scope, ActivityImpl activity) {
102 injectLogExecutionListener(activity);
105 public void parseExclusiveGateway(Element exclusiveGwElement, ScopeImpl scope, ActivityImpl activity) {
106 injectLogExecutionListener(activity);
109 public void parseInclusiveGateway(Element inclusiveGwElement, ScopeImpl scope, ActivityImpl activity) {
110 injectLogExecutionListener(activity);
113 public void parseParallelGateway(Element parallelGwElement, ScopeImpl scope, ActivityImpl activity) {
114 injectLogExecutionListener(activity);
117 public void parseScriptTask(Element scriptTaskElement, ScopeImpl scope, ActivityImpl activity) {
118 injectLogExecutionListener(activity);
121 public void parseBusinessRuleTask(Element businessRuleTaskElement, ScopeImpl scope, ActivityImpl activity) {
122 injectLogExecutionListener(activity);
125 public void parseTask(Element taskElement, ScopeImpl scope, ActivityImpl activity) {
126 injectLogExecutionListener(activity);
129 public void parseManualTask(Element manualTaskElement, ScopeImpl scope, ActivityImpl activity) {
130 injectLogExecutionListener(activity);
133 public void parseUserTask(Element userTaskElement, ScopeImpl scope, ActivityImpl activity) {
134 injectLogExecutionListener(activity);
137 public void parseEndEvent(Element endEventElement, ScopeImpl scope, ActivityImpl activity) {
138 injectLogExecutionListener(activity);
141 public void parseBoundaryTimerEventDefinition(Element timerEventDefinition, boolean interrupting, ActivityImpl timerActivity) {
142 injectLogExecutionListener(timerActivity);
145 public void parseBoundaryErrorEventDefinition(Element errorEventDefinition, boolean interrupting, ActivityImpl activity, ActivityImpl nestedErrorEventActivity) {
146 injectLogExecutionListener(activity);
149 public void parseSubProcess(Element subProcessElement, ScopeImpl scope, ActivityImpl activity) {
150 injectLogExecutionListener(activity);
153 public void parseCallActivity(Element callActivityElement, ScopeImpl scope, ActivityImpl activity) {
154 injectLogExecutionListener(activity);
157 public void parseProperty(Element propertyElement, VariableDeclaration variableDeclaration, ActivityImpl activity) {
158 injectLogExecutionListener(activity);
161 public void parseSequenceFlow(Element sequenceFlowElement, ScopeImpl scopeElement, TransitionImpl transition) {
162 //injectLogExecutionListener(activity);
165 public void parseSendTask(Element sendTaskElement, ScopeImpl scope, ActivityImpl activity) {
166 injectLogExecutionListener(activity);
169 public void parseMultiInstanceLoopCharacteristics(Element activityElement, Element multiInstanceLoopCharacteristicsElement, ActivityImpl activity) {
170 injectLogExecutionListener(activity);
173 public void parseIntermediateTimerEventDefinition(Element timerEventDefinition, ActivityImpl timerActivity) {
174 injectLogExecutionListener(timerActivity);
177 public void parseRootElement(Element rootElement, List<ProcessDefinitionEntity> processDefinitions) {
178 //injectLogExecutionListener(activity);
181 public void parseReceiveTask(Element receiveTaskElement, ScopeImpl scope, ActivityImpl activity) {
182 injectLogExecutionListener(activity);
185 public void parseIntermediateSignalCatchEventDefinition(Element signalEventDefinition, ActivityImpl signalActivity) {
186 injectLogExecutionListener(signalActivity);
189 public void parseBoundarySignalEventDefinition(Element signalEventDefinition, boolean interrupting, ActivityImpl signalActivity) {
190 injectLogExecutionListener(signalActivity);
193 public void parseEventBasedGateway(Element eventBasedGwElement, ScopeImpl scope, ActivityImpl activity) {
194 injectLogExecutionListener(activity);
197 public void parseTransaction(Element transactionElement, ScopeImpl scope, ActivityImpl activity) {
198 injectLogExecutionListener(activity);
201 public void parseCompensateEventDefinition(Element compensateEventDefinition, ActivityImpl compensationActivity) {
202 injectLogExecutionListener(compensationActivity);
205 public void parseIntermediateThrowEvent(Element intermediateEventElement, ScopeImpl scope, ActivityImpl activity) {
206 injectLogExecutionListener(activity);
209 public void parseIntermediateCatchEvent(Element intermediateEventElement, ScopeImpl scope, ActivityImpl activity) {
210 injectLogExecutionListener(activity);
213 public void parseBoundaryEvent(Element boundaryEventElement, ScopeImpl scopeElement, ActivityImpl nestedActivity) {
214 injectLogExecutionListener(nestedActivity);
217 public void parseIntermediateMessageCatchEventDefinition(Element messageEventDefinition, ActivityImpl nestedActivity) {
218 injectLogExecutionListener(nestedActivity);
221 public void parseBoundaryMessageEventDefinition(Element element, boolean interrupting, ActivityImpl messageActivity) {
222 injectLogExecutionListener(messageActivity);
227 * Initializes URN mapping variables on process entry.
229 public static class URNMappingInitializerListener implements ExecutionListener {
230 private String event;
232 public URNMappingInitializerListener(String eventData) {
233 this.event = eventData;
236 public String getEvent() {
240 public void notify(DelegateExecution execution) throws Exception {
241 ProcessEngineConfigurationImpl processEngineConfiguration =
242 Context.getProcessEngineConfiguration();
243 loadURNProperties(execution, processEngineConfiguration);
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");
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");
255 loadFromDB(execution, processEngineConfiguration);
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);
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");
267 loadFromDB(execution, processEngineConfiguration);
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");
274 loadFromDB(execution, processEngineConfiguration);
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);
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);
298 CustomMyBatisSessionFactory sessionFactory = new CustomMyBatisSessionFactory();
299 sessionFactory.initFromProcessEngineConfiguration(processEngineConfiguration,
300 "customMyBatisConfiguration.xml");
302 List<URNMapping> mappings = sessionFactory.getCommandExecutorTxRequired().execute(command);
304 if (mappings != null && mappings.size() > 0) {
305 for (URNMapping mapping : mappings) {
306 String varName = URNMapping.createIdentifierFromURN(mapping.getName());
307 String varValue = mapping.getValue();
309 LOGGER.debug("URN Mapping = '" + mapping.getName()
310 + "', setting variable '" + varName + "' to '" + varValue + "'");
312 execution.setVariable(varName, varValue);
319 * Sets the isDebugLogEnabled variable on process entry.
321 public static class LoggingInitializerListener implements ExecutionListener {
322 private String event;
324 public LoggingInitializerListener(String eventData) {
325 this.event = eventData;
328 public String getEvent() {
332 public void notify(DelegateExecution execution) throws Exception {
333 String processKey = execution.getProcessEngineServices().getRepositoryService()
334 .getProcessDefinition(execution.getProcessDefinitionId()).getKey();
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
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.
346 String injectedValue = (String) execution.getVariable("isDebugLogEnabled");
347 String urnValue = "true".equals(execution.getVariable("URN_log_debug_" + processKey)) ? "true" : "false";
349 if ("true".equals(injectedValue)) {
350 LOGGER.debug("Setting isDebugLogEnabled to \"" + injectedValue + "\" for process: " + processKey + " (injected value)");
351 execution.setVariable("isDebugLogEnabled", injectedValue);
353 LOGGER.debug("Setting isDebugLogEnabled to \"" + urnValue + "\" for process: " + processKey + " (from URN mapping)");
354 execution.setVariable("isDebugLogEnabled", urnValue);
360 * Logs details about the current activity.
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>();
366 private String event;
368 public LoggingExecutionListener(String event) {
372 public String getEvent() {
376 public void notify(DelegateExecution execution) throws Exception {
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());
390 if (!isBlank(execution.getCurrentActivityName())) {
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");
398 if (prefix != null ) {
399 MsoLogger.setServiceName("MSO." + prefix.substring(0,prefix.length()-1));
402 String requestId = (String) execution.getVariable("att-mso-request-id");
403 String svcid = (String) execution.getVariable("att-mso-service-instance-id");
404 MsoLogger.setLogContext(requestId, svcid);
405 long startTime = startTimes.remove(id);
407 if (startTime != 0) {
409 LOGGER.recordMetricEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc,
410 event + ": " + execution.getCurrentActivityName(), "BPMN", execution.getCurrentActivityName(), null);
414 } catch(Exception e) {
420 private boolean isBlank(Object object) {
421 return object == null || object.toString().trim().equals("");