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    }