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

com.caucho.v5.bartender.pod.MethodPod Maven / Gradle / Ivy

There is a newer version: 1.0.1
Show newest version
/*
 * Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
 *
 * This file is part of Baratine(TM)
 *
 * Each copy or derived work must preserve the copyright notice and this
 * notice unmodified.
 *
 * Baratine is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Baratine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
 * of NON-INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Baratine; if not, write to the
 *
 *   Free Software Foundation, Inc.
 *   59 Temple Place, Suite 330
 *   Boston, MA 02111-1307  USA
 *
 * @author Scott Ferguson
 */

package com.caucho.v5.bartender.pod;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.logging.Logger;

import com.caucho.v5.amp.ServiceRefAmp;
import com.caucho.v5.amp.marshal.ModuleMarshal;
import com.caucho.v5.amp.marshal.PodImport;
import com.caucho.v5.amp.marshal.PodImportContext;
import com.caucho.v5.amp.marshal.ResultImport;
import com.caucho.v5.amp.marshal.ResultStreamImport;
import com.caucho.v5.amp.message.ResultStreamAmp;
import com.caucho.v5.amp.message.StreamForkMessage;
import com.caucho.v5.amp.remote.StubLink;
import com.caucho.v5.amp.spi.HeadersAmp;
import com.caucho.v5.amp.spi.MethodRefAmp;
import com.caucho.v5.amp.spi.OutboxAmp;
import com.caucho.v5.amp.stub.MethodAmp;
import com.caucho.v5.amp.stub.ParameterAmp;
import com.caucho.v5.amp.stub.StubAmp;
import com.caucho.v5.util.L10N;

import io.baratine.pipe.ResultPipeIn;
import io.baratine.pipe.ResultPipeOut;
import io.baratine.service.Result;
import io.baratine.service.ServiceExceptionUnavailable;
import io.baratine.service.ServiceRef;
import io.baratine.stream.ResultStream;

/**
 * Method for a pod node call.
 * 
 * The method calls the owning service, and fails over if the primary is
 * down.
 * 
 * The node has already been selected using the hash of the URL.
 */
public class MethodPod implements MethodAmp
{
  private static final L10N L = new L10N(MethodPod.class);
  private static final Logger log = Logger.getLogger(MethodPod.class.getName());
  
  private final ServiceRefPod _serviceRef;
  private final String _name;
  private final Type _type;
  private final ClassLoader _sourceLoader;
  
  private MethodRefActive _methodRefActive;
  
  MethodPod(ServiceRefPod serviceRef,
            String name,
            Type type)
  {
    _name = name;
    _type = type;
    _serviceRef = serviceRef;

    _sourceLoader = Thread.currentThread().getContextClassLoader();
  }
  
  @Override
  public String name()
  {
    return _name;
  }
  
  @Override
  public ParameterAmp []parameters()
  {
    MethodRefAmp localMethod = findLocalMethod();
    
    if (localMethod != null) {
      return localMethod.parameters();
    }
    else {
      return null;
    }
  }
  
  @Override
  public Annotation []getAnnotations()
  {
    MethodRefAmp localMethod = findLocalMethod();
    
    if (localMethod != null) {
      return localMethod.getAnnotations();
    }
    else {
      return null;
    }
  }
  
  @Override
  public boolean isVarArgs()
  {
    MethodRefAmp localMethod = findLocalMethod();
    
    if (localMethod != null) {
      return localMethod.isVarArgs();
    }
    else {
      return false;
    }
  }
  
  @Override
  public boolean isModify()
  {
    MethodRefAmp localMethod = findLocalMethod();
    
    if (localMethod != null) {
      return localMethod.method().isModify();
    }
    else {
      return false;
    }
  }

  @Override
  public Class getReturnType()
  {
    MethodRefAmp localMethod = findLocalMethod();
    
    if (localMethod != null) {
      return (Class) localMethod.getReturnType();
    }
    else {
      return null;
    }
  }

  @Override
  public boolean isClosed()
  {
    ServiceRefAmp serviceRefActive = _serviceRef.getActiveService();
    
    return serviceRefActive == null;
  }

