001 package biz.hammurapi.remoting; 002 003 import java.io.Serializable; 004 import java.lang.reflect.InvocationTargetException; 005 006 import org.apache.xmlbeans.XmlObject; 007 import org.w3c.dom.Element; 008 import org.w3c.dom.Node; 009 010 import biz.hammurapi.invocation.Invocation.Arg; 011 import biz.hammurapi.invocation.Invocation.State; 012 import biz.hammurapi.xml.dom.AbstractDomObject; 013 import biz.hammurapi.xml.dom.CompositeDomSerializer; 014 import biz.hammurapi.xml.dom.DOMUtils; 015 import biz.hammurapi.xml.dom.DomSerializable; 016 import biz.hammurapi.xmlbeans.XmlObjectSerializable; 017 018 /** 019 * Method invocation. 020 * @author Pavel 021 */ 022 public class Invocation implements DomSerializable, Serializable, XmlObjectSerializable { 023 024 /** 025 * Interface to inject client state into the server 026 * object before invocation and reset it after. 027 * Implementations shall store state in a thread local 028 * variable. 029 * @author Pavel 030 * 031 */ 032 public interface Stateful { 033 034 /** 035 * Sets client state before method invocation. 036 * @param state 037 */ 038 void setState(Object state); 039 040 /** 041 * Resets client state after invocation. 042 * @param state 043 */ 044 void resetState(); 045 } 046 047 private Object state; 048 private String methodName; 049 private String[] parameterTypes; 050 private Object[] args; 051 private String declaringClass; 052 private String id; 053 054 public Invocation(Object state, String declaringClass, String methodName, String[] parameterTypes, Object[] args, String id) { 055 this.state = state; 056 this.declaringClass = declaringClass; 057 this.methodName = methodName; 058 this.parameterTypes = parameterTypes; 059 this.args = args; 060 this.id = id; 061 } 062 063 public Invocation(Object state, java.lang.reflect.Method method, Object[] args, String id) { 064 this.state = state; 065 this.declaringClass = method.getDeclaringClass().getName(); 066 this.methodName = method.getName(); 067 Class[] mpt = method.getParameterTypes(); 068 this.parameterTypes = new String[mpt.length]; 069 for (int i=0; i<mpt.length; ++i) { 070 parameterTypes[i] = mpt[i].getName(); 071 } 072 this.args = args; 073 this.id = id; 074 } 075 076 public Object getState() { 077 return state; 078 } 079 080 public String getId() { 081 return id; 082 } 083 084 public String getMethodName() { 085 return methodName; 086 } 087 088 public String getDeclaringClass() { 089 return declaringClass; 090 } 091 092 public String[] getParameterTypes() { 093 return parameterTypes; 094 } 095 096 public Object[] getArguments() { 097 return args; 098 } 099 100 public void toDom(Element holder) { 101 holder.setAttribute("method-name", methodName); 102 if (declaringClass!=null) { 103 holder.setAttribute("declaring-class", declaringClass); 104 } 105 holder.setAttribute("type", getClass().getName()); 106 107 if (id!=null) { 108 holder.setAttribute("id", id); 109 } 110 111 if (state!=null) { 112 DOMUtils.toDom(state, "state", holder); 113 } 114 115 if (parameterTypes!=null) { 116 for (int i=0; i<parameterTypes.length; ++i) { 117 AbstractDomObject.addTextElement(holder, "parameter-type", parameterTypes[i]); 118 } 119 } 120 121 if (args!=null) { 122 for (int i=0; i<args.length; ++i) { 123 if (args[i]==null) { 124 AbstractDomObject.addElement(holder, "argument").setAttribute("is-null", "true"); 125 } else { 126 DOMUtils.toDom(args[i], "argument", holder); 127 } 128 } 129 } 130 131 } 132 133 public XmlObject toXmlObject() { 134 biz.hammurapi.invocation.InvocationDocument ret = biz.hammurapi.invocation.InvocationDocument.Factory.newInstance(); 135 biz.hammurapi.invocation.Invocation invocation = ret.addNewInvocation(); 136 if (declaringClass!=null) { 137 invocation.setDeclaringClass(declaringClass); 138 } 139 140 invocation.setMethodName(methodName); 141 142 if (id!=null) { 143 invocation.setId(id); 144 } 145 146 if (parameterTypes!=null) { 147 for (int i=0; i<parameterTypes.length; ++i) { 148 invocation.addParameterType(parameterTypes[i]); 149 } 150 } 151 152 if (state!=null) { 153 State xmlState = invocation.addNewState(); 154 if (state instanceof XmlObject) { 155 xmlState.set((XmlObject) state); 156 } else { 157 Node domNode = xmlState.getDomNode(); 158 CompositeDomSerializer.getThreadInstance().toDomSerializable(state).toDom((Element) domNode); 159 } 160 } 161 162 if (args!=null) { 163 for (int i=0; i<args.length; ++i) { 164 Arg arg = invocation.addNewArg(); 165 if (args[i] instanceof XmlObject) { 166 arg.set((XmlObject) args[i]); 167 } else { 168 Node domNode = arg.getDomNode(); 169 CompositeDomSerializer.getThreadInstance().toDomSerializable(args[i]).toDom((Element) domNode); 170 } 171 } 172 } 173 174 return ret; 175 } 176 177 /** 178 * Finds method to invoke. 179 * @param invocation 180 * @param classLoader Classloader, can be null. 181 * @return 182 * @throws ClassNotFoundException 183 */ 184 public static java.lang.reflect.Method findMethod(biz.hammurapi.invocation.Invocation invocation, ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException { 185 Class declaringClass = classLoader==null ? Class.forName(invocation.getDeclaringClass()) : classLoader.loadClass(invocation.getDeclaringClass()); 186 String[] pta = invocation.getParameterTypeArray(); 187 Class[] parameterTypes = new Class[pta.length]; 188 for (int i=0; i<pta.length; ++i) { 189 if ("int".equals(pta[i])) { 190 parameterTypes[i] = int.class; 191 } else if ("short".equals(pta[i])) { 192 parameterTypes[i] = short.class; 193 } else if ("long".equals(pta[i])) { 194 parameterTypes[i] = long.class; 195 } else if ("boolean".equals(pta[i])) { 196 parameterTypes[i] = boolean.class; 197 } else if ("byte".equals(pta[i])) { 198 parameterTypes[i] = byte.class; 199 } else if ("double".equals(pta[i])) { 200 parameterTypes[i] = double.class; 201 } else if ("float".equals(pta[i])) { 202 parameterTypes[i] = float.class; 203 } else if ("char".equals(pta[i])) { 204 parameterTypes[i] = char.class; 205 } else { 206 parameterTypes[i] = classLoader==null ? Class.forName(pta[i]) : classLoader.loadClass(pta[i]); 207 } 208 } 209 return declaringClass.getMethod(invocation.getMethodName(), parameterTypes); 210 } 211 212 /** 213 * Finds method to invoke. 214 * @param invocation 215 * @param classLoader Classloader, can be null. 216 * @return 217 * @throws ClassNotFoundException 218 */ 219 public java.lang.reflect.Method findMethod(ClassLoader classLoader) throws ClassNotFoundException, NoSuchMethodException { 220 Class declaringClass = classLoader==null ? Class.forName(getDeclaringClass()) : classLoader.loadClass(getDeclaringClass()); 221 Class[] parameterTypes = new Class[this.parameterTypes.length]; 222 for (int i=0; i<this.parameterTypes.length; ++i) { 223 if ("int".equals(this.parameterTypes[i])) { 224 parameterTypes[i] = int.class; 225 } else if ("short".equals(this.parameterTypes[i])) { 226 parameterTypes[i] = short.class; 227 } else if ("long".equals(this.parameterTypes[i])) { 228 parameterTypes[i] = long.class; 229 } else if ("boolean".equals(this.parameterTypes[i])) { 230 parameterTypes[i] = boolean.class; 231 } else if ("byte".equals(this.parameterTypes[i])) { 232 parameterTypes[i] = byte.class; 233 } else if ("double".equals(this.parameterTypes[i])) { 234 parameterTypes[i] = double.class; 235 } else if ("float".equals(this.parameterTypes[i])) { 236 parameterTypes[i] = float.class; 237 } else if ("char".equals(this.parameterTypes[i])) { 238 parameterTypes[i] = char.class; 239 } else { 240 parameterTypes[i] = classLoader==null ? Class.forName(this.parameterTypes[i]) : classLoader.loadClass(this.parameterTypes[i]); 241 } 242 } 243 return declaringClass.getMethod(getMethodName(), parameterTypes); 244 } 245 246 /** 247 * Method for simple invocation. 248 * @param instance 249 * @return 250 * @throws IllegalAccessException 251 * @throws InvocationTargetException 252 * @throws ClassNotFoundException 253 * @throws NoSuchMethodException 254 */ 255 public Object invoke(Object instance) throws IllegalAccessException, InvocationTargetException, ClassNotFoundException, NoSuchMethodException { 256 if (instance instanceof Stateful) { 257 ((Stateful) instance).setState(state); 258 } 259 try { 260 return findMethod(instance==null ? getClass().getClassLoader() : instance.getClass().getClassLoader()).invoke(instance, args); 261 } finally { 262 if (instance instanceof Stateful) { 263 ((Stateful) instance).resetState(); 264 } 265 } 266 } 267 268 }