| /******************************************************************************* |
| * Copyright (c) 2003, 2006 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 API and implementation |
| *******************************************************************************/ |
| /* |
| * Created on Mar 4, 2004 |
| * |
| * To change the template for this generated file go to |
| * Window>Preferences>Java>Code Generation>Code and Comments |
| */ |
| package org.eclipse.wst.common.internal.emfworkbench.integration; |
| |
| import java.lang.ref.WeakReference; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceChangeEvent; |
| import org.eclipse.core.resources.IResourceDelta; |
| import org.eclipse.core.resources.IResourceDeltaVisitor; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.IWorkspaceRunnable; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.common.util.WrappedException; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.jem.internal.util.emf.workbench.EMFWorkbenchContextFactory; |
| import org.eclipse.jem.internal.util.emf.workbench.ProjectResourceSetImpl; |
| import org.eclipse.jem.util.emf.workbench.ProjectResourceSet; |
| import org.eclipse.jem.util.emf.workbench.ResourceSetWorkbenchSynchronizer; |
| import org.eclipse.jem.util.plugin.JEMUtilPlugin; |
| import org.eclipse.wst.common.internal.emf.resource.ReferencedResource; |
| import org.eclipse.wst.common.internal.emfworkbench.WorkbenchResourceHelper; |
| |
| /** |
| * @author schacher |
| * |
| * To change the template for this generated type comment go to |
| * Window>Preferences>Java>Code Generation>Code and Comments |
| */ |
| public class ResourceSetWorkbenchEditSynchronizer extends ResourceSetWorkbenchSynchronizer implements IResourceDeltaVisitor { |
| private static final String CLASS_EXTENSION = "class"; //$NON-NLS-1$ |
| private static final String JAVA_EXTENSION = "java"; //$NON-NLS-1$ |
| private static final String JAVA_ARCHIVE = "jar"; //$NON-NLS-1$ |
| private Set recentlySavedFiles = new HashSet(); |
| private Map ignoredFilesCache = new HashMap(); |
| private class SavedFileKey { |
| private WeakReference res; |
| private IFile savedFile; |
| public SavedFileKey(Resource res, IFile savedFile) { |
| super(); |
| this.res = new WeakReference(res); |
| this.savedFile = savedFile; |
| } |
| public Resource getRes() { |
| return this.res == null ? null : (Resource)res.get(); |
| } |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + getOuterType().hashCode(); |
| result = prime * result + ((getRes() == null) ? 0 : getRes().hashCode()); |
| result = prime * result + ((savedFile == null) ? 0 : savedFile.hashCode()); |
| return result; |
| } |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| SavedFileKey other = (SavedFileKey) obj; |
| if (!getOuterType().equals(other.getOuterType())) |
| return false; |
| if (getRes() == null) { |
| if (other.getRes() != null) |
| return false; |
| } else if (!getRes().equals(other.getRes())) |
| return false; |
| if (savedFile == null) { |
| if (other.savedFile != null) |
| return false; |
| } else if (!savedFile.equals(other.savedFile)) |
| return false; |
| return true; |
| } |
| private ResourceSetWorkbenchEditSynchronizer getOuterType() { |
| return ResourceSetWorkbenchEditSynchronizer.this; |
| } |
| } |
| |
| /** The emf resources to be removed from the resource set as a result of a delta */ |
| protected List deferredRemoveResources = new ArrayList(); |
| protected List deferredUnloadResources = new ArrayList(); |
| protected List deferredLoadResources = new ArrayList(); |
| |
| protected List autoloadResourcesURIs = new ArrayList(); |
| protected List autoloadResourcesExts = new ArrayList(); |
| |
| |
| /** |
| * @param aResourceSet |
| * @param aProject |
| */ |
| public ResourceSetWorkbenchEditSynchronizer(ResourceSet aResourceSet, IProject aProject) { |
| super(aResourceSet, aProject); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.wst.common.internal.emfworkbench.ResourceSetWorkbenchSynchronizer#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) |
| */ |
| @Override |
| public void resourceChanged(IResourceChangeEvent event) { |
| super.resourceChanged(event); |
| try { |
| acceptDelta(event); |
| notifyExtendersIfNecessary(); |
| processDeferredResources(); |
| } catch (Exception e) { |
| EMFWorkbenchEditPlugin.logError(e); |
| } finally { |
| deferredRemoveResources.clear(); |
| deferredUnloadResources.clear(); |
| deferredLoadResources.clear(); |
| } |
| } |
| |
| protected void processDeferredRemovedResources() { |
| Resource resource = null; |
| for (int i = 0; i < deferredRemoveResources.size(); i++) { |
| resource = (Resource) deferredRemoveResources.get(i); |
| resourceSet.getResources().remove(resource); |
| resource.unload(); |
| } |
| } |
| |
| protected void processDeferredUnloadedResources() { |
| Resource resource = null; |
| for (int i = 0; i < deferredUnloadResources.size(); i++) { |
| resource = (Resource) deferredUnloadResources.get(i); |
| resource.unload(); |
| } |
| } |
| |
| private void processDeferredLoadResources() { |
| URI uri = null; |
| for (int i = 0; i < deferredLoadResources.size(); i++) { |
| uri = (URI) deferredLoadResources.get(i); |
| try { |
| resourceSet.getResource(uri, true); |
| } catch (WrappedException ex) { |
| EMFWorkbenchEditPlugin.logError(ex); |
| } |
| |
| } |
| } |
| |
| protected void acceptDelta(final IResourceChangeEvent event) { |
| |
| final IResourceDelta delta = event.getDelta(); |
| |
| if (ResourcesPlugin.getWorkspace().isTreeLocked()) { |
| primAcceptDelta(delta, event); |
| } |
| else { |
| IWorkspaceRunnable runnable = new IWorkspaceRunnable() { |
| public void run(IProgressMonitor monitor) throws CoreException { |
| primAcceptDelta(delta, event); |
| } |
| }; |
| try { |
| ResourcesPlugin.getWorkspace().run(runnable, project, IWorkspace.AVOID_UPDATE, null); |
| } catch (CoreException e) { |
| EMFWorkbenchEditPlugin.logError(e); |
| } |
| } |
| } |
| |
| private void primAcceptDelta(IResourceDelta delta, IResourceChangeEvent event) { |
| if (delta != null) { |
| try { |
| currentProjectDelta = null; |
| delta.accept(ResourceSetWorkbenchEditSynchronizer.this); |
| } catch (Exception e) { |
| EMFWorkbenchEditPlugin.logError(e); |
| } |
| } |
| } |
| |
| /** |
| * The project is going away so we need to cleanup ourself and the ResourceSet. TODO Need to |
| * push up this code to ResourceSetWorkbenchSynchronizer in next release. |
| */ |
| @Override |
| protected void release() { |
| if (JEMUtilPlugin.isActivated()) { |
| try { |
| if (resourceSet instanceof ProjectResourceSet) |
| ((ProjectResourceSet) resourceSet).release(); |
| } finally { |
| EMFWorkbenchContextFactory.INSTANCE.removeCachedProject(getProject()); |
| dispose(); |
| } |
| } |
| } |
| |
| private void processDeferredResources() { |
| processDeferredRemovedResources(); |
| processDeferredUnloadedResources(); |
| processDeferredLoadResources(); |
| } |
| |
| public boolean visit(IResourceDelta delta) { |
| IResource resource = delta.getResource(); |
| // only respond to project changes |
| if (resource != null) { |
| if (resource.getType() == IResource.PROJECT) { |
| IProject p = (IProject) resource; |
| if (isInterrestedInProject(p)) { |
| currentProjectDelta = delta; |
| return true; |
| } |
| return false; |
| } |
| if (resource.getType() == IResource.FILE && isInterrestedInFile((IFile) resource)) { |
| switch (delta.getKind()) { |
| case IResourceDelta.REMOVED : |
| removedResource((IFile) resource); |
| break; |
| case IResourceDelta.ADDED : |
| addedResource((IFile) resource); |
| break; |
| case IResourceDelta.CHANGED : |
| if ((delta.getFlags() & IResourceDelta.CONTENT) != 0) |
| changedResource((IFile) resource); |
| break; |
| default : |
| if ((delta.getFlags() & IResourceDelta.MOVED_FROM) != 0 || (delta.getFlags() & IResourceDelta.MOVED_TO) != 0) |
| movedResource((IFile) resource); |
| break; |
| } |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * Queue up the <code>Resource</code> that corresponds to <code>aFile</code>, for removal |
| * from the cache of resources. |
| * |
| * @post Return true if a <code>Resource</code> was queued up to be removed. |
| */ |
| protected boolean removedResource(IFile aFile) { |
| return processResource(aFile, true); |
| } |
| |
| /** |
| * Queue up the <code>Resource</code> that corresponds to <code>aFile</code>, for reload. |
| * |
| * @post Return true if a <code>Resource</code> was queued up to be reloaded. |
| */ |
| protected boolean addedResource(IFile aFile) { |
| boolean didProcess = false; |
| List resources = getResources(aFile); |
| for (Iterator iterator = resources.iterator(); iterator.hasNext();) { |
| Resource resource = (Resource) iterator.next(); |
| |
| if (resource != null) { |
| if (recentlySavedFilesContains(resource)) { |
| |
| /* |
| * The IFile was just added to the workspace but we have a |
| * changed resource in memory. Need to decide if it should |
| * be unloaded. |
| */ |
| if (resource.isModified()) { |
| if (WorkbenchResourceHelper.isReferencedResource(resource)) { |
| ReferencedResource refRes = (ReferencedResource) resource; |
| if (refRes.shouldForceRefresh()) { |
| deferredUnloadResources.add(resource); |
| didProcess = true; |
| } |
| } |
| } |
| } else { |
| /* Unload if found and is not modified but inconsistent. */ |
| if (resource.isLoaded()) { |
| if (WorkbenchResourceHelper.isReferencedResource(resource)) { |
| if (!WorkbenchResourceHelper.isConsistent((ReferencedResource) resource)) { |
| deferredUnloadResources.add(resource); |
| didProcess = true; |
| } |
| } else { |
| deferredUnloadResources.add(resource); |
| didProcess = true; |
| } |
| } else { |
| /* Process autoload resources on added file */ |
| URI uri = URI.createPlatformResourceURI(aFile.getFullPath().toString()); |
| if ((autoloadResourcesURIs.contains(uri)) || (autoloadResourcesExts.contains(aFile.getFileExtension()))) { |
| deferredLoadResources.add(uri); |
| didProcess = true; |
| } |
| } |
| } |
| } |
| } |
| return didProcess; |
| } |
| |
| private synchronized boolean recentlySavedFilesContains(Resource resource) { |
| for (Iterator iterator = recentlySavedFiles.iterator(); iterator.hasNext();) { |
| SavedFileKey key = (SavedFileKey) iterator.next(); |
| if (key.getRes() != null && (key.getRes().getURI().equals(resource.getURI()) && key.getRes().getClass().equals(resource.getClass()))) |
| return true; |
| } |
| return false; |
| } |
| |
| protected boolean processResource(IFile aFile, boolean isRemove) { |
| List resources = getResources(aFile); |
| for (Iterator iterator = resources.iterator(); iterator.hasNext();) { |
| Resource resource = (Resource) iterator.next(); |
| if ((resource != null)) { |
| if (recentlySavedFilesContains(resource)) { |
| if (resource.isModified()) { |
| if (WorkbenchResourceHelper.isReferencedResource(resource)) { |
| ReferencedResource refRes = (ReferencedResource) resource; |
| if (!refRes.shouldForceRefresh()) |
| continue; // Do not do anything |
| } else |
| continue; |
| } |
| } |
| if (isRemove) |
| deferredRemoveResources.add(resource); |
| else if (resource.isLoaded()) { |
| if (WorkbenchResourceHelper.isReferencedResource(resource)) { |
| if (!WorkbenchResourceHelper.isConsistent((ReferencedResource) resource)) |
| deferredUnloadResources.add(resource); |
| } else |
| deferredUnloadResources.add(resource); |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * For now, do the same as if the <code>aFile</code> was removed. |
| */ |
| protected boolean movedResource(IFile aFile) { |
| return removedResource(aFile); |
| } |
| |
| /** |
| * The contents of <code>aFile</code> have changed in the Workbench and we may need to update |
| * our cached resources. |
| * |
| * We will process this resource to be refreshed and not removed. |
| * |
| * @post Return true if a <code>Resource</code> was actually removed. |
| */ |
| |
| protected boolean changedResource(IFile aFile) { |
| //Process resource as a refresh. |
| return processResource(aFile, false); |
| } |
| |
| protected Resource getResource(IFile aFile) { |
| |
| return resourceSet.getResource(URI.createPlatformResourceURI(aFile.getFullPath().toString()), false); |
| } |
| |
| protected List getResources(IFile aFile) { |
| |
| List resources = new ArrayList(); |
| String aFileString = URI.decode(aFile.getFullPath().toString()); |
| IPath aFilePath = new Path(aFileString).removeFirstSegments(1); |
| if (!aFilePath.isEmpty()) |
| { |
| aFileString = aFilePath.toString(); |
| } |
| if (aFileString.length() > 0) |
| { |
| List allResources = null; |
| if (resourceSet instanceof ProjectResourceSetImpl) { |
| ProjectResourceSetImpl projResSet =(ProjectResourceSetImpl)resourceSet; |
| allResources = projResSet.getImmutableResources(); |
| } else { |
| allResources = resourceSet.getResources(); |
| } |
| for (Iterator iterator = allResources.iterator(); iterator.hasNext();) { |
| Resource res = (Resource) iterator.next(); |
| URI resURI = res.getURI(); |
| String resURIString = ""; //$NON-NLS-1$ |
| if (resURI.path() != null) { |
| IPath resURIPath; |
| if (WorkbenchResourceHelper.isPlatformResourceURI(resURI)) |
| resURIPath = new Path(URI.decode(resURI.path())).removeFirstSegments(2); |
| else |
| resURIPath = new Path(URI.decode(resURI.path())).removeFirstSegments(1); |
| resURIString = resURIPath.toString(); |
| } |
| |
| if (resURIString.length() > 0) |
| { |
| if (aFileString.equals(resURIString)) |
| //if (!resURIString.equals("") && aFile.getFullPath().toString().indexOf(resURIString) != -1) //$NON-NLS-1$ |
| resources.add(res); |
| } |
| } |
| } |
| return resources; |
| } |
| |
| |
| /** |
| * This method should be called prior to writing to an IFile from a MOF resource. |
| */ |
| @Override |
| public void preSave(IFile aFile) { |
| if (aFile != null) { |
| recentlySavedFilesAdd(aFile,null); |
| ignoredFilesCache.remove(aFile); |
| } |
| } |
| |
| /** |
| * This method should be called prior to writing to an IFile from a MOF resource. |
| */ |
| public void preSave(IFile aFile, Resource res) { |
| if (aFile != null) { |
| recentlySavedFilesAdd(aFile, res); |
| ignoredFilesCache.remove(aFile); |
| } |
| } |
| |
| private synchronized boolean recentlySavedFilesAdd(IFile file, Resource res) { |
| return recentlySavedFiles.add(new SavedFileKey(res, file)); |
| } |
| |
| /** |
| * This method should be called after a preSave if the save fails |
| */ |
| public void removeFromRecentlySavedList(IFile aFile) { |
| if (aFile != null) { |
| recentlySavedFilesForceRemove(aFile); |
| ignoredFilesCache.remove(aFile); |
| } |
| } |
| |
| private synchronized boolean recentlySavedFilesRemove(IFile file) { |
| |
| boolean removedFromList = false; |
| for (Iterator iterator = recentlySavedFiles.iterator(); iterator.hasNext();) { |
| SavedFileKey key = (SavedFileKey) iterator.next(); |
| if (key.savedFile != null && key.savedFile.equals(file)) { |
| List resources = getResources(file); |
| if (key.getRes() == null || resources.contains(key.getRes()) ) { |
| iterator.remove(); |
| removedFromList = true; |
| } |
| } |
| } |
| return removedFromList; |
| } |
| private synchronized boolean recentlySavedFilesForceRemove(IFile file) { |
| |
| boolean removedFromList = false; |
| for (Iterator iterator = recentlySavedFiles.iterator(); iterator.hasNext();) { |
| SavedFileKey key = (SavedFileKey) iterator.next(); |
| if (key.savedFile != null && key.savedFile.equals(file)) { |
| iterator.remove(); |
| removedFromList = true; |
| } |
| } |
| return removedFromList; |
| } |
| |
| /** |
| * This method should be called just after writing to an IFile from a MOF resource. |
| * |
| * @deprecated No longer needs to be called. |
| */ |
| public void postSave(IFile aFile) { |
| //TODO remove this method |
| } |
| |
| /** |
| * Return <code>true</code> if <code>aProject</code> has the projectNatureID. |
| */ |
| protected boolean isInterrestedInProject(IProject aProject) { |
| return aProject.equals(getProject()); |
| } |
| |
| /** |
| * Optimized not to be not interrested in files with an extension of .java or .class or if the |
| * file has just been saved by our own internal mechanism. |
| */ |
| protected boolean isInterrestedInFile(IFile aFile) { |
| String extension = aFile.getFileExtension(); |
| if (CLASS_EXTENSION.equals(extension) || JAVA_EXTENSION.equals(extension) || JAVA_ARCHIVE.equals(extension)) |
| return false; |
| if (recentlySavedFilesRemove(aFile)) { |
| cacheIgnored(aFile); |
| return false; |
| } |
| return !hasIgnored(aFile); |
| } |
| |
| /** |
| * Return true if we have already ignored this <code>file</code> and that its modification |
| * stamp is the same as when we processed it. |
| * |
| * @param file |
| * @return |
| */ |
| private boolean hasIgnored(IFile file) { |
| Long cachedStamp = (Long) ignoredFilesCache.get(file); |
| if (cachedStamp == null) |
| return false; |
| long stamp = WorkbenchResourceHelper.computeModificationStamp(file); |
| return cachedStamp.longValue() == stamp; |
| } |
| |
| /** |
| * Cache the modification stamp of the <code>file</code>. |
| * |
| * @param file |
| */ |
| private void cacheIgnored(IFile file) { |
| long stamp = WorkbenchResourceHelper.computeModificationStamp(file); |
| ignoredFilesCache.put(file, new Long(stamp)); |
| } |
| |
| public void enableAutoload(URI uri) { |
| URI normalized = resourceSet.getURIConverter().normalize(uri); |
| autoloadResourcesURIs.add(normalized); |
| } |
| |
| public void disableAutoload(URI uri) { |
| URI normalized = resourceSet.getURIConverter().normalize(uri); |
| autoloadResourcesURIs.remove(normalized); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.wst.common.internal.emfworkbench.ResourceSetWorkbenchSynchronizer#initialize() |
| */ |
| @Override |
| protected void initialize() { |
| getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.PRE_CLOSE | IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.POST_CHANGE); |
| } |
| public void enableAutoload(String extension) { |
| autoloadResourcesExts.add(extension); |
| |
| } |
| public void disableAutoload(String extension) { |
| autoloadResourcesExts.remove(extension); |
| } |
| |
| @Override |
| public void dispose() { |
| super.dispose(); |
| currentProjectDelta = null; |
| extenders = null; |
| } |
| |
| } |