View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2005 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  
18  package ch.elca.el4j.services.remoting;
19  
20  import java.lang.reflect.InvocationHandler;
21  import java.lang.reflect.InvocationTargetException;
22  import java.lang.reflect.Method;
23  import java.util.Map;
24  
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  
28  import ch.elca.el4j.core.contextpassing.ImplicitContextPassingRegistry;
29  import ch.elca.el4j.util.interfaceenrichment.MethodDescriptor;
30  
31  /**
32   * This class passes the context additionally with every method call.
33   *
34   * @svnLink $Revision: 3873 $;$Date: 2009-08-04 13:59:45 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/remoting_core/src/main/java/ch/elca/el4j/services/remoting/ClientContextInvocationHandler.java $
35   *
36   * @author Martin Zeltner (MZE)
37   */
38  public class ClientContextInvocationHandler implements InvocationHandler {
39  	/**
40  	 * Private logger.
41  	 */
42  	private static Logger s_logger = LoggerFactory
43  			.getLogger(ClientContextInvocationHandler.class);
44  
45  	/**
46  	 * Is the remote object where the invocations has to be delegated.
47  	 */
48  	private final Object m_innerRemoteObject;
49  
50  	/**
51  	 * Is the modificated service interface to be able to send context
52  	 * information with.
53  	 */
54  	private final Class m_serviceInterfaceWithContext;
55  
56  	/**
57  	 * Describes how the service interface has to be modificated.
58  	 */
59  	private final ContextEnrichmentDecorator m_contextInterfaceDecorator;
60  
61  	/**
62  	 * Is the registry for the implicit context passing.
63  	 */
64  	private final ImplicitContextPassingRegistry
65  		m_implicitContextPassingRegistry;
66  	
67  	/**
68  	 * Constructor.
69  	 *
70  	 * @param innerRemoteObject
71  	 *                  Is the object to which invokations must be delegated.
72  	 * @param serviceInterfaceWithContext
73  	 *                  Is the enriched service interface.
74  	 * @param implicitContextPassingRegistry
75  	 *                  Is the implicit context passing registry.
76  	 */
77  	public ClientContextInvocationHandler(Object innerRemoteObject,
78  			Class serviceInterfaceWithContext,
79  			ImplicitContextPassingRegistry implicitContextPassingRegistry) {
80  		m_innerRemoteObject = innerRemoteObject;
81  		m_serviceInterfaceWithContext = serviceInterfaceWithContext;
82  		m_contextInterfaceDecorator = new ContextEnrichmentDecorator();
83  		m_implicitContextPassingRegistry = implicitContextPassingRegistry;
84  		if (m_implicitContextPassingRegistry == null) {
85  			s_logger.warn("No ImplicitContextPassingRegistry defined! "
86  					+ "Context will not be passed through.");
87  		}
88  	}
89  
90  	/**
91  	 * {@inheritDoc}
92  	 */
93  	public Object invoke(Object proxy, Method method, Object[] args)
94  		throws Throwable {
95  		Method m;
96  		Object[] newArgs;
97  		String methodName = method.getName();
98  		Class[] methodParametersTypes = method.getParameterTypes();
99  		Class declaringClass = method.getDeclaringClass();
100 
101 		/* HACK Here we should ensure that the declaring class is the interface
102 		 *      which the proxy was created for (and not just testing whether
103 		 *      the method is declared in an (arbitrary) interface). But this
104 		 *      resulted in a very strange behaviour in EJB containers, which
105 		 *      weren't able anymore to reactivate passivated beans (i.e. they
106 		 *      threw a ClassNotFoundException).
107 		 */
108 		if (declaringClass.isInterface()) {
109 			MethodDescriptor md = new MethodDescriptor();
110 			md.setParameterTypes(methodParametersTypes);
111 			m_contextInterfaceDecorator.changedMethodSignature(md);
112 			Class[] methodParametersTypesWithContext = md.getParameterTypes();
113 			
114 			m = m_serviceInterfaceWithContext.getMethod(methodName,
115 					methodParametersTypesWithContext);
116 	
117 			int argsLength = (args == null) ? 0 : args.length;
118 			newArgs = new Object[argsLength + 1];
119 			for (int i = 0; i < argsLength; i++) {
120 				newArgs[i] = args[i];
121 			}
122 			Map map = null;
123 			if (m_implicitContextPassingRegistry != null) {
124 				map = m_implicitContextPassingRegistry
125 						.getAssembledImplicitContext();
126 			}
127 			newArgs[newArgs.length - 1] = map;
128 		} else {
129 			m = declaringClass.getMethod(methodName, methodParametersTypes);
130 			newArgs = args;
131 		}
132 
133 		try {
134 			return m.invoke(m_innerRemoteObject, newArgs);
135 		} catch (InvocationTargetException e) {
136 			throw e.getTargetException();
137 		}
138 	}
139 
140 	/**
141 	 * @return Returns the inner remote object where method calls are delegated
142 	 * to.
143 	 */
144 	protected Object getInnerRemoteObject() {
145 		return m_innerRemoteObject;
146 	}
147 }