blob: 903acc12881786a4b8d5434680e27064902c8af2 [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.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IResource;
import org.eclipse.jst.jsf.common.internal.managedobject.IManagedObject;
import org.eclipse.jst.jsf.common.internal.managedobject.ObjectManager;
import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.EventType;
import org.eclipse.jst.jsf.common.internal.resource.ResourceLifecycleEvent.ReasonType;
/**
* An object manager that manages a single instanceof an IManagedObject per
* resource. The manager takes care of ensuring that a managed object is
* properly disposed when a resource lifecycle event renders it inaccessible
* (i.e file is deleted, project is closed or delete).
*
* @author cbateman
*
* @param <RESOURCE>
* @param <MANAGEDOBJECT>
*/
public abstract class ResourceSingletonObjectManager<MANAGEDOBJECT extends IManagedObject, RESOURCE extends IResource>
extends ObjectManager<MANAGEDOBJECT, RESOURCE>
{
// lazily initialized
private LifecycleListener _lifecycleListener;
private final Map<RESOURCE, ManagedResourceObject> _perResourceObjects;
/**
* Default constructor
*/
protected ResourceSingletonObjectManager()
{
_perResourceObjects = new HashMap<RESOURCE, ManagedResourceObject>();
}
@Override
public final MANAGEDOBJECT getInstance(final RESOURCE key)
throws ManagedObjectException
{
synchronized(this)
{
runBeforeGetInstance(key);
ManagedResourceObject managedResObject = _perResourceObjects.get(key);
if (managedResObject == null)
{
final MANAGEDOBJECT managedObject = createNewInstance(key);
if (managedObject == null)
{
throw new ManagedObjectException(
"No object available for resource"); //$NON-NLS-1$
}
managedResObject = manageResource(key, managedObject);
}
runAfterGetInstance(key);
return managedResObject.getManagedObject();
}
}
/**
* @param resource
* @return a new instance of T associated with S. This operation must not
* cache T: a brand new instance is always required. getInstance
* will perform caching and resource listening.
*/
protected abstract MANAGEDOBJECT createNewInstance(RESOURCE resource);
/**
* @param resource
*/
protected void runBeforeGetInstance(final RESOURCE resource)
{
// do nothing by default
}
/**
* @param resource
*/
protected void runAfterGetInstance(final RESOURCE resource)
{
// do nothing by default
}
/**
* @param resource
* @return true if there already exists a managed object associated with
* the resource
*/
public synchronized boolean isInstance(RESOURCE resource)
{
return _perResourceObjects.containsKey(resource);
}
/**
* @return a copy of the current set of RESOURCE object keys that we
* are managing singletons for. Collection is mutable, but as a copy,
* changes to it do not effect thie object manager.
*/
public synchronized Collection<RESOURCE> getManagedResources()
{
final Set resources = new HashSet(_perResourceObjects.keySet());
return resources;
}
/**
* Should be called by concrete classes to indicate they have created a new
* managed object for resource, for which they want to track lifecycle
* changes.
*
* @param resource
* @param managedObject
*/
private synchronized ManagedResourceObject manageResource(final RESOURCE resource,
final MANAGEDOBJECT managedObject)
{
final LifecycleListener listener = lazilyGetLifecycleListener();
listener.addResource(resource);
final MyLifecycleEventListener eventListener = new MyLifecycleEventListener(
managedObject, resource);
listener.addListener(eventListener);
final ManagedResourceObject managedResourceObject = new ManagedResourceObject(
managedObject, eventListener);
_perResourceObjects.put(resource, managedResourceObject);
return managedResourceObject;
}
/**
* Stop managing the resource. If resource is the last one, the resource
* change listener will be removed (it will be added again when next
* manageResource is called).
*
* @param resource
*/
protected final synchronized void unmanageResource(final RESOURCE resource)
{
final ManagedResourceObject managedResourceObject =
_perResourceObjects.remove(resource);
final LifecycleListener listener = lazilyGetLifecycleListener();
if (managedResourceObject != null)
{
listener.removeListener(managedResourceObject.getEventListener());
}
listener.removeResource(resource);
}
/**
* Call to register a listener
*
* @param listener
*/
protected final void addLifecycleEventListener(
final IResourceLifecycleListener listener)
{
final LifecycleListener lifecycleListener = lazilyGetLifecycleListener();
lifecycleListener.addListener(listener);
}
/**
* Call to remove a listener
*
* @param listener
*/
protected final void removeLifecycleEventListener(
final IResourceLifecycleListener listener)
{
final LifecycleListener lifecycleListener = lazilyGetLifecycleListener();
lifecycleListener.removeListener(listener);
}
private synchronized LifecycleListener lazilyGetLifecycleListener()
{
if (_lifecycleListener == null)
{
_lifecycleListener = new LifecycleListener();
}
return _lifecycleListener;
}
private class ManagedResourceObject
{
private final MANAGEDOBJECT _managedObject;
private final MyLifecycleEventListener _eventListener;
private ManagedResourceObject(final MANAGEDOBJECT managedObject,
final MyLifecycleEventListener eventListener)
{
_managedObject = managedObject;
_eventListener = eventListener;
}
public MANAGEDOBJECT getManagedObject()
{
return _managedObject;
}
public MyLifecycleEventListener getEventListener()
{
return _eventListener;
}
}
private class MyLifecycleEventListener implements
IResourceLifecycleListener
{
private final RESOURCE _resource;
private final MANAGEDOBJECT _managedObject;
private MyLifecycleEventListener(final MANAGEDOBJECT managedObject,
final RESOURCE resource)
{
_resource = resource;
_managedObject = managedObject;
}
public EventResult acceptEvent(final ResourceLifecycleEvent event)
{
final EventResult result = EventResult.getDefaultEventResult();
// not interested
if (!_resource.equals(event.getAffectedResource()))
{
return EventResult.getDefaultEventResult();
}
if (event.getEventType() == EventType.RESOURCE_INACCESSIBLE)
{
try
{
if (event.getReasonType() == ReasonType.RESOURCE_DELETED
|| event.getReasonType() == ReasonType.RESOURCE_PROJECT_DELETED)
{
_managedObject.destroy();
}
else
{
_managedObject.dispose();
}
}
// dispose is external code out our control, so make sure
// unmanage gets called if it blows up.
finally
{
unmanageResource(_resource);
}
}
return result;
}
}
}