blob: d5fc3ba871d3b655828f54bb74d4caf6dc7517ef [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2012 Red Hat, Inc.
* All rights reserved.
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*
* @author Bob Brodt
******************************************************************************/
package org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.features;
import java.util.Hashtable;
import java.util.List;
import java.util.Map.Entry;
import org.eclipse.bpmn2.Assignment;
import org.eclipse.bpmn2.BaseElement;
import org.eclipse.bpmn2.DataInput;
import org.eclipse.bpmn2.DataInputAssociation;
import org.eclipse.bpmn2.DataOutput;
import org.eclipse.bpmn2.FormalExpression;
import org.eclipse.bpmn2.InputOutputSpecification;
import org.eclipse.bpmn2.InputSet;
import org.eclipse.bpmn2.ItemDefinition;
import org.eclipse.bpmn2.ItemKind;
import org.eclipse.bpmn2.OutputSet;
import org.eclipse.bpmn2.Task;
import org.eclipse.bpmn2.modeler.core.IBpmn2RuntimeExtension;
import org.eclipse.bpmn2.modeler.core.adapters.ExtendedPropertiesAdapter;
import org.eclipse.bpmn2.modeler.core.features.CustomElementFeatureContainer;
import org.eclipse.bpmn2.modeler.core.features.CustomShapeFeatureContainer;
import org.eclipse.bpmn2.modeler.core.features.IShapeFeatureContainer;
import org.eclipse.bpmn2.modeler.core.model.Bpmn2ModelerFactory;
import org.eclipse.bpmn2.modeler.core.model.ModelDecorator;
import org.eclipse.bpmn2.modeler.core.runtime.ModelExtensionDescriptor.Property;
import org.eclipse.bpmn2.modeler.core.runtime.TargetRuntime;
import org.eclipse.bpmn2.modeler.core.utils.BusinessObjectUtil;
import org.eclipse.bpmn2.modeler.core.utils.JavaProjectClassLoader;
import org.eclipse.bpmn2.modeler.core.utils.ModelUtil;
import org.eclipse.bpmn2.modeler.core.utils.ShapeDecoratorUtil;
import org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.JBPM5RuntimeExtension;
import org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.features.JbpmTaskFeatureContainer.JbpmAddTaskFeature;
import org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.util.JbpmModelUtil;
import org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.wid.WorkItemDefinition;
import org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.wid.WorkItemDefinition.Parameter;
import org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.wid.editor.DroolsProxy;
import org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.wid.editor.ParameterDefinition;
import org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.wid.editor.Work;
import org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.wid.editor.WorkDefinition;
import org.eclipse.bpmn2.modeler.runtime.jboss.jbpm5.wid.editor.WorkItemEditor;
import org.eclipse.bpmn2.modeler.ui.ImageProvider;
import org.eclipse.bpmn2.modeler.ui.editor.BPMN2Editor;
import org.eclipse.bpmn2.modeler.ui.features.activity.task.TaskFeatureContainer;
import org.eclipse.bpmn2.modeler.ui.features.activity.task.TaskFeatureContainer.CreateTaskFeature;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.graphiti.features.IAddFeature;
import org.eclipse.graphiti.features.ICreateFeature;
import org.eclipse.graphiti.features.IFeatureProvider;
import org.eclipse.graphiti.features.context.IAddContext;
import org.eclipse.graphiti.features.context.IContext;
import org.eclipse.graphiti.features.context.ICreateContext;
import org.eclipse.graphiti.features.context.ICustomContext;
import org.eclipse.graphiti.features.custom.ICustomFeature;
import org.eclipse.graphiti.mm.pictograms.ContainerShape;
import org.eclipse.graphiti.mm.pictograms.PictogramElement;
import org.eclipse.graphiti.services.Graphiti;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class JbpmCustomTaskFeatureContainer extends CustomShapeFeatureContainer {
@Override
protected IShapeFeatureContainer createFeatureContainer(IFeatureProvider fp) {
return new TaskFeatureContainer() {
@Override
public ICreateFeature getCreateFeature(IFeatureProvider fp) {
return new JbpmCreateCustomTaskFeature(fp);
}
@Override
public IAddFeature getAddFeature(IFeatureProvider fp) {
return new JbpmAddCustomTaskFeature(fp);
}
};
}
protected class JbpmCreateCustomTaskFeature extends CreateTaskFeature {
public JbpmCreateCustomTaskFeature(IFeatureProvider fp) {
super(fp);
}
@Override
public String getCreateImageId() {
final String iconPath = (String) customTaskDescriptor.getPropertyValue("icon"); //$NON-NLS-1$
if (iconPath != null && iconPath.trim().length() > 0) {
return iconPath.trim();
}
return null;
}
@Override
public String getCreateLargeImageId() {
return getCreateImageId();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public Task createBusinessObject(ICreateContext context) {
Task task = super.createBusinessObject(context);
final String name = customTaskDescriptor.getName();
if (name!=null && !name.isEmpty()) {
task.setName(name.trim());
}
// make sure the ioSpecification has both a default InputSet and OutputSet
InputOutputSpecification ioSpecification = task.getIoSpecification();
if (ioSpecification!=null) {
Resource resource = getResource(context);
if (ioSpecification.getInputSets().size()==0) {
InputSet is = Bpmn2ModelerFactory.createObject(resource, InputSet.class);
ioSpecification.getInputSets().add(is);
}
if (ioSpecification.getOutputSets().size()==0) {
OutputSet os = Bpmn2ModelerFactory.createObject(resource, OutputSet.class);
ioSpecification.getOutputSets().add(os);
}
}
// Create the ItemDefinitions for each I/O parameter if needed
JBPM5RuntimeExtension rx = (JBPM5RuntimeExtension)customTaskDescriptor.getRuntime().getRuntimeExtension();
String id = customTaskDescriptor.getId();
WorkItemDefinition wid = rx.getWorkItemDefinition(id);
if (ioSpecification!=null && wid!=null) {
for (DataInput input : ioSpecification.getDataInputs()) {
for (Entry<String, Parameter> entry : wid.getParameters().entrySet()) {
if (input.getName().equals(entry.getKey())) {
if (entry.getValue()!=null)
input.setItemSubjectRef(JbpmModelUtil.getDataType(context.getTargetContainer(), entry.getValue()));
break;
}
}
}
for (DataOutput output : ioSpecification.getDataOutputs()) {
for (Entry<String, Parameter> entry : wid.getResults().entrySet()) {
if (output.getName().equals(entry.getKey())) {
if (entry.getValue()!=null)
output.setItemSubjectRef(JbpmModelUtil.getDataType(context.getTargetContainer(), entry.getValue()));
break;
}
}
}
}
return task;
}
}
protected class JbpmAddCustomTaskFeature extends JbpmAddTaskFeature {
public JbpmAddCustomTaskFeature(IFeatureProvider fp) {
super(fp);
}
@Override
protected void decorateShape(IAddContext context, ContainerShape containerShape, Task businessObject) {
super.decorateShape(context, containerShape, businessObject);
final String iconPath = (String) customTaskDescriptor.getPropertyValue("icon"); //$NON-NLS-1$
ShapeDecoratorUtil.createActivityImage(containerShape, iconPath);
}
}
public String getId(EObject object) {
if (object==null)
return null;
List<EStructuralFeature> features = ModelDecorator.getAnyAttributes(object);
for (EStructuralFeature f : features) {
if ("taskName".equals(f.getName())) { //$NON-NLS-1$
Object attrValue = object.eGet(f);
if (attrValue!=null) {
// search the extension attributes for a "taskName" and compare it
// against the new object's taskName value
for (Property p : customTaskDescriptor.getProperties()) {
String propValue = p.getFirstStringValue();
if (attrValue.equals(propValue))
return getId();
}
}
}
}
return null;
}
@Override
public ICustomFeature[] getCustomFeatures(IFeatureProvider fp) {
ICustomFeature[] superFeatures = super.getCustomFeatures(fp);
ICustomFeature[] thisFeatures = new ICustomFeature[superFeatures.length + 1];
int i = 0;
while (i<superFeatures.length)
thisFeatures[i] = superFeatures[i++];
thisFeatures[i] = new ConfigureWorkItemFeature(fp);
return thisFeatures;
}
private static JavaProjectClassLoader getProjectClassLoader(BaseElement baseElement) {
Resource res = ExtendedPropertiesAdapter.getResource(baseElement);
URI uri = res.getURI();
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(uri.segment(1));
JavaProjectClassLoader cl = new JavaProjectClassLoader(project);
return cl;
}
/**
* Returns the Java class that implements a Work Item Editor dialog for the
* given BaseElement if the WID file defines one.
*
* @param task
* @return a Work Item Editor dialog class or null if the BaseElement is not
* a custom task (defined by a WID file) or if the WID file does
* declare a "eclipse:customEditor" class.
*
* TODO: make this return an object instance and make sure it implements
* the {@code WorkEditor} interface.
*/
@SuppressWarnings("rawtypes")
private static WorkItemEditor getWorkItemEditor(Task task) {
String customTaskId = CustomElementFeatureContainer.findId(task);
TargetRuntime rt = TargetRuntime.getRuntime(task);
JBPM5RuntimeExtension rte = (JBPM5RuntimeExtension)rt.getRuntimeExtension();
WorkItemDefinition wid = ((JBPM5RuntimeExtension)rte).getWorkItemDefinition(customTaskId);
Dialog dialog = null;
WorkItemEditor workItemEditor = null;
if (wid!=null) {
String customEditor = wid.getEclipseCustomEditor();
if (customEditor!=null && !customEditor.isEmpty()) {
workItemEditor = WorkItemEditor.create(wid, task);
if (workItemEditor!=null) {
// set actual parameter values from Task object here...
for (Entry<String, Parameter> entry : wid.getParameters().entrySet()) {
ParameterDefinition parameterDefinition = workItemEditor.getParameter(entry.getKey());
Parameter parameter = entry.getValue();
parameterDefinition.setType(parameter.type);
}
for (Entry<String, Parameter> entry : wid.getResults().entrySet()) {
ParameterDefinition parameterDefinition = workItemEditor.getResult(entry.getKey());
Parameter parameter = entry.getValue();
parameterDefinition.setType(parameter.type);
}
}
}
}
return workItemEditor;
}
public class ConfigureWorkItemFeature implements ICustomFeature {
protected IFeatureProvider fp;
boolean hasChanges = false;
/**
* @param fp
*/
public ConfigureWorkItemFeature(IFeatureProvider fp) {
this.fp = fp;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.IFeature#isAvailable(org.eclipse.graphiti.features.context.IContext)
*/
@Override
public boolean isAvailable(IContext context) {
PictogramElement[] pes = ((ICustomContext)context).getPictogramElements();
if (pes.length==1) {
BaseElement be = BusinessObjectUtil.getFirstBaseElement(pes[0]);
String id = getId(be);
return id!=null;
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.custom.ICustomFeature#canExecute(org.eclipse.graphiti.features.context.ICustomContext)
*/
@Override
public boolean canExecute(ICustomContext context) {
return canExecute((IContext)context);
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.IFeature#canExecute(org.eclipse.graphiti.features.context.IContext)
*/
@Override
public boolean canExecute(IContext context) {
BPMN2Editor editor = (BPMN2Editor)getFeatureProvider().getDiagramTypeProvider().getDiagramBehavior().getDiagramContainer();
IBpmn2RuntimeExtension rte = editor.getTargetRuntime().getRuntimeExtension();
if (rte instanceof JBPM5RuntimeExtension && context instanceof ICustomContext) {
PictogramElement[] pes = ((ICustomContext) context).getPictogramElements();
if (pes.length==1) {
Object o = Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(pes[0]);
if (o instanceof Task) {
Task task = (Task)o;
List<EStructuralFeature> features = ModelDecorator.getAnyAttributes(task);
for (EStructuralFeature f : features) {
if ("taskName".equals(f.getName())) { //$NON-NLS-1$
// make sure the Work Item Definition exists
String taskName = (String)task.eGet(f);
WorkItemDefinition wid = ((JBPM5RuntimeExtension)rte).getWorkItemDefinition(taskName);
return wid!=null && wid.getEclipseCustomEditor()!=null;
}
}
}
}
}
return false;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.custom.ICustomFeature#execute(org.eclipse.graphiti.features.context.ICustomContext)
*/
@Override
public void execute(ICustomContext context) {
execute((IContext)context);
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.IFeature#execute(org.eclipse.graphiti.features.context.IContext)
*/
@Override
public void execute(IContext context) {
BPMN2Editor editor = (BPMN2Editor)getFeatureProvider().getDiagramTypeProvider().getDiagramBehavior().getDiagramContainer();
PictogramElement pe = ((ICustomContext) context).getPictogramElements()[0];
final Task task = (Task)Graphiti.getLinkService().getBusinessObjectForLinkedPictogramElement(pe);
String taskName = ""; //$NON-NLS-1$
List<EStructuralFeature> features = ModelDecorator.getAnyAttributes(task);
for (EStructuralFeature f : features) {
if ("taskName".equals(f.getName())) { //$NON-NLS-1$
taskName = (String)task.eGet(f);
break;
}
}
// get the WorkEditor dialog
WorkItemEditor workItemEditor = getWorkItemEditor(task);
if (workItemEditor==null)
return;
IBpmn2RuntimeExtension rte = editor.getTargetRuntime().getRuntimeExtension();
WorkItemDefinition workItemDefinition = ((JBPM5RuntimeExtension)rte).getWorkItemDefinition(taskName);
Hashtable<String, ParameterDefinition> parameterDefinitions = new Hashtable<String, ParameterDefinition>();
WorkDefinition workDefinition = workItemEditor.getWorkDefinition();
for (Entry<String, Parameter> entry : workItemDefinition.getParameters().entrySet()) {
String name = entry.getKey();
ParameterDefinition parameterDefinition = workItemEditor.getWorkDefinition().getParameter(name);
parameterDefinitions.put(name, parameterDefinition);
}
Work work = workItemEditor.getWork();
for (DataInputAssociation dia : task.getDataInputAssociations()) {
DataInput dataInput = (DataInput)dia.getTargetRef();
if (dataInput!=null) {
String name = dataInput.getName();
ParameterDefinition parameterDefinition = parameterDefinitions.get(name);
if (parameterDefinition!=null) {
// set the value of this parameter for WorkImpl
Object type = parameterDefinition.getType();
Object value = null;
if (dia.getAssignment().isEmpty()) {
value = parameterDefinition.setStringValue("");
}
else {
String body = ModelUtil.getExpressionBody(((FormalExpression)dia.getAssignment().get(0).getFrom()));
value = parameterDefinition.setStringValue(body);
}
work.setParameter(name, value);
}
}
}
if (workItemEditor.show()) {
hasChanges = true;
work = workItemEditor.getWork();
for (DataInputAssociation dia : task.getDataInputAssociations()) {
DataInput dataInput = (DataInput)dia.getTargetRef();
if (dataInput!=null) {
String name = dataInput.getName();
ItemDefinition itemDefinition = dataInput.getItemSubjectRef();
// this always comes back as a String from the SampleCustomEditor dialog
Object parameterValue = work.getParameter(name);
if (parameterValue!=null) {
ParameterDefinition parameterDefinition = parameterDefinitions.get(name);
Object type = parameterDefinition.getType();
String value = parameterDefinition.getStringValue(parameterValue);
if (dia.getAssignment().isEmpty()) {
String typename = type.getClass().getName();
EObject structureRef = ModelUtil.createStringWrapper(typename);
if (itemDefinition==null) {
itemDefinition = Bpmn2ModelerFactory.createObject(task.eResource(), ItemDefinition.class);
ModelUtil.getDefinitions(task).getRootElements().add(itemDefinition);
ModelUtil.setID(itemDefinition);
}
itemDefinition.setItemKind(ItemKind.INFORMATION);
itemDefinition.setStructureRef(structureRef);
dataInput.setItemSubjectRef(itemDefinition);
FormalExpression from = Bpmn2ModelerFactory.createObject(task.eResource(), FormalExpression.class);
from.setBody(value);
FormalExpression to = Bpmn2ModelerFactory.createObject(task.eResource(), FormalExpression.class);
to.setBody(dia.getTargetRef().getId());
Assignment assignment = Bpmn2ModelerFactory.createObject(task.eResource(), Assignment.class);
assignment.setFrom(from);
assignment.setTo(to);
dia.getAssignment().add(assignment);
}
else {
Assignment assignment = dia.getAssignment().get(0);
FormalExpression from = (FormalExpression) assignment.getFrom();
if (from==null) {
from = Bpmn2ModelerFactory.createObject(task.eResource(), FormalExpression.class);
assignment.setFrom(from);
}
FormalExpression to = (FormalExpression) assignment.getTo();
if (to==null) {
to = Bpmn2ModelerFactory.createObject(task.eResource(), FormalExpression.class);
to.setBody(dia.getTargetRef().getId());
assignment.setTo(to);
}
from.setBody(value);
}
}
else if (itemDefinition!=null) {
// TODO: remove Item Definition if it is on longer referenced anywhere
// ModelUtil.getDefinitions(task).getRootElements().remove(itemDefinition);
dataInput.setItemSubjectRef(null);
}
}
}
}
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.IFeature#canUndo(org.eclipse.graphiti.features.context.IContext)
*/
@Override
public boolean canUndo(IContext context) {
return true;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.IFeature#hasDoneChanges()
*/
@Override
public boolean hasDoneChanges() {
return hasChanges;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.IName#getName()
*/
@Override
public String getName() {
return Messages.JbpmCustomTaskFeatureContainer_Name;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.IDescription#getDescription()
*/
@Override
public String getDescription() {
return Messages.JbpmCustomTaskFeatureContainer_Description;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.IFeatureProviderHolder#getFeatureProvider()
*/
@Override
public IFeatureProvider getFeatureProvider() {
return fp;
}
/* (non-Javadoc)
* @see org.eclipse.graphiti.features.custom.ICustomFeature#getImageId()
*/
@Override
public String getImageId() {
return ImageProvider.IMG_16_CONFIGURE;
}
}
}