/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.kie.workbench.common.stunner.bpmn.backend.marshall.json.oryx;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.kie.workbench.common.stunner.bpmn.definition.BPMNDiagram;
import org.kie.workbench.common.stunner.bpmn.definition.BusinessRuleTask;
import org.kie.workbench.common.stunner.bpmn.definition.EndNoneEvent;
import org.kie.workbench.common.stunner.bpmn.definition.EndTerminateEvent;
import org.kie.workbench.common.stunner.bpmn.definition.ExclusiveDatabasedGateway;
import org.kie.workbench.common.stunner.bpmn.definition.IntermediateTimerEvent;
import org.kie.workbench.common.stunner.bpmn.definition.NoneTask;
import org.kie.workbench.common.stunner.bpmn.definition.ReusableSubprocess;
import org.kie.workbench.common.stunner.bpmn.definition.ScriptTask;
import org.kie.workbench.common.stunner.bpmn.definition.StartNoneEvent;
import org.kie.workbench.common.stunner.bpmn.definition.StartSignalEvent;
import org.kie.workbench.common.stunner.bpmn.definition.StartTimerEvent;
import org.kie.workbench.common.stunner.bpmn.definition.UserTask;
import org.kie.workbench.common.stunner.bpmn.definition.property.connectors.ConditionExpression;
import org.kie.workbench.common.stunner.bpmn.definition.property.connectors.ConditionExpressionLanguage;
import org.kie.workbench.common.stunner.bpmn.definition.property.connectors.Priority;
import org.kie.workbench.common.stunner.bpmn.definition.property.dataio.AssignmentsInfo;
import org.kie.workbench.common.stunner.bpmn.definition.property.diagram.AdHoc;
import org.kie.workbench.common.stunner.bpmn.definition.property.diagram.ProcessInstanceDescription;
import org.kie.workbench.common.stunner.bpmn.definition.property.event.IsInterrupting;
import org.kie.workbench.common.stunner.bpmn.definition.property.event.SignalRef;
import org.kie.workbench.common.stunner.bpmn.definition.property.event.TimeCycle;
import org.kie.workbench.common.stunner.bpmn.definition.property.event.TimeCycleLanguage;
import org.kie.workbench.common.stunner.bpmn.definition.property.event.TimeDate;
import org.kie.workbench.common.stunner.bpmn.definition.property.event.TimeDuration;
import org.kie.workbench.common.stunner.bpmn.definition.property.gateway.DefaultRoute;
import org.kie.workbench.common.stunner.bpmn.definition.property.general.Name;
import org.kie.workbench.common.stunner.bpmn.definition.property.simulation.DistributionType;
import org.kie.workbench.common.stunner.bpmn.definition.property.simulation.StandardDeviation;
import org.kie.workbench.common.stunner.bpmn.definition.property.simulation.TimeUnit;
import org.kie.workbench.common.stunner.bpmn.definition.property.simulation.UnitCost;
import org.kie.workbench.common.stunner.bpmn.definition.property.simulation.WorkingHours;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.AdHocAutostart;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.CalledElement;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.CreatedBy;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.Description;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.IsAsync;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.OnEntryAction;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.OnExitAction;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.RuleFlowGroup;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.ScriptLanguage;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.Skippable;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.Subject;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.TaskName;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.TaskType;
import org.kie.workbench.common.stunner.bpmn.definition.property.task.WaitForCompletion;
import org.kie.workbench.common.stunner.bpmn.definition.property.variables.ProcessVariables;
import org.kie.workbench.common.stunner.core.api.DefinitionManager;
import org.kie.workbench.common.stunner.core.definition.adapter.binding.BindableAdapterUtils;
/**
* This class contains the mappings for the different stencil identifiers that are different from
* the patterns used in this tool.
*/
public abstract class BaseOryxIdMappings implements OryxIdMappings {
private final DefinitionManager definitionManager;
private final Map<Class<?>, String> defMappings = new HashMap<>();
private final Map<Class<?>, String> globalMappings = getGlobalMappings();
private final Map<Class<?>, String> customMappings = getCustomMappings();
private final Map<Class<?>, Set<String>> skippedProperties = getSkippedProperties();
private final Map<Class<?>, Map<Class<?>, String>> definitionMappings = getDefinitionMappings();
protected BaseOryxIdMappings() {
this(null);
}
public BaseOryxIdMappings(final DefinitionManager definitionManager) {
this.definitionManager = definitionManager;
}
protected abstract Class<? extends BPMNDiagram> getDiagramType();
@Override
public void init(final List<Class<?>> definitions) {
// Load default & custom mappings for BPMN definitions.
for (final Class<?> defClass : definitions) {
String customMapping = customMappings.get(defClass);
customMapping = customMapping != null ? customMapping : globalMappings.get(defClass);
final String orxId = customMapping != null ? customMapping : getDefaultOryxDefinitionId(defClass);
defMappings.put(defClass,
orxId);
}
}
@Override
public Map<Class<?>, String> getGlobalMappings() {
final Map<Class<?>, String> globalMappings = new HashMap<Class<?>, String>() {{
put(getDiagramType(),
"BPMNDiagram");
// Add here global class <-> oryxId mappings, if any.
put(Name.class,
"name");
put(TaskType.class,
"tasktype");
put(NoneTask.class,
"Task");
put(UserTask.class,
"Task");
put(ScriptTask.class,
"Task");
put(BusinessRuleTask.class,
"Task");
put(RuleFlowGroup.class,
"ruleflowgroup");
put(CalledElement.class,
"calledelement");
put(ScriptLanguage.class,
"script_language");
put(ConditionExpression.class,
"conditionexpression");
put(ConditionExpressionLanguage.class,
"conditionexpressionlanguage");
put(Priority.class,
"priority");
put(ExclusiveDatabasedGateway.class,
"Exclusive_Databased_Gateway");
put(TimeDate.class,
"timedate");
put(TimeDuration.class,
"timeduration");
put(TimeCycle.class,
"timecycle");
put(TimeCycleLanguage.class,
"timecyclelanguage");
put(AdHoc.class,
"adhocprocess");
put(ProcessInstanceDescription.class,
"customdescription");
put(WaitForCompletion.class,
"waitforcompletion");
put(IsAsync.class,
"isasync");
put(Skippable.class,
"skippable");
put(Subject.class,
"subject");
put(Description.class,
"description");
put(CreatedBy.class,
"createdby");
put(AdHocAutostart.class,
"customautostart");
put(OnEntryAction.class,
"onentryactions");
put(OnExitAction.class,
"onexitactions");
put(IsInterrupting.class,
"isinterrupting");
put(SignalRef.class,
"signalref");
// Simulation properties
put(TimeUnit.class,
"timeunit");
put(StandardDeviation.class,
"standarddeviation");
put(DistributionType.class,
"distributiontype");
put(WorkingHours.class,
"workinghours");
put(UnitCost.class,
"unitcost");
}};
return globalMappings;
}
@Override
public Map<Class<?>, String> getCustomMappings() {
// No custom mappings, for now.
return Collections.emptyMap();
}
@Override
public Map<Class<?>, Set<String>> getSkippedProperties() {
final Map<Class<?>, Set<String>> skippedProperties = new HashMap<Class<?>, Set<String>>() {{
// Add here global class <-> collection oryx property identifiers to skip processing, if any.
put(getDiagramType(),
new HashSet<String>() {{
add("name");
}});
}};
return skippedProperties;
}
@Override
public Map<Class<?>, Map<Class<?>, String>> getDefinitionMappings() {
final Map<Class<?>, Map<Class<?>, String>> definitionMappings = new HashMap<Class<?>, Map<Class<?>, String>>() {{
// Add here class <-> oryxId mappings just for a concrete definition (stencil), if any.
Map<Class<?>, String> diagramPropertiesMap = new HashMap<Class<?>, String>();
put(getDiagramType(),
diagramPropertiesMap);
// The name property in the diagram stencil is "processn".
diagramPropertiesMap.put(Name.class,
"processn");
// The process variables property in the diagram stencil is "vardefs".
diagramPropertiesMap.put(ProcessVariables.class,
"vardefs");
Map<Class<?>, String> userTaskPropertiesMap = new HashMap<Class<?>, String>();
put(UserTask.class,
userTaskPropertiesMap);
userTaskPropertiesMap.put(AssignmentsInfo.class,
"assignmentsinfo");
userTaskPropertiesMap.put(TaskName.class,
"taskname");
Map<Class<?>, String> businesRuleTaskPropertiesMap = new HashMap<Class<?>, String>();
put(BusinessRuleTask.class,
businesRuleTaskPropertiesMap);
businesRuleTaskPropertiesMap.put(AssignmentsInfo.class,
"assignmentsinfo");
Map<Class<?>, String> startNoneEventPropertiesMap = new HashMap<Class<?>, String>();
put(StartNoneEvent.class,
startNoneEventPropertiesMap);
startNoneEventPropertiesMap.put(AssignmentsInfo.class,
"assignmentsinfo");
Map<Class<?>, String> startSignalEventPropertiesMap = new HashMap<Class<?>, String>();
put(StartSignalEvent.class,
startSignalEventPropertiesMap);
startSignalEventPropertiesMap.put(AssignmentsInfo.class,
"assignmentsinfo");
Map<Class<?>, String> startTimerEventPropertiesMap = new HashMap<Class<?>, String>();
put(StartTimerEvent.class,
startTimerEventPropertiesMap);
startTimerEventPropertiesMap.put(AssignmentsInfo.class,
"assignmentsinfo");
Map<Class<?>, String> intermediateTimerEventPropertiesMap = new HashMap<Class<?>, String>();
put(IntermediateTimerEvent.class,
intermediateTimerEventPropertiesMap);
intermediateTimerEventPropertiesMap.put(AssignmentsInfo.class,
"assignmentsinfo");
Map<Class<?>, String> endEventPropertiesMap = new HashMap<Class<?>, String>();
put(EndNoneEvent.class,
endEventPropertiesMap);
put(EndTerminateEvent.class,
endEventPropertiesMap);
endEventPropertiesMap.put(AssignmentsInfo.class,
"assignmentsinfo");
Map<Class<?>, String> reusableSubprocessPropertiesMap = new HashMap<Class<?>, String>();
put(ReusableSubprocess.class,
reusableSubprocessPropertiesMap);
reusableSubprocessPropertiesMap.put(AssignmentsInfo.class,
"assignmentsinfo");
Map<Class<?>, String> exclusiveDatabasedGatewayPropertiesMap = new HashMap<Class<?>, String>();
put(ExclusiveDatabasedGateway.class,
exclusiveDatabasedGatewayPropertiesMap);
exclusiveDatabasedGatewayPropertiesMap.put(DefaultRoute.class,
"defaultgate");
}};
return definitionMappings;
}
@Override
public String getOryxDefinitionId(final Class<?> clazz) {
return defMappings.get(clazz);
}
@Override
public String getOryxPropertyId(final Class<?> clazz) {
String mapping = customMappings.get(clazz);
mapping = mapping != null ? mapping : globalMappings.get(clazz);
return mapping != null ? mapping : getDefaultOryxPropertyId(clazz);
}
@Override
public String getOryxPropertyId(final Class<?> definitionClass,
final Class<?> clazz) {
Map<Class<?>, String> mappings = definitionMappings.get(definitionClass);
if (null != mappings) {
String r = mappings.get(clazz);
if (null != r) {
return r;
}
}
return getOryxPropertyId(clazz);
}
@Override
public boolean isSkipProperty(final Class<?> definitionClass,
final String oryxPropertyId) {
Set<String> toSkip = skippedProperties.get(definitionClass);
return toSkip != null && toSkip.contains(oryxPropertyId);
}
@Override
@SuppressWarnings("unchecked")
public <T> Class<?> getProperty(final T definition,
final String oryxId) {
Class<?> clazz = getKey(oryxId,
customMappings);
if (null != clazz) {
return clazz;
}
clazz = getKey(oryxId,
globalMappings);
if (null != clazz) {
return clazz;
}
Set<Object> properties = (Set<Object>) definitionManager.adapters().forDefinition().getProperties(definition);
if (null != properties && !properties.isEmpty()) {
for (Object property : properties) {
Class<?> pClass = property.getClass();
String pId = getDefaultOryxPropertyId(pClass);
if (oryxId.equals(pId)) {
return pClass;
}
}
}
return null;
}
@Override
public Class<?> getDefinition(final String oryxId) {
return get(oryxId,
defMappings);
}
@Override
public <T> String getPropertyId(final T definition,
final String oryxId) {
Class<?> definitionClass = definition.getClass();
Map<Class<?>, String> mappings = definitionMappings.get(definitionClass);
if (null != mappings) {
Class<?> p = get(oryxId,
mappings);
if (null != p) {
return getPropertyId(p);
}
}
Class<?> c = getProperty(definition,
oryxId);
return null != c ? getPropertyId(c) : null;
}
@Override
public String getDefinitionId(final String oryxId) {
Class<?> c = getDefinition(oryxId);
return null != c ? getDefinitionId(c) : null;
}
@Override
public String getPropertyId(final Class<?> clazz) {
return BindableAdapterUtils.getPropertyId(clazz);
}
@Override
public String getDefinitionId(final Class<?> clazz) {
return BindableAdapterUtils.getDefinitionId(clazz);
}
private Class<?> get(final String oryxId,
final Map<Class<?>, String> map) {
Class<?> r = getKey(oryxId,
map);
if (null != r) {
return r;
}
return null;
}
private Class<?> getKey(final String value,
final Map<Class<?>, String> map) {
Set<Map.Entry<Class<?>, String>> entrySet = map.entrySet();
for (Map.Entry<Class<?>, String> entry : entrySet) {
String oId = entry.getValue();
if (oId.equals(value)) {
return entry.getKey();
}
}
return null;
}
private String getDefaultOryxDefinitionId(final Class<?> clazz) {
return clazz.getSimpleName();
}
private String getDefaultOryxPropertyId(final Class<?> clazz) {
return StringUtils.uncapitalize(clazz.getSimpleName());
}
}