001 /***************************************************************************** 002 * Copyright (C) NanoContainer 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 *****************************************************************************/ 009 package org.nanocontainer.reflection; 010 011 import org.nanocontainer.integrationkit.ContainerRecorder; 012 import org.picocontainer.MutablePicoContainer; 013 import org.picocontainer.PicoException; 014 015 import java.io.IOException; 016 import java.io.ObjectInputStream; 017 import java.io.ObjectOutputStream; 018 import java.io.Serializable; 019 import java.lang.reflect.InvocationHandler; 020 import java.lang.reflect.InvocationTargetException; 021 import java.lang.reflect.Method; 022 import java.lang.reflect.Proxy; 023 import java.util.ArrayList; 024 import java.util.Iterator; 025 import java.util.List; 026 027 /** 028 * This class is serializable. The original container will not be serialized 029 * (for performance reasons), but the invocations will, so they can be replayed at the 030 * other end of the wire. 031 * 032 * @author Konstantin Pribluda ( konstantin.pribluda(at)infodesire.com ) 033 * @author Aslak Hellesøy 034 * @author Mauro Talevi 035 */ 036 public class DefaultContainerRecorder implements Serializable, ContainerRecorder { 037 038 private final List invocations = new ArrayList(); 039 private transient MutablePicoContainer container; 040 041 private final InvocationHandler invocationRecorder = new InvocationRecorder(); 042 043 public DefaultContainerRecorder(MutablePicoContainer container) { 044 this.container = container; 045 } 046 047 public MutablePicoContainer getContainerProxy() { 048 return (MutablePicoContainer) Proxy.newProxyInstance(getClass().getClassLoader(), 049 new Class[]{MutablePicoContainer.class}, invocationRecorder); 050 } 051 052 public void replay(MutablePicoContainer target) { 053 for (Iterator iter = invocations.iterator(); iter.hasNext();) { 054 Invocation invocation = (Invocation) iter.next(); 055 try { 056 invocation.invoke(target); 057 } catch (IllegalAccessException e) { 058 throw new PicoException(e) { 059 }; 060 } catch (InvocationTargetException e) { 061 throw new PicoException(e) { 062 }; 063 } 064 } 065 } 066 067 private class Invocation implements Serializable { 068 private transient Method method; 069 private Object[] args; 070 071 Invocation(Method method, Object[] args) { 072 this.method = method; 073 this.args = args; 074 } 075 076 private void writeObject(ObjectOutputStream out) throws IOException { 077 out.defaultWriteObject(); 078 out.writeUTF(method.getName()); 079 out.writeObject(method.getDeclaringClass()); 080 Class[] parameterTypes = method.getParameterTypes(); 081 out.writeInt(parameterTypes.length); 082 for (int i = 0; i < parameterTypes.length; i++) { 083 out.writeObject(parameterTypes[i]); 084 } 085 } 086 087 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { 088 in.defaultReadObject(); 089 String methodName = in.readUTF(); 090 Class declaringClass = (Class) in.readObject(); 091 int n = in.readInt(); 092 Class[] parameterTypes = new Class[n]; 093 for (int i = 0; i < n; i++) { 094 parameterTypes[i] = (Class) in.readObject(); 095 } 096 try { 097 method = declaringClass.getMethod(methodName, parameterTypes); 098 } catch (NoSuchMethodException e) { 099 throw new IOException("Couldn't load method " + methodName); 100 } 101 } 102 103 public void invoke(Object target) throws IllegalAccessException, InvocationTargetException { 104 method.invoke(target, args); 105 } 106 } 107 108 private class InvocationRecorder implements InvocationHandler, Serializable { 109 /** 110 * Record invocation and invoke on underlying container 111 */ 112 public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException, InvocationTargetException { 113 invocations.add(new Invocation(method, args)); 114 return method.invoke(container, args); 115 } 116 }; 117 118 }