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
011package org.picocontainer.behaviors;
012
013import org.picocontainer.ComponentAdapter;
014import org.picocontainer.Parameter;
015import org.picocontainer.PicoCompositionException;
016import org.picocontainer.Characteristics;
017import org.picocontainer.ComponentMonitor;
018import org.picocontainer.LifecycleStrategy;
019import org.picocontainer.references.ThreadLocalMapObjectReference;
020
021import java.io.Serializable;
022import java.util.Properties;
023import java.util.HashMap;
024import java.util.Map;
025import java.util.Collections;
026//import java.util.concurrent.ConcurrentHashMap;
027
028/**
029 * @author Paul Hammant
030 */
031@SuppressWarnings("serial")
032public 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}