blob: 3aee0decdc71b312b44b7218c804e47038f66d52 [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.common.internal.resource;
import java.util.List;
import org.eclipse.core.resources.IContainer;
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.IWorkspace;
import org.eclipse.jst.jsf.common.internal.ITestTracker;
import org.eclipse.jst.jsf.common.internal.ITestTracker.Event;
import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.EventType;
import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.ReasonType;
/**
* Listens to resource changes and fires lifecycle events
*
* @author cbateman
*
*/
public class LifecycleListener extends
AbstractLifecycleListener<ResourceLifecycleEvent, IResourceLifecycleListener, IResource>
implements IResourceChangeListener
{
private static boolean ENABLE_TEST_TRACKING = false;
private static long _seqId;
private ITestTracker _testTracker; // ==
final IWorkspace _workspace;
// null;
// initialized
// by
// setter
// injection
/**
* Initialize an inactive lifecycle listener. A workspace listener will not
* be installed by this constructor. The object created using this
* constructor will not fire any events until addResource is called at least
* once to add a target resource
*
* @param workspace
* the workspace to listen to for changes.
* @throws NullPointerException
* if workspace is null.
*/
public LifecycleListener(final IWorkspace workspace)
{
super();
if (workspace == null)
{
throw new NullPointerException(CANNOT_ADD_NULL_RESOURCE);
}
_workspace = workspace;
}
/**
* Create a new lifecycle listener for the res
*
* @param res
* @param workspace
* the workspace to listen to for changes.
* @throws NullPointerException
* if res or workspace is null.
*/
public LifecycleListener(final IResource res, final IWorkspace workspace)
{
this(workspace);
if (res == null)
{
throw new NullPointerException(CANNOT_ADD_NULL_RESOURCE);
}
addResource(res);
}
/**
* @param resources
* @param workspace
* the workspace to listen to for changes.
* @throws NullPointerException
* if resources, a member of resources or workspace is null.
*/
public LifecycleListener(final List<IResource> resources,
final IWorkspace workspace)
{
this(workspace);
for (final IResource resource : resources)
{
if (resource != null)
{
addResource(resource);
} else
{
throw new NullPointerException(CANNOT_ADD_NULL_RESOURCE);
}
}
}
@Override
protected void addSystemChangeListener()
{
_workspace.addResourceChangeListener(this);
}
@Override
protected void removeSystemChangeListener()
{
_workspace.removeResourceChangeListener(this);
}
/**
* @param testTracker
*/
public final void setTestTracker(final ITestTracker testTracker)
{
_testTracker = testTracker;
}
/**
* @param newValue
*/
protected final void setEnableTracing(final boolean newValue)
{
ENABLE_TEST_TRACKING = newValue;
}
/**
* @param res
* a resource you want to receive events for. MUST NOT BE NULL.
* @throw {@link NullPointerException} if res is null
*/
public void addResource(final IResource res)
{
addLifecycleObject(res);
}
public void resourceChanged(final IResourceChangeEvent event)
{
final long seqId = _seqId++;
if (_testTracker != null && ENABLE_TEST_TRACKING)
{
_testTracker.fireEvent(Event.START_TRACKING, seqId,
"trackMethod_resourceChanged"); //$NON-NLS-1$
}
assert (!isDisposed());
switch (event.getType())
{
case IResourceChangeEvent.PRE_CLOSE:
{
final IProject proj = (IProject) event.getResource();
// must use iterator to ensure copy on write behaviour
for (final IResource res : getLifecycleObjects())
{
if (proj == res || proj == res.getProject())
{
fireLifecycleEvent(new ResourceLifecycleEvent(this,
res, EventType.RESOURCE_INACCESSIBLE,
ReasonType.RESOURCE_PROJECT_CLOSED));
}
}
}
break;
case IResourceChangeEvent.PRE_DELETE:
{
final IProject proj = (IProject) event.getResource();
// must use iterator to ensure copy on write behaviour
for (final IResource res : getLifecycleObjects())
{
// if the resource being tracked is the resource being
// deleted,
// then fire a resource delete event
if (proj == res)
{
fireLifecycleEvent(new ResourceLifecycleEvent(this,
res, EventType.RESOURCE_INACCESSIBLE,
ReasonType.RESOURCE_DELETED));
}
// if the resource being tracked is a resource in the
// project being
// deleted, then fire a project deleted event
else if (proj == res.getProject())
{
fireLifecycleEvent(new ResourceLifecycleEvent(this,
res, EventType.RESOURCE_INACCESSIBLE,
ReasonType.RESOURCE_PROJECT_DELETED));
}
}
}
break;
case IResourceChangeEvent.POST_CHANGE:
{
for (final IResource res : getLifecycleObjects())
{
IResourceDelta delta = event.getDelta();
// only care about post change events to resources
// that we are tracking
if (delta != null)
{
delta = delta.findMember(res.getFullPath());
if (delta != null)
{
visit(delta);
}
}
}
}
break;
default:
// do nothing
// we only handle these three
}
if (ENABLE_TEST_TRACKING && _testTracker != null)
{
_testTracker.fireEvent(Event.STOP_TRACKING, seqId,
"trackMethod_resourceChanged"); //$NON-NLS-1$
}
}
private void visit(final IResourceDelta delta)
{
assert (!isDisposed());
final IResource res = delta.getResource();
// the wkspace root is a special case since even though
// it is registered as the target resource, we are interested
// in new projects created in the root
if (res.getType() == IResource.ROOT)
{
handleWorkspaceRoot(delta);
} else if (res instanceof IContainer)
{
handleContainer(delta, res);
} else
{
handleFile(delta, res);
}
}
private void handleContainer(final IResourceDelta delta, IResource container)
{
handleChange(delta, container, container);
for (final IResourceDelta childDelta : delta.getAffectedChildren())
{
if (childDelta.getResource().getType() == IResource.FILE
|| childDelta.getResource().getType() == IResource.FOLDER)
{
handleChange(childDelta, childDelta.getResource(), container);
}
}
}
private void handleFile(final IResourceDelta delta, final IResource res)
{
switch (delta.getKind())
{
case IResourceDelta.ADDED:
case IResourceDelta.REMOVED:
{
handleChange(delta, res, res);
}
break;
case IResourceDelta.CHANGED:
{
// the contents of the file have changed
if ((delta.getFlags() & IResourceDelta.CONTENT) != 0)
{
fireLifecycleEvent(new ResourceLifecycleEvent(this, res,
EventType.RESOURCE_CHANGED,
ReasonType.RESOURCE_CHANGED_CONTENTS));
}
}
break;
}
}
private void handleChange(final IResourceDelta delta, final IResource res,
final IResource interestedResource)
{
switch (delta.getKind())
{
case IResourceDelta.ADDED:
{
handleAdd(delta, res, interestedResource);
}
break;
case IResourceDelta.REMOVED:
{
handleRemove(delta, res, interestedResource);
}
break;
}
}
private void handleRemove(final IResourceDelta delta, final IResource res,
final IResource interestedResource)
{
if ((delta.getFlags() & IResourceDelta.MOVED_TO) != 0)
{
if (res.equals(interestedResource))
{
fireLifecycleEvent(new ResourceLifecycleEvent(this, res,
EventType.RESOURCE_INACCESSIBLE,
ReasonType.RESOURCE_MOVED));
} else if (res.getParent().equals(interestedResource))
{
fireLifecycleEvent(new ResourceLifecycleEvent(this, res,
EventType.RESOURCE_INACCESSIBLE,
ReasonType.RESOURCE_MOVED_CONTAINER));
}
} else
{
if (res.equals(interestedResource))
{
fireLifecycleEvent(new ResourceLifecycleEvent(this, res,
EventType.RESOURCE_INACCESSIBLE,
ReasonType.RESOURCE_DELETED));
} else if (res.getParent().equals(interestedResource))
{
fireLifecycleEvent(new ResourceLifecycleEvent(this, res,
EventType.RESOURCE_INACCESSIBLE,
ReasonType.RESOURCE_DELETED_FROM_CONTAINER));
}
}
}
private void handleAdd(final IResourceDelta delta, final IResource res,
final IResource interestedResource)
{
if ((delta.getFlags() & IResourceDelta.MOVED_FROM) != 0)
{
if (res.equals(interestedResource))
{
fireLifecycleEvent(new ResourceLifecycleEvent(this, res,
EventType.RESOURCE_ADDED, ReasonType.RESOURCE_MOVED));
} else if (res.getParent().equals(interestedResource))
{
fireLifecycleEvent(new ResourceLifecycleEvent(this, res,
EventType.RESOURCE_ADDED,
ReasonType.RESOURCE_MOVED_CONTAINER));
}
} else
{
if (res.equals(interestedResource))
{
fireLifecycleEvent(new ResourceLifecycleEvent(this, res,
EventType.RESOURCE_ADDED, ReasonType.RESOURCE_ADDED));
} else if (res.getParent().equals(interestedResource))
{
fireLifecycleEvent(new ResourceLifecycleEvent(this, res,
EventType.RESOURCE_ADDED,
ReasonType.RESOURCE_ADDED_TO_CONTAINER));
}
}
}
private void handleWorkspaceRoot(final IResourceDelta delta)
{
for (final IResourceDelta childDelta : delta
.getAffectedChildren(IResourceDelta.ADDED|IResourceDelta.CHANGED))
{
final IResource res = childDelta.getResource();
if ((childDelta.getFlags() & IResourceDelta.OPEN) != 0 &&
// project was just opened
res.getType() == IResource.PROJECT)
{
fireLifecycleEvent(new ResourceLifecycleEvent(this, res,
EventType.RESOURCE_ADDED, ReasonType.PROJECT_OPENED));
}
}
}
}