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 }