Package com.peterhi

Source Code of com.peterhi.RemoteRegistry

package com.peterhi;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.SocketAddress;
import java.util.EventListener;
import java.util.HashSet;
import java.util.Set;

import com.peterhi.ModelInputStream;

public final class RemoteRegistry {
  public static final int BODY_TYPE_DATA = 0;
  public static final int BODY_TYPE_OBJECT = 1;
 
  private static RudpLocalEndpoint localEndpoint;
  private static Set<RemoteRegistryItem> registryItems;
  private static Set<EventListener> listeners;
  private static RudpDataListener dataListener;
 
  public static RudpLocalEndpoint getLocalEndpoint() {
    return localEndpoint;
  }
 
  public static void setLocalEndpoint(RudpLocalEndpoint localEndpoint) {
    if (RemoteRegistry.localEndpoint != null) {
      RemoteRegistry.localEndpoint.removeListener(getDataListener());
    }
   
    RemoteRegistry.localEndpoint = localEndpoint;
   
    if (RemoteRegistry.localEndpoint != null) {
      RemoteRegistry.localEndpoint.addListener(getDataListener());
    }
  }
 
  public static boolean publish(String name, Class<?> type, RemoteObject object) {
    synchronized (getRegistryItems()) {
      RemoteRegistryItem registryItem = new RemoteRegistryItem(name, type, object);
      boolean result = getRegistryItems().add(registryItem);
      return result;
    }
  }
 
