blob: 9f630bc399e9d58b792873d2c93a167d2d66896f [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.diagram.core.services;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.internal.events.ResourceChangeEvent;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.impl.AdapterImpl;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.emf.ecore.xmi.XMLHelper;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain;
import org.eclipse.emf.workspace.AbstractEMFOperation;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.epf.common.CommonPlugin;
import org.eclipse.epf.diagram.core.DiagramCorePlugin;
import org.eclipse.epf.diagram.core.bridge.BridgeHelper;
import org.eclipse.epf.diagram.core.providers.AccessibleDiagramModificationListener;
import org.eclipse.epf.diagram.core.services.FileSynchronizer.FileInfo;
import org.eclipse.epf.diagram.model.ActivityDetailDiagram;
import org.eclipse.epf.diagram.model.ModelFactory;
import org.eclipse.epf.diagram.model.WorkProductDependencyDiagram;
import org.eclipse.epf.diagram.model.impl.DiagramImpl;
import org.eclipse.epf.diagram.model.util.TxUtil;
import org.eclipse.epf.library.ILibraryServiceListener;
import org.eclipse.epf.library.LibraryService;
import org.eclipse.epf.library.LibraryServiceListener;
import org.eclipse.epf.library.LibraryServiceUtil;
import org.eclipse.epf.library.edit.util.IDiagramManager;
import org.eclipse.epf.library.edit.util.ProcessUtil;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.library.persistence.ILibraryResource;
import org.eclipse.epf.library.persistence.internal.IFailSafeSavable;
import org.eclipse.epf.library.persistence.util.ExtendedResourceSet;
import org.eclipse.epf.persistence.FailSafePersistenceHelper;
import org.eclipse.epf.persistence.FileManager;
import org.eclipse.epf.persistence.MultiFileSaveUtil;
import org.eclipse.epf.persistence.MultiFileURIConverter;
import org.eclipse.epf.services.ILibraryPersister;
import org.eclipse.epf.uma.Activity;
import org.eclipse.epf.uma.MethodLibrary;
import org.eclipse.epf.uma.Process;
import org.eclipse.epf.uma.ProcessComponent;
import org.eclipse.epf.uma.util.UmaUtil;
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.ui.resources.editor.ide.internal.l10n.EditorMessages;
import org.eclipse.gmf.runtime.diagram.ui.resources.editor.internal.util.DiagramIOUtil;
import org.eclipse.gmf.runtime.emf.core.internal.util.EMFCoreConstants;
import org.eclipse.gmf.runtime.emf.core.resources.GMFHelper;
import org.eclipse.gmf.runtime.emf.core.resources.GMFResource;
import org.eclipse.gmf.runtime.emf.core.resources.GMFResourceFactory;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.ui.PlatformUI;
import org.eclipse.uml2.uml.UMLFactory;
/**
* @author Phong Nguyen Le
*
* @since 1.2
*/
public class DiagramManager {
private static final boolean DEBUG = DiagramCorePlugin.getDefault().isDebugging();
private static final String DIAGRAM_FILENAME_WITHOUT_EXTENSION = "diagram"; //$NON-NLS-1$
private static final String DIAGRAM_FILENAME = DIAGRAM_FILENAME_WITHOUT_EXTENSION + MultiFileSaveUtil.DEFAULT_FILE_EXTENSION;
private static final Map<Process, DiagramManager> processToDiagramManagerMap = new HashMap<Process, DiagramManager>();
private static ILibraryServiceListener libSvcListener;
private static final FileSynchronizer fileSynchronizer = new FileSynchronizer() {
@Override
protected Collection<IFile> handleChangedFiles(Collection<IFile> changedFiles) {
try {
Collection<DiagramManager> mgrs = getDiagramManagers();
if(!mgrs.isEmpty()) {
Collection<IFile> handledFiles = new ArrayList<IFile>();
for (DiagramManager mgr : mgrs) {
Resource resource = mgr.getResource(false);
if(resource != null && resource.isLoaded()) {
IFile file = WorkspaceSynchronizer.getFile(mgr.getResource());
if(changedFiles.contains(file)) {
try {
mgr.reload();
handledFiles.add(file);
} catch (IOException e) {
CommonPlugin.getDefault().getLogger().logError(e);
if(DEBUG) {
e.printStackTrace();
}
}
}
}
}
return handledFiles;
}
}
catch(CoreException e) {
handleCoreException(e, e.getMessage());
}
return Collections.emptyList();
}
@Override
protected Map<IFile, IPath> handleMovedFiles(Map<IFile, IPath> movedFileToNewPathMap) {
for (Map.Entry<IFile, IPath> entry : movedFileToNewPathMap.entrySet()) {
IFile iFile = entry.getKey();
if(DIAGRAM_FILENAME.equals(iFile.getName())) {
synchronized (processToDiagramManagerMap) {
DiagramManager mgr = getDiagramManager(iFile);
if(mgr != null) {
mgr.updateResourceURI();
}
}
}
}
return super.handleMovedFiles(movedFileToNewPathMap);
}
@Override
protected Collection handleDeletedFiles(Collection<IFile> deletedFiles) {
// TODO Auto-generated method stub
return super.handleDeletedFiles(deletedFiles);
}
};
public static final String ADD_kind = "ADD"; //$NON-NLS-1$
public static final String AD_kind = "AD"; //$NON-NLS-1$
public static final String WPD_kind = "WPDD"; //$NON-NLS-1$
private static DiagramManager getDiagramManager(IFile iFile) {
for (Iterator iterator = processToDiagramManagerMap.values().iterator(); iterator
.hasNext();) {
DiagramManager mgr = (DiagramManager) iterator.next();
if(mgr.resource != null && iFile.equals(WorkspaceSynchronizer.getFile(mgr.resource))) {
return mgr;
}
}
return null;
}
public static void disposeDiagramManagers(MethodLibrary library) {
synchronized(processToDiagramManagerMap) {
for (Iterator<Map.Entry<Process, DiagramManager>> iterator = processToDiagramManagerMap.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<Process, DiagramManager> entry = iterator.next();
if(UmaUtil.getMethodLibrary(entry.getKey()) == library) {
entry.getValue().doDispose();
iterator.remove();
}
}
}
}
private static synchronized void setupLibraryServiceListener() {
if(libSvcListener == null) {
libSvcListener = new LibraryServiceListener() {
@Override
public void libraryClosed(MethodLibrary library) {
disposeDiagramManagers(library);
}
@Override
public void libraryReopened(MethodLibrary library) {
disposeDiagramManagers(library);
}
};
LibraryService.getInstance().addListener(libSvcListener);
}
}
/**
* Gets a instance of DiagramManager for the specified process. Caller must
* release the returned DiagramManager instance when it's no longer needed
* using {@link #removeConsumer(Object)}.
*
* @param process
* @return
*/
public static final DiagramManager getInstance(Process process, Object consumer) {
if(DEBUG) {
if(process.eIsProxy()) {
System.err.println("Process is a proxy: " + process); //$NON-NLS-1$
}
}
assert process != null && consumer != null && !process.eIsProxy();
setupLibraryServiceListener();
DiagramManager mgr = (DiagramManager) processToDiagramManagerMap.get(process);
if(mgr != null && mgr.isDisposed()) {
processToDiagramManagerMap.remove(process);
mgr = null;
}
if(mgr == null) {
synchronized(processToDiagramManagerMap) {
mgr = (DiagramManager) processToDiagramManagerMap.get(process);
if(mgr == null) {
mgr = new DiagramManager(process);
processToDiagramManagerMap.put(process, mgr);
if(!fileSynchronizer.fIsInstalled) {
fileSynchronizer.install();
}
}
}
}
mgr.addConsumer(consumer);
return mgr;
}
/**
* Checks if an diagram manager for the given process already exists.
*
* @param process
* @return
*/
public static final boolean hasDiagramManager(Process process) {
return processToDiagramManagerMap.containsKey(process);
}
public static boolean disposeDiagramManager(Process process) {
synchronized (processToDiagramManagerMap) {
DiagramManager mgr = processToDiagramManagerMap.get(process);
if(mgr != null) {
mgr.doDispose();
processToDiagramManagerMap.remove(process);
return true;
}
return false;
}
}
@SuppressWarnings("unchecked")
public static Collection<DiagramManager> getDiagramManagers() {
ArrayList<DiagramManager> mgrs;
synchronized(processToDiagramManagerMap) {
mgrs = new ArrayList<DiagramManager>(processToDiagramManagerMap.values());
}
return mgrs.isEmpty() ? Collections.EMPTY_LIST : mgrs;
}
private class GMFResourceEx extends GMFResource implements IFailSafeSavable {
private FailSafePersistenceHelper failSafePersistenceHelper;
public GMFResourceEx(URI uri) {
super(uri);
}
@Override
protected XMLHelper createXMLHelper() {
return new GMFHelper(this) {
protected URI getHREF(Resource otherResource, EObject obj) {
if(otherResource instanceof ILibraryResource) {
return ((ILibraryResource)otherResource).getProxyURI(obj);
}
return super.getHREF(otherResource, obj);
}
};
}
public void updateInfo() {
IFile file = WorkspaceSynchronizer.getFile(this);
if(DiagramManager.this.resourceIsNew) {
DiagramManager.this.resourceIsNew = false;
fileSynchronizer.monitor(file);
}
fileSynchronizer.updateModificationStamp(file);
try {
file.refreshLocal(IResource.DEPTH_ZERO, null);
} catch (CoreException e) {
CommonPlugin.getDefault().getLogger().logError(e);
}
}
@Override
public void save(Map options) throws IOException {
super.save(options);
if(!hasTempURI()) {
updateInfo();
}
}
private Adapter superCreateModificationAdapter() {
return super.createModificationTrackingAdapter();
}
@Override
protected Adapter createModificationTrackingAdapter() {
return new AdapterImpl() {
private Adapter delegate = superCreateModificationAdapter();
@Override
public void notifyChanged(Notification msg) {
delegate.notifyChanged(msg);
notifyDiagramChangeListeners(msg);
}
};
}
/**
* Don't notify DiagramModificationListener about resource modification event but rather
* let {@link #notifyDiagramChangeListeners(Notification) handle it.
*/
@Override
public void eNotify(Notification notification) {
if(isLoaded() && notification.getNotifier() instanceof Resource
&& notification.getFeatureID(Resource.class) == Resource.RESOURCE__IS_MODIFIED
&& notification.getEventType() == Notification.SET) {
if (eAdapters != null && eDeliver())
{
int size = eAdapters.size();
if (size > 0)
{
Adapter [] adapters = (Adapter [])eAdapters.data();
for (int i = 0; i < size; ++i)
{
Adapter adapter = adapters[i];
if(!(adapter instanceof AccessibleDiagramModificationListener)) {
adapter.notifyChanged(notification);
}
}
}
}
}
else {
super.eNotify(notification);
}
}
protected void notifyDiagramChangeListeners(Notification msg) {
BasicEList<Adapter> eAdapters = eBasicAdapters();
if (eAdapters != null && eDeliver())
{
int size = eAdapters.size();
if (size > 0)
{
Adapter [] adapters = (Adapter [])eAdapters.data();
for (int i = 0; i < size; ++i)
{
Adapter adapter = adapters[i];
if(adapter instanceof AccessibleDiagramModificationListener) {
adapter.notifyChanged(msg);
}
}
}
}
}
private FailSafePersistenceHelper getFailSafePersistenceHelper() {
if(failSafePersistenceHelper == null) {
// id format: <process_guid>diagram
String id = DiagramManager.this.process.getGuid() + DIAGRAM_FILENAME_WITHOUT_EXTENSION;
failSafePersistenceHelper = new FailSafePersistenceHelper(this, id);
failSafePersistenceHelper.setCommitEmptyResource(true);
}
return failSafePersistenceHelper;
}
public void commit() {
getFailSafePersistenceHelper().commit();
}
public void deleteBackup() {
getFailSafePersistenceHelper().deleteBackup();
}
public boolean hasTempURI() {
return getFailSafePersistenceHelper().hasTempURI();
}
public boolean restore() {
return getFailSafePersistenceHelper().restore();
}
public void setTxID(String txID) {
getFailSafePersistenceHelper().setTempURI(txID);
}
public void txFinished(boolean successful) {
getFailSafePersistenceHelper().txFinished(successful);
if(successful) {
updateInfo();
}
}
@Override
protected void doUnload() {
super.doUnload();
Iterator<EObject> allContents = getAllProperContents(unloadingContents);
List<EObject> list = new ArrayList<EObject>();
while (allContents.hasNext()) {
list.add(allContents.next());
}
for (EObject object : list) {
EcoreUtil.remove(object);
}
}
}
private class GMFExtendedResourceSet extends ExtendedResourceSet {
@Override
protected int getURIType(URI uri) {
if(MultiFileURIConverter.SCHEME.equals(uri.scheme())) {
return URI_TYPE_EXTERNAL;
}
if(DIAGRAM_FILENAME.equals(uri.lastSegment())) {
return URI_TYPE_LOCAL;
}
return URI_TYPE_EXTERNAL;
}
@SuppressWarnings("unchecked")
@Override
public Resource createResource(URI uri) {
XMIResource resource = new GMFResourceEx(uri);
resource.getDefaultLoadOptions().putAll(GMFResourceFactory.getDefaultLoadOptions());
resource.getDefaultSaveOptions().putAll(GMFResourceFactory.getDefaultSaveOptions());
if (!resource.getEncoding().equals(EMFCoreConstants.XMI_ENCODING))
resource.setEncoding(EMFCoreConstants.XMI_ENCODING);
getResources().add(resource);
return resource;
}
}
/**
* Reference count to this diagram manager
*/
private Process process;
private Resource resource;
private InternalTransactionalEditingDomain editingDomain;
private IProgressMonitor monitor;
private boolean resourceIsNew;
private List<IResourceChangeListener> resourceChangeListeners = new UniqueEList<IResourceChangeListener>();
private ExtendedResourceSet resourceSet;
private HashMap<Activity, Map<String, Diagram>> activityToSavedDiagramMap;
protected UniqueEList<Object> consumers = new UniqueEList<Object>();
private DiagramManager(Process process) {
this.process = process;
}
public Process getProcess() {
return process;
}
public void addResourceChangeListener(IResourceChangeListener listener) {
if(!resourceChangeListeners.contains(listener)) {
resourceChangeListeners.add(listener);
}
}
public void removeResourceChangeListener(IResourceChangeListener listener) {
resourceChangeListeners.remove(listener);
}
public synchronized boolean addConsumer(Object consumer) {
return consumers.add(consumer);
}
/**
* Removes the given consumer from the consumer list of this diagram manager. Unload
* this diagram manager if it does not have any more consumer after this call.
*/
public synchronized boolean removeConsumer(Object consumer) {
boolean ret = consumers.remove(consumer);
if(ret && consumers.isEmpty()) {
synchronized(processToDiagramManagerMap) {
processToDiagramManagerMap.remove(process);
if(processToDiagramManagerMap.isEmpty()) {
fileSynchronizer.uninstall();
}
}
doDispose();
}
return ret;
}
public boolean isNewResource() {
return resourceIsNew;
}
public void setResourceIsNew(boolean resourceIsNew) {
this.resourceIsNew = resourceIsNew;
}
public InternalTransactionalEditingDomain getEditingDomain() {
if (editingDomain == null && !isDisposed()) {
editingDomain = createEditingDomain();
resourceSet = (ExtendedResourceSet) editingDomain.getResourceSet();
}
return editingDomain;
}
private InternalTransactionalEditingDomain createEditingDomain() {
GMFExtendedResourceSet resourceSet = new GMFExtendedResourceSet();
resourceSet.add(process.eResource().getResourceSet());
return (InternalTransactionalEditingDomain) DiagramEditingDomainFactory.getInstance()
.createEditingDomain(resourceSet);
}
private void doDispose() {
if(resource != null) {
IFile file = WorkspaceSynchronizer.getFile(resource);
if(file != null) {
fileSynchronizer.unmonitor(file);
}
resource = null;
}
resourceChangeListeners.clear();
if(editingDomain != null) {
resourceSet.dispose();
resourceSet = null;
editingDomain.dispose();
editingDomain = null;
}
consumers.clear();
if(activityToSavedDiagramMap != null) {
activityToSavedDiagramMap.clear();
}
process = null;
}
public void dispose() {
synchronized (processToDiagramManagerMap) {
processToDiagramManagerMap.remove(process);
}
doDispose();
}
public boolean isDisposed() {
return process == null;
}
/**
* Gets diagrams of the given type for the specified activity
* <code>act</code>
*
* @param act
* @param type
* must be one of the following constants:
* {@link IDiagramManager#ACTIVITY_DIAGRAM},
* {@link IDiagramManager#ACTIVITY_DETAIL_DIAGRAM},
* {@link IDiagramManager#WORK_PRODUCT_DEPENDENCY_DIAGRAM}
* @return
* @throws CoreException
*/
public List<Diagram> getDiagrams(Activity act, int type) throws CoreException {
checkActivity(act);
Resource resource = getResource(false);
if(resource != null) {
ArrayList<Diagram> diagrams = new ArrayList<Diagram>();
for (EObject o : resource.getContents()) {
if(o instanceof Diagram) {
Diagram diagram = (Diagram) o;
String typeStr = getDiagramTypeString(type);
if(typeStr.equals(diagram.getType()) && isDiagramOf(diagram, act)) {
EObject model = diagram.getElement();
if(model instanceof DiagramImpl) {
// disable creation of UMA graphical data
//
((DiagramImpl)model).setGraphicalDataRequired(false);
}
diagrams.add(diagram);
}
}
}
if(!diagrams.isEmpty()) {
return diagrams;
}
}
return Collections.emptyList();
}
private static void markInherited(Diagram diagram) {
List<?> children = diagram.getChildren();
int size = children.size();
for (int i = 0; i < size; i++) {
View view = (View) children.get(i);
BridgeHelper.markInherited(view);
}
for (Object edge : diagram.getEdges()) {
BridgeHelper.markInherited((View) edge);
}
}
private static String getDiagramTypeString(int diagramType) {
switch(diagramType) {
case IDiagramManager.ACTIVITY_DETAIL_DIAGRAM:
return ADD_kind;
case IDiagramManager.ACTIVITY_DIAGRAM:
return AD_kind;
case IDiagramManager.WORK_PRODUCT_DEPENDENCY_DIAGRAM:
return WPD_kind;
}
return null;
}
public static int getDiagramType(String typeStr) {
if(AD_kind.equals(typeStr)) {
return IDiagramManager.ACTIVITY_DIAGRAM;
}
else if(ADD_kind.equals(typeStr)) {
return IDiagramManager.ACTIVITY_DETAIL_DIAGRAM;
}
else if(WPD_kind.equals(typeStr)) {
return IDiagramManager.WORK_PRODUCT_DEPENDENCY_DIAGRAM;
}
return -1;
}
/**
* Associates a new diagram with the given activity
*
* @param diagram
* @param type
* @param activity
* @throws CoreException
*/
public void associate(Diagram newDiagram, int type, Activity activity) throws CoreException {
switch(type) {
case IDiagramManager.ACTIVITY_DIAGRAM:
associateAD(newDiagram, activity);
return;
case IDiagramManager.ACTIVITY_DETAIL_DIAGRAM:
associateADD(newDiagram, activity);
return;
case IDiagramManager.WORK_PRODUCT_DEPENDENCY_DIAGRAM:
associateWPD(newDiagram, activity);
}
}
private void associateWPD(Diagram copy, Activity activity) throws CoreException {
// TODO - consolidate one method with ADD.
if(copy.getElement() instanceof WorkProductDependencyDiagram) {
((WorkProductDependencyDiagram)copy.getElement()).setLinkedElement(activity);
((DiagramImpl)copy.getElement()).setGraphicalDataRequired(false);
}
getResource().getContents().add(copy.getElement());
getResource().getContents().add(copy);
}
private void associateAD(Diagram copy, Activity act) throws CoreException {
if(copy.getElement() instanceof EModelElement) {
BridgeHelper.associate((EModelElement) copy.getElement(), act);
}
getResource().getContents().add(copy.getElement());
getResource().getContents().add(copy);
}
private void associateADD(Diagram copy, Activity activity) throws CoreException {
if(copy.getElement() instanceof ActivityDetailDiagram) {
((ActivityDetailDiagram)copy.getElement()).setLinkedElement(activity);
((DiagramImpl)copy.getElement()).setGraphicalDataRequired(false);
}
getResource().getContents().add(copy.getElement());
getResource().getContents().add(copy);
}
private Diagram copyDiagram(Diagram diagram, Activity targetActivity) {
Diagram copy = DiagramHelper.copyDiagram(getEditingDomain(), diagram);
DiagramHelper.reassociate(targetActivity, copy);
return copy;
}
public Diagram createDiagram(final Activity act, final int type, final PreferencesHint hint) throws CoreException {
checkActivity(act);
// check if this activity contributes/extends other activity and try
// copy
// the existing diagram from the base
//
if (ProcessUtil.isExtendingOrLocallyContributing(act)) {
Activity baseAct = (Activity) act.getVariabilityBasedOnElement();
DiagramManager mgr = DiagramManager.getInstance(TngUtil.getOwningProcess(baseAct), this);
try {
List baseDiagrams = mgr.getDiagrams(baseAct, type);
if(!baseDiagrams.isEmpty()) {
Diagram baseDiagram = (Diagram) baseDiagrams.get(0);
if (baseDiagram != null) {
final Diagram copy = copyDiagram(baseDiagram, act);
TxUtil.runInTransaction(getEditingDomain(), new Runnable() {
public void run() {
markInherited(copy);
try {
associate(copy, type, act);
} catch (CoreException e) {
throw new WrappedException(e);
}
}
});
return copy;
}
}
} catch(Exception e){
CommonPlugin.getDefault().getLogger().logError("Error in retrieving base diagram: ", e); //$NON-NLS-1$
}
finally {
if(mgr != null) {
mgr.removeConsumer(this);
}
}
}
final Diagram[] resultHolder = new Diagram[1];
try {
TxUtil.runInTransaction(getEditingDomain(), new Runnable() {
public void run() {
try {
resultHolder[0] = doCreateDiagram(act, type, hint);
} catch (CoreException e) {
throw new WrappedException(e);
}
}
});
} catch (Exception e) {
DiagramCorePlugin.getDefault().getLogger().logError(e);
if(DEBUG) {
e.printStackTrace();
}
}
return resultHolder[0];
}
private Diagram doCreateDiagram(Activity act, int type, PreferencesHint hint) throws CoreException {
switch(type) {
case IDiagramManager.ACTIVITY_DIAGRAM:
return createAD(act, hint);
case IDiagramManager.ACTIVITY_DETAIL_DIAGRAM:
return createADD(act, hint);
case IDiagramManager.WORK_PRODUCT_DEPENDENCY_DIAGRAM:
return createWPDD(act, hint);
}
return null;
}
private Diagram createWPDD(Activity act, PreferencesHint hint)
throws CoreException {
// ProcessPackage model = (ProcessPackage) act.eContainer();
WorkProductDependencyDiagram model = ModelFactory.eINSTANCE
.createWorkProductDependencyDiagram();
if (model instanceof DiagramImpl) {
// disable creation of UMA graphical data
//
((DiagramImpl) model).setGraphicalDataRequired(false);
}
model.setNew(true);
Diagram diagram = ViewService
.createDiagram(
model,
getDiagramTypeString(IDiagramManager.WORK_PRODUCT_DEPENDENCY_DIAGRAM),
hint);
if (diagram != null) {
diagram.setName(act.getName());
model.setLinkedElement(act);
getResource().getContents().add(model);
getResource().getContents().add(diagram);
// add ResourceDomainLink to the method library resource set
//
// EcoreUtil.getAdapter(getResource().getResourceSet().eAdapters(),
// ResourceDo)
}
return diagram;
}
private Diagram createADD(Activity act, PreferencesHint hint)
throws CoreException {
ActivityDetailDiagram model = ModelFactory.eINSTANCE
.createActivityDetailDiagram();
if (model instanceof DiagramImpl) {
// disable creation of UMA graphical data
//
((DiagramImpl) model).setGraphicalDataRequired(false);
}
model.setNew(true);
Diagram diagram = ViewService.createDiagram(model,
getDiagramTypeString(IDiagramManager.ACTIVITY_DETAIL_DIAGRAM),
hint);
if (diagram != null) {
model.setLinkedElement(act);
diagram.setName(act.getName());
getResource().getContents().add(model);
getResource().getContents().add(diagram);
}
return diagram;
}
private Diagram createAD(Activity act, PreferencesHint hint) throws CoreException {
org.eclipse.uml2.uml.Activity model = UMLFactory.eINSTANCE
.createActivity();
Diagram diagram = ViewService.createDiagram(model,
getDiagramTypeString(IDiagramManager.ACTIVITY_DIAGRAM), hint);
if (diagram != null) {
BridgeHelper.associate(model, act);
diagram.setName(act.getName());
model.setName(act.getName());
getResource().getContents().add(model);
getResource().getContents().add(diagram);
}
return diagram;
}
private IProgressMonitor getMonitor() {
if(monitor == null) {
monitor = new NullProgressMonitor();
}
return monitor;
}
public static String getDiagramFilePath(Process process) {
try {
ProcessComponent procComp = (ProcessComponent) process.eContainer();
if(procComp == null) {
return null;
}
if(UmaUtil.hasDirectResource(procComp)) {
// existing process
//
return new File(new File(FileManager.toFileString(process.eResource().getURI())).getParentFile(), DIAGRAM_FILENAME).getCanonicalPath();
}
else {
// new process that has not been saved yet
//
URI uri = MultiFileSaveUtil.createURI(procComp, procComp.eResource().getResourceSet());
return new File(new File(uri.toFileString()).getParentFile(),
DIAGRAM_FILENAME).getCanonicalPath();
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public void reload() throws IOException {
if(resource == null) {
return;
}
resource.unload();
resource.load(Collections.EMPTY_MAP);
IFile file = WorkspaceSynchronizer.getFile(resource);
fileSynchronizer.updateModificationStamp(file);
notifyReloaded();
}
public Resource getResource() throws CoreException {
if(resource == null) {
resource = getResource(true);
}
return resource;
}
private static URI createDiagramResourceURI(String path) {
IFile diagramFile = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(path));
return URI.createPlatformResourceURI(diagramFile
.getFullPath().toString());
}
private static Resource loadDiagramResource(IFile fFile,
EditingDomain domain, Map loadOptions, IProgressMonitor monitor)
throws CoreException, IOException {
fFile.refreshLocal(IResource.DEPTH_ZERO, monitor);
URI uri = URI.createPlatformResourceURI(fFile.getFullPath()
.toString(), true);
Resource resource = domain.getResourceSet().getResource(uri, false);
if (resource == null) {
resource = domain.getResourceSet().createResource(uri);
}
if (!resource.isLoaded()) {
Map loadingOptions = new HashMap(GMFResourceFactory.getDefaultLoadOptions());
// propogate passed in options to the defaults
Iterator iter = loadOptions.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
loadingOptions.put(key, loadOptions.get(key));
}
try {
resource.load(loadingOptions);
} catch (IOException e) {
resource.unload();
throw e;
}
}
return resource;
}
private Resource getResource(boolean create) throws CoreException {
if(resource == null) {
String path = getDiagramFilePath(process);
if(path != null) {
IResource wsRes = FileManager.getResourceForLocation(path);
if(wsRes instanceof IFile) {
IFile file = (IFile) wsRes;
try {
Diagram diagram = DiagramIOUtil.load(getEditingDomain(), file, true, getMonitor());
resource = diagram.eResource();
}
catch(CoreException e) {
// handled exception that is thrown if resource does not have any diagram
//
if(org.eclipse.gmf.runtime.diagram.ui.resources.editor.internal.l10n.EditorMessages.Diagram_NO_DIAGRAM_IN_RESOURCE
.equals(e.getMessage())) {
try {
resource = loadDiagramResource(file, getEditingDomain(), Collections.EMPTY_MAP, getMonitor());
} catch (IOException e1) {
if(DEBUG) {
DiagramCorePlugin.getDefault().getLogger().logError(e);
}
throw new CoreException(new Status(IStatus.ERROR, DiagramCorePlugin.PLUGIN_ID, e1.getMessage(), e1));
}
}
else {
throw e;
}
}
fileSynchronizer.monitor(file);
}
else if(create) {
resource = getEditingDomain().getResourceSet().createResource(
createDiagramResourceURI(path));
resourceIsNew = true;
try {
TxUtil.runInTransaction(getEditingDomain(), new Runnable() {
public void run() {
resource.getContents().clear();
}
});
} catch (Exception e) {
DiagramCorePlugin.getDefault().getLogger().logError(e);
}
}
}
}
else if(!resource.isLoaded()) {
try {
resource.load(Collections.EMPTY_MAP);
notifyReloaded();
} catch (IOException e) {
CommonPlugin.getDefault().getLogger().logError(e);
if(DEBUG) {
e.printStackTrace();
}
}
}
return resource;
}
private void notifyReloaded() {
for (Iterator iter = resourceChangeListeners.iterator(); iter.hasNext();) {
IResourceChangeListener listener = (IResourceChangeListener) iter.next();
try {
listener.resourceChanged(new ResourceChangeEvent(this, IResourceChangeEvent.POST_CHANGE, 0, null));
}
catch(Exception e) {
CommonPlugin.getDefault().getLogger().logError(e);
if(DEBUG) {
e.printStackTrace();
}
}
}
}
private void checkActivity(Activity act) {
Process proc = TngUtil.getOwningProcess(act);
if(proc != process) {
throw new IllegalArgumentException("The specified activity does not belong to the process of this diagram manager."); //$NON-NLS-1$
}
}
private static boolean isDiagramOf(Diagram diagram, Activity act) {
if(AD_kind.equals(diagram.getType())) {
return BridgeHelper.getMethodElementFromAnnotation((EModelElement) diagram.getElement(), act.eResource().getResourceSet()) == act;
}
else if(ADD_kind.equals(diagram.getType())) {
EObject model = diagram.getElement();
return model instanceof ActivityDetailDiagram && ((ActivityDetailDiagram)model).getLinkedElement() == act;
}
else if(WPD_kind.equals(diagram.getType())) {
EObject model = diagram.getElement();
return model instanceof WorkProductDependencyDiagram && ((WorkProductDependencyDiagram)model).getLinkedElement() == act;
}
return false;
}
/**
* Checks whether the given resource has been changed on the
* local file system by comparing the actual time stamp with the
* cached one. If the resource has been changed, a <code>CoreException</code>
* is thrown.
*
* @param cachedModificationStamp the cached modification stamp
* @param resource the resource to check
* @throws org.eclipse.core.runtime.CoreException if resource has been changed on the file system
*/
public static void checkSynchronizationState(Resource resource) throws CoreException {
if(!isSynchronized(resource)) {
Status status= new Status(IStatus.ERROR, PlatformUI.PLUGIN_ID, IResourceStatus.OUT_OF_SYNC_LOCAL, EditorMessages.FileDocumentProvider_error_out_of_sync, null);
throw new CoreException(status);
}
}
public static boolean isSynchronized(Resource resource) {
IFile file = WorkspaceSynchronizer.getFile(resource);
if(file != null) {
// don't refresh to prevent resource from automatically reloaded
//
// file.refreshLocal(IResource.DEPTH_ZERO, monitor);
FileInfo info = fileSynchronizer.getFileInfo(file);
if(info != null) {
return info.fModificationStamp == FileSynchronizer.computeModificationStamp(file);
}
}
return true;
}
private Map<Activity, Map<String, Diagram>> getActivityToSavedDiagramsMap() {
if(activityToSavedDiagramMap == null) {
activityToSavedDiagramMap = new HashMap<Activity, Map<String, Diagram>>();
}
return activityToSavedDiagramMap;
}
private Diagram getDiagramBackup(Activity act, String type) {
if(activityToSavedDiagramMap != null) {
Map<String, Diagram> typeToDiagamMap = activityToSavedDiagramMap.get(act);
if(typeToDiagamMap != null) {
return (Diagram) typeToDiagamMap.get(type);
}
}
return null;
}
public void replaceTemporarily(final Activity act, final Diagram diagram) {
try {
new AbstractEMFOperation(getEditingDomain(), StringStatics.BLANK) {
@Override
protected IStatus doExecute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
try {
List diagrams = getDiagrams(act, getDiagramType(diagram.getType()));
if(!diagrams.isEmpty()) {
Diagram savedDiagram = (Diagram) diagrams.get(0);
Map<String, Diagram> typeToDiagamMap = getActivityToSavedDiagramsMap().get(act);
if(typeToDiagamMap == null) {
typeToDiagamMap = new HashMap<String, Diagram>();
getActivityToSavedDiagramsMap().put(act, typeToDiagamMap);
}
if(typeToDiagamMap.get(diagram.getType()) == null) {
typeToDiagamMap.put(diagram.getType(), savedDiagram);
}
((InternalEObject) diagram).eSetProxyURI(null);
for (Iterator iter = diagram.eAllContents(); iter
.hasNext(); ((InternalEObject) iter.next()).eSetProxyURI(null));
((InternalEObject) diagram.getElement()).eSetProxyURI(null);
for (Iterator iter = diagram.getElement().eAllContents(); iter
.hasNext(); ((InternalEObject) iter.next()).eSetProxyURI(null));
resource.getContents().set(resource.getContents().indexOf(savedDiagram), diagram);
resource.getContents().set(resource.getContents().indexOf(savedDiagram.getElement()), diagram.getElement());
}
else {
resource.getContents().add(diagram.getElement());
resource.getContents().add(diagram);
}
} catch (CoreException e) {
CommonPlugin.getDefault().getLogger().logError(e);
}
return Status.OK_STATUS;
}
}.execute(new NullProgressMonitor(), null);
} catch (ExecutionException e1) {
CommonPlugin.getDefault().getLogger().logError(e1);
}
}
private Diagram getSavedDiagram(Activity act, Diagram diagram) {
Diagram savedDiagram = getDiagramBackup(act, diagram.getType());
// if(savedDiagram == null) {
// // try to load diagram from file
// //
// IFile file = WorkspaceSynchronizer.getFile(resource);
// if(file != null) {
// TransactionalEditingDomain domain = createEditingDomain();
// try {
// Diagram d = DiagramIOUtil.load(domain, file, true, getMonitor());
// if(d != null) {
// int index = resource.getContents().indexOf(diagram);
// savedDiagram = (Diagram) d.eResource().getContents().get(index);
// }
// } catch (CoreException e) {
// DiagramCorePlugin.getDefault().getLogger().logError(e);
// } finally {
// if(domain != null) {
// domain.dispose();
// }
// }
// }
// }
return savedDiagram;
}
public synchronized boolean reverseToSaved(final Activity act, final Diagram diagram, PreferencesHint hint) {
final Diagram savedDiagram = getSavedDiagram(act, diagram);
try {
new AbstractEMFOperation(getEditingDomain(), StringStatics.BLANK) {
@Override
protected IStatus doExecute(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
if(savedDiagram != null) {
// restore diagram to its backup
//
resource.getContents().set(resource.getContents().indexOf(diagram), savedDiagram);
resource.getContents().set(resource.getContents().indexOf(diagram.getElement()), savedDiagram.getElement());
removeDiagramBackup(act, diagram.getType());
}
else {
// diagram is newly created, remove it from resource
//
resource.getContents().remove(diagram.getElement());
resource.getContents().remove(diagram);
}
ILibraryPersister.FailSafeMethodLibraryPersister persister = LibraryServiceUtil
.getPersisterFor(act.eResource())
.getFailSafePersister();
try {
persister.save(resource);
persister.commit();
} catch (Exception e) {
DiagramCorePlugin.getDefault().getLogger().logError(e);
try {
persister.rollback();
}
catch(Exception ex) {}
throw new ExecutionException(e.getMessage(), e);
}
return Status.OK_STATUS;
}
}.execute(new NullProgressMonitor(), null);
return true;
} catch (ExecutionException e1) {
CommonPlugin.getDefault().getLogger().logError(e1);
}
return false;
}
/**
* Updates URI of diagram resource after the URI of process resource has been changed.
*/
public void updateResourceURI() {
if(resource == null) {
return;
}
File folder = new File(FileManager.toFileString(resource.getURI())).getParentFile();
File procFolder = new File(process.eResource().getURI().toFileString()).getParentFile();
if(!folder.equals(procFolder)) {
String path = getDiagramFilePath(process);
if(path != null && new File(path).exists()) {
resource.setURI(createDiagramResourceURI(path));
}
}
}
public void backupDiagram(Activity activity, Diagram diagram) {
Map<String, Diagram> typeToDiagamMap = getActivityToSavedDiagramsMap().get(activity);
if(typeToDiagamMap == null) {
typeToDiagamMap = new HashMap<String, Diagram>();
getActivityToSavedDiagramsMap().put(activity, typeToDiagamMap);
}
typeToDiagamMap.put(diagram.getType(), DiagramHelper.copyDiagram(getEditingDomain(), diagram));
}
public Diagram removeDiagramBackup(Activity act, String type) {
if(activityToSavedDiagramMap != null) {
Map<String, Diagram> typeToDiagamMap = activityToSavedDiagramMap.get(act);
if(typeToDiagamMap != null) {
return (Diagram) typeToDiagamMap.remove(type);
}
}
return null;
}
}