protected void onForwardMessage(Map<String, Object> data, boolean broadcast) { logger.debug("Received {} action {}", broadcast ? "broadcast" : "forwarded", data); Map<String, Object> resultData = new HashMap<>(3); resultData.put(ID_FIELD, data.get(ID_FIELD)); resultData.put(OORT_URL_FIELD, getOort().getURL()); String oortURL = (String) data.get(OORT_URL_FIELD); try { Result<R> result = onForward(new Request(oort.getURL(), data.get(PARAMETER_FIELD), oortURL)); logger.debug("Forwarded action result {}", result); if (result.succeeded()) { resultData.put(RESULT_FIELD, true); resultData.put(DATA_FIELD, result.data); } else if (result.failed()) { resultData.put(RESULT_FIELD, false); resultData.put(DATA_FIELD, result.data); } else { if (broadcast) { // Ignore and therefore return logger.debug("Ignoring broadcast action result {}", result); return; } else { // Convert ignore into failure resultData.put(RESULT_FIELD, false); resultData.put(DATA_FIELD, result.data); } } } catch (Exception x) { if (broadcast) return; String failure = x.getMessage(); if (failure == null || failure.length() == 0) failure = x.getClass().getName(); resultData.put(RESULT_FIELD, false); resultData.put(DATA_FIELD, failure); } if (getOort().getURL().equals(oortURL)) { // Local case logger.debug("Returning forwarded action result {} to local {}", resultData, oortURL); onResultMessage(resultData); } else { // Remote case OortComet comet = getOort().getComet(oortURL); if (comet != null) { logger.debug("Returning forwarded action result {} to remote {}", resultData, oortURL); comet.getChannel(resultChannelName).publish(resultData); } else { // Probably the node disconnected concurrently logger.debug( "Could not return forwarded action result {} to remote {}", resultData, oortURL); } } }
/** * Subclasses must call this method to forward the action to the owner node. * * <p>If the {@code targetOortURL} is {@code null}, then the action is broadcast to all nodes. * Nodes that receive an action request that they can't fullfill because they don't own the entity * the action should be applied to must return {@link Result#ignore(Object)}. * * @param targetOortURL the owner node Oort URL, or null to broadcast the action to all nodes * @param parameter the action parameter that will be passed to {@link #onForward(Request)} * @param context the opaque context passed to {@link #onForwardSucceeded(Object, Object)} * @return whether the forward succeeded */ protected boolean forward(String targetOortURL, Object parameter, C context) { Map<String, Object> ctx = new HashMap<>(4); long contextId = contextIds.incrementAndGet(); ctx.put(ID_FIELD, contextId); ctx.put(CONTEXT_FIELD, context); callbacks.put(contextId, ctx); Map<String, Object> data = new HashMap<>(3); data.put(ID_FIELD, contextId); data.put(PARAMETER_FIELD, parameter); String localOortURL = getOort().getURL(); data.put(OORT_URL_FIELD, localOortURL); if (targetOortURL == null) { // Application does not know where the entity is, broadcast if (logger.isDebugEnabled()) { logger.debug("Broadcasting action: {}", data); } startTimeout(ctx); oort.getBayeuxServer().getChannel(broadcastChannelName).publish(getLocalSession(), data); return true; } else { if (localOortURL.equals(targetOortURL)) { // Local case if (logger.isDebugEnabled()) { logger.debug("Forwarding action locally ({}): {}", localOortURL, data); } startTimeout(ctx); onForwardMessage(data, false); return true; } else { // Remote case OortComet comet = getOort().getComet(targetOortURL); if (comet != null) { if (logger.isDebugEnabled()) { logger.debug("Forwarding action from {} to {}: {}", localOortURL, targetOortURL, data); } startTimeout(ctx); comet.getChannel(forwardChannelName).publish(data); return true; } else { if (logger.isDebugEnabled()) { logger.debug( "Could not forward action from {} to {}: {}", localOortURL, targetOortURL, data); } return false; } } } }
protected void receive(String cometURL) { if (!oort.getKnownComets().contains(cometURL)) { if (logger.isDebugEnabled()) logger.debug("Received comet URL via multicast: {}", cometURL); OortComet oortComet = oort.observeComet(cometURL); if (oortComet != null) { boolean elapsed = !oortComet.waitFor( getConnectTimeout(), BayeuxClient.State.CONNECTED, BayeuxClient.State.DISCONNECTED); // If we could not connect, let's disconnect, we will be advertised again if (elapsed) { if (logger.isDebugEnabled()) logger.debug("Interrupting attempts to connect to {}", cometURL); oort.deobserveComet(cometURL); } } } }