1 /* 2 * Copyright 2002-2014 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.remoting.support; 18 19 import java.io.Serializable; 20 import java.lang.reflect.InvocationTargetException; 21 import java.lang.reflect.Method; 22 import java.util.HashMap; 23 import java.util.Map; 24 25 import org.aopalliance.intercept.MethodInvocation; 26 27 import org.springframework.util.ClassUtils; 28 29 /** 30 * Encapsulates a remote invocation, providing core method invocation properties 31 * in a serializable fashion. Used for RMI and HTTP-based serialization invokers. 32 * 33 * <p>This is an SPI class, typically not used directly by applications. 34 * Can be subclassed for additional invocation parameters. 35 * 36 * <p>Both {@link RemoteInvocation} and {@link RemoteInvocationResult} are designed 37 * for use with standard Java serialization as well as JavaBean-style serialization. 38 * 39 * @author Juergen Hoeller 40 * @since 25.02.2004 41 * @see RemoteInvocationResult 42 * @see RemoteInvocationFactory 43 * @see RemoteInvocationExecutor 44 * @see org.springframework.remoting.rmi.RmiProxyFactoryBean 45 * @see org.springframework.remoting.rmi.RmiServiceExporter 46 * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean 47 * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter 48 */ 49 public class RemoteInvocation implements Serializable { 50 51 /** use serialVersionUID from Spring 1.1 for interoperability */ 52 private static final long serialVersionUID = 6876024250231820554L; 53 54 55 private String methodName; 56 57 private Class<?>[] parameterTypes; 58 59 private Object[] arguments; 60 61 private Map<String, Serializable> attributes; 62 63 64 /** 65 * Create a new RemoteInvocation for the given AOP method invocation. 66 * @param methodInvocation the AOP invocation to convert 67 */ 68 public RemoteInvocation(MethodInvocation methodInvocation) { 69 this.methodName = methodInvocation.getMethod().getName(); 70 this.parameterTypes = methodInvocation.getMethod().getParameterTypes(); 71 this.arguments = methodInvocation.getArguments(); 72 } 73 74 /** 75 * Create a new RemoteInvocation for the given parameters. 76 * @param methodName the name of the method to invoke 77 * @param parameterTypes the parameter types of the method 78 * @param arguments the arguments for the invocation 79 */ 80 public RemoteInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments) { 81 this.methodName = methodName; 82 this.parameterTypes = parameterTypes; 83 this.arguments = arguments; 84 } 85 86 /** 87 * Create a new RemoteInvocation for JavaBean-style deserialization 88 * (e.g. with Jackson). 89 */ 90 public RemoteInvocation() { 91 } 92 93 94 /** 95 * Set the name of the target method. 96 * <p>This setter is intended for JavaBean-style deserialization. 97 */ 98 public void setMethodName(String methodName) { 99 this.methodName = methodName; 100 } 101 102 /** 103 * Return the name of the target method. 104 */ 105 public String getMethodName() { 106 return this.methodName; 107 } 108 109 /** 110 * Set the parameter types of the target method. 111 * <p>This setter is intended for JavaBean-style deserialization. 112 */ 113 public void setParameterTypes(Class<?>[] parameterTypes) { 114 this.parameterTypes = parameterTypes; 115 } 116 117 /** 118 * Return the parameter types of the target method. 119 */ 120 public Class<?>[] getParameterTypes() { 121 return this.parameterTypes; 122 } 123 124 /** 125 * Set the arguments for the target method call. 126 * <p>This setter is intended for JavaBean-style deserialization. 127 */ 128 public void setArguments(Object[] arguments) { 129 this.arguments = arguments; 130 } 131 132 /** 133 * Return the arguments for the target method call. 134 */ 135 public Object[] getArguments() { 136 return this.arguments; 137 } 138 139 140 /** 141 * Add an additional invocation attribute. Useful to add additional 142 * invocation context without having to subclass RemoteInvocation. 143 * <p>Attribute keys have to be unique, and no overriding of existing 144 * attributes is allowed. 145 * <p>The implementation avoids to unnecessarily create the attributes 146 * Map, to minimize serialization size. 147 * @param key the attribute key 148 * @param value the attribute value 149 * @throws IllegalStateException if the key is already bound 150 */ 151 public void addAttribute(String key, Serializable value) throws IllegalStateException { 152 if (this.attributes == null) { 153 this.attributes = new HashMap<String, Serializable>(); 154 } 155 if (this.attributes.containsKey(key)) { 156 throw new IllegalStateException("There is already an attribute with key '" + key + "' bound"); 157 } 158 this.attributes.put(key, value); 159 } 160 161 /** 162 * Retrieve the attribute for the given key, if any. 163 * <p>The implementation avoids to unnecessarily create the attributes 164 * Map, to minimize serialization size. 165 * @param key the attribute key 166 * @return the attribute value, or {@code null} if not defined 167 */ 168 public Serializable getAttribute(String key) { 169 if (this.attributes == null) { 170 return null; 171 } 172 return this.attributes.get(key); 173 } 174 175 /** 176 * Set the attributes Map. Only here for special purposes: 177 * Preferably, use {@link #addAttribute} and {@link #getAttribute}. 178 * @param attributes the attributes Map 179 * @see #addAttribute 180 * @see #getAttribute 181 */ 182 public void setAttributes(Map<String, Serializable> attributes) { 183 this.attributes = attributes; 184 } 185 186 /** 187 * Return the attributes Map. Mainly here for debugging purposes: 188 * Preferably, use {@link #addAttribute} and {@link #getAttribute}. 189 * @return the attributes Map, or {@code null} if none created 190 * @see #addAttribute 191 * @see #getAttribute 192 */ 193 public Map<String, Serializable> getAttributes() { 194 return this.attributes; 195 } 196 197 198 /** 199 * Perform this invocation on the given target object. 200 * Typically called when a RemoteInvocation is received on the server. 201 * @param targetObject the target object to apply the invocation to 202 * @return the invocation result 203 * @throws NoSuchMethodException if the method name could not be resolved 204 * @throws IllegalAccessException if the method could not be accessed 205 * @throws InvocationTargetException if the method invocation resulted in an exception 206 * @see java.lang.reflect.Method#invoke 207 */ 208 public Object invoke(Object targetObject) 209 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { 210 211 Method method = targetObject.getClass().getMethod(this.methodName, this.parameterTypes); 212 return method.invoke(targetObject, this.arguments); 213 } 214 215 216 @Override 217 public String toString() { 218 return "RemoteInvocation: method name '" + this.methodName + "'; parameter types " + 219 ClassUtils.classNamesToString(this.parameterTypes); 220 } 221 222 }