blob: ea2f5b8162aaef18541793c27a30245050dea9b8 [file] [log] [blame]
/*******************************************************************************
* 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);
}
}