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 *****************************************************************************/
010 package org.picocontainer.gems.adapters;
011
012 import com.thoughtworks.proxy.ProxyFactory;
013 import com.thoughtworks.proxy.factory.StandardProxyFactory;
014 import com.thoughtworks.proxy.kit.ObjectReference;
015 import com.thoughtworks.proxy.kit.ReflectionUtils;
016 import com.thoughtworks.proxy.toys.delegate.Delegating;
017 import com.thoughtworks.proxy.toys.hotswap.HotSwapping;
018
019 import org.picocontainer.ComponentAdapter;
020 import org.picocontainer.PicoContainer;
021 import org.picocontainer.defaults.DecoratingComponentAdapter;
022
023 import java.util.Arrays;
024 import java.util.HashSet;
025 import java.util.Set;
026
027
028 /**
029 * This component adapter makes it possible to hide the implementation of a real subject (behind a proxy). If the key of the
030 * component is of type {@link Class} and that class represents an interface, the proxy will only implement the interface
031 * represented by that Class. Otherwise (if the key is something else), the proxy will implement all the interfaces of the
032 * underlying subject. In any case, the proxy will also implement {@link com.thoughtworks.proxy.toys.hotswap.Swappable}, making
033 * it possible to swap out the underlying subject at runtime. <p/> <em>
034 * Note that this class doesn't cache instances. If you want caching,
035 * use a {@link org.picocontainer.defaults.CachingComponentAdapter} around this one.
036 * </em>
037 *
038 * @author Paul Hammant
039 * @author Aslak Hellesøy
040 * @version $Revision: 2631 $
041 */
042 public class HotSwappingComponentAdapter extends DecoratingComponentAdapter {
043 private final ProxyFactory proxyFactory;
044
045 private static class ImplementationHidingReference implements ObjectReference {
046 private final ComponentAdapter delegate;
047 private Object componentInstance;
048 private final PicoContainer container;
049
050 public ImplementationHidingReference(ComponentAdapter delegate, PicoContainer container) {
051 this.delegate = delegate;
052 this.container = container;
053 }
054
055 public Object get() {
056 if (componentInstance == null) {
057 componentInstance = delegate.getComponentInstance(container);
058 }
059 return componentInstance;
060 }
061
062 public void set(Object item) {
063 componentInstance = item;
064 }
065 }
066
067 public HotSwappingComponentAdapter(final ComponentAdapter delegate, ProxyFactory proxyFactory) {
068 super(delegate);
069 this.proxyFactory = proxyFactory;
070 }
071
072 public HotSwappingComponentAdapter(ComponentAdapter delegate) {
073 this(delegate, new StandardProxyFactory());
074 }
075
076 public Object getComponentInstance(final PicoContainer container) {
077 final Class[] proxyTypes;
078 if (getComponentKey() instanceof Class && proxyFactory.canProxy((Class)getComponentKey())) {
079 proxyTypes = new Class[]{(Class)getComponentKey()};
080 } else {
081 Set types = new HashSet(Arrays.asList(getComponentImplementation().getInterfaces()));
082 ReflectionUtils.addIfClassProxyingSupportedAndNotObject(getComponentImplementation(), types, proxyFactory);
083 proxyTypes = (Class[])types.toArray(new Class[types.size()]);
084 }
085 ObjectReference reference = new ImplementationHidingReference(getDelegate(), container);
086 return HotSwapping.object(proxyTypes, proxyFactory, reference, Delegating.MODE_DIRECT);
087 }
088 }