All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.snapscript.platform.android.ProxyMethodInvocation Maven / Gradle / Ivy

package org.snapscript.platform.android;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicLong;

import org.snapscript.core.InternalStateException;
import org.snapscript.core.function.Invocation;
import org.snapscript.core.scope.Scope;
import org.snapscript.dx.stock.ProxyAdapter;

public class ProxyMethodInvocation implements Invocation {
   
   private volatile MethodExchanger exchanger;
   private volatile ProxyAdapter reference;
   private volatile Executor executor;
   private volatile Method method;
   
   public ProxyMethodInvocation(ProxyAdapterBuilder generator, Method method, Executor executor) {
      this.exchanger = new MethodExchanger(generator, method);
      this.reference = new MethodAdapter(method);
      this.executor = executor;
      this.method = method;
   }

   @Override
   public Object invoke(Scope scope, Object value, Object... arguments) throws Exception {
      try {
         return reference.invoke(value, arguments);
      }catch(InvocationTargetException cause) {
         Throwable target = cause.getTargetException();
         
         if(target != null) {
            throw new InternalStateException("Error occured invoking " + method, target);
         }
         throw cause;
      }catch(InternalError cause) {
         Throwable target = cause.getCause();
         
         if(target != null) {
            throw new InternalStateException("Error occured invoking " + method, target);
         }
         throw cause;
      }
   }
   
   private class MethodAdapter implements ProxyAdapter {

      private final AtomicLong counter;
      private final Method method;
      
      public MethodAdapter(Method method) {
         this(method, 10);
      }
      
      public MethodAdapter(Method method, int threshold) {
         this.counter = new AtomicLong(threshold);
         this.method = method;
      }
      
      @Override
      public Object invoke(Object object, Object... list) throws Exception {
         long count = counter.getAndDecrement();
         
         if(count == 0) {
            executor.execute(exchanger); // generate proxy adapter
         }
         return method.invoke(object, list);
      }   
   }
   
   private class MethodExchanger implements Runnable {
      
      private final ProxyAdapterBuilder generator;
      private final InternalClassFilter filter;
      private final Method method;
      
      public MethodExchanger(ProxyAdapterBuilder generator, Method method) {
         this.filter = new InternalClassFilter();
         this.generator = generator;
         this.method = method;
      }

      @Override
      public void run() {
         if(filter.accept(method)) { // in a private dex class loader
            ProxyAdapter adapter = generator.generate(method);
            
            if(adapter != null) {
               reference = adapter;
            }
         }
      }
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy