/** * Removes a local object. * * <p>This method also sends "UNSUBSCRIBE own-object-ID-as-channel" to pubsub server to stop * receiving PUBLISH destined to the remote object. * * @param localObject a remote object */ public void removeLocalObject(RemoteObject localObject) { String objectId = localObject.getObjectId(); if (localObjectsMap.remove(objectId) != null) { // Unsubscribes objectId as a channel to stop receiving Request // from remote objects via PubSub. driverImpl.unsubscribeChannel(objectId); } }
/** * Adds a local object as a listener of messages. * * <p>The user (i.e., RemoteObject) of this class calls this method to register the RemoteObject * as "local RemoteObject" with this class. * * <pre> * [RemoteObject] [RemoteObject] [RemoteObject] * dispatchEvent() dispatchRequest() dispatchRequest() * ^ ^ ^ * | | | * +---------------+ + +---------------+ * | | | * [MessageDispatcher]<>-----[SubscribersMap] * | * message * | * [pubsub server] * </pre> * * <p>This method also sends "SUBSCRIBE own-object-ID-as-channel" to pubsub server to receive * PUBLISH destined to the remote object, since requestSync() method sends PUBLISH as "request" to * the remote object. * * @param localObject a remote object * @see org.o3project.odenos.remoteobject.RemoteObject#dispatchEvent * @see org.o3project.odenos.remoteobject.RemoteObject#dispatchRequest */ public void addLocalObject(RemoteObject localObject) { String objectId = localObject.getObjectId(); if (localObjectsMap.putIfAbsent(objectId, localObject) == null) { driverImpl.subscribeChannel(objectId); } if (objectId.equals(systemManagerId)) { driverImpl.systemManagerAttached(); } }
/** * Synchronous request/response service (remote transactions) * * <p>This method operates in two modes: * * <ul> * <li>if the request is to "local RemoteObject", then this method works like a local loopback * interface to dispatch the request to "local RemoteObject". * <li>else if the request is to "remote RemoteObject", then this method uses RemoteTransactions * class to send the request to "remote RemoteObject" via pubsub server. * </ul> * * <pre> * (local) * [RemoteObject] [RemoteObject] * requestSync() ^ * | | * | | * +---------------+ * loopback * * (remote) * [RemoteObject] [RemoteObject] * requsetSync() ^ * | | * | | * +-------[pubsub server]-------+ * </pre> * * @param request Request to be sent * @return Response response to the request * @throws Exception exception */ public Response requestSync(Request request) throws Exception { String objectId = request.objectId; Response response; RemoteObject localObject = localObjectsMap.get(objectId); if (localObject != null && !localRequestsToPubSubServer) { // synchronized with Actor#read() synchronized (localObject) { Request requested = deepCopy(request); Response responsed = localObject.dispatchRequest(requested); response = deepCopy(responsed); } // TODO: remoteObjectsMap is not unused. } else if (remoteObjectsMap.containsKey(objectId)) { response = remoteTransactions.sendRequest(request); } else { // request to an unregistered remote object remoteObjectsMap.put(objectId, Boolean.valueOf(false)); response = remoteTransactions.sendRequest(request); } return response; }
// When closed, componentManager will be deleted. (Expect when // componentManager is finalized, the components created by it automatically // deleted.) @Override public void onFinalize() { deleteAllComponentConnection(); deleteAllComponentManagers(); super.onFinalize(); }
/** * onMessage implementation. * * <p>This method has two roles: * * <ul> * <li>Works like a mail transfer agent to transfer a received request or event to {@link * org.o3project.odenos.remoteobject.RemoteObject}. * <li>Supports both synchronous and asynchronous messaging. * </ul> */ @Override public void onMessage(final String channel, byte[] message) { serial++; // Serial number for incoming messages. try { BufferUnpacker upk = msgpack.createBufferUnpacker(message); // read delivery header. byte type = upk.readByte(); final int sno = upk.readInt(); // Sequence number for outgoing request messages. final String sourceObjectId = upk.readString(); // i.e., channel RemoteObject localObject = null; Queue<Mail> mailbox = null; Mail mail = null; switch (type) { case TYPE_REQUEST: // Transaction(request): synchronous operation /* * --- request --> dispatchRequest() -------> [RemoteObject] * | * <-- response --- publishResponseAsync() <-------+ */ final Request request = upk.read(Request.class); if (log.isDebugEnabled()) { log.debug( "Request received:\n" + " MessageDispatcher: {}\n" + " sno: {}\n" + " channel: {}\n" + " method: {}\n" + " objectId: {}\n" + " sourceObjectId: {}\n" + " path: /{}/\n" + " body: {}", sourceDispatcherId, sno, channel, request.method, request.objectId, sourceObjectId, request.path, request.getBodyValue()); } // Wraps the request with Mail and deliver it to a mailbox. String to = request.objectId; mail = new Mail(serial, sno, to, sourceObjectId, this, request, null); localObject = localObjectsMap.get(to); if (localObject != null) { mailbox = localObject.getMailbox(); synchronized (mailbox) { mailbox.add(mail); if (!localObject.isRunning()) { localObject.setRunning(true); // Assigns a thread to read a mail in the mailbox. actor.read(localObject); } } } break; case TYPE_RESPONSE: // Transaction(response): synchronous operation /* * publishRequestAsync() * requestSync() -> [RemoteTransaction] ---- request -----> [RemoteObject] * <-- ^ | * | publishResponseAsync() * | | * +- signalResponse() <-- response --+ */ Response response = upk.read(Response.class); if (log.isDebugEnabled()) { log.debug( "Response received:\n" + " MessageDispatcher: {}\n" + " channel: {}\n" + " statusCode: {}\n" + " body: {}", sourceDispatcherId, channel, response.statusCode, response.getBodyValue()); } remoteTransactions.signalResponse(sno, response); break; case TYPE_EVENT: // Asynchronous /* * publishEventAsync() -- event --> dispatchEvent() --> [RemoteObject] * : * [EventSubscriptionMap] */ final Event event = upk.read(Event.class); if (log.isDebugEnabled()) { log.debug( "Event received:\n" + " MessageDispatcher: {}\n" + " channel: {}\n" + " body: {}", sourceDispatcherId, channel, event.getBodyValue()); } // All the subscribers of the channel final Collection<String> subscribers = subscribersMap.getSubscribers(channel); if (subscribers == null) { // No subscribers found on the channel if (log.isDebugEnabled()) { log.debug("no subscribers subscribing the channel: {}", channel); } return; // Silently discards the event } // Wraps the event with Mail and deliver it to a mailbox. for (String subscriber : subscribers) { localObject = localObjectsMap.get(subscriber); if (localObject != null) { mail = new Mail(serial, sno, subscriber, channel, this, null, event); mailbox = localObject.getMailbox(); synchronized (mailbox) { mailbox.add(mail); if (!localObject.isRunning()) { localObject.setRunning(true); // Assigns a thread to read a mail in the mailbox. actor.read(localObject); } } } } break; default: break; } } catch (Exception e) { log.error("onMessage failed", e); } }