001 /***************************************************************************** 002 * Copyright (C) PicoContainer Organization. All rights reserved. * 003 * ------------------------------------------------------------------------- * 004 * The software in this package is published under the terms of the BSD * 005 * style license a copy of which has been included with this distribution in * 006 * the LICENSE.txt file. * 007 * * 008 * Original code by Mike Rimov * 009 *****************************************************************************/ 010 package org.picocontainer.gems.containers; 011 012 import java.util.ArrayList; 013 import java.util.HashMap; 014 import java.util.List; 015 import java.util.Map; 016 import java.util.Properties; 017 018 import org.picocontainer.ComponentAdapter; 019 import org.picocontainer.ComponentFactory; 020 import org.picocontainer.ComponentMonitor; 021 import org.picocontainer.DefaultPicoContainer; 022 import org.picocontainer.LifecycleStrategy; 023 import org.picocontainer.MutablePicoContainer; 024 import org.picocontainer.Parameter; 025 import org.picocontainer.PicoCompositionException; 026 import org.picocontainer.PicoContainer; 027 import org.picocontainer.adapters.InstanceAdapter; 028 import org.picocontainer.behaviors.Stored; 029 030 /** 031 * Normal PicoContainers are meant to be created, started, stopped, disposed and 032 * garbage collected. The goal of this container is to reduce the number of 033 * registration calls (and therefore objects created) in areas where performance 034 * is key (for example, this might be used in NanoContainer request containers). 035 * <p> 036 * It accomplishes its goal in two ways: <br/> (1) Once a container is disposed 037 * of, start() may be called again, allowing for recycling of the container. (This is default 038 * behavior with a picocontainer) 039 * </p> 040 * <p> 041 * (2) All instance registrations will be unregistered when stop is called. (For example, 042 * HttpServletRequest would be removed), and all component adapter instance values 043 * are flushed. 044 * </p> 045 * <h4>Container Storage</h4> 046 * <p>It is still up to the builder of this container to decide where to store its reference. Since 047 * it is reusable, it needs to be stored someplace that doesn't easily expire. Probably the most 048 * common storage location would be ThreadLocal storage. HttpSession might be another valid 049 * storage location.</p> 050 * @author Michael Rimov 051 */ 052 @SuppressWarnings("serial") 053 public class ReusablePicoContainer extends DefaultPicoContainer { 054 055 private final List<ComponentAdapter<?>> instanceRegistrations = new ArrayList<ComponentAdapter<?>>(); 056 057 private final Map<ComponentAdapter<?>, Stored<?>> storedReferences = new HashMap<ComponentAdapter<?>, Stored<?>>(); 058 059 public ReusablePicoContainer() { 060 super(); 061 } 062 063 public ReusablePicoContainer(final ComponentFactory componentFactory, 064 final LifecycleStrategy lifecycleStrategy, final PicoContainer parent, 065 final ComponentMonitor componentMonitor) { 066 super(componentFactory, lifecycleStrategy, parent, componentMonitor); 067 } 068 069 public ReusablePicoContainer(final ComponentFactory componentFactory, 070 final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { 071 super(componentFactory, lifecycleStrategy, parent); 072 } 073 074 public ReusablePicoContainer(final ComponentFactory componentFactory, 075 final PicoContainer parent) { 076 super(componentFactory, parent); 077 } 078 079 public ReusablePicoContainer(final ComponentFactory componentFactory) { 080 super(componentFactory); 081 } 082 083 public ReusablePicoContainer(final ComponentMonitor monitor, 084 final LifecycleStrategy lifecycleStrategy, final PicoContainer parent) { 085 super(monitor, lifecycleStrategy, parent); 086 } 087 088 public ReusablePicoContainer(final ComponentMonitor monitor, final PicoContainer parent) { 089 super(monitor, parent); 090 } 091 092 public ReusablePicoContainer(final ComponentMonitor monitor) { 093 super(monitor); 094 } 095 096 public ReusablePicoContainer(final LifecycleStrategy lifecycleStrategy, 097 final PicoContainer parent) { 098 super(lifecycleStrategy, parent); 099 } 100 101 public ReusablePicoContainer(final PicoContainer parent) { 102 super(parent); 103 } 104 105 @Override 106 public MutablePicoContainer addComponent(final Object componentKey, 107 final Object componentImplementationOrInstance, 108 final Parameter... parameters) throws PicoCompositionException { 109 110 if (componentKey == null) { 111 throw new NullPointerException("componentKey"); 112 } 113 114 if (componentImplementationOrInstance == null) { 115 throw new NullPointerException("componentImplementationOrInstance"); 116 } 117 118 super.addComponent(componentKey, 119 componentImplementationOrInstance, 120 parameters); 121 122 if (! (componentImplementationOrInstance instanceof Class)) { 123 instanceRegistrations.add(super.getComponentAdapter(componentKey)); 124 } else { 125 addStoredReference(componentKey); 126 } 127 128 return this; 129 } 130 131 @Override 132 public MutablePicoContainer addComponent(final Object implOrInstance) 133 throws PicoCompositionException { 134 if ((implOrInstance instanceof Class)) { 135 super.addComponent(implOrInstance); 136 addStoredReference(implOrInstance); 137 return this; 138 } else { 139 return this.addComponent(implOrInstance.getClass(), implOrInstance); 140 } 141 } 142 143 /** 144 * Precalculates all references to Stored behaviors. 145 * @param key the object key. 146 */ 147 private void addStoredReference(final Object key) { 148 ComponentAdapter<?> ca = this.getComponentAdapter(key); 149 Stored<?> stored = ca.findAdapterOfType(Stored.class); 150 if (stored != null) { 151 storedReferences.put(ca, stored); 152 } 153 } 154 155 @Override 156 public synchronized void stop() { 157 super.stop(); 158 159 //Remove all instance registrations. 160 for (ComponentAdapter<?> eachAdapter : this.instanceRegistrations) { 161 this.removeComponent(eachAdapter.getComponentKey()); 162 } 163 164 instanceRegistrations.clear(); 165 166 //Flush all remaining objects. 167 for (Stored<?> eachStoredBehavior : this.storedReferences.values()) { 168 eachStoredBehavior.flush(); 169 } 170 } 171 172 @Override 173 public MutablePicoContainer addAdapter(final ComponentAdapter<?> componentAdapter, final Properties properties) { 174 super.addAdapter(componentAdapter, properties); 175 if (componentAdapter.findAdapterOfType(InstanceAdapter.class) != null) { 176 this.instanceRegistrations.add(componentAdapter); 177 } else { 178 this.addStoredReference(componentAdapter.getComponentKey()); 179 } 180 181 return this; 182 } 183 184 @Override 185 public MutablePicoContainer addAdapter(final ComponentAdapter<?> componentAdapter) { 186 super.addAdapter(componentAdapter); 187 if (componentAdapter.findAdapterOfType(InstanceAdapter.class) != null) { 188 this.instanceRegistrations.add(componentAdapter); 189 } else { 190 this.addStoredReference(componentAdapter.getComponentKey()); 191 } 192 193 return this; 194 } 195 196 private void removeLocalReferences(final ComponentAdapter<?> ca) { 197 this.storedReferences.remove(ca); 198 } 199 200 @Override 201 public <T> ComponentAdapter<T> removeComponent(final Object componentKey) { 202 ComponentAdapter<T> result = super.removeComponent(componentKey); 203 if (result != null) { 204 removeLocalReferences(result); 205 } 206 207 return result; 208 } 209 210 @Override 211 public <T> ComponentAdapter<T> removeComponentByInstance(final T componentInstance) { 212 ComponentAdapter<T> result = super.removeComponentByInstance(componentInstance); 213 if (result != null) { 214 removeLocalReferences(result); 215 } 216 217 return result; 218 } 219 220 @Override 221 public MutablePicoContainer makeChildContainer() { 222 ReusablePicoContainer pc = new ReusablePicoContainer(componentFactory, lifecycleStrategy, this); 223 addChildContainer(pc); 224 return pc; 225 } 226 227 }