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 }