| //------------------------------------------------------------------------------ |
| // 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.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.library.persistence.util.FileSynchronizer.FileInfo; |
| 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 Collection<IFile> 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 movedFileToNewPathMap.keySet(); |
| } |
| |
| @Override |
| protected Collection<IFile> handleDeletedFiles(Collection<IFile> deletedFiles) { |
| 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.isInstalled()) { |
| 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; |
| } |
| } |