| /******************************************************************************* |
| * Copyright (c) 2001, 2008 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.wst.validation.internal; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.util.Set; |
| import java.util.concurrent.CopyOnWriteArraySet; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceChangeEvent; |
| import org.eclipse.core.resources.IResourceChangeListener; |
| import org.eclipse.core.resources.IResourceDelta; |
| import org.eclipse.core.resources.IResourceDeltaVisitor; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.wst.validation.internal.operations.IWorkbenchContext; |
| import org.eclipse.wst.validation.internal.plugin.ValidationPlugin; |
| |
| /** |
| * This class manages resource change events for the validation framework. |
| */ |
| public class EventManager implements IResourceChangeListener { |
| private static EventManager _inst; |
| |
| // false means that eclipse is not shutting down, and true means that it is shutting down. |
| private boolean _shutdown; |
| |
| private IResourceDeltaVisitor _postAutoBuildVisitor; |
| private boolean _isActive; // has the registry been read? |
| |
| private Set<IProjectChangeListener> _listeners = new CopyOnWriteArraySet<IProjectChangeListener>(); |
| |
| private EventManager() { |
| } |
| |
| public static EventManager getManager() { |
| if (_inst == null)_inst = new EventManager(); |
| return _inst; |
| } |
| |
| public void addProjectChangeListener(IProjectChangeListener listener){ |
| Tracing.log("EventManager-03: add listener: ", listener); //$NON-NLS-1$ |
| _listeners.add(listener); |
| } |
| |
| public void removeProjectChangeListener(IProjectChangeListener listener){ |
| _listeners.remove(listener); |
| } |
| |
| private void signal(IProject project, int type){ |
| if (Tracing.isLogging()){ |
| String name = "Null"; //$NON-NLS-1$ |
| if (project != null)name = project.getName(); |
| Tracing.log("EventManager-02: signal project: " + name + ", IProjectChangeListener type: " + type); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| for (IProjectChangeListener pcl : _listeners){ |
| try { |
| pcl.projectChanged(project, type); |
| } |
| catch (Exception e){ |
| ValidationPlugin.getPlugin().handleException(e); |
| } |
| } |
| } |
| |
| public void opening(IProject project) { |
| if (project == null || !ValidationPlugin.isActivated())return; |
| |
| signal(project, IProjectChangeListener.ProjectOpened); |
| |
| // When the project is opened, check for any orphaned tasks or tasks whose owners need to be updated. |
| // ConfigurationManager.getManager().opening(project); |
| } |
| |
| public void closing(IProject project) { |
| if (project == null || !ValidationPlugin.isActivated())return; |
| |
| signal(project, IProjectChangeListener.ProjectClosed); |
| |
| try { |
| boolean isMigrated = ConfigurationManager.getManager().isMigrated(project); |
| // If it's not migrated, then it hasn't been loaded, and we don't want to load the |
| // validator and its prerequisite plug-ins until they're needed. |
| if (isMigrated) { |
| ValidatorMetaData[] vmds = ConfigurationManager.getManager().getProjectConfiguration(project).getValidators(); |
| for (ValidatorMetaData vmd : vmds) { |
| |
| if (!vmd.isActive()) { |
| // If this validator has not been activated, or if it has been shut down, |
| // don't activate it again. |
| continue; |
| } |
| |
| IWorkbenchContext helper = null; |
| try { |
| helper = vmd.getHelper(project); |
| helper.closing(); |
| } catch (InstantiationException e) { |
| // Remove the vmd from the reader's list |
| ValidationRegistryReader.getReader().disableValidator(vmd); |
| |
| ValidationPlugin.getPlugin().handleException(e); |
| } catch (Exception e) { |
| // If there is a problem with this particular helper, log the error and |
| // continue with the next validator. |
| ValidationPlugin.getPlugin().handleException(e); |
| } |
| } |
| |
| ConfigurationManager.getManager().closing(project); |
| } |
| } catch (InvocationTargetException e) { |
| ValidationPlugin.getPlugin().handleException(e); |
| if (e.getTargetException() != null) |
| ValidationPlugin.getPlugin().handleException(e.getTargetException()); |
| } |
| } |
| |
| public void deleting(IProject project) { |
| if (project == null)return; |
| |
| signal(project, IProjectChangeListener.ProjectDeleted); |
| |
| try { |
| boolean isMigrated = ConfigurationManager.getManager().isMigrated(project); |
| // If it's not migrated, then it hasn't been loaded, and we don't want to load the |
| // validator and its prerequisite plug-ins until they're needed. |
| if (isMigrated) { |
| ValidatorMetaData[] vmds = ConfigurationManager.getManager().getProjectConfiguration(project).getValidators(); |
| for (ValidatorMetaData vmd : vmds) { |
| |
| if (!vmd.isActive()) { |
| // If this validator has not been activated, or if it has been shut down, |
| // don't activate it again. |
| continue; |
| } |
| |
| IWorkbenchContext helper = null; |
| try { |
| helper = vmd.getHelper(project); |
| helper.deleting(); |
| } catch (InstantiationException e) { |
| // Remove the vmd from the reader's list |
| ValidationRegistryReader.getReader().disableValidator(vmd); |
| ValidationPlugin.getPlugin().handleException(e); |
| continue; |
| } catch (Exception e) { |
| // If there is a problem with this particular helper, log the error and |
| // continue with the next validator. |
| ValidationPlugin.getPlugin().handleException(e); |
| continue; |
| } |
| } |
| |
| // ConfigurationManager.getManager().deleting(project); |
| } |
| } catch (InvocationTargetException e) { |
| ValidationPlugin.getPlugin().handleException(e); |
| if (e.getTargetException() != null) |
| ValidationPlugin.getPlugin().handleException(e.getTargetException()); |
| |
| } |
| } |
| |
| /** |
| * If a project's description changes, The project may have changed its nature. Update the cache |
| * to reflect the new natures. The project could be opening. Migrate. |
| */ |
| private void postAutoChange(IResourceDelta delta) { |
| if (_postAutoBuildVisitor == null) { |
| _postAutoBuildVisitor = new IResourceDeltaVisitor() { |
| public boolean visit(IResourceDelta subdelta) throws CoreException { |
| if (subdelta == null)return false; |
| |
| IResource resource = subdelta.getResource(); |
| if (resource instanceof IWorkspaceRoot)return true; |
| if (resource instanceof IProject) { |
| IProject project = (IProject) resource; |
| if ((subdelta.getFlags() & IResourceDelta.DESCRIPTION) == IResourceDelta.DESCRIPTION) { |
| signal(project, IProjectChangeListener.ProjectChanged); |
| return false; |
| } |
| |
| if ((subdelta.getFlags() & IResourceDelta.OPEN) == IResourceDelta.OPEN) { |
| if (project.isOpen()) { |
| // Project was just opened. If project.isOpen() had returned false, |
| // project would just have been closed. |
| opening(project); |
| } |
| return false; |
| } |
| |
| if ((subdelta.getFlags() & IResourceDelta.ADDED) == IResourceDelta.ADDED) { |
| signal(project, IProjectChangeListener.ProjectAdded); |
| return false; |
| } |
| } |
| |
| return false; |
| } |
| }; |
| } |
| |
| try { |
| delta.accept(_postAutoBuildVisitor, true); |
| } catch (CoreException exc) { |
| ValidationPlugin.getPlugin().handleException(exc); |
| } |
| } |
| |
| /** |
| * Notifies this manager that some resource changes have happened on the platform. If the change |
| * is a project deletion, that project should be removed from the cache. |
| * |
| * @see IResourceDelta |
| * @see IResource |
| */ |
| public void resourceChanged(IResourceChangeEvent event) { |
| if (_shutdown && !isActive()) { |
| // If we're shutting down, and nothing has been activated, don't need to do anything. |
| return; |
| } |
| |
| if (Tracing.isLogging()){ |
| Tracing.log("Eventmanager-01: IResourceChangeEvent type=" + //$NON-NLS-1$ |
| Misc.resourceChangeEventType(event.getType()) + |
| ", resource=" + //$NON-NLS-1$ |
| event.getResource() + ", source=" + event.getSource() + ", delta=" + //$NON-NLS-1$//$NON-NLS-2$ |
| event.getDelta()); |
| } |
| |
| if (event.getSource() instanceof IWorkspace) { |
| boolean isProject = event.getResource() instanceof IProject; |
| if ((event.getType() == IResourceChangeEvent.PRE_DELETE) && isProject) { |
| deleting((IProject) event.getResource()); |
| } else if ((event.getType() == IResourceChangeEvent.PRE_CLOSE) && isProject) { |
| closing((IProject) event.getResource()); |
| } else if (event.getType() == IResourceChangeEvent.POST_BUILD) { |
| postAutoChange(event.getDelta()); |
| } |
| } |
| } |
| |
| /** |
| * Notifies this manager that the ValidationPlugin is shutting down. (Usually implies that |
| * either the plug-in could not load, or that the workbench is shutting down.) |
| * <p> |
| * The manager will then notify all active helpers of the shutdown, so that they may perform any |
| * last-minute writes to disk, cleanup, etc. |
| */ |
| public void shutdown() { |
| try { |
| // resourceChanged(IResourceChangeEvent) needs to know when a shutdown has started. |
| _shutdown = true; |
| |
| // If the validators are loaded, then for every project in the workbench, |
| // we must see if it has been loaded. If it has, every enabled IWorkbenchContext |
| // must be called to clean up. If the project hasn't been loaded, then no |
| // IWorkbenchContext built anything, and there's nothing to clean up. |
| IWorkspace workspace = ResourcesPlugin.getWorkspace(); |
| IWorkspaceRoot workspaceRoot = workspace.getRoot(); |
| IProject[] projects = workspaceRoot.getProjects(); |
| ProjectConfiguration prjp = null; |
| for (IProject project : projects) { |
| if (!project.isOpen()) { |
| // If the project isn't opened, there's nothing to clean up. |
| // If the project was opened, it would have been migrated, and there's something |
| // to clean up. |
| continue; |
| } |
| |
| try { |
| boolean isMigrated = ConfigurationManager.getManager().isMigrated(project); |
| // If it's not migrated, then it hasn't been loaded, and we don't want to load |
| // the validator and its prerequisite plug-ins until they're needed. |
| if (isMigrated) { |
| prjp = ConfigurationManager.getManager().getProjectConfiguration(project); |
| |
| ValidatorMetaData[] vmdList = prjp.getEnabledValidators(); |
| // if vmdList is null, IProject has never been loaded, so nothing to clean up |
| if (vmdList != null) { |
| for (int j = 0; j < vmdList.length; j++) { |
| ValidatorMetaData vmd = vmdList[j]; |
| |
| if (!vmd.isActive()) { |
| // If this validator has not been activated, or if it has been |
| // shut down, don't activate it again. |
| continue; |
| } |
| |
| IWorkbenchContext helper = vmd.getHelper(project); |
| if (helper != null) { |
| try { |
| helper.shutdown(); |
| } catch (Exception exc) { |
| // Since we're shutting down, ignore the exception. |
| } |
| } |
| } |
| } |
| } |
| } catch (InvocationTargetException e) { |
| ValidationPlugin.getPlugin().handleException(e); |
| if (e.getTargetException() != null) |
| ValidationPlugin.getPlugin().handleException(e.getTargetException()); |
| |
| } |
| } |
| } catch (Exception exc) { |
| // Since we're shutting down, ignore the exception. |
| } |
| } |
| |
| public boolean isActive() { |
| // Have to use this convoluted technique for the shutdown problem. |
| // i.e., when eclipse is shut down, if validation plug-in hasn't been loaded, |
| // the EventManager is activated for the first time, and it |
| // sends many exceptions to the .log. At first, I wrote a |
| // static method on ValidationRegistryReader, which returned true |
| // if the registry had been read, and false otherwise. However, |
| // that didn't solve the exception problem, because eclipse's |
| // class loader failed to load the ValidationRegistryReader class. |
| // |
| // The fix is to keep all shutdown mechanisms in this class. |
| // Track everything in here. |
| return _isActive; |
| } |
| |
| /** |
| * This method should only be called by the ValidationRegistryReader once the registry has been |
| * read. |
| */ |
| public void setActive(boolean b) { |
| _isActive = b; |
| } |
| |
| /** |
| * This method should be used to determine if the workbench is running in UI or Headless. |
| * |
| * @deprecated This plug-in no longer depends on jem. If you need this function use the jem |
| * code directly. |
| */ |
| public static boolean isHeadless() { |
| //return UIContextDetermination.getCurrentContext() == UIContextDetermination.HEADLESS_CONTEXT; |
| return false; |
| } |
| } |