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 Joerg Schaible *
009 *****************************************************************************/
010 package org.picocontainer.defaults;
011
012 import java.io.Serializable;
013 import java.lang.reflect.InvocationHandler;
014 import java.lang.reflect.InvocationTargetException;
015 import java.lang.reflect.Method;
016 import java.lang.reflect.Proxy;
017
018 import org.picocontainer.Disposable;
019 import org.picocontainer.PicoContainer;
020 import org.picocontainer.Startable;
021
022
023 /**
024 * A factory for immutable PicoContainer proxies.
025 *
026 * @author Jörg Schaible
027 * @since 1.2
028 */
029 public class ImmutablePicoContainerProxyFactory implements InvocationHandler, Serializable {
030
031 private static final Class[] interfaces = new Class[]{PicoContainer.class};
032 protected static Method startMethod = null;
033 protected static Method stopMethod = null;
034 protected static Method disposeMethod = null;
035 protected static Method equalsMethod = null;
036
037 static {
038 try {
039 startMethod = Startable.class.getMethod("start", new Class[0]);
040 stopMethod = Startable.class.getMethod("stop", new Class[0]);
041 disposeMethod = Disposable.class.getMethod("dispose", new Class[0]);
042 equalsMethod = Object.class.getMethod("equals", new Class[]{Object.class});
043 } catch (final NoSuchMethodException e) {
044 throw new InternalError(e.getMessage());
045 }
046 }
047
048 private final PicoContainer pico;
049
050 /**
051 * Construct a ImmutablePicoContainerProxyFactory.
052 *
053 * @param pico the container to hide
054 * @throws NullPointerException if <tt>pico</tt> is <code>null</code>
055 * @since 1.2
056 */
057 protected ImmutablePicoContainerProxyFactory(final PicoContainer pico) {
058 if (pico == null) {
059 throw new NullPointerException();
060 }
061 this.pico = pico;
062 }
063
064 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
065 if (method.equals(startMethod) || method.equals(stopMethod) || method.equals(disposeMethod)) {
066 throw new UnsupportedOperationException("This container is immutable, "
067 + method.getName()
068 + " is not allowed");
069 } else if (method.equals(equalsMethod)) { // necessary for JDK 1.3
070 return new Boolean(args[0] != null && args[0].equals(pico));
071 }
072 try {
073 return method.invoke(pico, args);
074 } catch (final InvocationTargetException e) {
075 throw e.getTargetException();
076 }
077 }
078
079 /**
080 * Create a new immutable PicoContainer proxy. The proxy will completly hide the implementation of the given
081 * {@link PicoContainer} and will also prevent the invocation of any methods of the lifecycle methods from
082 * {@link Startable} or {@link Disposable}.
083 *
084 * @param pico
085 * @return the new proxy
086 * @throws NullPointerException if <tt>pico</tt> is <code>null</code>
087 * @since 1.2
088 */
089 public static PicoContainer newProxyInstance(final PicoContainer pico) {
090 return (PicoContainer)Proxy.newProxyInstance(
091 PicoContainer.class.getClassLoader(), interfaces,
092 new ImmutablePicoContainerProxyFactory(pico));
093 }
094 }