  @Override
  public void send(HeadersAmp headers, StubAmp actor, Object[] args)
  {
    MethodShim methodShim = findActiveMethodShim();

    methodShim.send(headers, actor, args);
  }

  @Override
  public void query(HeadersAmp headers, 
                    Result result,
                    StubAmp actor,
                    Object[] args)
  {
    try {
      MethodShim methodShim = findActiveMethodShim();
      
      methodShim.query(headers, result, actor, args);
    } catch (Throwable exn) {
      result.fail(exn);
    }
  }
  
  /**
   * stream call with fork/join to all nodes in the pod.
   */
  @Override
  public  void stream(HeadersAmp headers, 
                         ResultStream result,
                         StubAmp actor,
                         Object[] args)
  {
    int nodeCount = _serviceRef.getPod().nodeCount();
    
    if (nodeCount <= 1) {
      try {
        MethodShim methodShim = findActiveMethodShim();
        
        methodShim.stream(headers, result, actor, args);
      } catch (Throwable exn) {
        result.fail(exn);
      }
      return;
    }
    
    //ResultStreamJoin joinLocal = null;
    
    ResultStreamAmp resultAmp = (ResultStreamAmp) result;

    // joinLocal = new ResultStreamJoin<>(result, _serviceRef.getSelfInbox());
    
    //ResultStream createFork = joinLocal.fork();
    //ResultStream createFork = resultAmp.fork();

    for (int i = 0; i < nodeCount; i++) {
      MethodRefActive method = findMethodRefActive(i);

      if (method != null) {
        // ResultStream resultFork = joinLocal.fork();
        ResultStream resultFork = resultAmp.fork();

        // MethodRefAmp methodRef = method.getMethodRef();
        //ActorAmp actorMessage = method.getMethodRef().getActor(actor);
        //ActorAmp actorMessage = method.getMethodRef().getService().getActor();
        //actorMessage = method.getMethodRef().getActor(actorMessage);

        method.getMethodShim().stream(headers, resultFork, actor, args);
        //methodRef.stream(headers, resultFork, args);
      }
      else {
        RuntimeException exn = new IllegalStateException();
        result.fail(exn);
      }
    }

    resultAmp.forkComplete();
  }
  
  /**
   * pipe publish registration call
   */
  @Override
  public  void outPipe(HeadersAmp headers, 
                          ResultPipeOut result,
                          StubAmp actor,
                          Object[] args)
  {
    result.fail(new UnsupportedOperationException(getClass().getName()));
  }
  
  /**
   * pipe publish registration call
   */
  @Override
  public  void inPipe(HeadersAmp headers, 
                          ResultPipeIn result,
                          StubAmp actor,
                          Object[] args)
  {
    result.fail(new UnsupportedOperationException(getClass().getName()));
  }

  /**
   * Return the local method for this pod method, when the pod is on the
   * same jvm. 
   */
  private MethodRefAmp findLocalMethod()
  {
    ServiceRefAmp serviceRefLocal = _serviceRef.getLocalService();
    
    if (serviceRefLocal == null) {
      return null;
    }

    if (_type != null) {
      return serviceRefLocal.methodByName(_name, _type);
    }
    else {
      return serviceRefLocal.methodByName(_name);
    }
  }
  
  private ServiceRefAmp getLocalService()
  {
    return _serviceRef.getLocalService();
  }
  
  /**
   * Return the method shim for the given server.
   */
  private MethodShim findActiveMethodShim(int i)
  {
    MethodRefActive methodRefActive = findMethodRefActive(i);
    
    return methodRefActive.getMethodShim();
  }
  
  private MethodRefActive findMethodRefActive(int i)
  {
    ServiceRefAmp serviceRefActive = _serviceRef.getActiveService(i);
    
    if (serviceRefActive == null) {
      throw new ServiceExceptionUnavailable(L.l("No service available for {0}",
                                                _serviceRef));
    }
    
    MethodRefActive methodRefActive = createMethodRefActive(serviceRefActive);
    
    return methodRefActive;
  }
  
  private MethodShim findActiveMethodShim()
  {
    MethodRefActive methodRefActive = findMethodRefActive();
    
    return methodRefActive.getMethodShim();
  }
  
