private static void open(final EventSource[] sources) { int i = 0; for (EventSource source : sources) { source.open(); LOGGER.info("[-->] SOURCE " + i++ + " opened."); } }
@Test public void testWithEventSource() throws IOException, NoSuchAlgorithmException, InterruptedException { final WebTarget target = target().register(SseFeature.class).path("events"); EventSource eventSource = new EventSource(target, false); final CountDownLatch count = new CountDownLatch(MSG_COUNT); final EventListener listener = new EventListener() { @Override public void onEvent(InboundEvent inboundEvent) { try { final Integer data = inboundEvent.getData(Integer.class); System.out.println(inboundEvent.getName() + "; " + data); Assert.assertEquals(SSE_NAME, inboundEvent.getName()); Assert.assertEquals(MSG_COUNT - count.getCount(), data.intValue()); count.countDown(); } catch (IOException e) { throw new RuntimeException("Error when deserializing of data."); } } }; eventSource.register(listener, "message-to-client"); eventSource.open(); final boolean sent = latch.await(5, TimeUnit.SECONDS); Assert.assertTrue("Awaiting for SSE message has timeout. Not all message were sent.", sent); final boolean handled = count.await(5, TimeUnit.SECONDS); Assert.assertTrue( "Awaiting for SSE message has timeout. Not all message were handled by the listener.", handled); }
public void removeCallback(String key) { // TODO remove an existing callback (if any) for bindings on key. // Be sure to close the event stream from the broadcaster. EventSource es = callbacks.remove(key); if (es != null) { es.close(); } // Done }
private static void close(final EventSource[] sources) { int i = 0; for (EventSource source : sources) { if (source.isOpen()) { assertTrue("Waiting to close a source has timed out.", source.close(1, TimeUnit.SECONDS)); // source.close(100, TimeUnit.MILLISECONDS); LOGGER.info("[<--] SOURCE " + i++ + " closed."); } } }
/** * Test the {@link EventSource} reconnect feature. * * @throws Exception in case of a test failure. */ @Test public void testEventSourceReconnect() throws Exception { final WebTarget itemsTarget = target("items"); final CountDownLatch latch = new CountDownLatch(MAX_ITEMS * MAX_LISTENERS * 2); // countdown only on new item events final List<Queue<String>> receivedQueues = new ArrayList<Queue<String>>(MAX_LISTENERS); final EventSource[] sources = new EventSource[MAX_LISTENERS]; for (int i = 0; i < MAX_LISTENERS; i++) { final int id = i; final EventSource es = EventSource.target(itemsTarget.path("events")).named("SOURCE " + id).build(); sources[id] = es; final Queue<String> received = new ConcurrentLinkedQueue<String>(); receivedQueues.add(received); es.register( new EventListener() { @Override public void onEvent(InboundEvent inboundEvent) { try { if (inboundEvent.getName() == null) { latch.countDown(); final String data = inboundEvent.readData(); LOGGER.info( "[-i-] SOURCE " + id + ": Received event id=" + inboundEvent.getId() + " data=" + data); received.add(data); } } catch (ProcessingException ex) { LOGGER.log(Level.SEVERE, "[-x-] SOURCE " + id + ": Error getting event data.", ex); received.add("[data processing error]"); } } }); } final String[] postedItems = new String[MAX_ITEMS * 2]; try { open(sources); for (int i = 0; i < MAX_ITEMS; i++) { final String item = String.format("round-1-%02d", i); postItem(itemsTarget, item); postedItems[i] = item; sendCommand(itemsTarget, "disconnect"); Thread.sleep(100); } final int reconnectDelay = 1; sendCommand(itemsTarget, "reconnect " + reconnectDelay); sendCommand(itemsTarget, "disconnect"); Thread.sleep(reconnectDelay * 1000); for (int i = 0; i < MAX_ITEMS; i++) { final String item = String.format("round-2-%02d", i); postedItems[i + MAX_ITEMS] = item; postItem(itemsTarget, item); } sendCommand(itemsTarget, "reconnect now"); assertTrue( "Waiting to receive all events has timed out.", latch.await(1 + MAX_LISTENERS * (MAX_ITEMS + 1) * reconnectDelay, TimeUnit.SECONDS)); // need to force disconnect on server in order for EventSource.close(...) to succeed with // HttpUrlConnection sendCommand(itemsTarget, "disconnect"); } finally { close(sources); } final String storedItems = itemsTarget.request().get(String.class); for (String item : postedItems) { assertThat("Posted item '" + item + "' stored on server", storedItems, containsString(item)); } int sourceId = 0; for (Queue<String> queue : receivedQueues) { assertThat( "Received events in source " + sourceId, queue, describedAs( "Collection containing %0", hasItems(postedItems), Arrays.asList(postedItems).toString())); assertThat( "Size of received queue for source " + sourceId, queue.size(), equalTo(postedItems.length)); sourceId++; } }
/** * Test the item addition, addition event broadcasting and item retrieval from {@link * ItemStoreResource}. * * @throws Exception in case of a test failure. */ @Test public void testItemsStore() throws Exception { final List<String> items = Collections.unmodifiableList(Arrays.asList("foo", "bar", "baz")); final WebTarget itemsTarget = target("items"); final CountDownLatch latch = new CountDownLatch(items.size() * MAX_LISTENERS * 2); // countdown on all events final List<Queue<Integer>> indexQueues = new ArrayList<Queue<Integer>>(MAX_LISTENERS); final EventSource[] sources = new EventSource[MAX_LISTENERS]; final AtomicInteger sizeEventsCount = new AtomicInteger(0); for (int i = 0; i < MAX_LISTENERS; i++) { final int id = i; final EventSource es = EventSource.target(itemsTarget.path("events")).named("SOURCE " + id).build(); sources[id] = es; final Queue<Integer> indexes = new ConcurrentLinkedQueue<Integer>(); indexQueues.add(indexes); es.register( new EventListener() { @Override public void onEvent(InboundEvent inboundEvent) { try { if (inboundEvent.getName() == null) { final String data = inboundEvent.readData(); LOGGER.info( "[-i-] SOURCE " + id + ": Received event id=" + inboundEvent.getId() + " data=" + data); indexes.add(items.indexOf(data)); } else if ("size".equals(inboundEvent.getName())) { sizeEventsCount.incrementAndGet(); } } catch (ProcessingException ex) { LOGGER.log(Level.SEVERE, "[-x-] SOURCE " + id + ": Error getting event data.", ex); indexes.add(-999); } finally { latch.countDown(); } } }); } try { open(sources); for (String item : items) { postItem(itemsTarget, item); } assertTrue( "Waiting to receive all events has timed out.", latch.await(1000 + MAX_LISTENERS * EventSource.RECONNECT_DEFAULT, TimeUnit.MILLISECONDS)); // need to force disconnect on server in order for EventSource.close(...) to succeed with // HttpUrlConnection sendCommand(itemsTarget, "disconnect"); } finally { close(sources); } String postedItems = itemsTarget.request().get(String.class); for (String item : items) { assertTrue("Item '" + item + "' not stored on server.", postedItems.contains(item)); } int queueId = 0; for (Queue<Integer> indexes : indexQueues) { for (int i = 0; i < items.size(); i++) { assertTrue( "Event for '" + items.get(i) + "' not received in queue " + queueId, indexes.contains(i)); } assertEquals( "Not received the expected number of events in queue " + queueId, items.size(), indexes.size()); queueId++; } assertEquals( "Number of received 'size' events does not match.", items.size() * MAX_LISTENERS, sizeEventsCount.get()); }