1 package org.apache.ws.jaxme.js.apps; 2 3 import java.lang.reflect.Method ; 4 import java.lang.reflect.UndeclaredThrowableException ; 5 import java.util.ArrayList ; 6 import java.util.HashMap ; 7 import java.util.Iterator ; 8 import java.util.List ; 9 import java.util.Map ; 10 import java.util.Vector ; 11 12 import org.apache.ws.jaxme.js.DirectAccessible; 13 import org.apache.ws.jaxme.js.JavaComment; 14 import org.apache.ws.jaxme.js.JavaConstructor; 15 import org.apache.ws.jaxme.js.JavaField; 16 import org.apache.ws.jaxme.js.JavaInnerClass; 17 import org.apache.ws.jaxme.js.JavaMethod; 18 import org.apache.ws.jaxme.js.JavaQName; 19 import org.apache.ws.jaxme.js.JavaQNameImpl; 20 import org.apache.ws.jaxme.js.JavaSource; 21 import org.apache.ws.jaxme.js.JavaSourceFactory; 22 import org.apache.ws.jaxme.js.LocalJavaField; 23 import org.apache.ws.jaxme.js.Parameter; 24 import org.apache.ws.jaxme.js.pattern.MethodKey; 25 26 27 39 public class XmlRpcClientGenerator { 40 private final JavaSourceFactory factory; 41 private final String targetPackage; 42 private final Map methods = new HashMap (); 43 private boolean dispatcherImplementsXmlRpcHandler = true; 44 45 48 public boolean isDispatcherImplementsXmlRpcHandler() { 49 return dispatcherImplementsXmlRpcHandler; 50 } 51 52 55 public void setDispatcherImplementsXmlRpcHandler( 56 boolean pDispatcherImplementsXmlRpcHandler) { 57 dispatcherImplementsXmlRpcHandler = pDispatcherImplementsXmlRpcHandler; 58 } 59 60 62 public XmlRpcClientGenerator(JavaSourceFactory pFactory, String pTargetPackage) { 63 factory = pFactory; 64 targetPackage = pTargetPackage; 65 } 66 67 69 public JavaSourceFactory getFactory() { return factory; } 70 71 73 public String getTargetPackage() { return targetPackage; } 74 75 79 protected String addMethod(JavaMethod pMethod) { 80 String className = pMethod.getJavaSource().getQName().toString(); 81 String methodName = pMethod.getName(); 82 for (int i = 0; ; i++) { 83 String name = className + "-" + methodName; 84 if (i > 0) { 85 name += i; 86 } 87 if (!methods.containsKey(name)) { 88 methods.put(name, pMethod); 89 return name; 90 } 91 } 92 } 93 94 97 protected Object getResultValue(JavaMethod pMethod, JavaQName pType, Object pValue) { 98 if (JavaQNameImpl.BOOLEAN.equals(pType)) { 99 return new Object []{"((", Boolean .class, ") ", pValue, ").booleanValue()"}; 100 } else if (JavaQNameImpl.BYTE.equals(pType)) { 101 return new Object []{"((", Byte .class, ") ", pValue, ").byteValue()"}; 102 } else if (JavaQNameImpl.SHORT.equals(pType)) { 103 return new Object []{"((", Short .class, ") ", pValue, ").shortValue()"}; 104 } else if (JavaQNameImpl.INT.equals(pType)) { 105 return new Object []{"((", Integer .class, ") ", pValue, ").intValue()"}; 106 } else if (JavaQNameImpl.LONG.equals(pType)) { 107 return new Object []{"((", Long .class, ") ", pValue, ").longValue()"}; 108 } else if (JavaQNameImpl.FLOAT.equals(pType)) { 109 return new Object []{"((", Float .class, ") ", pValue, ").floatValue()"}; 110 } else if (JavaQNameImpl.DOUBLE.equals(pType)) { 111 return new Object []{"((", Double .class, ") ", pValue, ").doubleValue()"}; 112 } else if (pType.isArray()) { 113 LocalJavaField resultV = pMethod.newJavaField(Vector .class); 114 resultV.addLine("(", Vector .class, ") ", pValue, ";"); 115 LocalJavaField resultA = pMethod.newJavaField(pType); 116 pMethod.addIf(resultV , " == null"); 117 pMethod.addLine(resultA, " = null;"); 118 pMethod.addElse(); 119 pMethod.addLine(resultA, " = new ", pType.getInstanceClass(), "[", resultV, ".size()];"); 120 DirectAccessible i = pMethod.addForArray(resultA); 121 Object element = new Object []{resultV, ".elementAt(", i, ")"}; 122 pMethod.addLine(resultA, "[", i, "] = ", getResultValue(pMethod, pType.getInstanceClass(), element), ";"); 123 pMethod.addEndFor(); 124 pMethod.addEndIf(); 125 return resultA; 126 } else if (JavaQNameImpl.getInstance(Object .class).equals(pType)) { 127 return pValue; 128 } else { 129 return new Object []{"(", pType, ") ", pValue}; 130 } 131 } 132 133 136 protected Object getInputValue(JavaMethod pMethod, JavaQName pType, Object pValue) { 137 if (pType.equals(JavaQNameImpl.BOOLEAN)) { 138 return new Object []{pValue, " ? ", Boolean .class, ".TRUE : ", Boolean .class, ".FALSE"}; 139 } else if (pType.equals(JavaQNameImpl.BYTE)) { 140 return new Object []{"new ", Byte .class, "(", pValue, ")"}; 141 } else if (pType.equals(JavaQNameImpl.SHORT)) { 142 return new Object []{"new ", Short .class, "(", pValue, ")"}; 143 } else if (pType.equals(JavaQNameImpl.INT)) { 144 return new Object []{"new ", Integer .class, "(", pValue, ")"}; 145 } else if (pType.equals(JavaQNameImpl.LONG)) { 146 return new Object []{"new ", Long .class, "(", pValue, ")"}; 147 } else if (pType.equals(JavaQNameImpl.FLOAT)) { 148 return new Object []{"new ", Float .class, "(", pValue, ")"}; 149 } else if (pType.equals(JavaQNameImpl.DOUBLE)) { 150 return new Object []{"new ", Double .class, "(", pValue, ")"}; 151 } else if (pType.isArray()) { 152 if (!(pValue instanceof DirectAccessible)) { 153 LocalJavaField val = pMethod.newJavaField(pType); 154 val.addLine(pValue); 155 pValue = val; 156 } 157 LocalJavaField v = pMethod.newJavaField(Vector .class); 158 pMethod.addIf(pValue, " == null"); 159 pMethod.addLine(v, " = null;"); 160 pMethod.addElse(); 161 pMethod.addLine(v, " = new ", Vector .class, "();"); 162 DirectAccessible i = pMethod.addForArray(pValue); 163 Object element = new Object []{pValue, "[", i, "]"}; 164 pMethod.addLine(v, ".add(", getInputValue(pMethod, pType.getInstanceClass(), element), ");"); 165 pMethod.addEndFor(); 166 pMethod.addEndIf(); 167 return v; 168 } else { 169 return pValue; 170 } 171 } 172 173 178 protected JavaMethod getMethod(JavaSource pJs, JavaField pCaller, 179 String pName, JavaMethod pMethod) 180 throws SecurityException , NoSuchMethodException { 181 Method m = XmlRpcCaller.class.getMethod("xmlRpcCall", new Class []{String .class, Vector .class}); 182 Class [] exceptions = m.getExceptionTypes(); 183 List exceptionList = new ArrayList (); 184 if (exceptions != null) { 185 for (int i = 0; i < exceptions.length; i++) { 186 JavaQName qName = JavaQNameImpl.getInstance(exceptions[i]); 187 if (!pMethod.isThrowing(qName)) { 188 exceptionList.add(qName); 189 } 190 } 191 } 192 193 JavaMethod jm = pJs.newJavaMethod(pMethod); 194 LocalJavaField v = jm.newJavaField(Vector .class); 195 v.addLine("new ", Vector .class, "()"); 196 Parameter[] params = jm.getParams(); 197 for (int i = 0; i < params.length; i++) { 198 Parameter p = params[i]; 199 jm.addLine(v, ".add(", getInputValue(jm, p.getType(), p), ");"); 200 } 201 if (!exceptionList.isEmpty()) { 202 jm.addTry(); 203 } 204 Object result = new Object []{pCaller, ".xmlRpcCall(", 205 JavaSource.getQuoted(pName), ", ", v, ")"}; 206 if (JavaQNameImpl.VOID.equals(jm.getType())) { 207 jm.addLine(result, ";"); 208 } else { 209 jm.addLine("return ", getResultValue(jm, jm.getType(), result), ";"); 210 } 211 if (!exceptionList.isEmpty()) { 212 for (int i = 0; i < exceptionList.size(); i++) { 213 JavaQName exClass = (JavaQName) exceptionList.get(i); 214 DirectAccessible e = jm.addCatch(exClass); 215 jm.addThrowNew(UndeclaredThrowableException .class, e); 216 } 217 jm.addEndTry(); 218 } 219 return jm; 220 } 221 222 protected JavaField getXmlRpcCaller(JavaSource pJs) { 223 JavaField jf = pJs.newJavaField("caller", XmlRpcCaller.class, JavaSource.PRIVATE); 224 jf.setFinal(true); 225 return jf; 226 } 227 228 protected JavaConstructor getConstructor(JavaSource pJs, JavaField jf) { 229 JavaConstructor jcon = pJs.newJavaConstructor(JavaSource.PUBLIC); 230 Parameter param = jcon.addParam(XmlRpcCaller.class, "pCaller"); 231 jcon.addLine(jf, " = ", param, ";"); 232 return jcon; 233 } 234 235 239 protected boolean isMethodGenerated(JavaMethod pMethod) { 240 return JavaSource.PUBLIC.equals(pMethod.getProtection()) 241 && !pMethod.isStatic(); 242 } 243 244 247 public JavaSource addClass(JavaSource pSource, JavaSourceResolver pResolver) 248 throws SecurityException , NoSuchMethodException { 249 JavaSource js = getFactory().newJavaSource(JavaQNameImpl.getInstance(getTargetPackage(), pSource.getQName().getClassName()), JavaSource.PUBLIC); 250 JavaField jf = getXmlRpcCaller(js); 251 getConstructor(js, jf); 252 Map keys = new HashMap (); 253 addMethods(js, pSource, keys, jf, pResolver); 254 return js; 255 } 256 257 protected void addMethods(JavaSource pResult, JavaSource pSource, Map pKeys, 258 JavaField pField, JavaSourceResolver pResolver) 259 throws SecurityException , NoSuchMethodException { 260 JavaMethod[] methods = pSource.getMethods(); 261 for (int i = 0; i < methods.length; i++) { 262 JavaMethod m = methods[i]; 263 if (isMethodGenerated(m)) { 264 MethodKey key = new MethodKey(m); 265 if (pKeys.containsKey(key)) { 266 continue; 267 } 268 String name = addMethod(m); 269 pKeys.put(key, getMethod(pResult, pField, name, m)); 270 } 271 } 272 if (pResolver != null) { 273 JavaQName[] qNames = pSource.getExtends(); 274 for (int i = 0; i < qNames.length; i++) { 275 JavaSource js = pResolver.getJavaSource(qNames[i]); 276 if (js != null) { 277 addMethods(pResult, js, pKeys, pField, pResolver); 278 } 279 } 280 } 281 } 282 283 285 public JavaSource getInvokerClass(JavaSource pSource) { 286 JavaInnerClass invoker = pSource.newJavaInnerClass("Invoker", JavaSource.PUBLIC); 287 JavaComment comment = invoker.newComment(); 288 comment.addLine("The dispatcher is implemented with a {@link java.util.Map}."); 289 comment.addLine("The map keys are the method names, the values"); 290 comment.addLine("are instances of <code>Invoker</code>."); 291 invoker.setType(JavaSource.INTERFACE); 292 JavaMethod jm = invoker.newJavaMethod("invoke", Object .class, JavaSource.PUBLIC); 293 comment = jm.newComment(); 294 comment.addLine("This method creates a new instance of the class being"); 295 comment.addLine("called, converts the parameter objects (if required)"); 296 comment.addLine("and invokes the requested method. If required, the"); 297 comment.addLine("result is converted also and returned."); 298 jm.addParam(Vector .class, "pParams"); 299 jm.addThrows(Throwable .class); 300 return invoker; 301 } 302 303 305 protected JavaField getInvokerMap(JavaSource pSource) { 306 JavaField result = pSource.newJavaField("map", Map .class, JavaSource.PRIVATE); 307 result.addLine("new ", HashMap .class, "()"); 308 return result; 309 } 310 311 313 protected JavaSource getInvoker(JavaSource pSource, JavaMethod pMethod, JavaQName pInvoker, int pNum) { 314 Parameter[] params = pMethod.getParams(); 315 316 JavaInnerClass js = pSource.newJavaInnerClass("Invoker" + pNum, JavaSource.PUBLIC); 317 StringBuffer sb = new StringBuffer (); 318 for (int i = 0; i < params.length; i++) { 319 if (i > 0) { 320 sb.append(", "); 321 } 322 sb.append(params[i].getType()); 323 } 324 JavaComment comment = js.newComment(); 325 comment.addLine("Invoker for method " + pMethod.getName() + "(" + sb + ")"); 326 comment.addLine("in class " + pMethod.getJavaSource().getQName() + "."); 327 js.setStatic(true); 328 js.addImplements(pInvoker); 329 JavaMethod jm = js.newJavaMethod("invoke", Object .class, JavaSource.PUBLIC); 330 Parameter param = jm.addParam(Vector .class, "params"); 331 JavaQName[] classes = pMethod.getExceptions(); 332 for (int i = 0; i < classes.length; i++) { 333 jm.addThrows(classes[i]); 334 } 335 List args = new ArrayList (); 336 for (int i = 0; i < params.length; i++) { 337 if (i > 0) { 338 args.add(", "); 339 } 340 Parameter p = params[i]; 341 args.add(getResultValue(jm, p.getType(), new Object []{param, ".elementAt(" + i + ")"})); 342 } 343 Object o = new Object []{"new ", pMethod.getJavaSource().getQName(), "().", 344 pMethod.getName(), "(", args, ")"}; 345 if (JavaQNameImpl.VOID.equals(pMethod.getType())) { 346 jm.addLine(o, ";"); 347 jm.addLine("return null;"); 348 } else { 349 jm.addLine("return ", getInputValue(jm, pMethod.getType(), o), ";"); 350 } 351 return js; 352 } 353 354 356 public JavaConstructor getDispatcherConstructor(JavaSource pSource, 357 JavaField pMap, 358 JavaQName pInvoker) { 359 JavaConstructor con = pSource.newJavaConstructor(JavaSource.PUBLIC); 360 JavaComment comment = con.newComment(); 361 comment.addLine("Creates a new dispatcher."); 362 int num = 0; 363 for (Iterator iter = methods.entrySet().iterator(); iter.hasNext(); ) { 364 Map.Entry entry = (Map.Entry ) iter.next(); 365 String name = (String ) entry.getKey(); 366 JavaMethod method = (JavaMethod) entry.getValue(); 367 JavaSource innerClass = getInvoker(pSource, method, pInvoker, num++); 368 con.addLine(pMap, ".put(", JavaSource.getQuoted(name), ", new ", innerClass.getQName(), "());"); 369 } 370 return con; 371 } 372 373 375 protected JavaMethod getGetInvokerMethod(JavaSource pSource, JavaQName pInvoker, JavaField pMap) { 376 JavaMethod jm = pSource.newJavaMethod("getInvoker", pInvoker, JavaSource.PROTECTED); 377 Parameter param = jm.addParam(String .class, "pName"); 378 jm.addLine("return (", pInvoker, ") ", pMap, ".get(", param, ");"); 379 return jm; 380 } 381 382 384 protected JavaMethod getDispatcherInvokeMethod(JavaSource pSource, JavaQName pInvoker) { 385 JavaMethod jm = pSource.newJavaMethod("execute", Object .class, JavaSource.PUBLIC); 386 JavaComment comment = jm.newComment(); 387 comment.addLine("Called for invocation of method <code>pName</code> with"); 388 comment.addLine("the parameters given by <code>pParams</code>."); 389 Parameter name = jm.addParam(String .class, "pName"); 390 Parameter args = jm.addParam(Vector .class, "pParams"); 391 jm.addThrows(Exception .class); 392 LocalJavaField invoker = jm.newJavaField(pInvoker); 393 invoker.addLine("getInvoker(", name, ")"); 394 jm.addIf(invoker, " == null"); 395 jm.addThrowNew(IllegalStateException .class, 396 JavaSource.getQuoted("Unknown method name: "), 397 " + ", name); 398 jm.addEndIf(); 399 jm.addTry(); 400 jm.addLine("return ", invoker, ".invoke(", args, ");"); 401 DirectAccessible e = jm.addCatch(Exception .class); 402 jm.addLine("throw ", e, ";"); 403 DirectAccessible t = jm.addCatch(Throwable .class); 404 jm.addThrowNew(UndeclaredThrowableException .class, t); 405 jm.addEndTry(); 406 return jm; 407 } 408 409 413 public JavaSource getDispatcher(JavaQName pQName) { 414 JavaSource js = getFactory().newJavaSource(pQName, JavaSource.PUBLIC); 415 if (isDispatcherImplementsXmlRpcHandler()) { 416 js.addImport(JavaQNameImpl.getInstance("org.apache.xmlrpc.XmlRpcHandler", true)); 417 } 418 JavaComment comment = js.newComment(); 419 comment.addLine("The dispatcher is being used by the XmlRpcServer."); 420 comment.addLine("It delegates incoming XML-RPC calls to the classes"); 421 comment.addLine("and methods, for which client classes have been"); 422 comment.addLine("created by the " + 423 XmlRpcClientGenerator.class.getName() + "."); 424 JavaSource invoker = getInvokerClass(js); 425 JavaField map = getInvokerMap(js); 426 getDispatcherConstructor(js, map, invoker.getQName()); 427 getGetInvokerMethod(js, invoker.getQName(), map); 428 getDispatcherInvokeMethod(js, invoker.getQName()); 429 return js; 430 } 431 } 432 | Popular Tags |