  private MethodRefActive findMethodRefActive()
  {
    ServiceRefAmp serviceRefActive = _serviceRef.getActiveService();
    
    if (serviceRefActive == null) {
      throw new ServiceExceptionUnavailable(L.l("No service available for {0}",
                                                _serviceRef));
    }

    MethodRefActive methodRefActive = _methodRefActive;
    
    if (methodRefActive == null
        || ! methodRefActive.isValid(serviceRefActive)) {
      _methodRefActive = methodRefActive = createMethodRefActive(serviceRefActive);
    }
    
    return methodRefActive;
  }
  
  /**
   * Create an MethodRefActive for the given serviceRef.
   * 
   * The MethodRefActive contains the methodRef and the cross-pod 
   * marshal/serialization shim.
   */
  private MethodRefActive createMethodRefActive(ServiceRefAmp serviceRef)
  {
    MethodRefAmp methodRef;
    
    if (_type != null) {
      methodRef = serviceRef.methodByName(_name, _type);
    }
    else {
      methodRef = serviceRef.methodByName(_name);
    }
    
    MethodShim methodShim;
    
    ClassLoader methodLoader = methodRef.serviceRef().classLoader();
    
    //System.out.println("SR: " + serviceRef + " " + serviceRef.getActor());
    
    if (methodLoader == _sourceLoader
        || serviceRef.stub() instanceof StubLink) {
      //methodShim = new MethodShimIdentity(methodRef.getMethod());
      methodShim = new MethodShimIdentity(methodRef, 
                                          isLocalService(serviceRef));
    }
    else {
      PodImport importContext; 
      
      importContext = PodImportContext.create(_sourceLoader).getPodImport(methodLoader);
      //importContext = ImportContext.create(methodLoader).getModuleImport(_sourceLoader);

      //methodShim = new MethodShimImport(methodRef.getMethod(), importContext);
      methodShim = new MethodShimImport(methodRef, importContext, 
                                        isLocalService(serviceRef));
    }
    
  
    return new MethodRefActive(serviceRef, 
                               methodRef,
                               methodShim);
  }

  private boolean isLocalService(ServiceRef serviceRef)
  {
    try {
      return (serviceRef == getLocalService());
    } catch (Exception e) {
      return false;
    }
  }
  
  @Override
  public String toString()
  {
    return (getClass().getSimpleName()
            + "[" + name()
            + "," + _serviceRef.address() + "]");
  }
  
  private static class MethodRefActive {
    private final ServiceRefAmp _serviceRef;
    private final MethodRefAmp _methodRef;
    private final MethodShim _methodShim;
    
    MethodRefActive(ServiceRefAmp serviceRef,
                    MethodRefAmp methodRef,
                    MethodShim methodShim)
    {
      _serviceRef = serviceRef;
      _methodRef = methodRef;
      _methodShim = methodShim;
    }
    
    MethodRefAmp getMethod(ServiceRefAmp serviceRefActive)
    {
      if (_serviceRef == serviceRefActive) {
        return _methodRef;
      }
      else {
        return null;
      }
    }
    
    public MethodRefAmp getMethodRef()
    {
      return _methodRef;
    }
    
    public MethodShim getMethodShim()
    {
      return _methodShim;
    }
    
    boolean isValid(ServiceRefAmp serviceRefActive)
    {
      return _serviceRef == serviceRefActive;
    }
  }
  
  private interface MethodShim
  {
    void send(HeadersAmp headers, StubAmp actor, Object []args);
    
    void query(HeadersAmp headers, Result result, StubAmp actor, Object []args);
    
     void stream(HeadersAmp headers, 
                    ResultStream queryRef,
                    StubAmp actor, 
                    Object[] args);
  }
  
  private static class MethodShimIdentity implements MethodShim
  {
    private final MethodRefAmp _methodRef;
    private final boolean _isLocalService;
    
    MethodShimIdentity(MethodRefAmp methodRef,
                       boolean isLocalService)
    {
      _methodRef = methodRef;
      _isLocalService = isLocalService;
    }

    @Override
    public void send(HeadersAmp headers, StubAmp actor, Object []args)
    {
      //_methodRef.send(headers, actor, args);
      _methodRef.method().send(headers, actor, args);
    }
    
