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