00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 package org.objectweb.proactive.core.mop;
00032
00033 import java.io.Serializable;
00034 import java.lang.reflect.GenericDeclaration;
00035 import java.lang.reflect.TypeVariable;
00036 import java.util.HashMap;
00037 import java.util.Iterator;
00038 import java.util.List;
00039 import java.util.Map;
00040 import java.util.Vector;
00041
00042 import javassist.CannotCompileException;
00043 import javassist.ClassClassPath;
00044 import javassist.ClassPool;
00045 import javassist.CtClass;
00046 import javassist.CtConstructor;
00047 import javassist.CtField;
00048 import javassist.CtMethod;
00049 import javassist.CtNewMethod;
00050 import javassist.Modifier;
00051 import javassist.NotFoundException;
00052
00053
00060 public class JavassistByteCodeStubBuilder {
00061 private static CtMethod proxyGetter;
00062 private static CtMethod proxySetter;
00063
00073 public static byte[] create(String className, Class[] genericParameters) throws NoClassDefFoundError {
00074 CtClass generatedCtClass = null;
00075 if (genericParameters == null) {
00076 genericParameters = new Class[0];
00077 }
00078 CtMethod[] reifiedMethodsWithoutGenerics;
00079 try {
00080 ClassPool pool = ClassPool.getDefault();
00081 generatedCtClass = pool.makeClass(Utils.convertClassNameToStubClassName(
00082 className, genericParameters));
00083
00084 CtClass superCtClass = null;
00085 try {
00086 superCtClass = pool.get(className);
00087 } catch (NotFoundException e) {
00088
00089
00090
00091 pool.appendClassPath(new ClassClassPath(Class.forName(className)));
00092 superCtClass = pool.get(className);
00093 }
00094
00095 CtField outsideOfConstructorField = new CtField(pool.get(CtClass.booleanType.getName()), "outsideOfConstructor", generatedCtClass);
00096
00097 generatedCtClass.addField(outsideOfConstructorField, (superCtClass.isInterface()? " false" : "true"));
00098 if (superCtClass.isInterface()) {
00099 generatedCtClass.addInterface(superCtClass);
00100 generatedCtClass.setSuperclass(pool.get(Object.class.getName()));
00101 } else {
00102 generatedCtClass.setSuperclass(superCtClass);
00103 }
00104 generatedCtClass.addInterface(pool.get(Serializable.class.getName()));
00105 generatedCtClass.addInterface(pool.get(StubObject.class.getName()));
00106
00107 createStubObjectMethods(generatedCtClass);
00108
00109
00110 CtField methodsField = new CtField(pool.get(
00111 "java.lang.reflect.Method[]"), "overridenMethods",
00112 generatedCtClass);
00113
00114 methodsField.setModifiers(Modifier.STATIC);
00115 generatedCtClass.addField(methodsField);
00116
00117
00118 CtField genericTypesMappingField = new CtField(pool.get(
00119 "java.util.Map"), "genericTypesMapping",
00120 generatedCtClass);
00121
00122 genericTypesMappingField.setModifiers(Modifier.STATIC);
00123 generatedCtClass.addField(genericTypesMappingField);
00124
00125
00126 java.util.Map<String, CtMethod> temp = new HashMap<String, CtMethod>();
00127
00128
00129
00130
00131 CtClass currentCtClass = superCtClass;
00132
00133 CtClass[] params;
00134 Object exists;
00135
00136 List<String> classesIndexer = new Vector<String>();
00137
00138 classesIndexer.add(superCtClass.getName());
00139
00140
00141
00142 if (superCtClass.isInterface()) {
00143 CtMethod[] allPublicMethods = superCtClass.getMethods();
00144 for (int i = 0; i < allPublicMethods.length; i++) {
00145 String key = "";
00146 key = key + allPublicMethods[i].getName();
00147 params = allPublicMethods[i].getParameterTypes();
00148 for (int k = 0; k < params.length; k++) {
00149 key = key + params[k].getName();
00150 }
00151 temp.put(key, allPublicMethods[i]);
00152 }
00153 classesIndexer.add("java.lang.Object");
00154 } else
00155 {
00156 do {
00157 if (!classesIndexer.contains(currentCtClass.getName())) {
00158 classesIndexer.add(currentCtClass.getName());
00159 }
00160
00161
00162 CtMethod[] declaredCtMethods = currentCtClass.getDeclaredMethods();
00163
00164
00165 for (int i = 0; i < declaredCtMethods.length; i++) {
00166 CtMethod currentMethod = declaredCtMethods[i];
00167
00168
00169
00170 String key = "";
00171 key = key + currentMethod.getName();
00172 params = currentMethod.getParameterTypes();
00173 for (int k = 0; k < params.length; k++) {
00174 key = key + params[k].getName();
00175 }
00176
00177 exists = temp.get(key);
00178 if (exists == null) {
00179
00180
00181
00182 if ((key.equals("finalize")) &&
00183 (params.length == 0)) {
00184
00185 } else {
00186
00187
00188
00189 temp.put(key, currentMethod);
00190 }
00191 } else {
00192
00193
00194 }
00195 }
00196 currentCtClass = currentCtClass.getSuperclass();
00197 } while (currentCtClass != null);
00198 }
00199
00200
00201 List<CtClass> superInterfaces = new Vector<CtClass>();
00202 addSuperInterfaces(superCtClass, superInterfaces);
00203
00204 CtClass[] implementedInterfacesTable = (superInterfaces.toArray(new CtClass[superInterfaces.size()]));
00205 for (int i=0; i< implementedInterfacesTable.length; i++) {
00206
00207 }
00208 for (int itfsIndex = 0;
00209 itfsIndex < implementedInterfacesTable.length;
00210 itfsIndex++) {
00211 if (!classesIndexer.contains(
00212 implementedInterfacesTable[itfsIndex].getName())) {
00213 classesIndexer.add(implementedInterfacesTable[itfsIndex].getName());
00214 }
00215
00216
00217 CtMethod[] declaredMethods = implementedInterfacesTable[itfsIndex].getDeclaredMethods();
00218
00219
00220
00221 for (int i = 0; i < declaredMethods.length; i++) {
00222 CtMethod currentMethod = declaredMethods[i];
00223
00224
00225
00226 String key = "";
00227 key = key + currentMethod.getName();
00228 params = currentMethod.getParameterTypes();
00229 for (int k = 0; k < params.length; k++) {
00230 key = key + params[k].getName();
00231 }
00232
00233
00234 temp.put(key, currentMethod);
00235 }
00236 }
00237
00238 reifiedMethodsWithoutGenerics = (CtMethod[]) (temp.values().toArray(new CtMethod[temp.size()]));
00239
00240
00241
00242
00243 Vector<CtMethod> v = new Vector<CtMethod>();
00244 int initialNumberOfMethods = reifiedMethodsWithoutGenerics.length;
00245
00246 for (int i = 0; i < initialNumberOfMethods; i++) {
00247 if (checkMethod(reifiedMethodsWithoutGenerics[i])) {
00248 v.addElement(reifiedMethodsWithoutGenerics[i]);
00249 }
00250 }
00251 CtMethod[] validMethods = new CtMethod[v.size()];
00252 v.copyInto(validMethods);
00253
00254
00255 reifiedMethodsWithoutGenerics = validMethods;
00256
00257
00258 Class realSuperClass = Class.forName(className);
00259 TypeVariable<GenericDeclaration>[] tv = realSuperClass.getTypeParameters();
00260 Map<TypeVariable, Class> genericTypesMapping = new HashMap<TypeVariable, Class>();
00261 if (genericParameters.length!=0) {
00262
00263 for (int i = 0; i < tv.length; i++) {
00264 genericTypesMapping.put(tv[i], genericParameters[i]);
00265 }
00266 }
00267
00268
00269 createStaticInitializer(generatedCtClass, reifiedMethodsWithoutGenerics,
00270 classesIndexer, className, genericParameters);
00271
00272 createReifiedMethods(generatedCtClass, reifiedMethodsWithoutGenerics, superCtClass.isInterface());
00273
00274
00275
00276
00277 byte[] bytecode = generatedCtClass.toBytecode();
00278 generatedCtClass.detach();
00279 return bytecode;
00280 } catch (Exception e) {
00281 e.printStackTrace();
00282 throw new NoClassDefFoundError("Cannot generated stub for class " +
00283 className + " with javassist : " + e.getMessage());
00284 }
00285 }
00286
00287
00288
00295 private static void createReifiedMethods(CtClass generatedClass,
00296 CtMethod[] reifiedMethods, boolean stubOnInterface)
00297 throws NotFoundException, CannotCompileException {
00298 for (int i = 0; i < reifiedMethods.length; i++) {
00299 CtClass[] paramTypes = reifiedMethods[i].getParameterTypes();
00300 String body = ("{\nObject[] parameters = new Object[" +
00301 paramTypes.length + "];\n");
00302 for (int j = 0; j < paramTypes.length; j++) {
00303 if (paramTypes[j].isPrimitive()) {
00304 body += (" parameters[" + j + "]=" +
00305 wrapPrimitiveParameter(paramTypes[j], "$" + (j + 1)) +
00306 ";\n");
00307 } else {
00308 body += (" parameters[" + j + "]=$" + (j + 1) + ";\n");
00309 }
00310 }
00311 CtClass returnType = reifiedMethods[i].getReturnType();
00312 String postWrap = null;
00313 String preWrap = null;
00314
00315 if (returnType != CtClass.voidType) {
00316 if (!returnType.isPrimitive()) {
00317 preWrap = "(" + returnType.getName() + ")";
00318 } else {
00319
00320 if (returnType.equals(CtClass.booleanType)) {
00321 preWrap = "((Boolean)";
00322 postWrap = ").booleanValue()";
00323 }
00324 if (returnType.equals(CtClass.byteType)) {
00325 preWrap = "((Byte)";
00326 postWrap = ").byteValue()";
00327 }
00328 if (returnType.equals(CtClass.charType)) {
00329 preWrap = "((Character)";
00330 postWrap = ").charValue()";
00331 }
00332 if (returnType.equals(CtClass.shortType)) {
00333 preWrap = "((Short)";
00334 postWrap = ").shortValue()";
00335 }
00336 if (returnType.equals(CtClass.intType)) {
00337 preWrap = "((Integer)";
00338 postWrap = ").intValue()";
00339 }
00340 if (returnType.equals(CtClass.longType)) {
00341 preWrap = "((Long)";
00342 postWrap = ").longValue()";
00343 }
00344 if (returnType.equals(CtClass.floatType)) {
00345 preWrap = "((Float)";
00346 postWrap = ").floatValue()";
00347 }
00348 if (returnType.equals(CtClass.doubleType)) {
00349 preWrap = "((Double)";
00350 postWrap = ").doubleValue()";
00351 }
00352 }
00353 body += "return ";
00354 if (preWrap != null) {
00355 body += preWrap;
00356 }
00357 }
00358 body += ("myProxy.reify(org.objectweb.proactive.core.mop.MethodCall.getMethodCall(" +
00359 "(java.lang.reflect.Method)overridenMethods[" + i + "]" +
00360 ", parameters, genericTypesMapping))");
00361
00362
00363
00364
00365
00366 if (postWrap != null) {
00367 body += postWrap;
00368 }
00369 body += ";";
00370
00371
00372
00373 if (!stubOnInterface) {
00374 String preReificationCode = "if (outsideOfConstructor) ";
00375
00376
00377 String postReificationCode = "\n} else {\n";
00378
00379
00380 if (!reifiedMethods[i].getReturnType().equals(CtClass.voidType)) {
00381 postReificationCode += "return ";
00382 }
00383 postReificationCode += "super." + reifiedMethods[i].getName() + "(";
00384 for (int j = 0; j < paramTypes.length; j++) {
00385 postReificationCode += "$" + (j + 1)
00386 + (((j + 1) < paramTypes.length) ? "," : "");
00387 }
00388
00389 postReificationCode += ");";
00390 body = preReificationCode + body + postReificationCode;
00391 }
00392 body += "\n}";
00393
00394
00395 CtMethod methodToGenerate = null;
00396 try {
00397 methodToGenerate = CtNewMethod.make(reifiedMethods[i].getReturnType(),
00398 reifiedMethods[i].getName(),
00399 reifiedMethods[i].getParameterTypes(),
00400 reifiedMethods[i].getExceptionTypes(), body, generatedClass);
00401 } catch (RuntimeException e) {
00402 e.printStackTrace();
00403 }
00404 generatedClass.addMethod(methodToGenerate);
00405 }
00406 }
00414 public static void createStaticInitializer(CtClass generatedClass,
00415 CtMethod[] reifiedMethods, List<String> classesIndexer, String superClassName, Class[] genericParameters)
00416 throws CannotCompileException, NotFoundException {
00417 if (genericParameters == null) {
00418 genericParameters = new Class[0];
00419 }
00420 CtConstructor classInitializer = generatedClass.makeClassInitializer();
00421
00422 String classInitializerBody = "{\n";
00423 classInitializerBody+="Class[] genericParameters = new Class[" + genericParameters.length+"];\n";
00424 for (int i=0; i<genericParameters.length; i++) {
00425 classInitializerBody+="genericParameters["+i+"] = Class.forName(\""+genericParameters[i].getName()+"\");\n";
00426 }
00427 classInitializerBody+="Class realSuperClass = Class.forName(\"" + superClassName+"\");\n";
00428 classInitializerBody+="java.lang.reflect.TypeVariable[] tv = realSuperClass.getTypeParameters();\n";
00429 classInitializerBody+="genericTypesMapping = new java.util.HashMap();\n";
00430
00431
00432 if (genericParameters.length!=0) {
00433 classInitializerBody+="for (int i = 0; i < tv.length; i++) {\n";
00434 classInitializerBody+=" genericTypesMapping.put(tv[i], genericParameters[i]);\n";
00435 classInitializerBody+="}\n";
00436 }
00437
00438 classInitializerBody += ("overridenMethods = new java.lang.reflect.Method[" +
00439 reifiedMethods.length + "];\n");
00440 classInitializerBody += ("Class classes[] = new Class[" +
00441 (classesIndexer.size()) + "];\n");
00442 classInitializerBody += "Class[] temp;\n";
00443
00444 int methodsIndex = 0;
00445 Iterator<String> it = classesIndexer.iterator();
00446 int index = 0;
00447 while (it.hasNext()) {
00448 classInitializerBody += ("classes[" + index +
00449 "] = Class.forName(\"" + it.next() + "\");\n");
00450 index++;
00451 }
00452 for (int i = 0; i < reifiedMethods.length; i++) {
00453 CtClass[] paramTypes = reifiedMethods[i].getParameterTypes();
00454 classInitializerBody += ("temp = new Class[" + paramTypes.length +
00455 "];\n");
00456 for (int n = 0; n < paramTypes.length; n++) {
00457 if (paramTypes[n].isPrimitive()) {
00458 classInitializerBody += ("temp[" + n + "] = " +
00459 getClassTypeInitializer(paramTypes[n], false) + ";\n");
00460 } else {
00461 classInitializerBody += ("temp[" + n +
00462 "] = Class.forName(\"" +
00463 getClassTypeInitializer(paramTypes[n], false) + "\");\n");
00464 }
00465 }
00466 classInitializerBody += ("overridenMethods[" + (methodsIndex) +
00467 "] = classes[" +
00468 classesIndexer.indexOf(reifiedMethods[i].getDeclaringClass()
00469 .getName()) +
00470 "].getDeclaredMethod(\"" + reifiedMethods[i].getName() +
00471 "\", temp);\n");
00472 methodsIndex++;
00473 }
00474
00475 classInitializerBody += "\n}";
00476
00477 classInitializer.setBody(classInitializerBody);
00478 }
00479
00485 public static void createStubObjectMethods(CtClass generatedClass)
00486 throws CannotCompileException, NotFoundException {
00487 CtField proxyField = new CtField(ClassPool.getDefault().get(Proxy.class.getName()),
00488 "myProxy", generatedClass);
00489 generatedClass.addField(proxyField);
00490 proxyGetter = CtNewMethod.getter("getProxy", proxyField);
00491 generatedClass.addMethod(proxyGetter);
00492 proxySetter = CtNewMethod.setter("setProxy", proxyField);
00493 generatedClass.addMethod(proxySetter);
00494 }
00495
00496 private static String getClassTypeInitializer(CtClass param,
00497 boolean elementInArray) throws NotFoundException {
00498 if (param.isArray()) {
00499 return "[" +
00500 getClassTypeInitializer(param.getComponentType(), true);
00501 } else if (param.equals(CtClass.byteType)) {
00502 return elementInArray ? "B" : "Byte.TYPE";
00503 } else if (param.equals(CtClass.charType)) {
00504 return elementInArray ? "C" : "Character.TYPE";
00505 } else if (param.equals(CtClass.doubleType)) {
00506 return elementInArray ? "D" : "Double.TYPE";
00507 } else if (param.equals(CtClass.floatType)) {
00508 return elementInArray ? "F" : "Float.TYPE";
00509 } else if (param.equals(CtClass.intType)) {
00510 return elementInArray ? "I" : "Integer.TYPE";
00511 } else if (param.equals(CtClass.longType)) {
00512 return elementInArray ? "L" : "Long.TYPE";
00513 } else if (param.equals(CtClass.shortType)) {
00514 return elementInArray ? "S" : "Short.TYPE";
00515 } else if (param.equals(CtClass.booleanType)) {
00516 return elementInArray ? "Z" : "Boolean.TYPE";
00517 } else if (param.equals(CtClass.voidType)) {
00518 return elementInArray ? "V" : "Void.TYPE";
00519 } else {
00520 return elementInArray ? ("L" + param.getName() + ";")
00521 : (param.getName());
00522 }
00523 }
00524
00525 public static String wrapPrimitiveParameter(CtClass paramType,
00526 String paramString) {
00527 if (CtClass.booleanType.equals(paramType)) {
00528 return "new Boolean(" + paramString + ")";
00529 }
00530 if (CtClass.byteType.equals(paramType)) {
00531 return "new Byte(" + paramString + ")";
00532 }
00533 if (CtClass.charType.equals(paramType)) {
00534 return "new Character(" + paramString + ")";
00535 }
00536 if (CtClass.doubleType.equals(paramType)) {
00537 return "new Double(" + paramString + ")";
00538 }
00539 if (CtClass.floatType.equals(paramType)) {
00540 return "new Float(" + paramString + ")";
00541 }
00542 if (CtClass.intType.equals(paramType)) {
00543 return "new Integer(" + paramString + ")";
00544 }
00545 if (CtClass.longType.equals(paramType)) {
00546 return "new Long(" + paramString + ")";
00547 }
00548 if (CtClass.shortType.equals(paramType)) {
00549 return "new Short(" + paramString + ")";
00550 }
00551
00552
00553 return null;
00554 }
00555
00556 static public boolean checkMethod(CtMethod met) throws NotFoundException {
00557 int modifiers = met.getModifiers();
00558
00559
00560
00561 if (Modifier.isFinal(modifiers)) {
00562 return false;
00563 }
00564
00565
00566 if (Modifier.isStatic(modifiers)) {
00567 return false;
00568 }
00569 if (!(Modifier.isPublic(modifiers))) {
00570 return false;
00571 }
00572
00573
00574 if ((met.getName().equals("finalize")) &&
00575 (met.getParameterTypes().length == 0)) {
00576 return false;
00577 }
00578
00579 if ((met.getSignature().equals(proxyGetter.getSignature()) || met.getSignature().equals(proxySetter.getSignature()))) {
00580 return false;
00581 }
00582
00583 return true;
00584 }
00585
00586 private static void addSuperInterfaces(CtClass cl, List<CtClass> superItfs) throws NotFoundException {
00587 if (!cl.isInterface() && !Modifier.isAbstract(cl.getModifiers())) {
00588
00589 return;
00590 }
00591 CtClass[] super_interfaces = cl.getInterfaces();
00592 for (int i = 0; i < super_interfaces.length; i++) {
00593 superItfs.add(super_interfaces[i]);
00594 addSuperInterfaces(super_interfaces[i], superItfs);
00595 }
00596 }
00597
00598 }