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                                                          *
009 *****************************************************************************/
010package org.picocontainer.gems.behaviors;
011
012import org.picocontainer.ComponentAdapter;
013import org.picocontainer.PicoContainer;
014import org.picocontainer.behaviors.Cached;
015
016import java.lang.reflect.Type;
017
018
019/**
020 * This component adapter makes it possible to hide the implementation of a real subject (behind a proxy). If the key of the
021 * component is of type {@link Class} and that class represents an interface, the proxy will only implement the interface
022 * represented by that Class. Otherwise (if the key is something else), the proxy will implement all the interfaces of the
023 * underlying subject. In any case, the proxy will also implement {@link com.thoughtworks.proxy.toys.hotswap.Swappable}, making
024 * it possible to swap out the underlying subject at runtime. <p/> <em>
025 * Note that this class doesn't cache instances. If you want caching,
026 * use a {@link Cached} around this one.
027 * </em>
028 *
029 * @author Paul Hammant
030 */
031@SuppressWarnings("serial")
032public class HotSwappable<T> extends AsmHiddenImplementation<T> {
033
034        private final Swappable swappable = new Swappable();
035    
036        private T instance;
037
038    public HotSwappable(final ComponentAdapter<T> delegate) {
039        super(delegate);
040    }
041
042    @Override
043        protected Swappable getSwappable() {
044        return swappable;
045    }
046
047    @SuppressWarnings("unchecked")
048        public T swapRealInstance(final T instance) {
049        return (T) swappable.swap(instance);
050    }
051
052    @SuppressWarnings("unchecked")
053        public T getRealInstance() {
054        return (T) swappable.getInstance();
055    }
056
057
058    @Override
059        public T getComponentInstance(final PicoContainer container, final Type into) {
060        synchronized (swappable) {
061            if (instance == null) {
062                instance = super.getComponentInstance(container, into);
063            }
064        }
065        return instance;
066    }
067
068    @Override
069        public String getDescriptor() {
070        return "HotSwappable";
071    }
072
073    public static class Swappable {
074
075        private transient Object delegate;
076
077        public Object getInstance() {
078            return delegate;
079        }
080
081        public Object swap(final Object delegate) {
082            Object old = this.delegate;
083            this.delegate = delegate;
084            return old;
085        }
086
087    }
088
089}