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     * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant   *
009     *****************************************************************************/
010    
011    package org.picocontainer.behaviors;
012    
013    import org.picocontainer.ComponentAdapter;
014    import org.picocontainer.Parameter;
015    import org.picocontainer.PicoCompositionException;
016    import org.picocontainer.Characteristics;
017    import org.picocontainer.ComponentMonitor;
018    import org.picocontainer.LifecycleStrategy;
019    import org.picocontainer.references.ThreadLocalMapObjectReference;
020    
021    import java.io.Serializable;
022    import java.util.Properties;
023    import java.util.HashMap;
024    import java.util.Map;
025    import java.util.Collections;
026    //import java.util.concurrent.ConcurrentHashMap;
027    
028    /**
029     * @author Paul Hammant
030     */
031    @SuppressWarnings("serial")
032    public class Storing extends AbstractBehaviorFactory {
033    
034        private final StoreThreadLocal mapThreadLocalObjectReference = new StoreThreadLocal();
035    
036        public <T> ComponentAdapter<T>  createComponentAdapter(ComponentMonitor componentMonitor, LifecycleStrategy lifecycleStrategy, Properties componentProperties, final Object componentKey, Class<T> componentImplementation, Parameter... parameters)
037    
038                throws PicoCompositionException {
039            if (removePropertiesIfPresent(componentProperties, Characteristics.NO_CACHE)) {
040                return super.createComponentAdapter(componentMonitor,
041                                                                                 lifecycleStrategy,
042                                                                                 componentProperties,
043                                                                                 componentKey,
044                                                                                 componentImplementation,
045                                                                                 parameters);
046            }
047            removePropertiesIfPresent(componentProperties, Characteristics.CACHE);
048            return componentMonitor.newBehavior(new Stored<T>(super.createComponentAdapter(componentMonitor, lifecycleStrategy,
049                                                                    componentProperties, componentKey, componentImplementation, parameters),
050                              new ThreadLocalMapObjectReference(mapThreadLocalObjectReference, componentKey)));
051    
052        }
053    
054        public <T> ComponentAdapter<T> addComponentAdapter(ComponentMonitor componentMonitor,
055                                        LifecycleStrategy lifecycleStrategy,
056                                        Properties componentProperties,
057                                        final ComponentAdapter<T> adapter) {
058            if (removePropertiesIfPresent(componentProperties, Characteristics.NO_CACHE)) {
059                return super.addComponentAdapter(componentMonitor, lifecycleStrategy, componentProperties, adapter);
060            }
061            removePropertiesIfPresent(componentProperties, Characteristics.CACHE);
062    
063            return componentMonitor.newBehavior(new Stored<T>(super.addComponentAdapter(componentMonitor, lifecycleStrategy, componentProperties, adapter),
064                              new ThreadLocalMapObjectReference(mapThreadLocalObjectReference, adapter.getComponentKey())));
065        }
066    
067        public StoreWrapper getCacheForThread() {
068            StoreWrapper wrappedMap = new StoreWrapper();
069            wrappedMap.wrapped = (Map)mapThreadLocalObjectReference.get();
070            return wrappedMap;
071        }
072    
073        public void putCacheForThread(StoreWrapper wrappedMap) {
074            mapThreadLocalObjectReference.set(wrappedMap.wrapped);
075        }
076    
077        public StoreWrapper resetCacheForThread() {
078            Map map = new HashMap();
079            mapThreadLocalObjectReference.set(map);
080            StoreWrapper storeWrapper = new StoreWrapper();
081            storeWrapper.wrapped = map;
082            return storeWrapper;
083        }
084    
085        public void invalidateCacheForThread() {
086            mapThreadLocalObjectReference.set(Collections.unmodifiableMap(Collections.emptyMap()));
087        }
088    
089        public int getCacheSize() {
090            return ((Map)mapThreadLocalObjectReference.get()).size();
091        }
092    
093        public static class StoreThreadLocal extends ThreadLocal<Map> implements Serializable {
094            protected Map initialValue() {
095                return new HashMap();
096            }
097        }
098    
099        public static class StoreWrapper implements Serializable {
100            private Map wrapped;
101        }
102    
103    }