| /******************************************************************************* |
| * Copyright (c) 2010 Boeing. |
| * All rights reserved. This program and the accompanying materials |
| * are 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: |
| * Boeing - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.osee.ats.workflow.editor.model; |
| |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| import org.eclipse.osee.ats.internal.AtsPlugin; |
| import org.eclipse.osee.ats.workdef.WorkDefinition; |
| import org.eclipse.osee.framework.core.enums.CoreAttributeTypes; |
| import org.eclipse.osee.framework.core.exception.OseeCoreException; |
| import org.eclipse.osee.framework.logging.OseeLevel; |
| import org.eclipse.osee.framework.logging.OseeLog; |
| import org.eclipse.osee.framework.skynet.core.transaction.SkynetTransaction; |
| import org.eclipse.osee.framework.ui.plugin.util.Result; |
| |
| /** |
| * A container for multiple shapes. This is the "root" of the model data structure. |
| * |
| * @author Donald G. Dunne |
| */ |
| public class WorkflowDiagram extends ModelElement { |
| |
| /** Property ID to use when a child is added to this diagram. */ |
| public static final String CHILD_ADDED_PROP = "WorkflowDiagram.ChildAdded"; |
| /** Property ID to use when a child is removed from this diagram. */ |
| public static final String CHILD_REMOVED_PROP = "WorkflowDiagram.ChildRemoved"; |
| private final List<Shape> shapes = new ArrayList<Shape>(); |
| private final List<Shape> deletedShapes = new ArrayList<Shape>(); |
| private final WorkDefinition workFlowDefinition; |
| |
| public WorkflowDiagram(WorkDefinition workFlowDefinition) { |
| super(); |
| this.workFlowDefinition = workFlowDefinition; |
| } |
| |
| @Override |
| public Result doSave(SkynetTransaction transaction) throws OseeCoreException { |
| Result result = validForSave(); |
| if (result.isFalse()) { |
| return result; |
| } |
| try { |
| |
| List<WorkPageShape> workPageShapes = new ArrayList<WorkPageShape>(); |
| for (Shape shape : getChildren()) { |
| if (shape instanceof WorkPageShape) { |
| workPageShapes.add((WorkPageShape) shape); |
| } |
| } |
| |
| // Remove all states that do not exist anymore |
| for (Shape shape : deletedShapes) { |
| if (WorkPageShape.class.isAssignableFrom(shape.getClass())) { |
| WorkPageShape workPageShape = (WorkPageShape) shape; |
| if (workPageShape.getArtifact() != null) { |
| workPageShape.getArtifact().deleteAndPersist(transaction); |
| // workFlowDefinition.removeWorkItem(((WorkPageShape) shape).getId()); |
| } |
| } |
| } |
| |
| // Save new states and modifications to states |
| for (WorkPageShape workPageShape : workPageShapes) { |
| result = workPageShape.doSave(transaction); |
| if (result.isFalse()) { |
| return result; |
| } |
| } |
| |
| // Set start page |
| for (WorkPageShape workPageShape : workPageShapes) { |
| if (workPageShape.isStartPage()) { |
| // workFlowDefinition.setStartPageId(workPageShape.getWorkPageDefinition().getPageName()); |
| break; |
| } |
| } |
| |
| // Validate transitions |
| validateTransitions(); |
| // workFlowDefinition.loadPageData(true); |
| |
| // Artifact artifact = workFlowDefinition.toArtifact(WriteType.Update); |
| // AtsWorkDefinitions.addUpdateWorkItemToDefaultHeirarchy(artifact, transaction); |
| // artifact.persist(transaction); |
| |
| // WorkItemDefinitionFactory.deCache(workFlowDefinition); |
| |
| // Validate saved workflows and all corresponding workItemDefinitions |
| // prior to completion of save |
| // result = AtsWorkDefinitions.validateWorkItemDefinition(workFlowDefinition); |
| // if (result.isFalse()) { |
| // return result; |
| // } |
| for (Shape shape : getChildren()) { |
| if (WorkPageShape.class.isAssignableFrom(shape.getClass())) { |
| // StateDefinition workPageDefinition = ((WorkPageShape) shape).getWorkPageDefinition(); |
| // result = AtsWorkDefinitions.validateWorkItemDefinition(workPageDefinition); |
| if (result.isFalse()) { |
| return result; |
| } |
| } |
| } |
| |
| } catch (OseeCoreException ex) { |
| OseeLog.log(AtsPlugin.class, OseeLevel.SEVERE_POPUP, ex); |
| } |
| return Result.TrueResult; |
| } |
| |
| private void validateTransitions() { |
| // workFlowDefinition.clearTransitions(); |
| // for (Relation connection : getConnections()) { |
| // if (TransitionConnection.class.isAssignableFrom(connection.getClass())) { |
| // TransitionConnection transConn = (TransitionConnection) connection; |
| // if (transConn instanceof DefaultTransitionConnection) { |
| // workFlowDefinition.addPageTransition( |
| // ((WorkPageShape) transConn.getSource()).getWorkPageDefinition().getPageName(), |
| // ((WorkPageShape) transConn.getTarget()).getWorkPageDefinition().getPageName(), |
| // TransitionType.ToPageAsDefault); |
| // } else if (transConn instanceof ReturnTransitionConnection) { |
| // workFlowDefinition.addPageTransition( |
| // ((WorkPageShape) transConn.getSource()).getWorkPageDefinition().getPageName(), |
| // ((WorkPageShape) transConn.getTarget()).getWorkPageDefinition().getPageName(), |
| // TransitionType.ToPageAsReturn); |
| // } else { |
| // workFlowDefinition.addPageTransition( |
| // ((WorkPageShape) transConn.getSource()).getWorkPageDefinition().getPageName(), |
| // ((WorkPageShape) transConn.getTarget()).getWorkPageDefinition().getPageName(), TransitionType.ToPage); |
| // } |
| // } |
| // } |
| } |
| |
| @Override |
| public Result validForSave() throws OseeCoreException { |
| |
| // Validate # Completed states |
| int num = 0; |
| for (Shape shape : getChildren()) { |
| num += shape instanceof CompletedWorkPageShape ? 1 : 0; |
| } |
| if (num > 1 || num == 0) { |
| return new Result("Must have only 1 Completed state; Currently " + num); |
| } |
| |
| // Validate # Cancelled states |
| num = 0; |
| for (Shape shape : getChildren()) { |
| num += shape instanceof CancelledWorkPageShape ? 1 : 0; |
| } |
| if (num > 1 || num == 0) { |
| return new Result("Must have only 1 Cancelled state; Currently " + num); |
| } |
| |
| // Validate # other states |
| num = 0; |
| for (Shape shape : getChildren()) { |
| num += !(shape instanceof CompletedWorkPageShape) && !(shape instanceof CancelledWorkPageShape) ? 1 : 0; |
| } |
| if (num == 0) { |
| return new Result("Must have > 0 states; Currently " + num); |
| } |
| |
| // Validate # other states |
| num = 0; |
| for (Shape shape : getChildren()) { |
| if (WorkPageShape.class.isAssignableFrom(shape.getClass()) && ((WorkPageShape) shape).isStartPage()) { |
| if (((WorkPageShape) shape).isCancelledState()) { |
| return new Result("Cancelled state can not be start page"); |
| } |
| if (((WorkPageShape) shape).isCompletedState()) { |
| return new Result("Completed state can not be start page"); |
| } |
| num++; |
| } |
| } |
| if (num > 1 || num == 0) { |
| return new Result("Must have 1 start page; Currently " + num); |
| } |
| |
| // Validate state names |
| List<String> stateNames = new ArrayList<String>(); |
| for (Shape shape : getChildren()) { |
| if (WorkPageShape.class.isAssignableFrom(shape.getClass())) { |
| String name = (String) ((WorkPageShape) shape).getPropertyValue(CoreAttributeTypes.WorkPageName); |
| if (stateNames.contains(name)) { |
| return new Result( |
| "Workflow can not have more than one state of same name. Multiples found of name " + name); |
| } |
| stateNames.add(name); |
| } |
| } |
| |
| // Validate transitions (each state must have a transition to or from |
| for (Shape shape : getChildren()) { |
| if (WorkPageShape.class.isAssignableFrom(shape.getClass()) && shape.getSourceConnections().isEmpty() && shape.getTargetConnections().isEmpty()) { |
| return new Result("States must have at least one transition to or from. None found for " + shape); |
| } |
| } |
| |
| // Validate children shapes |
| for (Shape shape : getChildren()) { |
| Result result = shape.validForSave(); |
| if (result.isFalse()) { |
| return result; |
| } |
| } |
| return Result.TrueResult; |
| } |
| |
| @Override |
| public String toString() { |
| return "Work Flow Definition: " + workFlowDefinition.getName(); |
| } |
| |
| /** |
| * Add a shape to this diagram. |
| * |
| * @param s a non-null shape instance |
| * @return true, if the shape was added, false otherwise |
| */ |
| public boolean addChild(Shape s) { |
| if (s != null && shapes.add(s)) { |
| deletedShapes.remove(s); |
| s.setWorkflowDiagram(this); |
| firePropertyChange(CHILD_ADDED_PROP, null, s); |
| return true; |
| } |
| return false; |
| } |
| |
| public boolean hasChild(Shape s) { |
| for (Object obj : shapes) { |
| Shape shape = (Shape) obj; |
| if (shape.equals(s)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** Return a List of Shapes in this diagram. The returned List should not be modified. */ |
| public List<Shape> getChildren() { |
| return shapes; |
| } |
| |
| public Set<Relation> getConnections() { |
| Set<Relation> connections = new HashSet<Relation>(); |
| for (Shape shape : getChildren()) { |
| connections.addAll(shape.getSourceConnections()); |
| connections.addAll(shape.getTargetConnections()); |
| } |
| return connections; |
| } |
| |
| /** |
| * Remove a shape from this diagram. |
| * |
| * @param s a non-null shape instance; |
| * @return true, if the shape was removed, false otherwise |
| */ |
| public boolean removeChild(Shape s) { |
| if (s != null && shapes.remove(s)) { |
| deletedShapes.add(s); |
| firePropertyChange(CHILD_REMOVED_PROP, null, s); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * @return the workFlowDefinition |
| */ |
| public WorkDefinition getWorkFlowDefinition() { |
| return workFlowDefinition; |
| } |
| |
| } |