Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.activemq.web; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.net.SocketTimeoutException; import java.util.HashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.jms.Message; import javax.jms.MessageProducer; import org.apache.activemq.transport.stomp.Stomp; import org.apache.activemq.transport.stomp.StompConnection; import org.apache.activemq.transport.stomp.StompFrame; import org.apache.commons.lang.StringUtils; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.client.util.BufferingResponseListener; import org.eclipse.jetty.client.util.InputStreamContentProvider; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AjaxTest extends JettyTestSupport { private static final Logger LOG = LoggerFactory.getLogger(AjaxTest.class); public void assertContains(String expected, String actual) { assertTrue("'" + actual + "' does not contain expected fragment '" + expected + "'", actual.indexOf(expected) != -1); } public void assertResponseCount(int expected, String actual) { int occurrences = StringUtils.countMatches(actual, "<response"); assertEquals("Expected number of <response> elements is not correct.", expected, occurrences); } @Test(timeout = 15 * 1000) public void testAjaxClientReceivesMessagesWhichAreSentToQueueWhileClientIsPolling() throws Exception { LOG.debug("*** testAjaxClientReceivesMessagesWhichAreSentToQueueWhileClientIsPolling ***"); int port = getPort(); HttpClient httpClient = new HttpClient(); httpClient.start(); // client 1 subscribes to a queue LOG.debug("SENDING LISTEN"); String sessionId = subscribe(httpClient, port, "destination=queue://test&type=listen&message=handler"); // client 1 polls for messages LOG.debug("SENDING POLL"); final StringBuffer buf = new StringBuffer(); final CountDownLatch latch = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000", buf, sessionId); // while client 1 is polling, client 2 sends messages to the queue LOG.debug("SENDING MESSAGES"); sendMessages(httpClient, port, ("destination=queue://test&type=send&message=msg1&" + "d1=queue://test&t1=send&m1=msg2&" + "d2=queue://test&t2=send&m2=msg3").getBytes()); LOG.debug("DONE POSTING MESSAGES"); // wait for poll to finish latch.await(); String response = buf.toString(); // messages might not all be delivered during the 1st poll. We need to check again. final StringBuffer buf2 = new StringBuffer(); final CountDownLatch latch2 = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000", buf2, sessionId); latch2.await(); String fullResponse = response + buf2.toString(); LOG.debug("full response : " + fullResponse); assertContains("<response id='handler' destination='queue://test' >msg1</response>", fullResponse); assertContains("<response id='handler' destination='queue://test' >msg2</response>", fullResponse); assertContains("<response id='handler' destination='queue://test' >msg3</response>", fullResponse); assertResponseCount(3, fullResponse); httpClient.stop(); } @Test(timeout = 15 * 1000) public void testAjaxClientReceivesMessagesWhichAreSentToTopicWhileClientIsPolling() throws Exception { LOG.debug("*** testAjaxClientReceivesMessagesWhichAreSentToTopicWhileClientIsPolling ***"); int port = getPort(); HttpClient httpClient = new HttpClient(); httpClient.start(); // client 1 subscribes to a queue LOG.debug("SENDING LISTEN"); String sessionId = subscribe(httpClient, port, "destination=topic://test&type=listen&message=handler"); // client 1 polls for messages LOG.debug("SENDING POLL"); final StringBuffer buf = new StringBuffer(); final CountDownLatch latch = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000", buf, sessionId); // while client 1 is polling, client 2 sends messages to the queue LOG.debug("SENDING MESSAGES"); sendMessages(httpClient, port, ("destination=topic://test&type=send&message=msg1&" + "d1=topic://test&t1=send&m1=msg2&" + "d2=topic://test&t2=send&m2=msg3").getBytes()); // wait for poll to finish latch.await(); String response = buf.toString(); // messages might not all be delivered during the 1st poll. We need to // check again. final StringBuffer buf2 = new StringBuffer(); final CountDownLatch latch2 = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000", buf2, sessionId); latch2.await(); String fullResponse = response + buf2.toString(); LOG.debug("full response : " + fullResponse); assertContains("<response id='handler' destination='topic://test' >msg1</response>", fullResponse); assertContains("<response id='handler' destination='topic://test' >msg2</response>", fullResponse); assertContains("<response id='handler' destination='topic://test' >msg3</response>", fullResponse); assertResponseCount(3, fullResponse); httpClient.stop(); } @Test(timeout = 15 * 1000) public void testAjaxClientReceivesMessagesWhichAreQueuedBeforeClientSubscribes() throws Exception { LOG.debug("*** testAjaxClientReceivesMessagesWhichAreQueuedBeforeClientSubscribes ***"); int port = getPort(); // send messages to queue://test producer.send(session.createTextMessage("test one")); producer.send(session.createTextMessage("test two")); producer.send(session.createTextMessage("test three")); HttpClient httpClient = new HttpClient(); httpClient.start(); // client 1 subscribes to queue LOG.debug("SENDING LISTEN"); String sessionId = subscribe(httpClient, port, "destination=queue://test&type=listen&message=handler"); // client 1 polls for messages LOG.debug("SENDING POLL"); final StringBuffer buf = new StringBuffer(); final CountDownLatch latch = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000", buf, sessionId); // wait for poll to finish latch.await(); String response = buf.toString(); assertContains("<response id='handler' destination='queue://test' >test one</response>", response); assertContains("<response id='handler' destination='queue://test' >test two</response>", response); assertContains("<response id='handler' destination='queue://test' >test three</response>", response); assertResponseCount(3, response); httpClient.stop(); } @Test(timeout = 15 * 1000) public void testStompMessagesAreReceivedByAjaxClient() throws Exception { LOG.debug("*** testStompMessagesAreRecievedByAjaxClient ***"); int port = getPort(); HttpClient httpClient = new HttpClient(); httpClient.start(); // client 1 subscribes to a queue LOG.debug("SENDING LISTEN"); String sessionId = subscribe(httpClient, port, "destination=queue://test&type=listen&message=handler"); // client 1 polls for messages LOG.debug("SENDING POLL"); final StringBuffer buf = new StringBuffer(); final CountDownLatch latch = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000", buf, sessionId); // stomp client queues some messages StompConnection connection = new StompConnection(); connection.open(stompUri.getHost(), stompUri.getPort()); connection.connect("user", "password"); HashMap<String, String> headers = new HashMap<String, String>(); headers.put("amq-msg-type", "text"); connection.send("/queue/test", "message1", (String) null, headers); connection.send("/queue/test", "message2", (String) null, headers); connection.send("/queue/test", "message3", (String) null, headers); connection.send("/queue/test", "message4", (String) null, headers); connection.send("/queue/test", "message5", (String) null, headers); String frame = "DISCONNECT\n" + "\n\n" + Stomp.NULL; connection.sendFrame(frame); // Need to let the transport have enough time to dispatch the incoming messages from // the socket before we break the connection. TimeUnit.SECONDS.sleep(5); connection.disconnect(); // wait for poll to finish latch.await(); String response = buf.toString(); // not all messages might be delivered during the 1st poll. We need to check again. final StringBuffer buf2 = new StringBuffer(); final CountDownLatch latch2 = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000", buf2, sessionId); latch2.await(); String fullResponse = response + buf2.toString(); assertContains("<response id='handler' destination='queue://test' >message1</response>", fullResponse); assertContains("<response id='handler' destination='queue://test' >message2</response>", fullResponse); assertContains("<response id='handler' destination='queue://test' >message3</response>", fullResponse); assertContains("<response id='handler' destination='queue://test' >message4</response>", fullResponse); assertContains("<response id='handler' destination='queue://test' >message5</response>", fullResponse); assertResponseCount(5, fullResponse); httpClient.stop(); } @Test(timeout = 15 * 1000) public void testAjaxMessagesAreReceivedByStompClient() throws Exception { LOG.debug("*** testAjaxMessagesAreReceivedByStompClient ***"); int port = getPort(); HttpClient httpClient = new HttpClient(); httpClient.start(); sendMessages(httpClient, port, ("destination=queue://test&type=send&message=msg1&" + "d1=queue://test&t1=send&m1=msg2&" + "d2=queue://test&t2=send&m2=msg3&" + "d3=queue://test&t3=send&m3=msg4").getBytes()); StompConnection connection = new StompConnection(); connection.open(stompUri.getHost(), stompUri.getPort()); connection.connect("user", "password"); connection.subscribe("/queue/test"); StompFrame message; String allMessageBodies = ""; try { while (true) { message = connection.receive(5000); allMessageBodies = allMessageBodies + "\n" + message.getBody(); } } catch (SocketTimeoutException e) { } LOG.debug("All message bodies : " + allMessageBodies); assertContains("msg1", allMessageBodies); assertContains("msg2", allMessageBodies); assertContains("msg3", allMessageBodies); assertContains("msg4", allMessageBodies); httpClient.stop(); } @Test(timeout = 15 * 1000) public void testAjaxClientMayUseSelectors() throws Exception { LOG.debug("*** testAjaxClientMayUseSelectors ***"); int port = getPort(); // send 2 messages to the same queue w/ different 'filter' values. Message msg = session.createTextMessage("test one"); msg.setStringProperty("filter", "one"); producer.send(msg); msg = session.createTextMessage("test two"); msg.setStringProperty("filter", "two"); producer.send(msg); HttpClient httpClient = new HttpClient(); httpClient.start(); // client subscribes to queue LOG.debug("SENDING LISTEN"); String sessionId = subscribe(httpClient, port, "destination=queue://test&type=listen&message=handler", "filter='two'", null); // client 1 polls for messages LOG.debug("SENDING POLL"); final StringBuffer buf = new StringBuffer(); final CountDownLatch latch = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000", buf, sessionId); latch.await(); LOG.debug(buf.toString()); String expected = "<response id='handler' destination='queue://test' >test two</response>"; assertContains(expected, buf.toString()); httpClient.stop(); } @Test(timeout = 15 * 1000) public void testMultipleAjaxClientsMayExistInTheSameSession() throws Exception { LOG.debug("*** testMultipleAjaxClientsMayExistInTheSameSession ***"); int port = getPort(); // send messages to queues testA and testB. MessageProducer producerA = session.createProducer(session.createQueue("testA")); MessageProducer producerB = session.createProducer(session.createQueue("testB")); producerA.send(session.createTextMessage("A1")); producerA.send(session.createTextMessage("A2")); producerB.send(session.createTextMessage("B1")); producerB.send(session.createTextMessage("B2")); HttpClient httpClient = new HttpClient(); httpClient.start(); // clientA subscribes to /queue/testA LOG.debug("SENDING LISTEN"); String sessionId = subscribe(httpClient, port, "destination=queue://testA&type=listen&message=handlerA&clientId=clientA"); // clientB subscribes to /queue/testB using the same JSESSIONID. subscribe(httpClient, port, "destination=queue://testB&type=listen&message=handlerB&clientId=clientB", null, sessionId); // clientA polls for messages final StringBuffer buf = new StringBuffer(); final CountDownLatch latch = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000&clientId=clientA", buf, sessionId); latch.await(); LOG.debug("clientA response : " + buf.toString()); String expected1 = "<response id='handlerA' destination='queue://testA' >A1</response>"; String expected2 = "<response id='handlerA' destination='queue://testA' >A2</response>"; assertContains(expected1, buf.toString()); assertContains(expected2, buf.toString()); // clientB polls for messages final StringBuffer buf2 = new StringBuffer(); final CountDownLatch latch2 = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000&clientId=clientB", buf2, sessionId); latch2.await(); LOG.debug("clientB response : " + buf2.toString()); expected1 = "<response id='handlerB' destination='queue://testB' >B1</response>"; expected2 = "<response id='handlerB' destination='queue://testB' >B2</response>"; assertContains(expected1, buf2.toString()); assertContains(expected2, buf2.toString()); httpClient.stop(); } @Test(timeout = 15 * 1000) public void testAjaxClientReceivesMessagesForMultipleTopics() throws Exception { LOG.debug("*** testAjaxClientReceivesMessagesForMultipleTopics ***"); int port = getPort(); HttpClient httpClient = new HttpClient(); httpClient.start(); LOG.debug("SENDING LISTEN FOR /topic/topicA"); String sessionId = subscribe(httpClient, port, "destination=topic://topicA&type=listen&message=handlerA"); LOG.debug("SENDING LISTEN FOR /topic/topicB"); subscribe(httpClient, port, "destination=topic://topicB&type=listen&message=handlerB", null, sessionId); // client 1 polls for messages final StringBuffer buf = new StringBuffer(); final CountDownLatch latch = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000", buf, sessionId); // while client 1 is polling, client 2 sends messages to the topics LOG.debug("SENDING MESSAGES"); sendMessages(httpClient, port, ("destination=topic://topicA&type=send&message=A1&" + "d1=topic://topicB&t1=send&m1=B1&" + "d2=topic://topicA&t2=send&m2=A2&" + "d3=topic://topicB&t3=send&m3=B2").getBytes()); LOG.debug("DONE POSTING MESSAGES"); // wait for poll to finish latch.await(); String response = buf.toString(); // not all messages might be delivered during the 1st poll. We need to check again. final StringBuffer buf2 = new StringBuffer(); final CountDownLatch latch2 = asyncRequest(httpClient, "http://localhost:" + port + "/amq?timeout=5000", buf2, sessionId); latch2.await(); String fullResponse = response + buf2.toString(); LOG.debug("full response " + fullResponse); assertContains("<response id='handlerA' destination='topic://topicA' >A1</response>", fullResponse); assertContains("<response id='handlerB' destination='topic://topicB' >B1</response>", fullResponse); assertContains("<response id='handlerA' destination='topic://topicA' >A2</response>", fullResponse); assertContains("<response id='handlerB' destination='topic://topicB' >B2</response>", fullResponse); assertResponseCount(4, fullResponse); httpClient.stop(); } protected void sendMessages(HttpClient httpClient, int port, byte[] content) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final StringBuffer buf = new StringBuffer(); httpClient.newRequest("http://localhost:" + port + "/amq") .header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") .content(new InputStreamContentProvider(new ByteArrayInputStream(content))).method(HttpMethod.POST) .send(new BufferingResponseListener() { @Override public void onComplete(Result result) { buf.append(getContentAsString()); latch.countDown(); } }); latch.await(); } protected String subscribe(HttpClient httpClient, int port, String content) throws InterruptedException { return this.subscribe(httpClient, port, content, null, null); } protected String subscribe(HttpClient httpClient, int port, String content, String selector, String session) throws InterruptedException { final CountDownLatch latch = new CountDownLatch(1); final StringBuffer buf = new StringBuffer(); final StringBuffer sessionId = new StringBuffer(); Request request = httpClient.newRequest("http://localhost:" + port + "/amq"); if (selector != null) { request.header("selector", selector); } if (session != null) { request.header(HttpHeader.COOKIE, session); } request.header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") .content(new InputStreamContentProvider(new ByteArrayInputStream(content.getBytes()))) .method(HttpMethod.POST).send(new BufferingResponseListener() { @Override public void onComplete(Result result) { buf.append(getContentAsString()); String cookie = result.getResponse().getHeaders().get(HttpHeader.SET_COOKIE); if (cookie != null) { String[] cookieParts = cookie.split(";"); sessionId.append(cookieParts[0]); } latch.countDown(); } }); latch.await(); return sessionId.toString(); } protected CountDownLatch asyncRequest(final HttpClient httpClient, final String url, final StringBuffer buffer, final String sessionId) { final CountDownLatch latch = new CountDownLatch(1); Request request = httpClient.newRequest(url); if (sessionId != null) { request.header(HttpHeader.COOKIE, sessionId); } request.send(new BufferingResponseListener() { @Override public void onComplete(Result result) { buffer.append(getContentAsString()); latch.countDown(); } }); return latch; } protected CountDownLatch asyncRequest(final HttpClient httpClient, final String url, final StringBuffer buffer, final AtomicInteger status) { final CountDownLatch latch = new CountDownLatch(1); httpClient.newRequest(url).send(new BufferingResponseListener() { @Override public void onComplete(Result result) { status.getAndSet(result.getResponse().getStatus()); buffer.append(getContentAsString()); latch.countDown(); } }); return latch; } }