| //------------------------------------------------------------------------------ |
| // Copyright (c) 2005, 2007 IBM Corporation and others. |
| // 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: |
| // IBM Corporation - initial implementation |
| //------------------------------------------------------------------------------ |
| /** |
| * |
| */ |
| package org.eclipse.epf.diagramming.base.persistence; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.IdentityHashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.commands.ExecutionException; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EModelElement; |
| import org.eclipse.emf.ecore.ENamedElement; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.ecore.util.InternalEList; |
| import org.eclipse.emf.ecore.util.EcoreUtil.Copier; |
| import org.eclipse.emf.transaction.Transaction; |
| import org.eclipse.emf.transaction.TransactionalEditingDomain; |
| import org.eclipse.emf.transaction.util.TransactionUtil; |
| import org.eclipse.emf.workspace.AbstractEMFOperation; |
| import org.eclipse.epf.diagram.core.bridge.BridgeHelper; |
| import org.eclipse.epf.diagram.core.services.DiagramManager; |
| import org.eclipse.epf.diagramming.base.util.UmaUmlUtil; |
| import org.eclipse.epf.library.edit.util.ProcessUtil; |
| import org.eclipse.epf.uma.Activity; |
| import org.eclipse.epf.uma.MethodElement; |
| import org.eclipse.epf.uma.UmaPackage; |
| import org.eclipse.epf.uma.VariabilityElement; |
| import org.eclipse.epf.uma.VariabilityType; |
| import org.eclipse.epf.uma.WorkOrder; |
| import org.eclipse.gmf.runtime.common.core.util.StringStatics; |
| import org.eclipse.gmf.runtime.diagram.core.DiagramEditingDomainFactory; |
| import org.eclipse.gmf.runtime.diagram.core.preferences.PreferencesHint; |
| import org.eclipse.gmf.runtime.diagram.core.services.ViewService; |
| import org.eclipse.gmf.runtime.diagram.core.util.ViewType; |
| import org.eclipse.gmf.runtime.emf.core.util.EMFCoreUtil; |
| import org.eclipse.gmf.runtime.notation.Diagram; |
| import org.eclipse.gmf.runtime.notation.Edge; |
| import org.eclipse.gmf.runtime.notation.Node; |
| import org.eclipse.gmf.runtime.notation.View; |
| import org.eclipse.uml2.uml.ActivityNode; |
| import org.eclipse.uml2.uml.ControlNode; |
| import org.eclipse.uml2.uml.NamedElement; |
| import org.eclipse.uml2.uml.ObjectNode; |
| import org.eclipse.uml2.uml.StructuredActivityNode; |
| import org.eclipse.uml2.uml.UMLFactory; |
| import org.eclipse.uml2.uml.UMLPackage; |
| |
| |
| /** |
| * Diagram service does diagram data specific work requested by clients. |
| * @author Shashidhar Kannoori |
| * @since 1.2 |
| */ |
| public class DiagramService implements IDiagramService { |
| |
| public static final String ID = "org.eclipse.epf.diagramming"; |
| public static final String EDITING_DOMIAN_ID = "org.eclipse.epf.diagramming.EditingDomain"; //$NON-NLS-1$ |
| |
| public static final String AD_kind = DiagramManager.AD_kind; |
| public static final String ADD_kind = DiagramManager.ADD_kind; |
| public static final String WPD_kind = DiagramManager.WPD_kind; |
| |
| static final int[] DIAGRAM_TYPES = { ACTIVITY_DIAGRAM, WORK_PRODUCT_DEPENDENCY_DIAGRAM, ACTIVITY_DETAIL_DIAGRAM }; |
| |
| static final String[] DIAGRAM_KINDS = new String[]{AD_kind, WPD_kind, ADD_kind}; |
| |
| public boolean debug = false; |
| |
| /** |
| * @generated |
| */ |
| public static final PreferencesHint DIAGRAM_PREFERENCES_HINT = new PreferencesHint( |
| ID); |
| |
| protected static DiagramService instance = new DiagramService(); |
| protected List dispatchers = new ArrayList(); |
| |
| /** |
| * |
| */ |
| public DiagramService() { |
| // TODO Auto-generated constructor stub |
| } |
| |
| public static DiagramService eInstance(){ |
| return instance; |
| } |
| |
| |
| /** |
| * Adds a dispatchers to monitor Library Service events. |
| * |
| * @param dispatchers |
| * a diagram service dispatchers |
| */ |
| public void addDispatchers(ISaveEventDispatcher dispatcher) { |
| dispatchers.add(dispatcher); |
| } |
| |
| /** |
| * Removes a dispatchers that was added to monitor Library Service events. |
| * |
| * @param dispatchers |
| * a diagram service dispatchers |
| */ |
| public void removeDispatchers(ISaveEventDispatcher dispatcher) { |
| dispatchers.remove(dispatcher); |
| } |
| |
| public void dispatch(ISaveInfo info){ |
| for (Iterator iter = dispatchers.iterator(); iter.hasNext();) { |
| ISaveEventDispatcher element = (ISaveEventDispatcher) iter.next(); |
| element.updateTimeStamp(info); |
| } |
| } |
| |
| public SaveInfo getSaveInfo(Object obj, long timeStamp){ |
| |
| return new SaveInfo(obj, timeStamp); |
| } |
| |
| /** |
| * Returns a TransactionalDomain for handling things with resources. |
| * @return |
| */ |
| public TransactionalEditingDomain createEditingDomain() { |
| String editingDomainID = EDITING_DOMIAN_ID; |
| if (editingDomainID != null) { |
| TransactionalEditingDomain editingDomain = TransactionalEditingDomain.Registry.INSTANCE |
| .getEditingDomain(editingDomainID); |
| if (editingDomain != null) { |
| return editingDomain; |
| } |
| } |
| return DiagramEditingDomainFactory.getInstance().createEditingDomain(); |
| } |
| |
| /** |
| * Returns a diagram for base activity. If diagram exists. |
| * |
| * @param act |
| * @param diagramType |
| * @return |
| */ |
| |
| public Diagram getDiagram(Activity activity, String diagramType, boolean create, IProgressMonitor monitor){ |
| Diagram diagram = null; |
| TransactionalEditingDomain domain = createEditingDomain(); |
| IFile file = DiagramPersister.getFile(DiagramFileCreatorEx.default_diagram_file, activity, DiagramFileCreatorEx.getInstance()); |
| |
| if(file != null){ |
| if(monitor == null)monitor = new NullProgressMonitor(); |
| try{ |
| diagram = DiagramPersister.load(domain, file, true, monitor, activity); |
| if(diagram != null){ |
| return diagram; |
| } |
| }catch(Exception e){ |
| if(debug){ |
| System.out.println("Error occured while retrieving diagram for " + activity + ":" + e.getMessage()); |
| } |
| } |
| } |
| if(create){ |
| diagram = createDiagram(activity, diagramType, false); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns a copy of Diagram. Also copies the references and also copies the umlObject. |
| * @param sourceDiagram |
| * @param act |
| * @return |
| */ |
| public Diagram copyDiagram(Diagram sourceDiagram, Activity act){ |
| Diagram copy = copy(sourceDiagram); |
| EObject umlCopy = copy.getElement(); |
| if(act != null){ |
| BridgeHelper.addEAnnotation((NamedElement)umlCopy, act); |
| } |
| if(copy != null){ |
| return copy; |
| } |
| return null; |
| } |
| |
| |
| private Diagram copy(Diagram sourceObject){ |
| Copier copier = new Copier() { |
| |
| /** |
| * |
| */ |
| private static final long serialVersionUID = 1L; |
| |
| protected void copyReference(EReference eReference, EObject eObject, |
| EObject copyEObject) { |
| if (eObject.eIsSet(eReference)) |
| { |
| if (eReference.isMany()) |
| { |
| InternalEList source = (InternalEList)eObject.eGet(eReference); |
| InternalEList target = (InternalEList)copyEObject.eGet(getTarget(eReference)); |
| if (source.isEmpty()) |
| { |
| target.clear(); |
| } |
| else |
| { |
| boolean isBidirectional = eReference.getEOpposite() != null; |
| int index = 0; |
| for (Iterator k = resolveProxies ? source.iterator() : source.basicIterator(); k.hasNext();) |
| { |
| Object referencedEObject = k.next(); |
| Object copyReferencedEObject = get(referencedEObject); |
| if (copyReferencedEObject == null) |
| { |
| if (!isBidirectional) |
| { |
| target.addUnique(index, referencedEObject); |
| ++index; |
| } |
| } |
| else |
| { |
| if (isBidirectional) |
| { |
| int position = target.indexOf(copyReferencedEObject); |
| if (position == -1) |
| { |
| target.addUnique(index, copyReferencedEObject); |
| } |
| else if (index != position) |
| { |
| target.move(index, copyReferencedEObject); |
| } |
| } |
| else |
| { |
| target.addUnique(index, copyReferencedEObject); |
| } |
| ++index; |
| } |
| } |
| } |
| } |
| else |
| { |
| Object referencedEObject = eObject.eGet(eReference, resolveProxies); |
| if (referencedEObject == null) |
| { |
| copyEObject.eSet(getTarget(eReference), null); |
| } |
| else |
| { |
| Object copyReferencedEObject = get(referencedEObject); |
| if (copyReferencedEObject == null) |
| { |
| if (eReference.getEOpposite() == null) |
| { |
| // Make a copy of Activity's elements |
| if(referencedEObject instanceof NamedElement){ |
| //copyReferencedEObject = copy((EObject)referencedEObject); |
| //copyEObject.eSet(getTarget(eReference), copyReferencedEObject); |
| copyEObject.eSet(getTarget(eReference), copyReferencedEObject); |
| }else{ |
| copyEObject.eSet(getTarget(eReference), referencedEObject); |
| } |
| |
| } |
| } |
| else |
| { |
| copyEObject.eSet(getTarget(eReference), copyReferencedEObject); |
| } |
| } |
| } |
| } |
| } |
| |
| }; |
| EObject umlCopy = copier.copy(sourceObject.getElement()); |
| Diagram result = (Diagram)copier.copy(sourceObject); |
| result.setElement(umlCopy); |
| copier.copyReferences(); |
| return result; |
| } |
| |
| |
| /** |
| * Copies the diagram from one resources to another. This is useful in case of |
| * deep copy. For copy of individual diagram look at copyDiagram(Diagram sourceDiagram, Activity act) |
| * @param sourceDiagram |
| * @param file |
| * @return |
| */ |
| public Diagram copyDiagramResource(Diagram sourceDiagram, IFile file) { |
| Resource sourceRes = sourceDiagram.eResource(); |
| EList contents = sourceRes.getContents(); |
| |
| int indexOfDiagram = contents.indexOf(sourceDiagram); |
| final Collection copiedContents = EcoreUtil.copyAll(contents); |
| |
| TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(sourceDiagram); |
| String fileName = file.getFullPath().toString(); |
| final Resource newResource = editingDomain.getResourceSet() |
| .createResource(URI.createPlatformResourceURI(fileName, true)); |
| |
| Map options = new HashMap(); |
| options.put(Transaction.OPTION_UNPROTECTED, Boolean.TRUE); |
| |
| AbstractEMFOperation operation = new AbstractEMFOperation( |
| editingDomain, StringStatics.BLANK, |
| options) { |
| |
| protected IStatus doExecute(IProgressMonitor monitor, |
| IAdaptable info) |
| throws ExecutionException { |
| |
| newResource.getContents().addAll(copiedContents); |
| |
| return Status.OK_STATUS; |
| } |
| }; |
| try { |
| operation.execute(new NullProgressMonitor(), null); |
| } catch (ExecutionException e) { |
| e.printStackTrace(); |
| } |
| |
| return (Diagram)newResource.getContents().get(indexOfDiagram); |
| } |
| |
| /** |
| * Create a diagram for given {@link Activity} and diagramKind. |
| * If Activity is extending/locallycontributing, gets a copy of base diagram. |
| * else creates a new diagram for it. |
| * @param act |
| * @param diagramKind |
| * @param save |
| * @return |
| */ |
| public Diagram createDiagram(Activity act, String diagramKind, boolean save){ |
| |
| if(ProcessUtil.isExtendingOrLocallyContributing(act)){ |
| Diagram baseDiagram = getDiagram((Activity)act.getVariabilityBasedOnElement(), |
| diagramKind, false, new NullProgressMonitor()); |
| if(baseDiagram != null){ |
| Diagram copy = copyDiagram(baseDiagram, act); |
| if(copy != null){ |
| return copy; |
| } |
| } |
| } |
| |
| Diagram diagram = DiagramPersister.createDiagram(createEditingDomain(), |
| diagramKind, act, false); |
| if (diagram != null) { |
| //populateDiagram(diagram, act, diagramKind); |
| return diagram; |
| } |
| return null; |
| } |
| |
| private void populateDiagram(Diagram diagram, Activity act, String diagramKind) { |
| // create GraphNode for each BreakdownElement and add it to the diagram |
| // |
| List nodes = new ArrayList(); |
| if(diagram == null) return; |
| for (Iterator iter = act.getBreakdownElements().iterator(); iter |
| .hasNext();) { |
| EObject element = (EObject)iter.next(); |
| nodes.add(createNode(diagram, (MethodElement)element)); |
| } |
| |
| // create GraphConnectors for each BreakdownElement |
| // |
| for (Iterator iter = nodes.iterator(); iter.hasNext();) { |
| Node node = (Node) iter.next(); |
| createConnectors(node, diagram, diagramKind); |
| } |
| } |
| |
| private void createConnectors(Node node, Diagram diagram, |
| String diagramKind){ |
| // In case of Activity diagram |
| if (diagramKind.equals(AD_kind)) { |
| MethodElement e = BridgeHelper.getMethodElement((ActivityNode)node.getElement()); |
| if (e instanceof Activity) { |
| Activity act = (Activity) e; |
| for (Iterator iter = act.getLinkToPredecessor().iterator(); iter |
| .hasNext();) { |
| WorkOrder workOrder = (WorkOrder) iter.next(); |
| Node srcNode = findNode(diagram, workOrder |
| .getPred()); |
| if (srcNode != null) { |
| createEdge(diagram, srcNode, node); |
| } |
| } |
| } |
| |
| } |
| } |
| |
| public static Node findNode(Diagram diagram, Object methodElement) { |
| for (Iterator iter = diagram.getChildren().iterator(); iter.hasNext();) { |
| View view = (View) iter.next(); |
| if(view instanceof Node){ |
| MethodElement e = BridgeHelper.getMethodElement((ActivityNode)view.getElement()); |
| if(methodElement.equals(e)){ |
| return (Node)view; |
| } |
| } |
| } |
| return null; |
| } |
| |
| public static Node findNode(Diagram diagram, NamedElement umlElement) { |
| for (Iterator iter = diagram.getChildren().iterator(); iter.hasNext();) { |
| View view = (View) iter.next(); |
| if(view instanceof Node){ |
| EObject e = view.getElement(); |
| if(umlElement.equals(e)){ |
| return (Node)view; |
| } |
| } |
| } |
| return null; |
| } |
| |
| public static Edge findEdge(Diagram diagram, Node srcNode, Node targetNode) { |
| // TODO : implement this. |
| return null; |
| } |
| |
| public static Edge findEdge(Diagram diagram, MethodElement src, |
| MethodElement target) { |
| |
| // TODO : implement |
| return null; |
| } |
| |
| |
| public Edge createEdge(Diagram diagram, Node srcNode, |
| Node targetNode) { |
| EObject container = diagram.getElement(); |
| EReference containment = UMLPackage.eINSTANCE.getActivity_Edge(); |
| EObject edge = EMFCoreUtil.create(container, containment, UMLPackage.eINSTANCE.getActivityEdge()); |
| //TODO: remove Creation node. Adding Model will create View. |
| return ViewService.createEdge(srcNode, targetNode, edge, ViewType.DIAGRAM_LINK, |
| DIAGRAM_PREFERENCES_HINT); |
| } |
| |
| public Node createNode(Diagram diagram, MethodElement e ){ |
| EObject element = e; |
| EObject umlClass = getElement(element); |
| EObject umlObject = UMLFactory.eINSTANCE.create((EClass)umlClass); |
| |
| //TODO: remove Creation node. Adding Model will create View. |
| Node node = ViewService.createNode(diagram, umlObject, "", |
| DIAGRAM_PREFERENCES_HINT); |
| BridgeHelper.addEAnnotation((EModelElement)node.getElement(),e); |
| return node; |
| } |
| |
| public int getDiagramType(Diagram diagram) { |
| String typeStr = diagram.getType(); |
| for (int i = 0; i < DIAGRAM_KINDS.length; i++) { |
| if (DIAGRAM_KINDS[i].equals(typeStr)) |
| return i; |
| } |
| return -1; |
| } |
| |
| public List getCommandListeners(){ |
| |
| return null; |
| } |
| |
| public boolean refreshFromBase(Diagram diagram, TransactionalEditingDomain domain) { |
| |
| class RefreshFromBaseOperation extends AbstractEMFOperation{ |
| |
| private Diagram diagram; |
| |
| public RefreshFromBaseOperation(TransactionalEditingDomain domain, Diagram diagram) { |
| super(domain, "Refresh from base"); |
| this.diagram = diagram; |
| } |
| |
| protected IStatus doExecute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException { |
| EObject umlObject = diagram.getElement(); |
| if(umlObject instanceof Activity){ |
| Activity act = (Activity)BridgeHelper.getMethodElementFromAnnotation((EModelElement)umlObject); |
| Activity base = (Activity)act.getVariabilityBasedOnElement(); |
| if(base == null |
| || act.getVariabilityType() == VariabilityType.LOCAL_REPLACEMENT_LITERAL ){ |
| return Status.CANCEL_STATUS; |
| } |
| |
| int type = DiagramService.eInstance().getDiagramType(diagram); |
| Diagram baseDiagram = DiagramService.eInstance().getDiagram(base, diagram.getType(), false, new NullProgressMonitor()); |
| if(baseDiagram == null) return Status.CANCEL_STATUS; |
| |
| List oldNodes = new ArrayList(); |
| Diagram baseCopy = copyDiagram(baseDiagram, base); |
| switch(type){ |
| case ACTIVITY_DIAGRAM:{ |
| |
| for (Iterator iter = baseDiagram.getChildren().iterator(); iter.hasNext();) { |
| Node baseNode = (Node) iter.next(); |
| umlObject = baseNode.getElement(); |
| if(umlObject instanceof StructuredActivityNode || |
| umlObject instanceof ObjectNode){ |
| MethodElement e = BridgeHelper.getMethodElementFromAnnotation((ActivityNode)umlObject); |
| Node node = findNode(diagram, e); |
| if(node !=null){ |
| oldNodes.add(node); |
| } |
| }else{ |
| Node node = findNode(diagram, umlObject); |
| if(node != null){ |
| oldNodes.add(node); |
| } |
| } |
| } |
| diagram.getChildren().removeAll(oldNodes); |
| |
| //TODO: check why this |
| // remove unused old UI nodes && nodes of contributor/replacer |
| for (Iterator iter = diagram.getChildren().iterator(); iter |
| .hasNext();) { |
| Node node = (Node) iter.next(); |
| EObject bridge = node.getElement(); |
| if (bridge instanceof ControlNode){ |
| iter.remove(); |
| } else { |
| if (bridge instanceof ActivityNode) { |
| MethodElement e = UmaUmlUtil.getUmaElement((NamedElement)bridge); |
| if (e instanceof Activity |
| && ((Activity) e) |
| .getVariabilityBasedOnElement() != null) { |
| iter.remove(); |
| } |
| } |
| } |
| } |
| |
| // replace associated base element with contributing/replacing |
| // element |
| // |
| for (Iterator iter = act.getBreakdownElements().iterator(); iter |
| .hasNext();) { |
| Object element = iter.next(); |
| if (element instanceof Activity) { |
| VariabilityElement baseElement = ((Activity) element) |
| .getVariabilityBasedOnElement(); |
| Node node = findNode(baseCopy, baseElement); |
| if (node != null) { |
| EObject umlObj = node.getElement(); |
| BridgeHelper.addEAnnotation((EModelElement)umlObj, (MethodElement)element); |
| } |
| } |
| } |
| // add new nodes |
| // |
| diagram.getChildren().addAll(baseCopy.getChildren()); |
| break; |
| } |
| default: { |
| |
| for (Iterator iter = baseDiagram.getChildren().iterator(); iter |
| .hasNext();) { |
| Node baseNode = (Node) iter.next(); |
| umlObject = baseNode.getElement(); |
| if (umlObject instanceof ActivityNode) { |
| // this is a element's node |
| MethodElement e = BridgeHelper.getMethodElement((ActivityNode)umlObject); |
| Node node = findNode(diagram, e); |
| if (node != null) { |
| oldNodes.add(node); |
| } |
| } |
| } |
| |
| // remove old nodes |
| // |
| diagram.getChildren().removeAll(oldNodes); |
| |
| // add new nodes |
| // |
| diagram.getChildren().addAll(baseCopy.getChildren()); |
| |
| break; |
| } |
| } |
| } |
| return Status.OK_STATUS; |
| } |
| } |
| try { |
| RefreshFromBaseOperation operation = new RefreshFromBaseOperation(domain, diagram); |
| IStatus status = operation.execute(new NullProgressMonitor(), null); |
| if(status.isOK()) return true; |
| } catch (ExecutionException e) { |
| // TODO : use Log |
| System.err.println("Error: Refresh from base" + e.getLocalizedMessage()); |
| } |
| |
| return false; |
| } |
| |
| /** |
| * |
| */ |
| private static Map elements; |
| |
| |
| /** |
| * Returns 'type' of the ecore object associated with the hint. |
| * |
| * |
| */ |
| public static ENamedElement getElement(EObject object) { |
| EClass eClass = object.eClass(); |
| if (elements == null) { |
| elements = new IdentityHashMap(); |
| elements.put(UmaPackage.eINSTANCE.getActivity() , UMLPackage.eINSTANCE |
| .getStructuredActivityNode()); |
| elements.put(UmaPackage.eINSTANCE.getTaskDescription(), UMLPackage.eINSTANCE |
| .getActivityParameterNode()); |
| } |
| return (ENamedElement) elements.get(eClass); |
| } |
| } |