package org.codehaus.plexus.component.manager;
/*
* Copyright 2001-2006 Codehaus Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.codehaus.plexus.component.factory.ComponentInstantiationException;
import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
import org.codehaus.plexus.component.repository.ComponentDescriptor;
import org.codehaus.plexus.MutablePlexusContainer;
import org.codehaus.plexus.lifecycle.LifecycleHandler;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ReferenceMap;
import static com.google.common.base.ReferenceType.WEAK;
/**
* Creates a new component manager for every lookup
*
* @author Jason van Zyl
*
* @version $Id$
*/
public class PerLookupComponentManager<T>
extends AbstractComponentManager<T>
{
private boolean disposed;
private final Map<T, T> instances = new ReferenceMap<T, T>( WEAK, WEAK);
public PerLookupComponentManager( MutablePlexusContainer container,
LifecycleHandler lifecycleHandler,
ComponentDescriptor<T> componentDescriptor )
{
super( container, lifecycleHandler, componentDescriptor );
}
public void dispose() throws ComponentLifecycleException
{
Set<T> instances;
synchronized (this) {
disposed = true;
instances = this.instances.keySet();
this.instances.clear();
}
ComponentLifecycleException componentLifecycleException = null;
for ( T instance : instances )
{
try
{
// do not call destroyInstance inside of a synchronized block because
// destroyInstance results in several callbacks to user code which
// could result in a dead lock
destroyInstance( instance );
}
catch ( ComponentLifecycleException e )
{
if (componentLifecycleException == null) {
componentLifecycleException = e;
}
}
}
if (componentLifecycleException == null) {
throw componentLifecycleException;
}
}
public T getComponent( ) throws ComponentInstantiationException, ComponentLifecycleException
{
synchronized (this) {
if (disposed)
{
throw new ComponentLifecycleException("This ComponentManager has already been destroyed");
}
}
// do not call createInstance inside of a synchronized block because
// createInstance results in several callbacks to user code which
// could result in a dead lock
T instance = createInstance();
synchronized (this) {
// if this manager has been destroyed during create, destroy newly
// created component
if (disposed)
{
try
{
destroyInstance( instance );
}
catch ( ComponentLifecycleException e )
{
// todo: log ignored exception
}
throw new ComponentLifecycleException("This ComponentManager has already been destroyed");
}
instances.put(instance, instance);
}
return instance;
}
public void release( Object component ) throws ComponentLifecycleException
{
T instance;
synchronized (this) {
instance = instances.remove(component);
}
// do not call destroyInstance inside of a synchronized block because
// destroyInstance results in several callbacks to user code which
// could result in a dead lock
if (instance != null ) {
destroyInstance( component );
}
}
}