    @Override
    public void query(HeadersAmp headers, 
                      Result result,
                      StubAmp actor,
                      Object []args)
    {
      //_methodRef.query(headers, result, actor, args);
      _methodRef.method().query(headers, result, actor, args);
    }
    
    @Override
    public  void stream(HeadersAmp headers, 
                           ResultStream result,
                           StubAmp actor, 
                           Object[] args)
    {
      //_methodRef.stream(headers, result, actor, args);
      if (_isLocalService) {
        _methodRef.method().stream(headers, result, actor, args);
      }
      else {
        ServiceRefAmp serviceRef = _methodRef.serviceRef();

        try (OutboxAmp outbox = OutboxAmp.currentOrCreate(serviceRef.manager())) {
          StreamForkMessage msg;
          
          long expires = 10000;
          
          msg = new StreamForkMessage(outbox,
                                  outbox.inbox(),
                                  headers,
                                  serviceRef,
                                  _methodRef.method(),
                                  result,
                                  expires,
                                 args);

          outbox.offer(msg);
          // XXX: Need forward stream
          // _methodRef.stream(headers, result, args);        }
        }
      }
    }
    
    @Override
    public String toString()
    {
      return getClass().getSimpleName() + "[" + _methodRef + "]";
    }
  }
  
  private static class MethodShimImport implements MethodShim
  {
    //private final MethodAmp _methodTarget;
    private final MethodRefAmp _methodRef;
    private boolean _isLocalService;
    private final PodImport _importContext;
    private ModuleMarshal[] _args;
    private ModuleMarshal _resultMarshal;
    
    MethodShimImport(MethodRefAmp methodRef,
                     PodImport importContext,
                     boolean isLocalService)
    {
      _methodRef = methodRef;
      _importContext = importContext;
      _isLocalService = isLocalService;
      
      _args = _importContext.marshalArgs(methodRef.parameters());
      
      Type retType = methodRef.getReturnType();
      
      if (retType instanceof Class) {
        Class retClass = (Class) retType;

        _resultMarshal = _importContext.marshalResult(retClass);
      }
      else {
        _resultMarshal = _importContext.marshalResult(Object.class);
      }
    }

    @Override
    public void send(HeadersAmp headers,
                     StubAmp actor,
                     Object []args)
    {
      //_methodTarget.send(headers, actor, marshalArgs(args));
      _methodRef.method().send(headers, actor, marshalArgs(args));
    }
    
    @Override
    public void query(HeadersAmp headers,
                      Result result, 
                      StubAmp actor,
                      Object []args)
    {
      ClassLoader loader = _importContext.getImportLoader();
      
      ResultImport queryRefImport
        = new ResultImport(result, _resultMarshal, loader);

      //_methodTarget.query(headers, queryRefImport, actor, marshalArgs(args));
      _methodRef.method().query(headers, queryRefImport, actor, marshalArgs(args));
    }
    
    @Override
    public  void stream(HeadersAmp headers, 
                           ResultStream result,
                           StubAmp actor, 
                           Object[] args)
    {
      ClassLoader loader = _importContext.getImportLoader();
      
      ResultStreamImport resultImport
        = new ResultStreamImport(result, _resultMarshal, loader);

      //_methodTarget.stream(headers, resultImport, actor, marshalArgs(args));
      if (_isLocalService) {
        _methodRef.method().stream(headers, resultImport, actor, marshalArgs(args));
      }
      else {
        _methodRef.stream(headers, resultImport, marshalArgs(args));
      }
    }
    
    private Object []marshalArgs(Object []args)
    {
      if (args == null) {
        return null;
      }
      
      Object []dstArgs = new Object[args.length];
      
      int len = Math.min(dstArgs.length, _args.length);
      
      for (int i = 0; i < len; i++) {
        dstArgs[i] = _args[i].convert(args[i]);
      }
      
      for (int i = len; i < dstArgs.length; i++) {
        // XXX: MarshalObject?
        dstArgs[i] = args[i];
      }
      
      return dstArgs;
    }
    
    public String toString()
    {
      return getClass().getSimpleName() + "[" + _methodRef + "]";
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy