protected Oort startOort(Server server) throws Exception { String url = (String) server.getAttribute(OortConfigServlet.OORT_URL_PARAM); final BayeuxServer bayeuxServer = (BayeuxServer) server.getAttribute(BayeuxServer.ATTRIBUTE); Oort oort = new Oort(bayeuxServer, url); oort.setClientDebugEnabled(Boolean.getBoolean("debugTests")); oort.start(); oorts.add(oort); return oort; }
protected BayeuxClient startClient(Oort oort, Map<String, Object> handshakeFields) { BayeuxClient client = new BayeuxClient(oort.getURL(), new LongPollingTransport(null, oort.getHttpClient())); client.setDebugEnabled(Boolean.getBoolean("debugTests")); client.handshake(handshakeFields); client.waitFor(5000, BayeuxClient.State.CONNECTED); clients.add(client); return client; }
@Override protected void doStop() throws Exception { oort.deobserveChannel(broadcastChannelName); BayeuxServer bayeuxServer = oort.getBayeuxServer(); bayeuxServer.getChannel(resultChannelName).removeListener(this); bayeuxServer.getChannel(broadcastChannelName).removeListener(this); bayeuxServer.getChannel(forwardChannelName).removeListener(this); session.disconnect(); logger.debug("Stopped {}", this); }
@Override protected void doStart() throws Exception { session.handshake(); BayeuxServer bayeuxServer = oort.getBayeuxServer(); bayeuxServer.createChannelIfAbsent(forwardChannelName).getReference().addListener(this); bayeuxServer.createChannelIfAbsent(broadcastChannelName).getReference().addListener(this); bayeuxServer.createChannelIfAbsent(resultChannelName).getReference().addListener(this); oort.observeChannel(broadcastChannelName); logger.debug("Started {}", this); }
/** * Creates an {@link OortService} with the given name. * * @param oort the Oort where this service lives * @param name the unique name across the cluster of this service */ protected OortService(Oort oort, String name) { this.oort = oort; this.name = name; this.forwardChannelName = "/service/oort/service/" + name; this.broadcastChannelName = "/oort/service/" + name; this.resultChannelName = forwardChannelName + "/result"; this.session = oort.getBayeuxServer().newLocalSession(name); this.logger = LoggerFactory.getLogger( getClass().getName() + "." + Oort.replacePunctuation(oort.getURL(), '_') + name); }
private void startTimeout(Map<String, Object> ctx) { long contextId = ((Number) ctx.get(ID_FIELD)).longValue(); TimeoutTask timeoutTask = new TimeoutTask(contextId); ctx.put( TIMEOUT_FIELD, ((BayeuxServerImpl) oort.getBayeuxServer()).schedule(timeoutTask, getTimeout())); }
@Test public void testTwoComets() throws Exception { Server server1 = startServer(0); int groupPort = ((NetworkConnector) server1.getConnectors()[0]).getLocalPort(); Oort oort1 = startOort(server1); startConfigurer(oort1, groupPort); Server server2 = startServer(0); Oort oort2 = startOort(server2); startConfigurer(oort2, groupPort); // Give some time to advertise Thread.sleep(1000); Assert.assertEquals(1, oort1.getKnownComets().size()); Assert.assertEquals(1, oort2.getKnownComets().size()); }
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); } } } }
@Override protected void doStop() throws Exception { oort.deobserveChannel(broadcastChannelName); BayeuxServer bayeuxServer = oort.getBayeuxServer(); ServerChannel channel = bayeuxServer.getChannel(resultChannelName); if (channel != null) { channel.removeListener(this); } channel = bayeuxServer.getChannel(broadcastChannelName); if (channel != null) { channel.removeListener(this); } channel = bayeuxServer.getChannel(forwardChannelName); if (channel != null) { channel.removeListener(this); } session.disconnect(); if (logger.isDebugEnabled()) { logger.debug("Stopped {}", this); } }
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 stopOort(Oort oort) throws Exception { oort.stop(); }
@Test public void testThreeComets() throws Exception { Server server1 = startServer(0); int groupPort = ((NetworkConnector) server1.getConnectors()[0]).getLocalPort(); Oort oort1 = startOort(server1); startConfigurer(oort1, groupPort); Server server2 = startServer(0); Oort oort2 = startOort(server2); final OortMulticastConfigurer configurer2 = startConfigurer(oort2, groupPort); // Give some time to advertise Thread.sleep(1000); Assert.assertEquals(1, oort1.getKnownComets().size()); Assert.assertEquals(1, oort2.getKnownComets().size()); // Create another comet Server server3 = startServer(0); Oort oort3 = startOort(server3); startConfigurer(oort3, groupPort); // Give some time to advertise Thread.sleep(1000); Assert.assertEquals(2, oort1.getKnownComets().size()); Assert.assertEquals(2, oort2.getKnownComets().size()); Assert.assertEquals(2, oort3.getKnownComets().size()); stopConfigurer(configurer2); stopOort(oort2); stopServer(server2); // Give some time to advertise Thread.sleep(1000); Assert.assertEquals(1, oort1.getKnownComets().size()); Assert.assertEquals(oort3.getURL(), oort1.getKnownComets().iterator().next()); Assert.assertEquals(1, oort3.getKnownComets().size()); Assert.assertEquals(oort1.getURL(), oort3.getKnownComets().iterator().next()); }
public OortMulticastConfigurer(Oort oort) { this.logger = LoggerFactory.getLogger( getClass().getName() + "." + Oort.replacePunctuation(oort.getURL(), '_')); this.oort = oort; }