  public static <T extends RemoteObject> T subscribe(SocketAddress address, String name, final Class<T> type, int timeout) throws IOException {
    final Reference<Object> reference = new Reference<Object>();
    final RemoteRequest request = ModelUtilities.newInstance(RemoteRequest.class);
    request.setName(name);
    request.setOperationId(request.hashCode());
   
    RudpDataListener callbackDataListener = new RudpDataListener() {
      @Override
      public void received(RudpDataEvent event) {
        Object object = processObject(event);
       
        if (!(object instanceof RemoteResponse)) {
          return;
        }
       
        RemoteResponse response = (RemoteResponse )object;
       
        if (response.getOperationId() != request.getOperationId()) {
          return;
        }
       
        if (response.getResult() == RemoteResponse.SUCCESS_OK) {
          reference.setArgument(response.getObjectId());
        } else if (response.getResult() == RemoteResponse.FAIL_CLASS_NOT_FOUND) {
          reference.setArgument(new ClassNotFoundException(type.toString()));
        }
       
        synchronized (request) {
          request.notifyAll();
        }
      }
    };
   
    localEndpoint.addListener(callbackDataListener);
    postObject(address, request);
   
    synchronized (request) {
      try {
        request.wait(timeout);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
   
    localEndpoint.removeListener(callbackDataListener);
   
    if (reference.getArgument() instanceof Exception) {
      throw new IOException((Exception )reference.getArgument());
    }
   
    if (reference.getArgument() instanceof Integer) {
      Integer objectId = (Integer )reference.getArgument();
      ClassLoader loader = type.getClassLoader();
      Class<?>[] types = new Class<?>[] { type };
      InvocationHandler invocationHandler = new RemoteInvocationHandler(type, address, objectId, timeout);
      Object proxy = Proxy.newProxyInstance(loader, types, invocationHandler);
      return type.cast(proxy);
    }
   
    throw new IllegalStateException();
  }
 
  protected static Object processObject(RudpDataEvent event) {
    if (!event.isReliable()) {
      return null;
    }
   
    try {
      Object object = null;
      InputStream is = event.getInputStream();
      is.mark(0);
      int bodyType = is.read();
     
      if (bodyType == BODY_TYPE_OBJECT) {
        ModelInputStream mis = new ModelInputStream(is);
        object = mis.readModel();
      }
     
      is.reset();
      return object;
    } catch (Exception ex) {
      ex.printStackTrace();
      return null;
    }
  }
 
  protected static void postObject(SocketAddress address, Model model) {
    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      baos.write(BODY_TYPE_OBJECT);
      ModelOutputStream mos = new ModelOutputStream(baos);
      mos.writeModel(model);
      byte[] data = baos.toByteArray();
      localEndpoint.post(address, data, 0, data.length, new Callback<RudpResult>() {
        @Override
        public void callback(RudpResult argument) {
        }
      });
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
 
  private static Set<RemoteRegistryItem> getRegistryItems() {
    if (registryItems == null) {
      registryItems = new HashSet<RemoteRegistryItem>();
    }
   
    return registryItems;
  }
 
  private static Set<EventListener> getListeners() {
    if (listeners == null) {
      listeners = new HashSet<EventListener>();
    }
   
    return listeners;
  }
 
  public static <T extends EventListener> T registerListener(T listener) {
    synchronized (getListeners()) {
      getListeners().add(listener);
    }
   
    return listener;
  }
 
  public static <T extends EventListener> T unregisterListener(T listener) {
    synchronized (getListeners()) {
      getListeners().remove(listener);
    }
   
    return listener;
  }
 
  public static <T extends EventListener> T getListener(int hashCode) {
    synchronized (getListeners()) {
      for (EventListener listener : getListeners()) {
        if (listener.hashCode() == hashCode) {
          return (T )listener;
        }
      }
    }
   
    return null;
  }
 
  public static boolean isListenerRegistered(EventListener listener) {
    synchronized (getListeners()) {
      for (EventListener element : getListeners()) {
        if (element.equals(listener)) {
          return true;
        }
      }
    }
   
    return false;
  }
 
  private static RudpDataListener getDataListener() {
    if (dataListener == null) {
      dataListener = new RudpDataListener() {
        @Override
        public void received(RudpDataEvent event) {
          onReceived(event);
        }
      };
    }
   
    return dataListener;
  }
 
  private static RemoteRegistryItem getRegistryItem(String name) {
    synchronized (getRegistryItems()) {
      for (RemoteRegistryItem registryItem : getRegistryItems()) {
        if (registryItem.getName().equals(name)) {
          return registryItem;
        }
      }
    }
   
    return null;
  }
 
  private static RemoteRegistryItem getRegistryItem(int objectId) {
    synchronized (getRegistryItems()) {
      for (RemoteRegistryItem registryItem : getRegistryItems()) {
        if (registryItem.getObject().hashCode() == objectId) {
          return registryItem;
        }
      }
    }
   
    return null;
  }
 
  private static void onReceived(RudpDataEvent event) {
    Object object = processObject(event);
   
    if (object instanceof RemoteRequest) {
      RemoteRequest request = (RemoteRequest )object;
      RemoteRegistryItem item = getRegistryItem(request.getName());
      RemoteResponse response = ModelUtilities.newInstance(RemoteResponse.class);
      response.setOperationId(request.getOperationId());
     
      if (item != null) {
        response.setResult(RemoteResponse.SUCCESS_OK);
        response.setObjectId(item.getObject().hashCode());
      } else {
        response.setResult(RemoteResponse.FAIL_CLASS_NOT_FOUND);
      }
     
      postObject(event.getSocketAddress(), response);
    } else if (object instanceof RemoteCall) {
      RemoteCall call = (RemoteCall )object;
      RemoteRegistryItem item = getRegistryItem(call.getObjectId());
     
      if (item != null) {
        RemoteReturn ret = ModelUtilities.newInstance(RemoteReturn.class);
        ret.setOperationId(call.getOperationId());
        Method method = getMethod(item.getObject().getClass(), call.getName(), call.getParameters());
       
        try {
          ret.setReturnValue(method.invoke(item.getObject(), transformListeners(event.getSocketAddress(), method, call.getParameters())));
          ret.setResult(RemoteReturn.SUCCESS_OK);
        } catch (Exception ex) {
          ex.printStackTrace();
          ret.setErrorMessage(ex.toString());
          ret.setResult(RemoteReturn.FAIL_ERROR);
        }
       
        postObject(event.getSocketAddress(), ret);
      } else {
        EventListener listener = getListener(call.getObjectId());
       
        if (listener == null) {
          throw new IllegalArgumentException("Listener not registered.");
        }
       
        RemoteReturn ret = ModelUtilities.newInstance(RemoteReturn.class);
        ret.setOperationId(call.getOperationId());
        Method method = getMethod(listener.getClass(), call.getName(), call.getParameters());
       
        try {
          ret.setReturnValue(method.invoke(listener, transformListeners(event.getSocketAddress(), method, call.getParameters())));
          ret.setResult(RemoteReturn.SUCCESS_OK);
        } catch (Exception ex) {
          ex.printStackTrace();
          ret.setErrorMessage(ex.toString());
          ret.setResult(RemoteReturn.FAIL_ERROR);
        }
       
        postObject(event.getSocketAddress(), ret);
      }
    }
  }
 
  private static Object[] transformListeners(SocketAddress address, Method method, Object[] parameters) {
    Class<?>[] types = method.getParameterTypes();
   
    for (int i = 0; i < types.length; i++) {
      Class<?> type = types[i];
     
      if (EventListener.class.isAssignableFrom(type) && parameters[i] instanceof Integer) {
        int objectId = (Integer )parameters[i];
        EventListener listener = getListener(objectId);
       
        if (listener == null) {
          ClassLoader loader = type.getClassLoader();
          Class<?>[] interfaces = new Class<?>[] { type };
          InvocationHandler invocationHandler = new RemoteInvocationHandler(type, address, objectId, 0);
          listener = (EventListener )Proxy.newProxyInstance(loader, interfaces, invocationHandler);
        }
       
        parameters[i] = listener;
      }
    }
   
    return parameters;
  }
 
  private static Method getMethod(Class<?> type, String name, Object[] args) {
    if (args == null) {
      args = new Object[0];
    }
   
    Method[] methods = type.getMethods();
    Method method = null;
   
    for (Method element : methods) {
      if (!element.getName().equals(name)) {
        continue;
      }
     
      if (element.getParameterTypes().length != args.length) {
        continue;
      }
     
      method = element;
      break;
    }
   
    return method;
  }
}
TOP

Related Classes of com.peterhi.RemoteRegistry

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.