All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.picocontainer.gems.containers.ReusablePicoContainer Maven / Gradle / Ivy

/*****************************************************************************
 * Copyright (C) PicoContainer Organization. All rights reserved.            *
 * ------------------------------------------------------------------------- *
 * The software in this package is published under the terms of the BSD      *
 * style license a copy of which has been included with this distribution in *
 * the LICENSE.txt file.                                                     *
 *                                                                           *
 * Original code by Mike Rimov                                               *
 *****************************************************************************/
package org.picocontainer.gems.containers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.picocontainer.ComponentAdapter;
import org.picocontainer.ComponentFactory;
import org.picocontainer.ComponentMonitor;
import org.picocontainer.DefaultPicoContainer;
import org.picocontainer.LifecycleStrategy;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.Parameter;
import org.picocontainer.PicoCompositionException;
import org.picocontainer.PicoContainer;
import org.picocontainer.adapters.InstanceAdapter;
import org.picocontainer.behaviors.Stored;

/**
 * Normal PicoContainers are meant to be created, started, stopped, disposed and
 * garbage collected. The goal of this container is to reduce the number of
 * registration calls (and therefore objects created) in areas where performance
 * is key (for example, this might be used in NanoContainer request containers).
 * 

* It accomplishes its goal in two ways:
(1) Once a container is disposed * of, start() may be called again, allowing for recycling of the container. (This is default * behavior with a picocontainer) *

*

* (2) All instance and adapter registrations will be unregistered when stop is called. (For example, * HttpServletRequest would be removed), and all component adapter instance values * are flushed. *

*

Container Storage

*

It is still up to the builder of this container to decide where to store its reference. Since * it is reusable, it needs to be stored someplace that doesn't easily expire. Probably the most * common storage location would be ThreadLocal storage. HttpSession might be another valid * storage location.

* @author Michael Rimov * @todo Convert to composition. */ @SuppressWarnings("serial") public class ReusablePicoContainer extends DefaultPicoContainer { /** * A list of all addComponent(key, instance) calls that were made. These will be removed from the container * each time the container is stopped. */ private final List> instanceRegistrations = new ArrayList>(); /** * A list of all addFlushableAdapter() calls that were made. These instances will be removed from * the container each time it is stopped. */ private final List> adapterRegistrations = new ArrayList>(); private final Map, Stored> storedReferences = new HashMap, Stored>(); /** * Default constructor. */ public ReusablePicoContainer() { super(); } public ReusablePicoContainer(final ComponentFactory componentFactory, final LifecycleStrategy lifecycleStrategy, final PicoContainer parent, final ComponentMonitor componentMonitor) { super(componentFactory, lifecycleStrategy, parent, componentMonitor); } public ReusablePicoContainer(final ComponentFactory componentFactory, final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { super(componentFactory, lifecycleStrategy, parent); } public ReusablePicoContainer(final ComponentFactory componentFactory, final PicoContainer parent) { super(componentFactory, parent); } public ReusablePicoContainer(final ComponentFactory componentFactory) { super(componentFactory); } public ReusablePicoContainer(final ComponentMonitor monitor, final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { super(monitor, lifecycleStrategy, parent); } public ReusablePicoContainer(final ComponentMonitor monitor, final PicoContainer parent) { super(monitor, parent); } public ReusablePicoContainer(final ComponentMonitor monitor) { super(monitor); } public ReusablePicoContainer(final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { super(lifecycleStrategy, parent); } public ReusablePicoContainer(final PicoContainer parent) { super(parent); } @Override public MutablePicoContainer addComponent(final Object componentKey, final Object componentImplementationOrInstance, final Parameter... parameters) throws PicoCompositionException { if (componentKey == null) { throw new NullPointerException("componentKey"); } if (componentImplementationOrInstance == null) { throw new NullPointerException("componentImplementationOrInstance"); } super.addComponent(componentKey, componentImplementationOrInstance, parameters); if (! (componentImplementationOrInstance instanceof Class)) { instanceRegistrations.add(super.getComponentAdapter(componentKey)); } else { addStoredReference(componentKey); } return this; } @Override public MutablePicoContainer addComponent(final Object implOrInstance) throws PicoCompositionException { if ((implOrInstance instanceof Class)) { super.addComponent(implOrInstance); addStoredReference(implOrInstance); return this; } else { return this.addComponent(implOrInstance.getClass(), implOrInstance); } } /** * Precalculates all references to Stored behaviors. * @param key the object key. */ private void addStoredReference(final Object key) { ComponentAdapter ca = this.getComponentAdapter(key); Stored stored = ca.findAdapterOfType(Stored.class); if (stored != null) { storedReferences.put(ca, stored); } } @Override public synchronized void stop() { super.stop(); flushInstances(); } /** * Automatically called by {@link #stop() stop()}, this method clears all instantiated * instances and readies the picocontainer for reuse. */ public void flushInstances() { //Remove all instance registrations. for (ComponentAdapter eachAdapter : this.instanceRegistrations) { this.removeComponent(eachAdapter.getComponentKey()); } instanceRegistrations.clear(); for (ComponentAdapter eachAdapter : this.adapterRegistrations) { this.removeComponent(eachAdapter.getComponentKey()); } adapterRegistrations.clear(); //Flush all remaining objects. for (Stored eachStoredBehavior : this.storedReferences.values()) { eachStoredBehavior.flush(); } } @Override public MutablePicoContainer addAdapter(final ComponentAdapter componentAdapter, final Properties properties) { super.addAdapter(componentAdapter, properties); if (componentAdapter.findAdapterOfType(InstanceAdapter.class) != null) { this.instanceRegistrations.add(componentAdapter); } else { this.addStoredReference(componentAdapter.getComponentKey()); } return this; } /** * Use this instead of addAdapter in cases where you have custom adapters that the container * cannot figure out whether it should be flushed after each request or not. Anything * added through this method will be flushed after each stop() of the container. * @param componentAdapter * @return this to allow for method chaining. */ public MutablePicoContainer addFlushableAdapter(final ComponentAdapter componentAdapter) { adapterRegistrations.add(componentAdapter); addAdapter(componentAdapter); return this; } @Override public MutablePicoContainer addAdapter(final ComponentAdapter componentAdapter) { super.addAdapter(componentAdapter); if (componentAdapter.findAdapterOfType(InstanceAdapter.class) != null) { this.instanceRegistrations.add(componentAdapter); } else { this.addStoredReference(componentAdapter.getComponentKey()); } return this; } private void removeLocalReferences(final ComponentAdapter ca) { this.storedReferences.remove(ca); } @Override public ComponentAdapter removeComponent(final Object componentKey) { ComponentAdapter< T > result= null; try { result = super.removeComponent(componentKey); } catch (PicoCompositionException e) { //Help with debugging any lifecycle errors. throw new PicoCompositionException("There was an error removing component by key: '" + componentKey + "'",e); } if (result != null) { removeLocalReferences(result); } return result; } @Override public ComponentAdapter removeComponentByInstance(final T componentInstance) { ComponentAdapter result = super.removeComponentByInstance(componentInstance); if (result != null) { removeLocalReferences(result); } return result; } @Override public MutablePicoContainer makeChildContainer() { ReusablePicoContainer pc = new ReusablePicoContainer(componentFactory, lifecycleStrategy, this); addChildContainer(pc); return pc; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy