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.behaviors;
011
012 import java.lang.reflect.InvocationHandler;
013 import java.lang.reflect.InvocationTargetException;
014 import java.lang.reflect.Method;
015 import java.lang.reflect.Proxy;
016
017 import org.picocontainer.ComponentAdapter;
018 import org.picocontainer.ComponentMonitor;
019 import org.picocontainer.PicoContainer;
020 import org.picocontainer.PicoCompositionException;
021 import org.picocontainer.behaviors.AbstractBehavior;
022
023 /**
024 * This component adapter makes it possible to hide the implementation
025 * of a real subject (behind a proxy) provided the key is an interface.
026 * <p/>
027 * This class exists here, because a) it has no deps on external jars, b) dynamic proxy is quite easy.
028 * The user is prompted to look at picocontainer-gems for alternate and bigger implementations.
029 *
030 * @author Aslak Hellesøy
031 * @author Paul Hammant
032 * @see org.picocontainer.gems.adapters.HotSwappingComponentAdapter for a more feature-rich version of this class.
033 */
034 public class HiddenImplementation extends AbstractBehavior {
035
036 /**
037 * Creates an ImplementationHidingComponentAdapter with a delegate
038 * @param delegate the component adapter to which this adapter delegates
039 */
040 public HiddenImplementation(ComponentAdapter delegate) {
041 super(delegate);
042 }
043
044 public Object getComponentInstance(final PicoContainer container) throws PicoCompositionException {
045
046 ComponentAdapter delegate = getDelegate();
047 Object componentKey = delegate.getComponentKey();
048 Class[] classes;
049 if (componentKey instanceof Class && ((Class) delegate.getComponentKey()).isInterface()) {
050 classes = new Class[]{(Class) delegate.getComponentKey()};
051 } else if (componentKey instanceof Class[]) {
052 classes = (Class[]) componentKey;
053 } else {
054 return delegate.getComponentInstance(container);
055 }
056
057 Class[] interfaces = verifyInterfacesOnly(classes);
058 return createProxy(interfaces, container, delegate.getComponentImplementation().getClassLoader());
059 }
060
061 private Object createProxy(Class[] interfaces, final PicoContainer container, final ClassLoader classLoader) {
062 return Proxy.newProxyInstance(classLoader,
063 interfaces, new InvocationHandler() {
064 public Object invoke(final Object proxy, final Method method,
065 final Object[] args)
066 throws Throwable {
067 return invokeMethod(method, args, container);
068 }
069 });
070 }
071
072 protected Object invokeMethod(Method method, Object[] args, PicoContainer container) throws Throwable {
073 Object componentInstance = getDelegate().getComponentInstance(container);
074 ComponentMonitor componentMonitor = currentMonitor();
075 try {
076 componentMonitor.invoking(container, this, method, componentInstance);
077 long startTime = System.currentTimeMillis();
078 Object object = method.invoke(componentInstance, args);
079 componentMonitor.invoked(container,
080 this,
081 method, componentInstance, System.currentTimeMillis() - startTime);
082 return object;
083 } catch (final InvocationTargetException ite) {
084 componentMonitor.invocationFailed(method, componentInstance, ite);
085 throw ite.getTargetException();
086 }
087 }
088
089 private Class[] verifyInterfacesOnly(Class[] classes) {
090 for (Class clazz : classes) {
091 if (!clazz.isInterface()) {
092 throw new PicoCompositionException(
093 "Class keys must be interfaces. " + clazz + " is not an interface.");
094 }
095 }
096 return classes;
097 }
098
099 public String toString() {
100 return getName() + super.toString();
101 }
102
103 protected String getName() {
104 return "Hidden:";
105 }
106
107
108 }