blob: 1f1a441f338d9e0f7004b0bd3c401478905bdccb [file] [log] [blame]
//------------------------------------------------------------------------------
// 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);
}
}