package com.kurento.tool.rom.client; import java.lang.reflect.Type; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.*; import com.kurento.kmf.jsonrpcconnector.Props; import com.kurento.kmf.media.Continuation; import com.kurento.tool.rom.transport.serialization.ParamsFlattener; public class RemoteObject { private static Logger LOG = LoggerFactory.getLogger(RemoteObject.class); private static ParamsFlattener FLATTENER = ParamsFlattener.getInstance(); public interface EventListener { public void onEvent(String eventType, Props data); } private final String objectRef; private final RomClient client; private final RomClientObjectManager manager; private final String type; // This object is used in the process of unflatten. It is common that // RemoteObject is used with a Typed wrapper (with reflexion, with code // generation or by hand). In this cases, the object reference is unflatten // to this value instead of RemoteObject itself. private Object wrapperForUnflatten; private final Multimap<String, EventListener> listeners = Multimaps .synchronizedMultimap(ArrayListMultimap .<String, EventListener> create()); public RemoteObject(String objectRef, String type, RomClient client, RomClientObjectManager manager) { this.objectRef = objectRef; this.client = client; this.manager = manager; this.type = type; this.manager.registerObject(objectRef, this); } public Object getWrapperForUnflatten() { return wrapperForUnflatten; } public void setWrapperForUnflatten(Object wrapperForUnflatten) { this.wrapperForUnflatten = wrapperForUnflatten; } @SuppressWarnings("unchecked") public <E> E invoke(String method, Props params, Class<E> clazz) { Type flattenType = FLATTENER.calculateFlattenType(clazz); Object obj = invoke(method, params, flattenType); return (E) FLATTENER.unflattenValue("return", clazz, obj, manager); } public Object invoke(String method, Props params, Type type) { Type flattenType = FLATTENER.calculateFlattenType(type); Object obj = client.invoke(objectRef, method, params, flattenType); return FLATTENER.unflattenValue("return", type, obj, manager); } @SuppressWarnings("rawtypes") public void invoke(String method, Props params, final Type type, final Continuation cont) { Type flattenType = FLATTENER.calculateFlattenType(type); client.invoke(objectRef, method, params, flattenType, new DefaultContinuation<Object>(cont) { @SuppressWarnings("unchecked") @Override public void onSuccess(Object result) { try { cont.onSuccess(FLATTENER.unflattenValue("return", type, result, manager)); } catch (Exception e) { log.warn( "[Continuation] error invoking onSuccess implemented by client", e); } } }); } public void release() { client.release(objectRef); this.manager.releaseObject(objectRef); } public void release(final Continuation<Void> cont) { client.release(objectRef, new DefaultContinuation<Void>(cont) { @Override public void onSuccess(Void result) { manager.releaseObject(objectRef); try { cont.onSuccess(null); } catch (Exception e) { log.warn( "[Continuation] error invoking onSuccess implemented by client", e); } } }); } public ListenerSubscription addEventListener(String eventType, EventListener listener) { String subscription = client.subscribe(objectRef, eventType); listeners.put(eventType, listener); return new ListenerSubscription(subscription, eventType, listener); } public void addEventListener(final String eventType, final Continuation<ListenerSubscription> cont, final EventListener listener) { client.subscribe(objectRef, eventType, new DefaultContinuation<String>( cont) { @Override public void onSuccess(String subscription) { listeners.put(eventType, listener); try { cont.onSuccess(new ListenerSubscription(subscription, eventType, listener)); } catch (Exception e) { log.warn( "[Continuation] error invoking onSuccess implemented by client", e); } } }); } public String getObjectRef() { return objectRef; } public void fireEvent(String type, Props data) { for (EventListener eventListener : this.listeners.get(type)) { try { eventListener.onEvent(type, data); } catch (Exception e) { LOG.error("Exception executing event listener", e); } } } public String getType() { return type; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((objectRef == null) ? 0 : objectRef.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; } RemoteObject other = (RemoteObject) obj; if (objectRef == null) { if (other.objectRef != null) { return false; } } else if (!objectRef.equals(other.objectRef)) { return false; } return true; } }