/* * Copyright (c) 2008-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.cometd.oort; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.cometd.bayeux.server.BayeuxServer; import org.cometd.bayeux.server.ServerChannel; import org.cometd.bayeux.server.ServerMessage; import org.cometd.bayeux.server.ServerSession; import org.cometd.client.BayeuxClient; import org.eclipse.jetty.server.Server; import org.junit.After; import org.junit.Assert; import org.junit.Before; public abstract class AbstractOortObjectTest extends OortTest { private final List<OortObject<?>> oortObjects = new ArrayList<>(); protected Oort oort1; protected Oort oort2; public AbstractOortObjectTest(String serverTransport) { super(serverTransport); } @Before public void prepare() throws Exception { prepare(new HashMap<String, String>()); } protected void prepare(Map<String, String> options) throws Exception { Server server1 = startServer(0, options); oort1 = startOort(server1); Server server2 = startServer(0, options); oort2 = startOort(server2); CountDownLatch latch = new CountDownLatch(2); CometJoinedListener listener = new CometJoinedListener(latch); oort1.addCometListener(listener); oort2.addCometListener(listener); OortComet oortComet12 = oort1.observeComet(oort2.getURL()); Assert.assertTrue(oortComet12.waitFor(5000, BayeuxClient.State.CONNECTED)); Assert.assertTrue(latch.await(5, TimeUnit.SECONDS)); OortComet oortComet21 = oort2.findComet(oort1.getURL()); Assert.assertNotNull(oortComet21); Assert.assertTrue(oortComet21.waitFor(5000, BayeuxClient.State.CONNECTED)); } @After public void dispose() throws Exception { for (int i = oortObjects.size() - 1; i >= 0; --i) { oortObjects.get(i).stop(); } } protected <T> void startOortObjects(OortObject<T> oortObject1, OortObject<T> oortObject2) throws Exception { String channelName = oortObject1.getChannelName(); CometSubscriptionListener listener1 = new CometSubscriptionListener(channelName, 1); oort1.getBayeuxServer().addListener(listener1); CometSubscriptionListener listener2 = new CometSubscriptionListener(channelName, 1); oort2.getBayeuxServer().addListener(listener2); OortObjectInitialListener<T> initialListener = new OortObjectInitialListener<>(2); oortObject1.addListener(initialListener); oortObject2.addListener(initialListener); oortObject1.start(); // Wait for node1 to be subscribed on node2 Assert.assertTrue(listener2.await(5, TimeUnit.SECONDS)); oortObject2.start(); // Wait for node2 to be subscribed on node1 Assert.assertTrue(listener1.await(5, TimeUnit.SECONDS)); // Wait for initialization of the oort objects on both nodes Assert.assertTrue(initialListener.await(5, TimeUnit.SECONDS)); oortObjects.add(oortObject1); oortObjects.add(oortObject2); logger.info("oort_object_1 -> {}", oortObject1.getOort().getURL()); logger.info("oort_object_2 -> {}", oortObject2.getOort().getURL()); } /** * A {@link BayeuxServer.SubscriptionListener} that is used to detect * whether nodeA is subscribed on nodeB on the given channel. */ public static class CometSubscriptionListener implements BayeuxServer.SubscriptionListener { private final String channelName; private final CountDownLatch latch; public CometSubscriptionListener(String channelName, int parties) { this.channelName = channelName; this.latch = new CountDownLatch(parties); } @Override public void subscribed(ServerSession session, ServerChannel channel, ServerMessage message) { if (channelName.equals(channel.getId())) { latch.countDown(); } } @Override public void unsubscribed(ServerSession session, ServerChannel channel, ServerMessage message) { } public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return latch.await(timeout, unit); } } /** * An {@link OortObject.Listener} that counts down a latch every time it receives an update * from a node that was not known before. * * @param <T> */ public static class OortObjectInitialListener<T> extends OortObject.Listener.Adapter<T> { private final CountDownLatch latch; public OortObjectInitialListener(int parties) { this.latch = new CountDownLatch(parties); } @Override public void onUpdated(OortObject.Info<T> oldInfo, OortObject.Info<T> newInfo) { if (oldInfo == null) { latch.countDown(); } } public boolean await(long timeout, TimeUnit unit) throws InterruptedException { return latch.await(timeout, unit); } } }