org/objectweb/proactive/core/component/gen/OutputInterceptorClassGenerator.java

00001 /* 
00002  * ################################################################
00003  * 
00004  * ProActive: The Java(TM) library for Parallel, Distributed, 
00005  *            Concurrent computing with Security and Mobility
00006  * 
00007  * Copyright (C) 1997-2007 INRIA/University of Nice-Sophia Antipolis
00008  * Contact: proactive@objectweb.org
00009  * 
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public
00012  * License as published by the Free Software Foundation; either
00013  * version 2.1 of the License, or any later version.
00014  *  
00015  * This library is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * Lesser General Public License for more details.
00019  * 
00020  * You should have received a copy of the GNU Lesser General Public
00021  * License along with this library; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
00023  * USA
00024  *  
00025  *  Initial developer(s):               The ProActive Team
00026  *                        http://www.inria.fr/oasis/ProActive/contacts.html
00027  *  Contributor(s): 
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             // check whether class has already been generated
00102             try {
00103                 generated_class = loadClass(representativeClassName);
00104             } catch (ClassNotFoundException cnfe) {
00105                 CtMethod[] reifiedMethods;
00106                 CtClass generatedCtClass = pool.makeClass(representativeClassName);
00107 
00108                 //this.fcInterfaceName = fcInterfaceName;
00109                 //isPrimitive = ((ProActiveComponentRepresentativeImpl) owner).getHierarchicalType()
00110                 //                                                    .equals(ComponentParameters.PRIMITIVE);
00111                 List interfacesToImplement = new ArrayList();
00112 
00113                 // add interface to reify
00114                 CtClass functional_itf = pool.get(interfaceType.getFcItfSignature());
00115                 generatedCtClass.addInterface(functional_itf);
00116 
00117                 interfacesToImplement.add(functional_itf);
00118 
00119                 // add Serializable interface
00120                 interfacesToImplement.add(pool.get(Serializable.class.getName()));
00121                 generatedCtClass.addInterface(pool.get(
00122                         Serializable.class.getName()));
00123 
00124                 // add StubObject, so we can set the proxy
00125                 generatedCtClass.addInterface(pool.get(
00126                         StubObject.class.getName()));
00127                 
00128                 // add ItfStubObject, so we can set the sender itf
00129                 generatedCtClass.addInterface(pool.get(ItfStubObject.class.getName()));
00130                 Utils.createItfStubObjectMethods(generatedCtClass);
00131 
00132 
00133                 //interfacesToImplement.add(pool.get(StubObject.class.getName()));
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                                 // field for remembering generic parameters
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                 // add outputInterceptorsField
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                 //                methodsListField.setModifiers(Modifier.STATIC);
00172                 // list all methods to implement
00173                 Map methodsToImplement = new HashMap();
00174                 List classesIndexer = new Vector();
00175 
00176                 CtClass[] params;
00177                 CtClass itf;
00178 
00179                 // now get the methods from implemented interfaces
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                         // Build a key with the simple name of the method
00193                         // and the names of its parameters in the right order
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                         // this gives the actual declaring Class of this method
00202                         methodsToImplement.put(key, currentMethod);
00203                     }
00204                 }
00205 
00206                 reifiedMethods = (CtMethod[]) (methodsToImplement.values()
00207                                                                  .toArray(new CtMethod[methodsToImplement.size()]));
00208 
00209                 // Determines which reifiedMethods are valid for reification
00210                 // It is the responsibility of method checkMethod in class Utils
00211                 // to decide if a method is valid for reification or not
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                 //                generatedCtClass.writeFile("generated/");
00233                 //                System.out.println("[JAVASSIST] generated class : " +
00234                 //                    representativeClassName);
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                 // convert the bytes into a Class
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             // delegate to outputinterceptors
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             //              delegate to outputinterceptors
00301             body += "it = outputInterceptors.listIterator();\n";
00302             // use output interceptors in reverse order after invocation
00303             // go to the end of the list first
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             // return casted result
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                     //boolean, byte, char, short, int, long, float, double
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 //                                 System.out.println("method : " + reifiedMethods[i].getName() +
00366 //                                     " : \n" + body);
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 }

Generated on Mon Jan 22 15:16:06 2007 for ProActive by  doxygen 1.5.1