blob: 9792d6de2a6ae5f424d9bc4c72340b58367ea512 [file] [log] [blame]
package org.eclipse.bpmn2.modeler.core.validation;
import java.util.List;
import org.eclipse.bpmn2.BaseElement;
import org.eclipse.bpmn2.Bpmn2Package;
import org.eclipse.bpmn2.CallActivity;
import org.eclipse.bpmn2.CatchEvent;
import org.eclipse.bpmn2.CompensateEventDefinition;
import org.eclipse.bpmn2.ComplexGateway;
import org.eclipse.bpmn2.ConditionalEventDefinition;
import org.eclipse.bpmn2.DataObject;
import org.eclipse.bpmn2.Definitions;
import org.eclipse.bpmn2.EndEvent;
import org.eclipse.bpmn2.Error;
import org.eclipse.bpmn2.ErrorEventDefinition;
import org.eclipse.bpmn2.Escalation;
import org.eclipse.bpmn2.EscalationEventDefinition;
import org.eclipse.bpmn2.EventBasedGateway;
import org.eclipse.bpmn2.EventDefinition;
import org.eclipse.bpmn2.ExclusiveGateway;
import org.eclipse.bpmn2.FlowElement;
import org.eclipse.bpmn2.FlowNode;
import org.eclipse.bpmn2.FormalExpression;
import org.eclipse.bpmn2.Gateway;
import org.eclipse.bpmn2.GatewayDirection;
import org.eclipse.bpmn2.InclusiveGateway;
import org.eclipse.bpmn2.ItemDefinition;
import org.eclipse.bpmn2.Message;
import org.eclipse.bpmn2.MessageEventDefinition;
import org.eclipse.bpmn2.ParallelGateway;
import org.eclipse.bpmn2.Process;
import org.eclipse.bpmn2.RootElement;
import org.eclipse.bpmn2.ScriptTask;
import org.eclipse.bpmn2.SendTask;
import org.eclipse.bpmn2.SequenceFlow;
import org.eclipse.bpmn2.Signal;
import org.eclipse.bpmn2.SignalEventDefinition;
import org.eclipse.bpmn2.StartEvent;
import org.eclipse.bpmn2.ThrowEvent;
import org.eclipse.bpmn2.TimerEventDefinition;
import org.eclipse.bpmn2.di.BPMNDiagram;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.validation.AbstractModelConstraint;
import org.eclipse.emf.validation.EMFEventType;
import org.eclipse.emf.validation.IValidationContext;
public class BPMN2BatchValidationConstraint extends AbstractModelConstraint {
public final static String ERROR_ID = "org.eclipse.bpmn2.modeler.core.validation.error";
public final static String WARNING_ID = "org.eclipse.bpmn2.modeler.core.validation.warning";
private boolean warnings = false;
public BPMN2BatchValidationConstraint() {
}
@Override
public IStatus validate(IValidationContext ctx) {
EObject eObj = ctx.getTarget();
EMFEventType eType = ctx.getEventType();
String id = ctx.getCurrentConstraintId();
if (WARNING_ID.equals(id))
warnings = true;
else
warnings = false;
// In the case of batch mode.
if (eType == EMFEventType.NULL) {
if (eObj instanceof BPMNDiagram) {
return validateDiagram(ctx, (BPMNDiagram) eObj);
}
if (eObj instanceof Definitions) {
return validateDefinitions(ctx, (Definitions) eObj);
}
if (eObj instanceof BaseElement) {
return validateBaseElement(ctx, (BaseElement) eObj);
}
} else { // In the case of live mode.
}
return ctx.createSuccessStatus();
}
private IStatus validateDiagram(IValidationContext ctx, BPMNDiagram obj) {
Definitions defs = (Definitions) obj.eContainer();
return validateDefinitions(ctx, defs);
}
private IStatus validateDefinitions(IValidationContext ctx, Definitions def) {
List<RootElement> rootElements = def.getRootElements();
for (RootElement root : rootElements) {
if (root instanceof Process) {
Process process = (Process) root;
if (warnings) {
// report warnings only
boolean foundStartEvent = false;
boolean foundEndEvent = false;
List<FlowElement> flowElements = process.getFlowElements();
for (FlowElement fe : flowElements) {
if (fe instanceof StartEvent) {
foundStartEvent = true;
}
if (fe instanceof EndEvent) {
foundEndEvent = true;
}
}
if (!foundStartEvent) {
ctx.addResult(root);
return ctx.createFailureStatus("Process has no Start Event");
}
if (!foundEndEvent) {
ctx.addResult(root);
return ctx.createFailureStatus("Process has no End Event");
}
}
else {
// report errors only
if (isEmpty(process.getName())) {
ctx.addResult(root);
return ctx.createFailureStatus("Process has no name");
}
}
}
else if (root instanceof Error) {
if (warnings) {
if (((Error)root).getStructureRef()==null) {
ctx.addResult(root);
return ctx.createFailureStatus("Error has no type definition");
}
}
}
else if (root instanceof Escalation) {
if (warnings) {
if (((Escalation)root).getStructureRef()==null) {
ctx.addResult(root);
return ctx.createFailureStatus("Escalation has no type definition");
}
}
}
else if (root instanceof Message) {
if (warnings) {
if (((Message)root).getItemRef()==null) {
ctx.addResult(root);
return ctx.createFailureStatus("Message has no type definition");
}
}
}
else if (root instanceof Signal) {
if (warnings) {
if (((Signal)root).getStructureRef()==null) {
ctx.addResult(root);
return ctx.createFailureStatus("Signal has no type definition");
}
}
}
else if (root instanceof ItemDefinition) {
if (!warnings) {
if (((ItemDefinition)root).getStructureRef()==null) {
ctx.addResult(root);
return ctx.createFailureStatus("Item Definition has no structure");
}
}
}
}
return ctx.createSuccessStatus();
}
private IStatus validateBaseElement(IValidationContext ctx, BaseElement fe) {
if (fe instanceof StartEvent) {
StartEvent se = (StartEvent) fe;
if (!warnings) {
if (se.getOutgoing() == null || se.getOutgoing().size() < 1) {
return ctx.createFailureStatus("Start Event has no outgoing connections");
}
}
}
else if (fe instanceof EndEvent) {
EndEvent ee = (EndEvent) fe;
if (!warnings) {
if (ee.getIncoming() == null || ee.getIncoming().size() < 1) {
return ctx.createFailureStatus("End Event has no incoming connections");
}
}
}
else if (fe instanceof ScriptTask) {
ScriptTask st = (ScriptTask) fe;
if (warnings) {
if (isEmpty(st.getScript())) {
return ctx.createFailureStatus("Script Task has no script");
}
if (isEmpty(st.getScriptFormat())) {
return ctx.createFailureStatus("Script Task has no script format");
}
}
}
else if (fe instanceof SendTask) {
SendTask st = (SendTask) fe;
if (!warnings) {
if (st.getOperationRef() == null) {
return ctx.createFailureStatus("Send Task has no operation");
}
if (st.getMessageRef() == null) {
return ctx.createFailureStatus("Send Task has no message");
}
}
}
else if (fe instanceof CatchEvent) {
CatchEvent event = (CatchEvent) fe;
if (!warnings) {
List<EventDefinition> eventdefs = event.getEventDefinitions();
if (eventdefs.size()==0) {
return ctx.createFailureStatus("Catch Event has no event definitions");
}
for (EventDefinition ed : eventdefs) {
if (ed instanceof TimerEventDefinition) {
TimerEventDefinition ted = (TimerEventDefinition) ed;
if ( ted.getTimeDate() == null
&& ted.getTimeDuration() == null
&& ted.getTimeCycle() == null
) {
return ctx.createFailureStatus("Timer Event has no timer definition");
}
} else if (ed instanceof SignalEventDefinition) {
if (((SignalEventDefinition) ed).getSignalRef() == null) {
return ctx.createFailureStatus("Signal Event has no signal definition");
}
} else if (ed instanceof ErrorEventDefinition) {
if (((ErrorEventDefinition) ed).getErrorRef() == null
|| ((ErrorEventDefinition) ed).getErrorRef().getErrorCode() == null) {
return ctx.createFailureStatus("Error Event has no error definition");
}
} else if (ed instanceof ConditionalEventDefinition) {
FormalExpression conditionalExp = (FormalExpression) ((ConditionalEventDefinition) ed)
.getCondition();
if (conditionalExp.getBody() == null) {
return ctx.createFailureStatus("Conditional Event has no condition expression");
}
} else if (ed instanceof EscalationEventDefinition) {
if (((EscalationEventDefinition) ed).getEscalationRef() == null) {
return ctx.createFailureStatus("Escalation Event has no escalation definition");
}
} else if (ed instanceof MessageEventDefinition) {
if (((MessageEventDefinition) ed).getMessageRef() == null) {
return ctx.createFailureStatus("Message Event has no message definition");
}
} else if (ed instanceof CompensateEventDefinition) {
if (((CompensateEventDefinition) ed).getActivityRef() == null) {
return ctx.createFailureStatus("Compensate Event has no activity definition");
}
}
}
}
}
else if (fe instanceof ThrowEvent) {
ThrowEvent event = (ThrowEvent) fe;
if (!warnings) {
List<EventDefinition> eventdefs = event.getEventDefinitions();
if (eventdefs.size()==0) {
return ctx.createFailureStatus("Throw Event has no event definitions");
}
for (EventDefinition ed : eventdefs) {
if (ed instanceof TimerEventDefinition) {
TimerEventDefinition ted = (TimerEventDefinition) ed;
if ( ted.getTimeDate() == null
&& ted.getTimeDuration() == null
&& ted.getTimeCycle() == null
) {
return ctx.createFailureStatus("Timer Event has no timer definition");
}
} else if (ed instanceof SignalEventDefinition) {
if (((SignalEventDefinition) ed).getSignalRef() == null) {
return ctx.createFailureStatus("Signal Event has no signal definition");
}
} else if (ed instanceof ErrorEventDefinition) {
if (((ErrorEventDefinition) ed).getErrorRef() == null
|| ((ErrorEventDefinition) ed).getErrorRef().getErrorCode() == null) {
return ctx.createFailureStatus("Error Event has no error definition");
}
} else if (ed instanceof ConditionalEventDefinition) {
FormalExpression conditionalExp = (FormalExpression) ((ConditionalEventDefinition) ed)
.getCondition();
if (conditionalExp.getBody() == null) {
return ctx.createFailureStatus("Conditional Event has no condition expression");
}
} else if (ed instanceof EscalationEventDefinition) {
if (((EscalationEventDefinition) ed).getEscalationRef() == null) {
return ctx.createFailureStatus("Escalation Event has no conditional escalation definition");
}
} else if (ed instanceof MessageEventDefinition) {
if (((MessageEventDefinition) ed).getMessageRef() == null) {
return ctx.createFailureStatus("Message Event has no conditional message definition");
}
} else if (ed instanceof CompensateEventDefinition) {
if (((CompensateEventDefinition) ed).getActivityRef() == null) {
return ctx.createFailureStatus("Compensate Event has no conditional activity definition");
}
}
}
}
}
else if (fe instanceof SequenceFlow) {
SequenceFlow sf = (SequenceFlow) fe;
if (!warnings) {
if (sf.getSourceRef() == null) {
return ctx.createFailureStatus("Sequence Flow is not connected to a source");
}
if (sf.getTargetRef() == null) {
return ctx.createFailureStatus("Sequence Flow is not connected to a target");
}
}
}
else if (fe instanceof Gateway) {
Gateway gw = (Gateway) fe;
if (!warnings) {
if (gw.getGatewayDirection() == null
|| gw.getGatewayDirection().getValue() == GatewayDirection.UNSPECIFIED.getValue()) {
ctx.addResult(Bpmn2Package.eINSTANCE.getGateway_GatewayDirection());
return ctx.createFailureStatus("Gateway does not specify a valid direction");
}
if (gw instanceof ExclusiveGateway) {
if (gw.getGatewayDirection().getValue() != GatewayDirection.DIVERGING.getValue()
&& gw.getGatewayDirection().getValue() != GatewayDirection.CONVERGING.getValue()) {
return ctx.createFailureStatus(
"Invalid Gateway direction for Exclusing Gateway. It should be 'Converging' or 'Diverging'");
}
}
if (gw instanceof EventBasedGateway) {
if (gw.getGatewayDirection().getValue() != GatewayDirection.DIVERGING.getValue()) {
return ctx.createFailureStatus(
"Invalid Gateway direction for EventBased Gateway. It should be 'Diverging'");
}
}
if (gw instanceof ParallelGateway) {
if (gw.getGatewayDirection().getValue() != GatewayDirection.DIVERGING.getValue()
&& gw.getGatewayDirection().getValue() != GatewayDirection.CONVERGING.getValue()) {
return ctx.createFailureStatus(
"Invalid Gateway direction for Parallel Gateway. It should be 'Converging' or 'Diverging'");
}
}
if (gw instanceof InclusiveGateway) {
if (gw.getGatewayDirection().getValue() != GatewayDirection.DIVERGING.getValue()
&& gw.getGatewayDirection().getValue() != GatewayDirection.CONVERGING.getValue()) {
return ctx.createFailureStatus(
"Invalid Gateway direction for Inclusive Gateway. It should be 'Converging' or 'Diverging'");
}
}
if (gw instanceof ComplexGateway) {
if (gw.getGatewayDirection().getValue() != GatewayDirection.DIVERGING.getValue()
&& gw.getGatewayDirection().getValue() != GatewayDirection.CONVERGING.getValue()) {
return ctx.createFailureStatus(
"Invalid Gateway direction for Complex Gateway. It should be 'Converging' or 'Diverging'");
}
}
}
}
else if (fe instanceof CallActivity) {
CallActivity ca = (CallActivity) fe;
if (!warnings) {
if (ca.getCalledElementRef() == null) {
return ctx.createFailureStatus(
"Reusable Subprocess has no called element specified");
}
}
}
else if (fe instanceof DataObject) {
DataObject dao = (DataObject) fe;
if (!warnings) {
if (dao.getName() == null || dao.getName().length() < 1) {
return ctx.createFailureStatus("Data Object has no name");
}
}
}
if (fe instanceof FlowNode) {
return validateFlowNode(ctx, (FlowNode) fe);
}
return ctx.createSuccessStatus();
}
private IStatus validateFlowNode(IValidationContext ctx, FlowNode fn) {
if (!warnings) {
boolean needIncoming = true;
boolean needOutgoing = true;
if (fn instanceof ThrowEvent)
needOutgoing = false;
if (fn instanceof CatchEvent)
needIncoming = false;
if (needOutgoing) {
if ((fn.getOutgoing() == null || fn.getOutgoing().size() < 1)) {
return ctx.createFailureStatus("Node has no outgoing connections");
}
}
if (needIncoming) {
if ((fn.getIncoming() == null || fn.getIncoming().size() < 1)) {
return ctx.createFailureStatus("Node has no incoming connections");
}
}
}
return ctx.createSuccessStatus();
}
private static boolean isEmpty(String str) {
return str == null || str.isEmpty();
}
private boolean containsWhiteSpace(String testString) {
if (testString != null) {
for (int i = 0; i < testString.length(); i++) {
if (Character.isWhitespace(testString.charAt(i))) {
return true;
}
}
}
return false;
}
}