001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.remoting.support;
018:
019: import java.io.Serializable;
020: import java.lang.reflect.InvocationTargetException;
021: import java.lang.reflect.Method;
022: import java.util.HashMap;
023: import java.util.Map;
024:
025: import org.aopalliance.intercept.MethodInvocation;
026:
027: import org.springframework.util.ClassUtils;
028:
029: /**
030: * Encapsulates a remote invocation, providing core method invocation properties
031: * in a serializable fashion. Used for RMI and HTTP-based serialization invokers.
032: *
033: * <p>This is an SPI class, typically not used directly by applications.
034: * Can be subclassed for additional invocation parameters.
035: *
036: * @author Juergen Hoeller
037: * @since 25.02.2004
038: * @see RemoteInvocationResult
039: * @see RemoteInvocationFactory
040: * @see RemoteInvocationExecutor
041: * @see org.springframework.remoting.rmi.RmiProxyFactoryBean
042: * @see org.springframework.remoting.rmi.RmiServiceExporter
043: * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
044: * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
045: */
046: public class RemoteInvocation implements Serializable {
047:
048: /** use serialVersionUID from Spring 1.1 for interoperability */
049: private static final long serialVersionUID = 6876024250231820554L;
050:
051: private String methodName;
052:
053: private Class[] parameterTypes;
054:
055: private Object[] arguments;
056:
057: private Map attributes;
058:
059: /**
060: * Create a new RemoteInvocation for use as JavaBean.
061: */
062: public RemoteInvocation() {
063: }
064:
065: /**
066: * Create a new RemoteInvocation for the given parameters.
067: * @param methodName the name of the method to invoke
068: * @param parameterTypes the parameter types of the method
069: * @param arguments the arguments for the invocation
070: */
071: public RemoteInvocation(String methodName, Class[] parameterTypes,
072: Object[] arguments) {
073: this .methodName = methodName;
074: this .parameterTypes = parameterTypes;
075: this .arguments = arguments;
076: }
077:
078: /**
079: * Create a new RemoteInvocation for the given AOP method invocation.
080: * @param methodInvocation the AOP invocation to convert
081: */
082: public RemoteInvocation(MethodInvocation methodInvocation) {
083: this .methodName = methodInvocation.getMethod().getName();
084: this .parameterTypes = methodInvocation.getMethod()
085: .getParameterTypes();
086: this .arguments = methodInvocation.getArguments();
087: }
088:
089: /**
090: * Set the name of the target method.
091: */
092: public void setMethodName(String methodName) {
093: this .methodName = methodName;
094: }
095:
096: /**
097: * Return the name of the target method.
098: */
099: public String getMethodName() {
100: return this .methodName;
101: }
102:
103: /**
104: * Set the parameter types of the target method.
105: */
106: public void setParameterTypes(Class[] parameterTypes) {
107: this .parameterTypes = parameterTypes;
108: }
109:
110: /**
111: * Return the parameter types of the target method.
112: */
113: public Class[] getParameterTypes() {
114: return this .parameterTypes;
115: }
116:
117: /**
118: * Set the arguments for the target method call.
119: */
120: public void setArguments(Object[] arguments) {
121: this .arguments = arguments;
122: }
123:
124: /**
125: * Return the arguments for the target method call.
126: */
127: public Object[] getArguments() {
128: return this .arguments;
129: }
130:
131: /**
132: * Add an additional invocation attribute. Useful to add additional
133: * invocation context without having to subclass RemoteInvocation.
134: * <p>Attribute keys have to be unique, and no overriding of existing
135: * attributes is allowed.
136: * <p>The implementation avoids to unnecessarily create the attributes
137: * Map, to minimize serialization size.
138: * @param key the attribute key
139: * @param value the attribute value
140: * @throws IllegalStateException if the key is already bound
141: */
142: public void addAttribute(String key, Serializable value)
143: throws IllegalStateException {
144: if (this .attributes == null) {
145: this .attributes = new HashMap();
146: }
147: if (this .attributes.containsKey(key)) {
148: throw new IllegalStateException(
149: "There is already an attribute with key '" + key
150: + "' bound");
151: }
152: this .attributes.put(key, value);
153: }
154:
155: /**
156: * Retrieve the attribute for the given key, if any.
157: * <p>The implementation avoids to unnecessarily create the attributes
158: * Map, to minimize serialization size.
159: * @param key the attribute key
160: * @return the attribute value, or <code>null</code> if not defined
161: */
162: public Serializable getAttribute(String key) {
163: if (this .attributes == null) {
164: return null;
165: }
166: return (Serializable) this .attributes.get(key);
167: }
168:
169: /**
170: * Set the attributes Map. Only here for special purposes:
171: * Preferably, use {@link #addAttribute} and {@link #getAttribute}.
172: * @param attributes the attributes Map
173: * @see #addAttribute
174: * @see #getAttribute
175: */
176: public void setAttributes(Map attributes) {
177: this .attributes = attributes;
178: }
179:
180: /**
181: * Return the attributes Map. Mainly here for debugging purposes:
182: * Preferably, use {@link #addAttribute} and {@link #getAttribute}.
183: * @return the attributes Map, or <code>null</code> if none created
184: * @see #addAttribute
185: * @see #getAttribute
186: */
187: public Map getAttributes() {
188: return this .attributes;
189: }
190:
191: /**
192: * Perform this invocation on the given target object.
193: * Typically called when a RemoteInvocation is received on the server.
194: * @param targetObject the target object to apply the invocation to
195: * @return the invocation result
196: * @throws NoSuchMethodException if the method name could not be resolved
197: * @throws IllegalAccessException if the method could not be accessed
198: * @throws InvocationTargetException if the method invocation resulted in an exception
199: * @see java.lang.reflect.Method#invoke
200: */
201: public Object invoke(Object targetObject)
202: throws NoSuchMethodException, IllegalAccessException,
203: InvocationTargetException {
204:
205: Method method = targetObject.getClass().getMethod(
206: this .methodName, this .parameterTypes);
207: return method.invoke(targetObject, this .arguments);
208: }
209:
210: public String toString() {
211: return "RemoteInvocation: method name '" + this .methodName
212: + "'; parameter types "
213: + ClassUtils.classNamesToString(this.parameterTypes);
214: }
215:
216: }
|