/** * @param config {@link MessageDispatcher}'s config * @see org.o3project.odenos.remoteobject.messagingclient.redis.PubSubDriverImpl */ public MessageDispatcher(Config config) { // Config systemManagerId = config.getSystemManagerId(); eventManagerId = config.getEventManagerId(); sourceDispatcherId = config.getSourceDispatcherId(); mode = config.getMode(); localRequestsToPubSubServer = config.getMode().contains(MODE.LOCAL_REQUESTS_TO_PUBSUB); // Actor system instantiation. // The number of woker threads: the max number of remote transactions. actor = Actor.getInstance(config.getRemoteTransactionsMax()); // Instantiates IPubSubDriver impl. class ClassLoader classLoader = ClassLoader.getSystemClassLoader(); try { Class<?> clazz = classLoader.loadClass(config.getPubSubDriverImpl()); Constructor<?> constructor = clazz.getDeclaredConstructor(Config.class, IMessageListener.class); driverImpl = (IPubSubDriver) constructor.newInstance(config, this); } catch (Exception e) { log.error("class load error", e); } // Remote Transactions pool remoteTransactions = new RemoteTransactions(this, config); }
/** * 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); } }