@Override public void onReconnected() { log.info("reconnected"); if (mode.contains(MODE.RESEND_SUBSCRIBE_ON_RECONNECTED)) { Set<String> channels; // channel as sourceDispatcherId channels = new HashSet<String>(); channels.add(getSourceDispatcherId()); driverImpl.subscribeChannels(channels); // channels as object_IDs registered with localObjectsMap channels = localObjectsMap.keySet(); if (!channels.isEmpty()) { driverImpl.subscribeChannels(channels); } // all channels registered with subscribersMap channels = subscribersMap.getSubscribedChannels(); if (!channels.isEmpty()) { driverImpl.subscribeChannels(channels); } // re-SUBSCRIBE completed with all the registered channels. pubSubDriverSuspended = false; // Resumed } else { // You may add some code here to inform other objects that // the network connectivity has resumed or the pubsub server // has become available. } }
/** * Closes the services. * * <p>You can also do "try-with-resources" to automatically close this class. */ public void close() { // TODO: Graceful termination of all the components and the transport // TODO: subscriptionFeeder termination driverImpl.close(); remoteTransactions.onFinalize(); subscribersMap.clear(); log.info("terminated"); }
/** * Channel unsubscription service. * * @param subscriberId subscriber's object ID * @param channelsToBeUnsubscribed channels to be unsubscribed */ public void unsubscribeChannels( final String subscriberId, final Map<String, Set<String>> channelsToBeUnsubscribed) { Set<String> channels = new HashSet<>(); for (String publisherId : channelsToBeUnsubscribed.keySet()) { Set<String> eventIds = channelsToBeUnsubscribed.get(publisherId); for (String eventId : eventIds) { String channel = channelString(publisherId, eventId); if (subscribersMap.removeSubscription(channel, subscriberId)) { channels.add(channel); } } } if (!channels.isEmpty() && !pubSubDriverSuspended) { driverImpl.unsubscribeChannels(channels); } }
/** * 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); } }