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