| /******************************************************************************* |
| * 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 API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.jee.model.internal; |
| |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.ISafeRunnable; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.ListenerList; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.SafeRunner; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.content.IContentDescription; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| 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.xmi.impl.XMLResourceImpl; |
| import org.eclipse.jem.util.emf.workbench.FlexibleProjectResourceSet; |
| import org.eclipse.jem.util.emf.workbench.ProjectResourceSet; |
| import org.eclipse.jem.util.emf.workbench.WorkbenchResourceHelperBase; |
| import org.eclipse.jst.j2ee.componentcore.EnterpriseArtifactEdit; |
| import org.eclipse.jst.j2ee.model.IModelProvider; |
| import org.eclipse.jst.j2ee.model.IModelProviderEvent; |
| import org.eclipse.jst.j2ee.model.IModelProviderListener; |
| import org.eclipse.jst.j2ee.model.ModelProviderEvent; |
| import org.eclipse.jst.javaee.core.internal.util.JavaeeResourceImpl; |
| import org.eclipse.jst.jee.JEEPlugin; |
| import org.eclipse.wst.common.componentcore.ComponentCore; |
| import org.eclipse.wst.common.componentcore.internal.impl.ModuleURIUtil; |
| import org.eclipse.wst.common.componentcore.internal.impl.PlatformURLModuleConnection; |
| import org.eclipse.wst.common.componentcore.internal.impl.WTPResourceFactoryRegistry; |
| import org.eclipse.wst.common.componentcore.resources.IVirtualFolder; |
| import org.eclipse.wst.common.internal.emfworkbench.WorkbenchResourceHelper; |
| import org.eclipse.wst.common.internal.emfworkbench.validateedit.ResourceStateInputProvider; |
| import org.eclipse.wst.common.internal.emfworkbench.validateedit.ResourceStateValidator; |
| import org.eclipse.wst.common.internal.emfworkbench.validateedit.ResourceStateValidatorImpl; |
| import org.eclipse.wst.common.internal.emfworkbench.validateedit.ResourceStateValidatorPresenter; |
| |
| public class JEE5ModelProvider implements IModelProvider, ResourceStateInputProvider, ResourceStateValidator, IModelProviderListener{ |
| |
| protected XMLResourceImpl writableResource; |
| protected IProject proj; |
| protected IPath defaultResourcePath; |
| protected ResourceStateValidator stateValidator; |
| protected ResourceAdapter resourceAdapter = new ResourceAdapter(); |
| protected final ListenerList listeners = new ListenerList(); |
| //private static boolean resourceChangeListenerEnabled = false; |
| |
| private List modelResources = new ArrayList(); |
| protected class ResourceAdapter extends AdapterImpl { |
| @Override |
| public void notifyChanged(Notification notification) { |
| if (notification.getEventType() == Notification.SET |
| && notification.getFeatureID(null) == Resource.RESOURCE__IS_LOADED) { |
| resourceIsLoadedChanged((Resource) notification.getNotifier(), notification.getOldBooleanValue(), notification.getNewBooleanValue()); |
| } else if (notification.getFeatureID(null) == Resource.RESOURCE__IS_MODIFIED) |
| resourceChanged((Resource) notification.getNotifier()); |
| } |
| @Override |
| public boolean equals(Object arg0) { |
| |
| return this.getClass().equals(arg0.getClass()); |
| } |
| |
| @Override |
| public int hashCode() { |
| |
| return getClass().hashCode(); |
| } |
| } |
| |
| public JEE5ModelProvider() { |
| super(); |
| } |
| |
| protected ProjectResourceSet getResourceSet(IProject proj2) { |
| return (ProjectResourceSet)WorkbenchResourceHelperBase.getResourceSet(proj); |
| } |
| |
| public XMLResourceImpl getWritableResource() { |
| return writableResource; |
| } |
| |
| public void setWritableResource(XMLResourceImpl writableResource) { |
| this.writableResource = writableResource; |
| } |
| |
| protected void resourceChanged(Resource aResource) { |
| if (hasListeners()) { |
| int eventCode = ModelProviderEvent.KNOWN_RESOURCES_CHANGED; |
| ModelProviderEvent evt = new ModelProviderEvent(eventCode, this, proj); |
| evt.addResource(aResource); |
| notifyListeners(evt); |
| } |
| } |
| |
| protected void resourceIsLoadedChanged(Resource aResource, boolean oldValue, boolean newValue) { |
| if (hasListeners()) { |
| int eventCode = newValue ? ModelProviderEvent.LOADED_RESOURCE : ModelProviderEvent.UNLOADED_RESOURCE; |
| ModelProviderEvent evt = new ModelProviderEvent(eventCode, this, proj); |
| evt.addResource(aResource); |
| notifyListeners(evt); |
| } |
| } |
| private void addManagedResource(XMLResourceImpl res) { |
| modelResources.add(res); |
| if (!res.eAdapters().contains(resourceAdapter)) |
| res.eAdapters().add(resourceAdapter); |
| } |
| /** |
| * Returns true if there are any listeners |
| */ |
| public boolean hasListeners() { |
| return !listeners.isEmpty(); |
| } |
| |
| private URI getModuleURI(URI uri) { |
| URI moduleuri = ModuleURIUtil.fullyQualifyURI(proj,getContentTypeDescriber()); |
| IPath requestPath = new Path(moduleuri.path()).append(new Path(uri.path())); |
| URI resourceURI = URI.createURI(PlatformURLModuleConnection.MODULE_PROTOCOL + requestPath.toString()); |
| return resourceURI; |
| } |
| |
| protected XMLResourceImpl getModelResource(final IPath modelPath) { |
| if (writableResource != null) { |
| addManagedResource(writableResource); |
| return writableResource; |
| } |
| IPath innerModelPath = modelPath; |
| if ((innerModelPath == null) || innerModelPath.equals(IModelProvider.FORCESAVE)) |
| innerModelPath = getDefaultResourcePath(); |
| ProjectResourceSet resSet = getResourceSet(proj); |
| IVirtualFolder container = ComponentCore.createComponent(proj).getRootFolder(); |
| String modelPathURI = innerModelPath.toString(); |
| URI uri = URI.createURI(modelPathURI); |
| |
| IPath projURIPath = new Path("");//$NON-NLS-1$ |
| projURIPath = projURIPath.append(container.getProjectRelativePath()); |
| projURIPath = projURIPath.addTrailingSeparator(); |
| projURIPath = projURIPath.append(innerModelPath); |
| URI projURI = URI.createURI(projURIPath.toString()); |
| XMLResourceImpl res = null; |
| try { |
| if (proj.getFile(projURI.toString()).exists()) |
| { |
| res = (XMLResourceImpl) resSet.getResource(getModuleURI(uri),true); |
| addManagedResource(res); |
| } else {//First find in resource set, then create if not found new Empty Resource. |
| XMLResourceImpl newRes = createModelResource(innerModelPath, resSet, projURI); |
| addManagedResource(newRes); |
| return newRes; |
| } |
| } catch (WrappedException ex) { |
| if (ex.getCause() instanceof FileNotFoundException) |
| return null; |
| throw ex; |
| } |
| return res; |
| } |
| |
| |
| protected XMLResourceImpl createModelResource(IPath modelPath, ProjectResourceSet resourceSet, URI uri) { |
| // First try to find existing cached resource. |
| XMLResourceImpl res = (XMLResourceImpl)resourceSet.getResource(getModuleURI(uri), false); |
| if (res == null || !res.isLoaded()) { |
| // Create temp resource if no file exists |
| res= (XMLResourceImpl)((FlexibleProjectResourceSet)resourceSet).createResource(getModuleURI(uri),WTPResourceFactoryRegistry.INSTANCE.getFactory(uri, getContentType(getContentTypeDescriber()))); |
| populateRoot(res, resourceSet.getProject().getName()); |
| } |
| return res; |
| } |
| |
| public void populateRoot(XMLResourceImpl res, String string) { |
| } |
| |
| private IContentDescription getContentType(String contentTypeDescriber) { |
| if (contentTypeDescriber != null) |
| return Platform.getContentTypeManager().getContentType(contentTypeDescriber).getDefaultDescription(); |
| return null; |
| } |
| |
| public IPath getDefaultResourcePath() { |
| return defaultResourcePath; |
| } |
| |
| public void setDefaultResourcePath(IPath defaultResourcePath) { |
| this.defaultResourcePath = defaultResourcePath; |
| } |
| |
| public Object getModelObject() { |
| return getModelObject(getDefaultResourcePath()); |
| } |
| |
| public Object getModelObject(IPath modelPath) { |
| return null; |
| } |
| |
| /** |
| * Used to optionally define an associated content type for XML file creation |
| * @return |
| */ |
| protected String getContentTypeDescriber() { |
| |
| return null; |
| } |
| |
| |
| |
| public IStatus validateEdit(final IPath modelPath, final Object context) { |
| IPath innaerModelPath = modelPath; |
| Object innerContext = context; |
| if (innaerModelPath == null) |
| innaerModelPath = getDefaultResourcePath(); |
| IWorkspace work = ResourcesPlugin.getWorkspace(); |
| IFile file = WorkbenchResourceHelper.getFile(getModelResource(innaerModelPath)); |
| if (file != null && file.exists()) { |
| IFile[] files = { file }; |
| if (innerContext == null) |
| innerContext = IWorkspace.VALIDATE_PROMPT; |
| return work.validateEdit(files, innerContext); |
| } |
| return Status.OK_STATUS; |
| } |
| |
| public void modify(Runnable runnable, IPath modelPath) { |
| //About to modify and save this model |
| try { |
| JavaeeResourceImpl res = (JavaeeResourceImpl)getModelResource(modelPath); |
| if (res != null) |
| setWritableResource(res); |
| runnable.run(); |
| try { |
| if (res != null) { |
| if (modelPath != null && modelPath.equals(IModelProvider.FORCESAVE)) |
| res.save(Collections.EMPTY_MAP,true); |
| else |
| res.save(Collections.EMPTY_MAP); |
| } |
| } catch (IOException e) { |
| JEEPlugin.logError(e); |
| } |
| } catch (Exception ex) { |
| JEEPlugin.logError(ex); |
| } finally { |
| setWritableResource(null); |
| } |
| |
| } |
| |
| // private class ResourceChangeListener implements IResourceChangeListener { |
| // public void resourceChanged(IResourceChangeEvent event) { |
| // IResourceDelta delta= event.getDelta(); |
| // // make sure that there is a delta (since some events don't have one) |
| // if (delta != null) |
| // { |
| // IResourceDelta[] affectedChildren= delta.getAffectedChildren(IResourceDelta.CHANGED | IResourceDelta.REMOVED , IResource.FILE); |
| // IResourceDelta projectDelta = null; |
| // IResource changedResource = null; |
| // IProject changedProject = null; |
| // IPath resourcePath = null; |
| // |
| // for (int i= 0; i < affectedChildren.length; i++) { |
| // projectDelta = affectedChildren[i]; |
| // changedResource = projectDelta.getResource(); |
| // changedProject = changedResource.getProject(); |
| // HashSet<IPath> currentResources = modelResources.get(changedProject); |
| // // only deal with the projects that have resources that have been loaded |
| // if (currentResources != null) |
| // { |
| // // if this is a project deletion, remove the project from the HashMap. |
| // if (changedResource == changedProject && projectDelta.getKind() == IResourceDelta.REMOVED) |
| // { |
| // modelResources.remove(changedProject); |
| // // if modelResources is empty, we should self-destruct |
| // if (modelResources.isEmpty()) |
| // { |
| // resourceChangeListenerEnabled = false; |
| // ResourcesPlugin.getWorkspace().removeResourceChangeListener(this); |
| // } |
| // } |
| // else |
| // { |
| // Iterator<IPath> iter = currentResources.iterator(); |
| // ArrayList<IPath> toUnload = new ArrayList<IPath>(); |
| // // check each resource that was loaded from the project to see if it is part of the change |
| // while (iter.hasNext()) |
| // { |
| // resourcePath = iter.next(); |
| // if (projectDelta.findMember(resourcePath) != null) |
| // { |
| // // limit the list of resources that need to be unloaded to those that have changed |
| // toUnload.add(resourcePath); |
| // } |
| // } |
| // if (toUnload.size() > 0) |
| // { |
| // Resource current = null; |
| // ProjectResourceSet resourceSet = getResourceSet(changedProject); |
| // URIConverter uriConverter = resourceSet.getURIConverter(); |
| // HashSet<URI> resourceURIs = new HashSet<URI>(); |
| // iter = toUnload.iterator(); |
| // while (iter.hasNext()) |
| // { |
| // // convert all of the resources to URIs - this is a faster match during the compare |
| // resourceURIs.add(uriConverter.normalize(URI.createURI(iter.next().toString()))); |
| // } |
| // Iterator<Resource> iter2 = resourceSet.getResources().iterator(); |
| // while (iter2.hasNext()) |
| // { |
| // current = iter2.next(); |
| // if (resourceURIs.contains(current.getURI())) |
| // { |
| // current.unload(); |
| // } |
| // } |
| // } |
| // } |
| // } |
| // } |
| // } |
| // } |
| // } |
| |
| public void addListener(IModelProviderListener listener) { |
| |
| listeners.add(listener); |
| } |
| |
| public void removeListener(IModelProviderListener listener) |
| { |
| listeners.remove(listener); |
| } |
| /** |
| * Save only resources that need to be saved (i.e., no other references). |
| */ |
| public void modelsChanged(IModelProviderEvent anEvent) { |
| int code = anEvent.getEventCode(); |
| switch (code) { |
| case IModelProviderEvent.REMOVED_RESOURCE : { |
| if (hasResourceReference(anEvent.getChangedResources())) |
| removeResources(anEvent.getChangedResources()); |
| else |
| return; |
| break; |
| } |
| } |
| if (hasListeners()) { |
| anEvent.setModel(this); |
| notifyListeners(anEvent); |
| } |
| } |
| protected void removeResources(List aList) { |
| Resource res; |
| for (int i = 0; i < aList.size(); i++) { |
| res = (Resource) aList.get(i); |
| removeResource(res) ; |
| } |
| } |
| /** |
| * Remove reference to the aResource. |
| */ |
| protected boolean removeResource(Resource aResource) { |
| if (aResource != null) { |
| aResource.eAdapters().remove(resourceAdapter); |
| return getResources().remove(aResource); |
| } |
| return false; |
| } |
| |
| /** |
| * Return true if any Resource in the list of |
| * |
| * @resources is referenced by me. |
| */ |
| protected boolean hasResourceReference(List tResources) { |
| for (int i = 0; i < tResources.size(); i++) { |
| if (hasResourceReference((Resource) tResources.get(i))) |
| return true; |
| } |
| return false; |
| } |
| /** |
| * Return true if aResource is referenced by me. |
| */ |
| protected boolean hasResourceReference(Resource aResource) { |
| if (aResource != null) |
| return getResources().contains(aResource); |
| return false; |
| } |
| |
| /** |
| * Notify listeners of |
| * |
| * @anEvent. |
| */ |
| protected void notifyListeners(IModelProviderEvent anEvent) { |
| |
| NotifyRunner notifier = new NotifyRunner(anEvent); |
| |
| Object[] notifyList = listeners.getListeners(); |
| for (int i = 0; i < notifyList.length; i++) { |
| notifier.setListener( (IModelProviderListener) notifyList[i] ); |
| SafeRunner.run(notifier); |
| } |
| } |
| public class NotifyRunner implements ISafeRunnable { |
| |
| private final IModelProviderEvent event; |
| private IModelProviderListener listener; |
| |
| public NotifyRunner(IModelProviderEvent event) { |
| Assert.isNotNull(event); |
| this.event = event; |
| } |
| |
| |
| public void setListener(IModelProviderListener listener) { |
| this.listener = listener; |
| } |
| |
| public void handleException(Throwable exception) { |
| JEEPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, JEEPlugin.PLUGIN_ID, 0, exception.getMessage(), exception)); |
| |
| } |
| |
| public void run() throws Exception { |
| if(listener != null) |
| listener.modelsChanged(event); |
| } |
| |
| } |
| public ResourceStateValidator getStateValidator() { |
| if (stateValidator == null) |
| stateValidator = createStateValidator(); |
| return stateValidator; |
| } |
| |
| /** |
| * Method createStateValidator. |
| * |
| * @return ResourceStateValidator |
| */ |
| private ResourceStateValidator createStateValidator() { |
| return new ResourceStateValidatorImpl(this); |
| } |
| |
| protected EnterpriseArtifactEdit createArtifactEdit() { |
| return null; |
| } |
| |
| public void checkActivation(ResourceStateValidatorPresenter presenter) throws CoreException { |
| getStateValidator().checkActivation(presenter); |
| |
| } |
| |
| public boolean checkReadOnly() { |
| return getStateValidator().checkReadOnly(); |
| } |
| |
| public boolean checkSave(ResourceStateValidatorPresenter presenter) throws CoreException { |
| return getStateValidator().checkSave(presenter); |
| } |
| |
| public void lostActivation(ResourceStateValidatorPresenter presenter) throws CoreException { |
| getStateValidator().lostActivation(presenter); |
| |
| } |
| |
| public IStatus validateState(ResourceStateValidatorPresenter presenter) throws CoreException { |
| if (presenter == null) |
| return Status.OK_STATUS; |
| return getStateValidator().validateState(presenter); |
| } |
| |
| public void cacheNonResourceValidateState(List roNonResourceFiles) { |
| // do nothing |
| } |
| |
| public List getNonResourceFiles() { |
| return null; |
| } |
| |
| public List getNonResourceInconsistentFiles() { |
| return null; |
| } |
| |
| public List getResources() { |
| return modelResources; |
| } |
| |
| |
| public boolean isDirty() { |
| |
| List list = getResources(); |
| for (int i = 0; i < list.size(); i++) { |
| if (((Resource) list.get(i)).isModified()) |
| return true; |
| } |
| return false; |
| } |
| } |