| /******************************************************************************* |
| * Copyright (c) 2001, 2008 Oracle 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: |
| * Oracle Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jst.jsf.ui.internal.tagregistry; |
| |
| import java.util.HashSet; |
| import java.util.Set; |
| import java.util.concurrent.CopyOnWriteArrayList; |
| |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.jst.jsf.common.internal.resource.IResourceLifecycleListener; |
| import org.eclipse.jst.jsf.common.internal.resource.LifecycleListener; |
| import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent; |
| import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.EventType; |
| import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.ReasonType; |
| import org.eclipse.jst.jsf.ui.internal.tagregistry.ProjectTracker.ProjectTrackingListener.Reason; |
| |
| /** |
| * Tracks the active JSF projects in the workspace, maintaining a list of valid |
| * projects and firing events when it changes |
| * |
| * @author cbateman |
| * |
| */ |
| class ProjectTracker |
| { |
| private final IWorkspaceRoot _root; |
| private final LifecycleListener _lifecycleListener; |
| private final CopyOnWriteArrayList<ProjectTrackingListener> _myListeners; |
| private Set<IProject> _validProjects; |
| private final ResourceChangeListener _resourceChangeListener; |
| private ProjectAdvisor _projectAdvisor; |
| |
| public ProjectTracker(final IWorkspaceRoot root, final ProjectAdvisor projectAdvisor) |
| { |
| _root = root; |
| _lifecycleListener = new LifecycleListener(); |
| _resourceChangeListener = new ResourceChangeListener(); |
| _myListeners = new CopyOnWriteArrayList<ProjectTrackingListener>(); |
| if (projectAdvisor != null) |
| { |
| _projectAdvisor = projectAdvisor; |
| } |
| else |
| { |
| _projectAdvisor = DEFAULT_ADVISOR; |
| } |
| } |
| |
| public void startTracking() |
| { |
| _lifecycleListener.addResource(_root); |
| |
| _validProjects = new HashSet<IProject>(); |
| |
| for (final IProject project : _root.getProjects()) |
| { |
| if (_projectAdvisor.shouldTrack(project)) |
| { |
| _validProjects.add(project); |
| _lifecycleListener.addResource(project); |
| } |
| } |
| // do this last, to ensure that any "simulataneous" events are handled |
| // by our listener only after everything is initialized. |
| _lifecycleListener.addListener(_resourceChangeListener); |
| } |
| |
| public Set<IProject> getProjects() |
| { |
| final Set<IProject> projects = new HashSet<IProject>(); |
| synchronized (this) |
| { |
| projects.addAll(_validProjects); |
| } |
| return projects; |
| } |
| |
| private synchronized void addProject(final IProject project) |
| { |
| if (_projectAdvisor.shouldTrack(project)) |
| { |
| synchronized (this) |
| { |
| _validProjects.add(project); |
| _lifecycleListener.addResource(project); |
| } |
| fireChangeEvent(project, Reason.ADDED); |
| } |
| } |
| |
| private void removeProject(final IProject project) |
| { |
| synchronized (this) |
| { |
| _validProjects.remove(project); |
| _lifecycleListener.removeResource(project); |
| } |
| fireChangeEvent(project, Reason.REMOVED); |
| } |
| |
| public void addListener(ProjectTrackingListener listener) |
| { |
| _myListeners.addIfAbsent(listener); |
| } |
| |
| public void removeListener(ProjectTrackingListener listener) |
| { |
| _myListeners.remove(listener); |
| } |
| |
| private void fireChangeEvent(final IProject project, |
| ProjectTrackingListener.Reason reason) |
| { |
| for (final ProjectTrackingListener listener : _myListeners) |
| { |
| listener.projectsChanged(project, reason); |
| } |
| } |
| |
| public void dispose() |
| { |
| _lifecycleListener.dispose(); |
| _validProjects.clear(); |
| _myListeners.clear(); |
| } |
| |
| private class ResourceChangeListener implements IResourceLifecycleListener |
| { |
| public EventResult acceptEvent(final ResourceLifecycleEvent event) |
| { |
| final IResource res = event.getAffectedResource(); |
| |
| // only interested if is affecting one of my resources |
| |
| // if the root is the source, check if a projected has been added |
| // or opened |
| // EventType eventType = event.getEventType(); |
| if (event.getEventType() == EventType.RESOURCE_ADDED |
| && event.getReasonType() == ReasonType.PROJECT_OPENED |
| && res instanceof IProject) |
| { |
| handleNewProject((IProject) res); |
| } |
| else if (_validProjects.contains(res) |
| && event.getEventType() == EventType.RESOURCE_INACCESSIBLE) |
| { |
| handleProjectClosed((IProject) res); |
| } |
| return EventResult.getDefaultEventResult(); |
| } |
| |
| private void handleNewProject(final IProject project) |
| { |
| addProject(project); |
| } |
| |
| private void handleProjectClosed(final IProject project) |
| { |
| removeProject(project); |
| } |
| } |
| |
| public static class ProjectTrackingListener |
| { |
| public enum Reason |
| { |
| /** |
| * Reason for change is a project added |
| */ |
| ADDED, |
| /** |
| * Reason for change is a project removed |
| */ |
| REMOVED |
| } |
| |
| protected void projectsChanged(final IProject project, Reason reason) |
| { |
| // do nothing by default |
| } |
| } |
| |
| private static final ProjectAdvisor DEFAULT_ADVISOR = new ProjectAdvisor() |
| { |
| @Override |
| public boolean shouldTrack( |
| IProject project) |
| { |
| return true; |
| } |
| }; |
| |
| public abstract static class ProjectAdvisor |
| { |
| public abstract boolean shouldTrack(final IProject project); |
| } |
| } |