001/* 002 * Copyright 2002-2014 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 * https://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 017package org.springframework.remoting.support; 018 019import java.io.Serializable; 020import java.lang.reflect.InvocationTargetException; 021import java.lang.reflect.Method; 022import java.util.HashMap; 023import java.util.Map; 024 025import org.aopalliance.intercept.MethodInvocation; 026 027import 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 * <p>Both {@link RemoteInvocation} and {@link RemoteInvocationResult} are designed 037 * for use with standard Java serialization as well as JavaBean-style serialization. 038 * 039 * @author Juergen Hoeller 040 * @since 25.02.2004 041 * @see RemoteInvocationResult 042 * @see RemoteInvocationFactory 043 * @see RemoteInvocationExecutor 044 * @see org.springframework.remoting.rmi.RmiProxyFactoryBean 045 * @see org.springframework.remoting.rmi.RmiServiceExporter 046 * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean 047 * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter 048 */ 049public class RemoteInvocation implements Serializable { 050 051 /** use serialVersionUID from Spring 1.1 for interoperability */ 052 private static final long serialVersionUID = 6876024250231820554L; 053 054 055 private String methodName; 056 057 private Class<?>[] parameterTypes; 058 059 private Object[] arguments; 060 061 private Map<String, Serializable> attributes; 062 063 064 /** 065 * Create a new RemoteInvocation for the given AOP method invocation. 066 * @param methodInvocation the AOP invocation to convert 067 */ 068 public RemoteInvocation(MethodInvocation methodInvocation) { 069 this.methodName = methodInvocation.getMethod().getName(); 070 this.parameterTypes = methodInvocation.getMethod().getParameterTypes(); 071 this.arguments = methodInvocation.getArguments(); 072 } 073 074 /** 075 * Create a new RemoteInvocation for the given parameters. 076 * @param methodName the name of the method to invoke 077 * @param parameterTypes the parameter types of the method 078 * @param arguments the arguments for the invocation 079 */ 080 public RemoteInvocation(String methodName, Class<?>[] parameterTypes, Object[] arguments) { 081 this.methodName = methodName; 082 this.parameterTypes = parameterTypes; 083 this.arguments = arguments; 084 } 085 086 /** 087 * Create a new RemoteInvocation for JavaBean-style deserialization 088 * (e.g. with Jackson). 089 */ 090 public RemoteInvocation() { 091 } 092 093 094 /** 095 * Set the name of the target method. 096 * <p>This setter is intended for JavaBean-style deserialization. 097 */ 098 public void setMethodName(String methodName) { 099 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}