Package com.kurento.tool.rom.client

Source Code of com.kurento.tool.rom.client.RemoteObjectInvocationHandler

package com.kurento.tool.rom.client;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.kurento.kmf.jsonrpcconnector.Props;
import com.kurento.kmf.media.Continuation;
import com.kurento.kmf.media.events.Event;
import com.kurento.kmf.media.events.MediaEventListener;
import com.kurento.tool.rom.ParamAnnotationUtils;
import com.kurento.tool.rom.server.FactoryMethod;

public class RemoteObjectInvocationHandler extends DefaultInvocationHandler {

  private static final Logger LOG = LoggerFactory
      .getLogger(RemoteObjectInvocationHandler.class);

  private final RemoteObject remoteObject;
  private final RemoteObjectFactory factory;

  @SuppressWarnings("unchecked")
  public static <E> E newProxy(RemoteObject remoteObject,
      RemoteObjectFactory factory, Class<E> clazz) {

    RemoteObjectInvocationHandler handler = new RemoteObjectInvocationHandler(
        remoteObject, factory);
    Object proxy = Proxy.newProxyInstance(clazz.getClassLoader(),
        new Class[] { clazz }, handler);

    // This automatically unflatten this remote object with the wrapper
    // instead of with the remote object itself
    remoteObject.setWrapperForUnflatten(proxy);

    return (E) proxy;
  }

  private RemoteObjectInvocationHandler(RemoteObject remoteObject,
      RemoteObjectFactory factory) {
    this.remoteObject = remoteObject;
    this.factory = factory;
  }

  @Override
  public Object internalInvoke(final Object proxy, Method method,
      Object[] args) throws Throwable {

    Continuation<?> cont = null;
    if (args != null && args[args.length - 1] instanceof Continuation) {
      cont = (Continuation<?>) args[args.length - 1];
      args = Arrays.copyOf(args, args.length - 1);
    }

    String methodName = method.getName();

    if (method.getAnnotation(FactoryMethod.class) != null) {

      Props props = ParamAnnotationUtils.extractProps(
          method.getParameterAnnotations(), args);

      return createBuilderObject(proxy, method, methodName, props);

    } else if (methodName.equals("release")) {

      return release(cont);

    } else if (methodName.startsWith("add")
        && methodName.endsWith("Listener")) {

      return subscribeEventListener(proxy, args, methodName, cont);

    } else {

      return invoke(method, args, cont);
    }
  }

  private Object invoke(Method method, Object[] args, Continuation<?> cont) {

    Props props = ParamAnnotationUtils.extractProps(
        method.getParameterAnnotations(), args);

    if (cont != null) {

      Type[] paramTypes = method.getGenericParameterTypes();
      ParameterizedType contType = (ParameterizedType) paramTypes[paramTypes.length - 1];
      Type returnType = contType.getActualTypeArguments()[0];
      remoteObject.invoke(method.getName(), props, returnType, cont);
      return null;
    }

    return remoteObject.invoke(method.getName(), props,
        method.getGenericReturnType());

  }

  @SuppressWarnings("unchecked")
  private Object release(Continuation<?> cont) {
    if (cont != null) {
      remoteObject.release((Continuation<Void>) cont);
    } else {
      remoteObject.release();
    }
    return null;
  }

  @SuppressWarnings("unchecked")
  private Object subscribeEventListener(final Object proxy,
      final Object[] args, String methodName, Continuation<?> cont) {

    String event = methodName.substring(3,
        methodName.length() - "Listener".length());

    RemoteObject.EventListener listener = new RemoteObject.EventListener() {
      @Override
      public void onEvent(String eventType, Props data) {
        propagateEventTo(proxy, eventType, data,
            (MediaEventListener<?>) args[0]);
      }
    };

    if (cont != null) {
      remoteObject.addEventListener(event,
          (Continuation<ListenerSubscription>) cont, listener);
      return null;
    }

    return remoteObject.addEventListener(event, listener);

  }

  private Object createBuilderObject(final Object proxy, Method method,
      String methodName, Props props) {

    if (props == null) {
      props = new Props();
    }

    FactoryMethod annotation = method.getAnnotation(FactoryMethod.class);
    props.add(annotation.value(), remoteObject.getObjectRef());

    Class<?> builderClass = method.getReturnType();

    return Proxy.newProxyInstance(this.getClass().getClassLoader(),
        new Class[] { method.getReturnType() },
        new BuilderInvocationHandler(builderClass.getEnclosingClass(),
            props, factory));

  }

  @SuppressWarnings({ "unchecked", "rawtypes" })
  protected void propagateEventTo(Object object, String eventType,
      Props data, MediaEventListener<?> listener) {

    // TODO Optimise this to create only one event for all listeners

    try {

      Class<?> eventClass = Class.forName("com.kurento.kmf.media.events."
          + eventType + "Event");

      Constructor<?> constructor = eventClass.getConstructors()[0];

      Object[] params = ParamAnnotationUtils.extractEventParams(
          constructor.getParameterAnnotations(), data);

      params[0] = object;

      Event e = (Event) constructor.newInstance(params);

      ((MediaEventListener) listener).onEvent(e);

    } catch (Exception e) {
      LOG.error("Exception while processing event '" + eventType
          + "' with params '" + data + "'", e);
    }
  }

  public RemoteObject getRemoteObject() {
    return remoteObject;
  }

  @Override
  public String toString() {
    return "[RemoteObject: type=" + this.remoteObject.getType()
        + " remoteRef=" + remoteObject.getObjectRef() + "";
  }

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result
        + ((remoteObject == null) ? 0 : remoteObject.hashCode());
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null) {
      return false;
    }
    if (getClass() != obj.getClass()) {
      return false;
    }
    RemoteObjectInvocationHandler other = (RemoteObjectInvocationHandler) obj;
    if (remoteObject == null) {
      if (other.remoteObject != null) {
        return false;
      }
    } else if (!remoteObject.equals(other.remoteObject)) {
      return false;
    }
    return true;
  }

}
TOP

Related Classes of com.kurento.tool.rom.client.RemoteObjectInvocationHandler

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.