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.ByteArrayInputStream;
00034 import java.lang.reflect.InvocationTargetException;
00035 import java.lang.reflect.Method;
00036 import java.lang.reflect.Type;
00037 import java.lang.reflect.TypeVariable;
00038 import java.util.Iterator;
00039 import java.util.LinkedList;
00040 import java.util.Map;
00041 
00042 import org.apache.log4j.Logger;
00043 import org.objectweb.proactive.ProActive;
00044 import org.objectweb.proactive.core.component.ComponentMethodCallMetadata;
00045 import org.objectweb.proactive.core.component.representative.ItfID;
00046 import org.objectweb.proactive.core.component.request.ComponentRequest;
00047 import org.objectweb.proactive.core.exceptions.manager.ExceptionHandler;
00048 import org.objectweb.proactive.core.util.ObjectToByteConverter;
00049 import org.objectweb.proactive.core.util.log.Loggers;
00050 import org.objectweb.proactive.core.util.log.ProActiveLogger;
00051 
00052 import sun.rmi.server.MarshalInputStream;
00053 
00054 
00062 public class MethodCall implements java.io.Serializable, Cloneable {
00063     
00064 
00065     
00066     
00067     
00068 
00074     private static transient java.util.Hashtable<String, ReifiableAndExceptions> REIF_AND_EXCEP = new java.util.Hashtable<String, ReifiableAndExceptions>();
00075     static Logger logger = ProActiveLogger.getLogger(Loggers.MOP);
00076 
00080     private static int RECYCLE_POOL_SIZE = 30;
00081 
00085     private static MethodCall[] recyclePool;
00086 
00090     private static int index;
00091 
00093     private static boolean recycleMethodCallObject;
00094     private static java.util.Hashtable<String, Method> reifiedMethodsTable = new java.util.Hashtable<String, Method>();
00095 
00099     static {
00100         MethodCall.setRecycleMethodCallObject(true);
00101     }
00102 
00103     
00104     
00105     
00106 
00110     private Object[] effectiveArguments;
00111 
00115     private LinkedList<String> tagsForBarrier = null;
00116 
00120     private transient Method reifiedMethod;
00121 
00125     private long methodCallID;
00126     private String key;
00127 
00128     private transient MethodCallExceptionContext exceptioncontext;
00129 
00130     ComponentMethodCallMetadata componentMetaData = null;
00131     
00132     private transient Map<TypeVariable, Class> genericTypesMapping = null;
00133 
00134 
00141     private byte[] serializedEffectiveArguments = null;
00142 
00146     public void transformEffectiveArgumentsIntoByteArray() {
00147         if ((serializedEffectiveArguments == null) &&
00148                 (effectiveArguments != null)) {
00149             try {
00150                 
00151                 
00152                 
00153                 
00154                 
00155                 
00156                 
00157                 
00158                 
00159                 serializedEffectiveArguments = ObjectToByteConverter.convert(effectiveArguments);
00160             } catch (Exception e) {
00161                 e.printStackTrace();
00162             }
00163             effectiveArguments = null;
00164         }
00165     }
00166 
00173     public static synchronized void setRecycleMethodCallObject(boolean value) {
00174         if (recycleMethodCallObject == value) {
00175             return;
00176         } else {
00177             recycleMethodCallObject = value;
00178             if (value) {
00179                 
00180                 recyclePool = new MethodCall[RECYCLE_POOL_SIZE];
00181                 index = 0;
00182             } else {
00183                 
00184                 
00185                 
00186                 recyclePool = null;
00187             }
00188         }
00189     }
00190 
00196     public static synchronized boolean getRecycleMethodCallObject() {
00197         return MethodCall.recycleMethodCallObject;
00198     }
00199 
00213     public synchronized static MethodCall getMethodCall(Method reifiedMethod, Map<TypeVariable,Class> genericTypesMapping,
00214         Object[] effectiveArguments, MethodCallExceptionContext exceptioncontext) {
00215         exceptioncontext = MethodCallExceptionContext.optimize(exceptioncontext);
00216 
00217         if (MethodCall.getRecycleMethodCallObject()) {
00218             
00219             
00220             if (MethodCall.index > 0) {
00221                 
00222                 MethodCall.index--;
00223                 MethodCall result = MethodCall.recyclePool[MethodCall.index];
00224                 MethodCall.recyclePool[MethodCall.index] = null;
00225                 
00226                 result.reifiedMethod = reifiedMethod;
00227                 result.genericTypesMapping = genericTypesMapping;
00228                 result.effectiveArguments = effectiveArguments;
00229                 result.key = buildKey(reifiedMethod, genericTypesMapping);
00230                 result.exceptioncontext = exceptioncontext;
00231                 return result;
00232             }
00233         }
00234         return new MethodCall(reifiedMethod, genericTypesMapping, effectiveArguments, exceptioncontext);
00235     }
00236 
00237     public synchronized static MethodCall getMethodCall(Method reifiedMethod,
00238         Object[] effectiveArguments, Map<TypeVariable,Class> genericTypesMapping) {
00239         MethodCallExceptionContext exceptioncontext = ExceptionHandler.getContextForCall(reifiedMethod);
00240         return getMethodCall(reifiedMethod, genericTypesMapping, effectiveArguments, exceptioncontext);
00241     }
00242 
00252     public synchronized static MethodCall getComponentMethodCall(
00253         Method reifiedMethod,  Object[] effectiveArguments, Map<TypeVariable,Class> genericTypesMapping,
00254         String interfaceName, ItfID senderItfID, short priority) {
00255         MethodCall mc = getMethodCall(reifiedMethod, effectiveArguments, genericTypesMapping);
00256         
00257         mc.componentMetaData = new ComponentMethodCallMetadata();
00258         mc.componentMetaData.setComponentInterfaceName(interfaceName);
00259         mc.componentMetaData.setSenderItfID(senderItfID);
00260         mc.componentMetaData.setPriority(priority);
00261         mc.componentMetaData.setShortcut(null);
00262         return mc;
00263     }
00264 
00265     public synchronized static MethodCall getComponentMethodCall(
00266         Method reifiedMethod, Object[] effectiveArguments,Map<TypeVariable,Class> genericTypesMapping, 
00267         String interfaceName, ItfID senderItfID ) {
00268         return MethodCall.getComponentMethodCall(reifiedMethod,
00269                         effectiveArguments, genericTypesMapping, interfaceName, senderItfID,
00270             ComponentRequest.STRICT_FIFO_PRIORITY);
00271     }
00272 
00278     public synchronized static void setMethodCall(MethodCall mc) {
00279         if (MethodCall.getRecycleMethodCallObject()) {
00280             
00281             if (MethodCall.recyclePool[MethodCall.index] == null) {
00282                 
00283                 
00284                 
00285                 
00286                 mc.componentMetaData = null;
00287                 mc.reifiedMethod = null;
00288                 mc.genericTypesMapping = null;
00289                 mc.effectiveArguments = null;
00290                 mc.tagsForBarrier = null;
00291                 mc.key = null;
00292                 mc.exceptioncontext = null;
00293                 
00294                 MethodCall.recyclePool[MethodCall.index] = mc;
00295                 MethodCall.index++;
00296                 if (MethodCall.index == RECYCLE_POOL_SIZE) {
00297                     MethodCall.index = RECYCLE_POOL_SIZE - 1;
00298                 }
00299             }
00300         }
00301     }
00302 
00309     
00310     
00311     
00312     public MethodCall(Method reifiedMethod, Map<TypeVariable,Class> genericTypesMapping, Object[] effectiveArguments, 
00313         MethodCallExceptionContext exceptionContext) {
00314         this.reifiedMethod = reifiedMethod;
00315         this.genericTypesMapping = (genericTypesMapping!=null && genericTypesMapping.size()>0)?genericTypesMapping:null;
00316         this.effectiveArguments = effectiveArguments;
00317         this.key = buildKey(reifiedMethod, genericTypesMapping);
00318         this.exceptioncontext = MethodCallExceptionContext.optimize(exceptionContext);
00319     }
00320 
00321     public MethodCall(Method reifiedMethod, Map<TypeVariable,Class> genericTypesMapping, Object[] effectiveArguments) {
00322         this(reifiedMethod, genericTypesMapping, effectiveArguments, null);
00323     }
00324 
00332     public MethodCall(MethodCall mc) {
00333         try {
00334             this.componentMetaData = mc.componentMetaData;
00335             this.reifiedMethod = mc.getReifiedMethod();
00336             if (mc.serializedEffectiveArguments == null) {
00337                 serializedEffectiveArguments = null;
00338             } else {
00339                 
00340                 byte[] source = mc.serializedEffectiveArguments;
00341                 serializedEffectiveArguments = new byte[source.length];
00342                 for (int i = 0; i < serializedEffectiveArguments.length; i++) {
00343                     serializedEffectiveArguments[i] = source[i];
00344                 }
00345             }
00346             if (mc.effectiveArguments == null) {
00347                 effectiveArguments = null;
00348             } else {
00349                 effectiveArguments = (Object[]) Utils.makeDeepCopy(mc.effectiveArguments);
00350             }
00351             this.genericTypesMapping = mc.getGenericTypesMapping();
00352             this.key = MethodCall.buildKey(mc.getReifiedMethod(), mc.getGenericTypesMapping());
00353             this.exceptioncontext = mc.exceptioncontext;
00354             
00355         } catch (java.io.IOException e) {
00356             e.printStackTrace();
00357         }
00358     }
00359 
00363     protected MethodCall() {
00364         this.reifiedMethod = null;
00365         this.effectiveArguments = null;
00366         this.serializedEffectiveArguments = null;
00367         this.exceptioncontext = null;
00368     }
00369 
00385     public Object execute(Object targetObject)
00386         throws InvocationTargetException, MethodCallExecutionFailedException {
00387         
00388         if ((serializedEffectiveArguments != null) &&
00389                 (effectiveArguments == null)) {
00390             try {
00391                 ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(serializedEffectiveArguments);
00392 
00393                 
00394                 MarshalInputStream objectInputStream = new MarshalInputStream(byteArrayInputStream);
00395                 effectiveArguments = (Object[]) objectInputStream.readObject();
00396                 objectInputStream.close();
00397                 byteArrayInputStream.close();
00398             } catch (Exception e) {
00399                 e.printStackTrace();
00400             }
00401             serializedEffectiveArguments = null;
00402         }
00403         if (logger.isDebugEnabled()) {
00404             logger.debug("MethodCall.execute() name = " + this.getName());
00405             logger.debug("MethodCall.execute() reifiedMethod = " +
00406                 reifiedMethod);
00407             logger.debug(
00408                 "MethodCall.execute() reifiedMethod.getDeclaringClass() = " +
00409                 reifiedMethod.getDeclaringClass());
00410             logger.debug("MethodCall.execute() targetObject " + targetObject);
00411         }
00412         if (reifiedMethod.getParameterTypes().length > 0) {
00413             reifiedMethod.setAccessible(true);
00414         }
00415         try {
00416             targetObject = ProActive.getFutureValue(targetObject);
00417             return reifiedMethod.invoke(targetObject, effectiveArguments);
00418         } catch (IllegalAccessException e) {
00419             throw new MethodCallExecutionFailedException(
00420                 "Access rights to the method denied: " + e);
00421         } catch (IllegalArgumentException e) {
00422             e.printStackTrace();
00423             throw new MethodCallExecutionFailedException(
00424                 "Arguments for the method " + this.getName() +
00425                 " are invalids: " + e);
00426         } 
00427 
00428 
00429 
00430 }
00431 
00432     protected void finalize() {
00433         MethodCall.setMethodCall(this);
00434     }
00435 
00436     public Method getReifiedMethod() {
00437         return reifiedMethod;
00438     }
00439 
00444     public String getName() {
00445         return reifiedMethod.getName();
00446     }
00447 
00448     public int getNumberOfParameter() {
00449         return this.effectiveArguments.length;
00450     }
00451 
00452     public Object getParameter(int index) {
00453         return this.effectiveArguments[index];
00454     }
00455 
00456     public Object[] getParameters() {
00457         return this.effectiveArguments;
00458     }
00459 
00460     public void setEffectiveArguments(Object[] o) {
00461         effectiveArguments = o;
00462     }
00463 
00464     public Object[] getEffectiveArguments() {
00465         return effectiveArguments;
00466     }
00467 
00471     public void makeDeepCopyOfArguments() throws java.io.IOException {
00472         effectiveArguments = (Object[]) Utils.makeDeepCopy(effectiveArguments);
00473     }
00474 
00475     
00476     
00477     
00478     private Class[] fixBugRead(FixWrapper[] para) {
00479         Class[] tmp = new Class[para.length];
00480         for (int i = 0; i < para.length; i++) {
00481             
00482             tmp[i] = para[i].getWrapped();
00483         }
00484         return tmp;
00485     }
00486 
00487     private FixWrapper[] fixBugWrite(Class[] para) {
00488         FixWrapper[] tmp = new FixWrapper[para.length];
00489         for (int i = 0; i < para.length; i++) {
00490             
00491             tmp[i] = new FixWrapper(para[i]);
00492         }
00493         return tmp;
00494     }
00495 
00496     
00497     private static String buildKey(Method reifiedMethod, Map<TypeVariable, Class> genericTypesMapping) {
00498         String sb = "";
00499         sb+=(reifiedMethod.getDeclaringClass().getName());
00500         
00501         Type returnType = reifiedMethod.getGenericReturnType();
00502         if (genericTypesMapping!=null && genericTypesMapping.containsKey(returnType)) {
00503                 sb+=genericTypesMapping.get(returnType);
00504         } else {
00505                 sb+=returnType;
00506         }
00507         sb+=(reifiedMethod.getName());
00508         
00509         Type[] parameters = reifiedMethod.getGenericParameterTypes();
00510         for (int i = 0; i < parameters.length; i++) {
00511             sb+=((genericTypesMapping!=null && genericTypesMapping.containsKey(parameters[i]))?genericTypesMapping.get(parameters[i]).getName():parameters[i]);
00512         }
00513         
00514         return sb.toString();
00515     }
00516 
00517     
00518     
00519     
00520     private void writeObject(java.io.ObjectOutputStream out)
00521         throws java.io.IOException {
00522         this.writeTheObject(out);
00523     }
00524 
00525     protected void writeTheObject(java.io.ObjectOutputStream out)
00526         throws java.io.IOException {
00527         out.defaultWriteObject();
00528         
00529         out.writeObject(reifiedMethod.getDeclaringClass());
00530         out.writeObject(reifiedMethod.getName());
00531         out.writeObject(fixBugWrite(reifiedMethod.getParameterTypes()));
00532     }
00533 
00534     private void readObject(java.io.ObjectInputStream in)
00535         throws java.io.IOException, ClassNotFoundException {
00536         this.readTheObject(in);
00537     }
00538 
00539     protected void readTheObject(java.io.ObjectInputStream in)
00540         throws java.io.IOException, ClassNotFoundException {
00541         in.defaultReadObject();
00542         reifiedMethod = (Method) reifiedMethodsTable.get(key);
00543         if (reifiedMethod == null) {
00544             
00545             Class declaringClass = (Class) in.readObject();
00546             String simpleName = (String) in.readObject();
00547             Class[] parameters = this.fixBugRead((FixWrapper[]) in.readObject());
00548 
00549             
00550             try {
00551                 reifiedMethod = declaringClass.getMethod(simpleName, parameters);
00552                 reifiedMethodsTable.put(key, reifiedMethod);
00553             } catch (NoSuchMethodException e) {
00554                 throw new InternalException("Lookup for method failed: " + e +
00555                     ". This may be caused by having different versions of the same class on different VMs. Check your CLASSPATH settings.");
00556             }
00557         } else { 
00558             in.readObject();
00559             in.readObject();
00560             in.readObject();
00561         }
00562         if ((serializedEffectiveArguments != null) &&
00563                 (effectiveArguments == null)) {
00564             try {
00565                 ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(serializedEffectiveArguments);
00566 
00567                 
00568                 MarshalInputStream objectInputStream = new MarshalInputStream(byteArrayInputStream);
00569                 effectiveArguments = (Object[]) objectInputStream.readObject();
00570                 objectInputStream.close();
00571                 byteArrayInputStream.close();
00572             } catch (Exception e) {
00573                 e.printStackTrace();
00574             }
00575             serializedEffectiveArguments = null;
00576         }
00577     }
00578 
00587     public boolean isOneWayCall() {
00588         return this.getReifiedMethod().getReturnType().equals(java.lang.Void.TYPE) &&
00589         (this.getReifiedMethod().getExceptionTypes().length == 0) &&
00590         !this.getExceptionContext().isRuntimeExceptionHandled();
00591     }
00592 
00593     
00594     static class ReifiableAndExceptions {
00595         boolean reifiable; 
00596         boolean exceptions; 
00597         String reason; 
00598     }
00599 
00600     public String getSynchronousReason() {
00601         Method m = this.getReifiedMethod();
00602         ReifiableAndExceptions cached = (ReifiableAndExceptions) REIF_AND_EXCEP.get(key);
00603         if (cached == null) {
00604             cached = new ReifiableAndExceptions();
00605             
00606             cached.reifiable = m.getReturnType().equals(java.lang.Void.TYPE);
00607             if (!cached.reifiable) {
00608                 try {
00609                         if (getGenericTypesMapping()!=null && getGenericTypesMapping().containsKey(m.getGenericReturnType())) {
00610                                 
00611                                 MOP.checkClassIsReifiable(getGenericTypesMapping().get(m.getGenericReturnType()));
00612                         } else {
00613                                 MOP.checkClassIsReifiable(m.getReturnType());
00614                         }
00615                     cached.reifiable = true;
00616                 } catch (ClassNotReifiableException e) {
00617                     cached.reason = e.getMessage();
00618                 }
00619             }
00620 
00621             cached.exceptions = m.getExceptionTypes().length != 0;
00622             if (cached.exceptions) {
00623                 cached.reason = "The method can throw a checked exception";
00624             }
00625             REIF_AND_EXCEP.put(key, cached);
00626         }
00627 
00628         if (cached.reifiable && cached.exceptions && getExceptionContext().isExceptionAsynchronously()) {
00629                 
00630                 return null;
00631         }
00632 
00633         return cached.reason;
00634     }
00635 
00647     public boolean isAsynchronousWayCall() {
00648         return getSynchronousReason() == null;
00649     }
00650 
00655     public void setBarrierTags(LinkedList<String> barrierTags) {
00656         this.tagsForBarrier = new LinkedList<String>();
00657         Iterator<String> it = barrierTags.iterator();
00658         while (it.hasNext()) {
00659             this.tagsForBarrier.add(new String(it.next()));
00660         }
00661     }
00662 
00667     public LinkedList getBarrierTags() {
00668         return this.tagsForBarrier;
00669     }
00670 
00671     public MethodCallExceptionContext getExceptionContext() {
00672         if (exceptioncontext == null) {
00673             return MethodCallExceptionContext.DEFAULT;
00674         }
00675 
00676         return exceptioncontext;
00677     }
00678     
00679     public ComponentMethodCallMetadata getComponentMetadata() {
00680         return componentMetaData;
00681     }
00682     
00683     public Map<TypeVariable, Class> getGenericTypesMapping() {
00684         return genericTypesMapping;
00685     }
00686     
00687 
00688     
00689     
00690     
00691     public class FixWrapper implements java.io.Serializable {
00692         public boolean isPrimitive;
00693         public Class encapsulated;
00694 
00695         public FixWrapper() {
00696         }
00697 
00701         public FixWrapper(Class c) {
00702             if (!c.isPrimitive()) {
00703                 encapsulated = c;
00704                 return;
00705             }
00706             isPrimitive = true;
00707             if (c.equals(Boolean.TYPE)) {
00708                 encapsulated = Boolean.class;
00709             } else if (c.equals(Byte.TYPE)) {
00710                 encapsulated = Byte.class;
00711             } else if (c.equals(Character.TYPE)) {
00712                 encapsulated = Character.class;
00713             } else if (c.equals(Double.TYPE)) {
00714                 encapsulated = Double.class;
00715             } else if (c.equals(Float.TYPE)) {
00716                 encapsulated = Float.class;
00717             } else if (c.equals(Integer.TYPE)) {
00718                 encapsulated = Integer.class;
00719             } else if (c.equals(Long.TYPE)) {
00720                 encapsulated = Long.class;
00721             } else if (c.equals(Short.TYPE)) {
00722                 encapsulated = Short.class;
00723             }
00724         }
00725 
00729         public Class getWrapped() {
00730             if (!isPrimitive) {
00731                 return encapsulated;
00732             }
00733             if (encapsulated.equals(Boolean.class)) {
00734                 return Boolean.TYPE;
00735             }
00736             if (encapsulated.equals(Byte.class)) {
00737                 return Byte.TYPE;
00738             }
00739             if (encapsulated.equals(Character.class)) {
00740                 return Character.TYPE;
00741             }
00742             if (encapsulated.equals(Double.class)) {
00743                 return Double.TYPE;
00744             }
00745             if (encapsulated.equals(Float.class)) {
00746                 return Float.TYPE;
00747             }
00748             if (encapsulated.equals(Integer.class)) {
00749                 return Integer.TYPE;
00750             }
00751             if (encapsulated.equals(Long.class)) {
00752                 return Long.TYPE;
00753             }
00754             if (encapsulated.equals(Short.class)) {
00755                 return Short.TYPE;
00756             }
00757             throw new InternalException("FixWrapper encapsulated class unkown " +
00758                 encapsulated);
00759         }
00760 
00761         public String toString() {
00762             return "FixWrapper: " + encapsulated.toString();
00763         }
00764     }
00765     
00766 
00767 
00768     
00769 }