1 45 package org.exolab.jms.plugins.proxygen; 46 47 import java.io.IOException ; 48 import java.io.OutputStream ; 49 import java.io.OutputStreamWriter ; 50 import java.lang.reflect.Method ; 51 import java.rmi.RemoteException ; 52 import java.util.Arrays ; 53 import java.util.Comparator ; 54 import java.util.HashMap ; 55 import java.util.Iterator ; 56 57 58 64 public class ProxyGenerator { 65 66 69 private final Class _clazz; 70 71 74 private final String _package; 75 76 79 private final String _className; 80 81 87 private HashMap _adapters = new HashMap (); 88 89 92 private Class [] _interfaces; 93 94 97 private Method [] _methods; 98 99 102 private static final Class [][] MAPPINGS = new Class [][]{ 103 {boolean.class, Boolean .class}, 104 {byte.class, Byte .class}, 105 {short.class, Short .class}, 106 {char.class, Character .class}, 107 {int.class, Integer .class}, 108 {long.class, Long .class}, 109 {float.class, Float .class}, 110 {double.class, Double .class}}; 111 112 115 private static final String DELEGATE = "org.exolab.jms.net.proxy.Delegate"; 116 117 120 private static final String PROXY = "org.exolab.jms.net.proxy.Proxy"; 121 122 125 private static final String PROXY_SUFFIX = "__Proxy"; 126 127 130 private static final String REMOTE_INVOCATION_EXCEPTION = 131 "org.exolab.jms.net.proxy.RemoteInvocationException"; 132 133 136 private static final String THROWABLE_ADAPTER = 137 "org.exolab.jms.net.proxy.ThrowableAdapter"; 138 139 140 149 public ProxyGenerator(Class clazz, Class [] adapters) 150 throws Exception { 151 if (clazz == null) { 152 throw new IllegalArgumentException ("Argument 'clazz' is null"); 153 } 154 if (clazz.isArray()) { 155 throw new IllegalArgumentException ( 156 "Can't generate proxies for array types"); 157 } 158 if (clazz.isPrimitive()) { 159 throw new IllegalArgumentException ( 160 "Can't generate proxies for primitive types"); 161 } 162 _clazz = clazz; 163 _package = ClassHelper.getPackage(_clazz); 164 165 String name; 166 if (_package != null) { 167 name = _clazz.getName().substring(_package.length() + 1); 168 } else { 169 name = _clazz.getName(); 170 } 171 _className = name + PROXY_SUFFIX; 172 173 _interfaces = _clazz.getInterfaces(); 174 if (_interfaces.length == 0) { 175 if (MethodHelper.getAllInterfaces(clazz).length == 0) { 176 throw new IllegalArgumentException ( 177 "Cannot generate proxy for class " + _clazz.getName() 178 + ": class doesn't implement any interfaces"); 179 } 180 } 181 182 if (adapters != null && adapters.length != 0) { 183 _adapters = getAdapters(adapters); 184 } 185 186 _methods = MethodHelper.getInterfaceMethods(_clazz); 187 Arrays.sort(_methods, new MethodComparator()); 188 } 189 190 196 public void generate(OutputStream stream) throws IOException { 197 SourceWriter writer = new SourceWriter(new OutputStreamWriter (stream)); 198 199 if (_package != null) { 200 writer.writeln("package " + _package + ";"); 201 } 202 203 writer.writelnInc("public class " + _className); 204 writer.writeln("extends " + getSuperclassProxy(_clazz)); 205 if (_interfaces.length != 0) { 206 writer.write("implements "); 207 for (int i = 0; i < _interfaces.length; ++i) { 208 if (i > 0) { 209 writer.write(", "); 210 } 211 writer.write(_interfaces[i].getName()); 212 } 213 } 214 writer.writeln(" {"); 215 generateStaticDeclarations(writer); 216 generateConstructor(writer); 217 generateMethods(writer); 218 generateStaticInitialiser(writer); 219 writer.writelnDec(); 220 writer.writeln("}"); 221 writer.flush(); 222 } 223 224 230 protected void generateStaticDeclarations(SourceWriter writer) 231 throws IOException { 232 233 if (_methods.length > 0) { 234 writer.writeln(); 235 for (int i = 0; i < _methods.length; ++i) { 236 Method method = _methods[i]; 237 String name = getMethodVarName(method); 238 writer.writeln("private static final java.lang.reflect.Method " 239 + name 240 + ";"); 241 } 242 writer.writeln(); 243 244 Iterator iterator = _adapters.values().iterator(); 245 while (iterator.hasNext()) { 246 Class adapter = (Class ) iterator.next(); 247 String name = getAdapterInstanceName(adapter); 248 writer.writeln("private static final " 249 + THROWABLE_ADAPTER + " " + name 250 + " = new " + adapter.getName()+ "();"); 251 } 252 writer.writeln(); 253 } 254 } 255 256 262 protected void generateConstructor(SourceWriter writer) 263 throws IOException { 264 265 writer.writelnInc("public " + _className + "(" + DELEGATE 266 + " delegate) {"); 267 writer.writelnDec("super(delegate);"); 268 writer.writeln("}"); 269 } 270 271 277 protected void generateMethods(SourceWriter writer) throws IOException { 278 for (int i = 0; i < _methods.length; ++i) { 279 writer.writeln(); 280 Method method = _methods[i]; 281 generateMethod(method, writer); 282 } 283 } 284 285 292 protected void generateMethod(Method method, SourceWriter writer) 293 throws IOException { 294 295 Class returnType = method.getReturnType(); 296 Class [] argTypes = method.getParameterTypes(); 297 Class [] exceptionTypes = method.getExceptionTypes(); 298 boolean declaresThrowable = false; 299 boolean declaresException = false; 300 boolean declaresRuntimeException = false; 301 boolean declaresRemoteException = false; 302 boolean declaresRemoteInvocationException = false; 303 boolean adaptThrowable = false; 304 Class adaptType = null; 305 306 for (int i = 0; i < exceptionTypes.length; ++i) { 307 Class exceptionType = exceptionTypes[i]; 308 if (exceptionType.equals(Throwable .class)) { 309 declaresThrowable = true; 310 } else if (exceptionType.equals(Exception .class)) { 311 declaresException = true; 312 } else if (exceptionType.equals(RuntimeException .class)) { 313 declaresRuntimeException = true; 314 } else if (exceptionType.equals(RemoteException .class)) { 315 declaresRemoteException = true; 316 } else if (exceptionType.getName().equals( 317 REMOTE_INVOCATION_EXCEPTION)) { 318 declaresRemoteInvocationException = true; 319 } else if (_adapters.get(exceptionType) != null) { 320 adaptType = exceptionType; 321 } 322 } 323 324 if (!declaresThrowable && adaptType != null) { 325 adaptThrowable = true; 327 } 328 329 Class [] catchTypes = method.getExceptionTypes(); 331 Arrays.sort(catchTypes, new ClassComparator()); 332 333 String returnClass = ClassHelper.getQualifiedName(returnType); 335 writer.write("public " + returnClass + " " + method.getName() + "("); 336 for (int i = 0; i < argTypes.length; ++i) { 337 if (i > 0) { 338 writer.write(", "); 339 } 340 String argClass = ClassHelper.getQualifiedName(argTypes[i]); 341 writer.write(argClass + " arg" + i); 342 } 343 writer.write(")"); 344 345 if (exceptionTypes.length > 0) { 347 writer.writelnInc(); 348 writer.write("throws "); 349 for (int i = 0; i < exceptionTypes.length; ++i) { 350 if (i > 0) { 351 writer.write(", "); 352 } 353 writer.write(exceptionTypes[i].getName()); 354 } 355 writer.writeln(" { "); 356 } else { 357 writer.writelnInc(" {"); 358 } 359 360 String argValue = null; 362 if (argTypes.length > 0) { 363 argValue = "args"; 364 writer.write("Object[] " + argValue + " = new Object[] {"); 365 for (int i = 0; i < argTypes.length; ++i) { 366 if (i > 0) { 367 writer.write(", "); 368 } 369 Class arg = argTypes[i]; 370 String name = "arg" + i; 371 writer.write(wrapArgument(arg, name)); 372 } 373 writer.writeln("};"); 374 } else { 375 argValue = "null"; 376 } 377 378 boolean hasReturn = (returnType != void.class); 380 if (hasReturn) { 381 writer.writeln("Object result;"); 382 } 383 384 writer.writelnInc("try {"); 385 386 if (hasReturn) { 387 writer.write("result = "); 388 } 389 long methodId = MethodHelper.getMethodID(method); 390 writer.writelnDec("invoke(" + getMethodVarName(method) + ", " 391 + argValue + ", 0x" + Long.toHexString(methodId) 392 + "L);"); 393 394 boolean caughtRIE = false; 395 boolean rethrowRIE = false; 396 if (!declaresThrowable && !declaresException 397 && !declaresRuntimeException 398 && !declaresRemoteInvocationException) { 399 rethrowRIE = true; 400 } 401 402 for (int i = 0; i < catchTypes.length; ++i) { 403 Class catchType = catchTypes[i]; 404 if (rethrowRIE && !caughtRIE) { 405 if (catchType.equals(Throwable .class) 406 || catchType.equals(Exception .class) 407 || catchType.equals(RuntimeException .class)) { 408 generateRethrow(writer, REMOTE_INVOCATION_EXCEPTION); 409 caughtRIE = true; 410 } 411 } 412 generateRethrow(writer, catchType.getName()); 413 } 414 if (rethrowRIE && !caughtRIE) { 415 generateRethrow(writer, REMOTE_INVOCATION_EXCEPTION); 416 } 417 if (!declaresThrowable) { 418 writer.writelnInc("} catch (java.lang.Throwable exception) {"); 419 if (adaptThrowable) { 420 Class adapter = (Class ) _adapters.get(adaptType); 421 String instance = getAdapterInstanceName(adapter); 422 writer.writeln(adaptType.getName() + " error = (" 423 + adaptType.getName() + ") " + instance 424 + ".adapt(exception);"); 425 writer.writelnDec("throw error;"); 426 } else if (declaresRemoteException) { 427 writer.writelnDec("throw new " 428 + RemoteException .class.getName() 429 + "(exception.getMessage(), exception);"); 430 } else { 431 writer.writelnDec("throw new " + REMOTE_INVOCATION_EXCEPTION 432 + "(exception);"); 433 } 434 } 435 writer.writeln("}"); 436 437 if (hasReturn) { 438 writer.writelnDec("return " + unwrapReturn(method.getReturnType(), 439 "result")); 440 } else { 441 writer.writelnDec(); 442 } 443 writer.writeln("}"); 444 } 445 446 452 protected void generateStaticInitialiser(SourceWriter writer) 453 throws IOException { 454 455 if (_methods.length > 0) { 456 writer.writeln(); 457 writer.writelnInc("static {"); 458 writer.writelnInc("try {"); 459 for (int i = 0; i < _methods.length; ++i) { 460 Method method = _methods[i]; 461 String name = getMethodVarName(method); 462 Class clazz = method.getDeclaringClass(); 463 writer.write(name + " = " + clazz.getName() 464 + ".class.getMethod(\"" + method.getName() 465 + "\", " + "new Class[] {"); 466 Class [] args = method.getParameterTypes(); 467 for (int j = 0; j < args.length; ++j) { 468 if (j > 0) { 469 writer.write(", "); 470 } 471 writer.write(ClassHelper.getQualifiedName(args[j]) + ".class"); 472 } 473 writer.writeln("});"); 474 } 475 writer.decIndent(); 476 writer.writelnInc("} catch (NoSuchMethodException exception) {"); 477 writer.writelnDec( 478 "throw new NoSuchMethodError(exception.getMessage());"); 479 writer.writelnDec("}"); 480 writer.writeln("}"); 481 } 482 } 483 484 491 protected void generateRethrow(SourceWriter writer, String name) 492 throws IOException { 493 writer.writelnInc("} catch (" + name + " exception) {"); 494 writer.writelnDec("throw exception;"); 495 } 496 497 505 protected String wrapArgument(Class clazz, String name) { 506 String result; 507 if (clazz.isPrimitive()) { 508 Class wrapper = null; 509 for (int i = 0; i < MAPPINGS.length; ++i) { 510 if (MAPPINGS[i][0] == clazz) { 511 wrapper = MAPPINGS[i][1]; 512 } 513 } 514 result = "new " + ClassHelper.getQualifiedName(wrapper) 515 + "(" + name + ")"; 516 } else { 517 result = name; 518 } 519 return result; 520 } 521 522 532 protected String unwrapReturn(Class clazz, String name) { 533 String result = null; 534 if (clazz.isPrimitive()) { 535 Class wrapper = null; 536 for (int i = 0; i < MAPPINGS.length; ++i) { 537 if (MAPPINGS[i][0] == clazz) { 538 wrapper = MAPPINGS[i][1]; 539 break; 540 } 541 } 542 result = "((" + wrapper.getName() + ") " + name + ")." 543 + clazz.getName() + "Value();"; 544 } else { 545 result = "(" + ClassHelper.getQualifiedName(clazz) + ") " + name + 546 ";"; 547 } 548 return result; 549 } 550 551 557 protected String getMethodVarName(Method method) { 558 return method.getName().toUpperCase() + "_" 559 + Long.toHexString(MethodHelper.getMethodID(method)); 560 } 561 562 568 protected String getAdapterInstanceName(Class adapter) { 569 String name; 571 String qualifiedName = adapter.getName(); 572 int lastDot = qualifiedName.lastIndexOf("."); 573 if (lastDot != -1) { 574 name = qualifiedName.substring(lastDot + 1); 575 } else { 576 name = qualifiedName; 577 } 578 StringBuffer result = new StringBuffer (name.toUpperCase()); 579 result.append("_"); 580 result.append(Long.toHexString(qualifiedName.hashCode())); 581 return result.toString(); 582 } 583 584 587 private HashMap getAdapters(Class [] adapterClasses) 588 throws Exception { 589 HashMap result = new HashMap (); 590 591 for (int i = 0; i < adapterClasses.length; ++i) { 592 Class adapterClass = adapterClasses[i]; 593 Object adapter = adapterClass.newInstance(); 594 Method method = adapterClass.getMethod("getTarget", new Class [0]); 595 Class exceptionType = (Class ) method.invoke(adapter, new Object [0]); 596 if (!Throwable .class.isAssignableFrom(exceptionType)) { 597 throw new Exception ( 598 "Invalid exception class " + exceptionType.getName() 599 + ": class doesn't extend " + Throwable .class); 600 } 601 result.put(exceptionType, adapterClass); 602 } 603 return result; 604 } 605 606 612 private static String getSuperclassProxy(Class clazz) { 613 String name = PROXY; 614 Class superClass = clazz.getSuperclass(); 615 if (superClass != null) { 616 if (superClass.getInterfaces().length != 0) { 617 name = superClass.getName() + PROXY_SUFFIX; 618 } else { 619 name = getSuperclassProxy(superClass); 620 } 621 } 622 return name; 623 } 624 625 628 private static class ClassComparator implements Comparator { 629 630 638 public int compare(Object o1, Object o2) { 639 int result; 640 Class c1 = (Class ) o1; 641 Class c2 = (Class ) o2; 642 if (c1 == c2) { 643 result = 0; 644 } else if (c1.isAssignableFrom(c2)) { 645 result = 1; 646 } else { 647 result = -1; 648 } 649 return result; 650 } 651 652 } 653 654 657 private static class MethodComparator implements Comparator { 658 659 667 public int compare(Object o1, Object o2) { 668 Method m1 = (Method ) o1; 669 Method m2 = (Method ) o2; 670 return m1.getName().compareTo(m2.getName()); 671 } 672 673 } 674 675 } 676 | Popular Tags |