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.component.gen;
00032 
00033 import java.io.Serializable;
00034 import java.util.ArrayList;
00035 import java.util.HashMap;
00036 import java.util.Iterator;
00037 import java.util.List;
00038 import java.util.Map;
00039 import java.util.Vector;
00040 
00041 import javassist.CannotCompileException;
00042 import javassist.ClassPool;
00043 import javassist.CtClass;
00044 import javassist.CtField;
00045 import javassist.CtMethod;
00046 import javassist.CtNewMethod;
00047 import javassist.Modifier;
00048 import javassist.NotFoundException;
00049 
00050 import org.objectweb.fractal.api.Component;
00051 import org.objectweb.proactive.core.component.ItfStubObject;
00052 import org.objectweb.proactive.core.component.ProActiveInterface;
00053 import org.objectweb.proactive.core.component.ProActiveInterfaceImpl;
00054 import org.objectweb.proactive.core.component.exceptions.InterfaceGenerationFailedException;
00055 import org.objectweb.proactive.core.component.type.ProActiveInterfaceType;
00056 import org.objectweb.proactive.core.mop.JavassistByteCodeStubBuilder;
00057 import org.objectweb.proactive.core.mop.StubObject;
00058 import org.objectweb.proactive.core.util.ClassDataCache;
00059 
00068 public class OutputInterceptorClassGenerator
00069     extends AbstractInterfaceClassGenerator {
00070     List outputInterceptors;
00071     private static OutputInterceptorClassGenerator instance;
00072 
00073     public static OutputInterceptorClassGenerator instance() {
00074         if (instance == null) {
00075             return new OutputInterceptorClassGenerator();
00076         } else {
00077             return instance;
00078         }
00079     }
00080 
00081     public ProActiveInterface generateInterface(
00082         ProActiveInterface representative, List outputInterceptors)
00083         throws InterfaceGenerationFailedException {
00084         this.outputInterceptors = outputInterceptors;
00085         ProActiveInterface generated = generateInterface(representative.getFcItfName(),
00086                 representative.getFcItfOwner(),
00087                 (ProActiveInterfaceType) representative.getFcItfType(), false, true);
00088         ((StubObject) generated).setProxy(((StubObject) representative).getProxy());
00089         return generated;
00090     }
00091 
00092     public ProActiveInterface generateInterface(final String interfaceName,
00093         Component owner, ProActiveInterfaceType interfaceType, boolean isInternal,
00094         boolean isFunctionalInterface)
00095         throws InterfaceGenerationFailedException {
00096         try {
00097             String representativeClassName = org.objectweb.proactive.core.component.gen.Utils.getOutputInterceptorClassName(interfaceName,
00098                     interfaceType.getFcItfSignature());
00099             Class generated_class;
00100 
00101             
00102             try {
00103                 generated_class = loadClass(representativeClassName);
00104             } catch (ClassNotFoundException cnfe) {
00105                 CtMethod[] reifiedMethods;
00106                 CtClass generatedCtClass = pool.makeClass(representativeClassName);
00107 
00108                 
00109                 
00110                 
00111                 List interfacesToImplement = new ArrayList();
00112 
00113                 
00114                 CtClass functional_itf = pool.get(interfaceType.getFcItfSignature());
00115                 generatedCtClass.addInterface(functional_itf);
00116 
00117                 interfacesToImplement.add(functional_itf);
00118 
00119                 
00120                 interfacesToImplement.add(pool.get(Serializable.class.getName()));
00121                 generatedCtClass.addInterface(pool.get(
00122                         Serializable.class.getName()));
00123 
00124                 
00125                 generatedCtClass.addInterface(pool.get(
00126                         StubObject.class.getName()));
00127                 
00128                 
00129                 generatedCtClass.addInterface(pool.get(ItfStubObject.class.getName()));
00130                 Utils.createItfStubObjectMethods(generatedCtClass);
00131 
00132 
00133                 
00134                 List interfacesToImplementAndSuperInterfaces = new ArrayList(interfacesToImplement);
00135                 addSuperInterfaces(interfacesToImplementAndSuperInterfaces);
00136                 generatedCtClass.setSuperclass(pool.get(
00137                         ProActiveInterfaceImpl.class.getName()));
00138                 JavassistByteCodeStubBuilder.createStubObjectMethods(generatedCtClass);
00139                 CtField interfaceNameField = new CtField(ClassPool.getDefault()
00140                                                                   .get(String.class.getName()),
00141                         "interfaceName", generatedCtClass);
00142                 interfaceNameField.setModifiers(Modifier.STATIC);
00143                 generatedCtClass.addField(interfaceNameField,
00144                     "\"" + interfaceName + "\"");
00145 
00146                 CtField methodsField = new CtField(pool.get(
00147                             "java.lang.reflect.Method[]"), "overridenMethods",
00148                         generatedCtClass);
00149                 methodsField.setModifiers(Modifier.STATIC);
00150                 generatedCtClass.addField(methodsField);
00151 
00152                                 
00153                 CtField genericTypesMappingField = new CtField(pool.get(
00154                 "java.util.Map"), "genericTypesMapping",
00155                 generatedCtClass);
00156 
00157                 genericTypesMappingField.setModifiers(Modifier.STATIC);
00158                 generatedCtClass.addField(genericTypesMappingField);
00159                 
00160                 
00161                 CtField outputInterceptorsField = new CtField(pool.get(
00162                             List.class.getName()), "outputInterceptors",
00163                         generatedCtClass);
00164                 generatedCtClass.addField(outputInterceptorsField,
00165                     "new java.util.ArrayList();");
00166                 CtMethod outputInterceptorsSetter = CtNewMethod.setter("setOutputInterceptors",
00167                         outputInterceptorsField);
00168                 generatedCtClass.addMethod(outputInterceptorsSetter);
00169                 generatedCtClass.addInterface(pool.get(
00170                         OutputInterceptorHelper.class.getName()));
00171                 
00172                 
00173                 Map methodsToImplement = new HashMap();
00174                 List classesIndexer = new Vector();
00175 
00176                 CtClass[] params;
00177                 CtClass itf;
00178 
00179                 
00180                 Iterator it = interfacesToImplementAndSuperInterfaces.iterator();
00181                 while (it.hasNext()) {
00182                     itf = (CtClass) it.next();
00183                     if (!classesIndexer.contains(itf.getName())) {
00184                         classesIndexer.add(itf.getName());
00185                     }
00186 
00187                     CtMethod[] declaredMethods = itf.getDeclaredMethods();
00188 
00189                     for (int i = 0; i < declaredMethods.length; i++) {
00190                         CtMethod currentMethod = declaredMethods[i];
00191 
00192                         
00193                         
00194                         String key = "";
00195                         key = key + currentMethod.getName();
00196                         params = currentMethod.getParameterTypes();
00197                         for (int k = 0; k < params.length; k++) {
00198                             key = key + params[k].getName();
00199                         }
00200 
00201                         
00202                         methodsToImplement.put(key, currentMethod);
00203                     }
00204                 }
00205 
00206                 reifiedMethods = (CtMethod[]) (methodsToImplement.values()
00207                                                                  .toArray(new CtMethod[methodsToImplement.size()]));
00208 
00209                 
00210                 
00211                 
00212                 Vector v = new Vector();
00213                 int initialNumberOfMethods = reifiedMethods.length;
00214 
00215                 for (int i = 0; i < initialNumberOfMethods; i++) {
00216                     if (JavassistByteCodeStubBuilder.checkMethod(
00217                                 reifiedMethods[i])) {
00218                         v.addElement(reifiedMethods[i]);
00219                     }
00220                 }
00221                 CtMethod[] validMethods = new CtMethod[v.size()];
00222                 v.copyInto(validMethods);
00223 
00224                 reifiedMethods = validMethods;
00225 
00226                 JavassistByteCodeStubBuilder.createStaticInitializer(generatedCtClass,
00227                     reifiedMethods, classesIndexer, interfaceType.getFcItfSignature(), null);
00228 
00229                 createReifiedMethods(generatedCtClass, reifiedMethods,
00230                     isFunctionalInterface);
00231 
00232                 
00233                 
00234                 
00235                 byte[] bytecode = generatedCtClass.toBytecode();
00236                 ClassDataCache.instance().addClassData(representativeClassName,
00237                     generatedCtClass.toBytecode());
00238                 if (logger.isDebugEnabled()) {
00239                     logger.debug("added " + representativeClassName +
00240                         " to cache");
00241                 }
00242                 if (logger.isDebugEnabled()) {
00243                     logger.debug("generated classes cache is : " +
00244                             ClassDataCache.instance().toString());
00245                 }
00246 
00247                 
00248                 generated_class = Utils.defineClass(representativeClassName, bytecode);
00249             }
00250 
00251             ProActiveInterfaceImpl reference = (ProActiveInterfaceImpl) generated_class.newInstance();
00252             reference.setFcItfName(interfaceName);
00253             reference.setFcItfOwner(owner);
00254             reference.setFcType(interfaceType);
00255             reference.setFcIsInternal(isInternal);
00256 
00257             ((OutputInterceptorHelper) reference).setOutputInterceptors(outputInterceptors);
00258 
00259             return reference;
00260         } catch (Exception e) {
00261                 throw new InterfaceGenerationFailedException(
00262                     "Cannot generate output interceptor on interface [" + interfaceName + "] with signature [" +  interfaceType.getFcItfSignature() + "] with javassist",
00263                     e);
00264         }
00265     }
00266 
00267     protected static void createReifiedMethods(CtClass generatedClass,
00268         CtMethod[] reifiedMethods, boolean isFunctionalInterface)
00269         throws NotFoundException, CannotCompileException {
00270         for (int i = 0; i < reifiedMethods.length; i++) {
00271             CtClass[] paramTypes = reifiedMethods[i].getParameterTypes();
00272             String body = ("{\nObject[] parameters = new Object[" +
00273                 paramTypes.length + "];\n");
00274             for (int j = 0; j < paramTypes.length; j++) {
00275                 if (paramTypes[j].isPrimitive()) {
00276                     body += ("  parameters[" + j + "]=" +
00277                     JavassistByteCodeStubBuilder.wrapPrimitiveParameter(paramTypes[j],
00278                         "$" + (j + 1)) + ";\n");
00279                 } else {
00280                     body += ("  parameters[" + j + "]=$" + (j + 1) + ";\n");
00281                 }
00282             }
00283 
00284             body += ("org.objectweb.proactive.core.mop.MethodCall methodCall = org.objectweb.proactive.core.mop.MethodCall.getComponentMethodCall(" +
00285             "(java.lang.reflect.Method)overridenMethods[" + i + "]" +
00286             ", parameters, null, interfaceName, senderItfID);\n");
00287 
00288             
00289             body += "java.util.ListIterator it = outputInterceptors.listIterator();\n";
00290             body += "while (it.hasNext()) {\n";
00291             body += "  ((org.objectweb.proactive.core.component.interception.OutputInterceptor) it.next()).beforeOutputMethodInvocation(methodCall);\n";
00292             body += "}\n";
00293 
00294             CtClass returnType = reifiedMethods[i].getReturnType();
00295             if (returnType != CtClass.voidType) {
00296                 body += "Object result = ";
00297             }
00298             body += ("myProxy.reify(methodCall);\n");
00299 
00300             
00301             body += "it = outputInterceptors.listIterator();\n";
00302             
00303             
00304             body += "while (it.hasNext()) {\n";
00305             body += "it.next();\n";
00306             body += "}\n";
00307             body += "while (it.hasPrevious()) {\n";
00308             body += "  ((org.objectweb.proactive.core.component.interception.OutputInterceptor) it.previous()).afterOutputMethodInvocation(methodCall);\n";
00309             body += "}\n";
00310 
00311             
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                 body += "result ";
00358             }
00359 
00360             if (postWrap != null) {
00361                 body += postWrap;
00362             }
00363             body += ";";
00364             body += "\n}";
00365 
00366 
00367             CtMethod methodToGenerate = CtNewMethod.make(reifiedMethods[i].getReturnType(),
00368                     reifiedMethods[i].getName(),
00369                     reifiedMethods[i].getParameterTypes(),
00370                     reifiedMethods[i].getExceptionTypes(), body, generatedClass);
00371             generatedClass.addMethod(methodToGenerate);
00372         }
00373     }
00374 }