CXF-7085: Introduce support for Server Sent Events (Client). Restructured SSE test cases to have separate modules for Tomcat and Jetty
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/76877054 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/76877054 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/76877054 Branch: refs/heads/master Commit: 76877054e1a86220fe1a546acde9a12e7c63e10b Parents: 1257780 Author: reta <drr...@gmail.com> Authored: Sat Jun 24 13:13:14 2017 -0400 Committer: reta <drr...@gmail.com> Committed: Sat Jun 24 13:13:14 2017 -0400 ---------------------------------------------------------------------- systests/rs-sse/pom.xml | 70 ++-------- systests/rs-sse/rs-sse-base/pom.xml | 53 ++++++++ .../systest/jaxrs/sse/AbstractSseBaseTest.java | 79 +++++++++++ .../cxf/systest/jaxrs/sse/AbstractSseTest.java | 136 +++++++++++++++++++ .../org/apache/cxf/systest/jaxrs/sse/Book.java | 71 ++++++++++ .../apache/cxf/systest/jaxrs/sse/BookStore.java | 136 +++++++++++++++++++ .../cxf/systest/jaxrs/sse/BookStore2.java | 135 ++++++++++++++++++ .../cxf/systest/jaxrs/sse/SseApplication.java | 38 ++++++ .../META-INF/cxf/org.apache.cxf.Logger | 1 + .../main/resources/jaxrs_sse/WEB-INF/web.xml | 28 ++++ .../rs-sse-base/src/main/resources/logback.xml | 12 ++ systests/rs-sse/rs-sse-jetty/pom.xml | 70 ++++++++++ .../jaxrs/sse/jetty/AbstractJettyServer.java | 98 +++++++++++++ .../jaxrs/sse/jetty/JettyEmbeddedTest.java | 49 +++++++ .../systest/jaxrs/sse/jetty/JettyWarTest.java | 48 +++++++ systests/rs-sse/rs-sse-tomcat/pom.xml | 67 +++++++++ .../jaxrs/sse/tomcat/AbstractTomcatServer.java | 111 +++++++++++++++ .../jaxrs/sse/tomcat/TomcatEmbeddedTest.java | 49 +++++++ .../systest/jaxrs/sse/tomcat/TomcatWarTest.java | 49 +++++++ .../jaxrs/sse/AbstractBroadcasterSseTest.java | 80 ----------- .../systest/jaxrs/sse/AbstractSseBaseTest.java | 79 ----------- .../cxf/systest/jaxrs/sse/AbstractSseTest.java | 87 ------------ .../org/apache/cxf/systest/jaxrs/sse/Book.java | 71 ---------- .../apache/cxf/systest/jaxrs/sse/BookStore.java | 136 ------------------- .../cxf/systest/jaxrs/sse/BookStore2.java | 135 ------------------ .../cxf/systest/jaxrs/sse/SseApplication.java | 38 ------ .../jaxrs/sse/jetty/AbstractJettyServer.java | 98 ------------- .../jaxrs/sse/jetty/JettyBroadcasterTest.java | 49 ------- .../jaxrs/sse/jetty/JettyEmbeddedTest.java | 49 ------- .../systest/jaxrs/sse/jetty/JettyWarTest.java | 48 ------- .../jaxrs/sse/tomcat/AbstractTomcatServer.java | 111 --------------- .../jaxrs/sse/tomcat/TomcatBroadcasterTest.java | 51 ------- .../jaxrs/sse/tomcat/TomcatEmbeddedTest.java | 49 ------- .../systest/jaxrs/sse/tomcat/TomcatWarTest.java | 49 ------- .../META-INF/cxf/org.apache.cxf.Logger | 1 - .../test/resources/jaxrs_sse/WEB-INF/web.xml | 28 ---- systests/rs-sse/src/test/resources/logback.xml | 12 -- 37 files changed, 1241 insertions(+), 1230 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/pom.xml ---------------------------------------------------------------------- diff --git a/systests/rs-sse/pom.xml b/systests/rs-sse/pom.xml index ce8c56d..c24dd79 100644 --- a/systests/rs-sse/pom.xml +++ b/systests/rs-sse/pom.xml @@ -27,40 +27,15 @@ <modelVersion>4.0.0</modelVersion> <groupId>org.apache.cxf.systests</groupId> <artifactId>cxf-systests-rs-sse</artifactId> + <packaging>pom</packaging> <name>Apache CXF SSE Integration System Tests</name> <description>Apache CXF SSE Integration System Tests</description> <url>http://cxf.apache.org</url> - <properties> - <cxf.jetty.version>${cxf.jetty9.version}</cxf.jetty.version> - <cxf.tomcat.version>8.0.32</cxf.tomcat.version> - </properties> + <dependencies> <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-annotations</artifactId> - <version>${cxf.jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-server</artifactId> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-plus</artifactId> - </dependency> - <dependency> - <groupId>org.eclipse.jetty.websocket</groupId> - <artifactId>websocket-server</artifactId> - <version>${cxf.jetty.version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.jetty</groupId> - <artifactId>jetty-webapp</artifactId> - </dependency> - <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> - <version>${cxf.logback.classic.version}</version> <scope>test</scope> </dependency> <dependency> @@ -89,24 +64,8 @@ <version>${project.version}</version> </dependency> <dependency> - <groupId>org.apache.tomcat.embed</groupId> - <artifactId>tomcat-embed-core</artifactId> - <version>${cxf.tomcat.version}</version> - </dependency> - <dependency> - <groupId>org.apache.tomcat.embed</groupId> - <artifactId>tomcat-embed-logging-juli</artifactId> - <version>${cxf.tomcat.version}</version> - </dependency> - <dependency> - <groupId>org.apache.tomcat</groupId> - <artifactId>tomcat-jasper</artifactId> - <version>${cxf.tomcat.version}</version> - </dependency> - <dependency> - <groupId>org.apache.cxf</groupId> - <artifactId>cxf-testutils</artifactId> - <version>${project.version}</version> + <groupId>junit</groupId> + <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> @@ -116,25 +75,11 @@ <scope>test</scope> </dependency> <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>com.fasterxml.jackson.jaxrs</groupId> - <artifactId>jackson-jaxrs-json-provider</artifactId> - </dependency> - <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <scope>test</scope> </dependency> <dependency> - <groupId>org.apache.commons</groupId> - <artifactId>commons-lang3</artifactId> - <scope>test</scope> - </dependency> - <dependency> <groupId>com.ning</groupId> <artifactId>async-http-client</artifactId> <version>${cxf.ahc.version}</version> @@ -147,6 +92,7 @@ </exclusions> </dependency> </dependencies> + <build> <plugins> <plugin> @@ -162,4 +108,10 @@ </plugin> </plugins> </build> + + <modules> + <module>rs-sse-base</module> + <module>rs-sse-tomcat</module> + <module>rs-sse-jetty</module> + </modules> </project> http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-base/pom.xml ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-base/pom.xml b/systests/rs-sse/rs-sse-base/pom.xml new file mode 100644 index 0000000..c431bd6 --- /dev/null +++ b/systests/rs-sse/rs-sse-base/pom.xml @@ -0,0 +1,53 @@ +<?xml version="1.0"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <parent> + <groupId>org.apache.cxf.systests</groupId> + <artifactId>cxf-systests-rs-sse</artifactId> + <version>3.2.0-SNAPSHOT</version> + <relativePath>../</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>cxf-systests-rs-sse-base</artifactId> + <name>Apache CXF SSE Integration System Tests base classes</name> + <description>Apache CXF SSE Integration System base classes</description> + <url>http://cxf.apache.org</url> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.jaxrs</groupId> + <artifactId>jackson-jaxrs-json-provider</artifactId> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-testutils</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseBaseTest.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseBaseTest.java b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseBaseTest.java new file mode 100644 index 0000000..87425b5 --- /dev/null +++ b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseBaseTest.java @@ -0,0 +1,79 @@ +/** + * 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.cxf.systest.jaxrs.sse; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.MediaType; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; + +import org.apache.cxf.jaxrs.client.WebClient; +import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase; + +public abstract class AbstractSseBaseTest extends AbstractBusClientServerTestBase { + private final ObjectMapper mapper = new ObjectMapper(); + + protected String toJson(final String name, final Integer id) throws JsonProcessingException { + return mapper.writeValueAsString(new Book(name, id)); + } + + protected WebClient createWebClient(final String url, final String media) { + final List< ? > providers = Arrays.asList(new JacksonJsonProvider()); + + final WebClient wc = WebClient + .create("http://localhost:" + getPort() + url, providers) + .accept(media); + + WebClient.getConfig(wc).getHttpConduit().getClient().setReceiveTimeout(8000L); + return wc; + } + + protected WebClient createWebClient(final String url) { + return createWebClient(url, MediaType.SERVER_SENT_EVENTS); + } + + protected WebTarget createWebTarget(final String url) { + return ClientBuilder + .newClient() + .property("http.receive.timeout", 8000) + .register(JacksonJsonProvider.class) + .target("http://localhost:" + getPort() + url); + } + + protected void awaitEvents(long timeout, final Collection<?> events, int size) throws InterruptedException { + final long sleep = timeout / 10; + + for (int i = 0; i < timeout; i += sleep) { + if (events.size() == size) { + break; + } else { + Thread.sleep(sleep); + } + } + } + + protected abstract int getPort(); +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseTest.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseTest.java b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseTest.java new file mode 100644 index 0000000..053bcb7 --- /dev/null +++ b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseTest.java @@ -0,0 +1,136 @@ +/** + * 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.cxf.systest.jaxrs.sse; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.UUID; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.sse.InboundSseEvent; +import javax.ws.rs.sse.SseEventSource; + +import com.fasterxml.jackson.core.JsonProcessingException; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.hasItems; + +public abstract class AbstractSseTest extends AbstractSseBaseTest { + @Test + public void testBooksStreamIsReturnedFromLastEventId() throws InterruptedException { + final WebTarget target = createWebTarget("/rest/api/bookstore/sse/" + UUID.randomUUID()) + .property(HttpHeaders.LAST_EVENT_ID_HEADER, 150); + final Collection<Book> books = new ArrayList<>(); + + try (final SseEventSource eventSource = SseEventSource.target(target).build()) { + eventSource.register(collect(books), System.out::println); + eventSource.open(); + // Give the SSE stream some time to collect all events + awaitEvents(3000, books, 4); + } + + // Easing the test verification here, it does not work well for Atm + Jetty + assertThat(books, + hasItems( + new Book("New Book #151", 151), + new Book("New Book #152", 152), + new Book("New Book #153", 153), + new Book("New Book #154", 154) + ) + ); + } + + @Test + public void testBooksStreamIsReturnedFromInboundSseEvents() throws InterruptedException { + final WebTarget target = createWebTarget("/rest/api/bookstore/sse/0"); + final Collection<Book> books = new ArrayList<>(); + + try (final SseEventSource eventSource = SseEventSource.target(target).build()) { + eventSource.register(collect(books), System.out::println); + eventSource.open(); + // Give the SSE stream some time to collect all events + awaitEvents(3000, books, 4); + } + + assertThat(books, + hasItems( + new Book("New Book #1", 1), + new Book("New Book #2", 2), + new Book("New Book #3", 3), + new Book("New Book #4", 4) + ) + ); + } + + @Test + public void testBooksStreamIsBroadcasted() throws Exception { + final Collection<Future<Response>> results = new ArrayList<>(); + + for (int i = 0; i < 2; ++i) { + results.add( + createWebClient("/rest/api/bookstore/broadcast/sse").async().get() + ); + } + + createWebClient("/rest/api/bookstore/broadcast/close") + .async() + .post(null) + .get(10, TimeUnit.SECONDS) + .close(); + + for (final Future<Response> result: results) { + final Response r = result.get(3, TimeUnit.SECONDS); + assertEquals(Status.OK.getStatusCode(), r.getStatus()); + + final String response = r.readEntity(String.class); + assertThat(response, containsString("id: 1000")); + assertThat(response, containsString("data: " + toJson("New Book #1000", 1000))); + + assertThat(response, containsString("id: 2000")); + assertThat(response, containsString("data: " + toJson("New Book #2000", 2000))); + + r.close(); + } + } + + @Test + public void testBooksAreReturned() throws JsonProcessingException { + Response r = createWebClient("/rest/api/bookstore", MediaType.APPLICATION_JSON).get(); + assertEquals(Status.OK.getStatusCode(), r.getStatus()); + + final Book[] books = r.readEntity(Book[].class); + assertThat(Arrays.asList(books), hasItems(new Book("New Book #1", 1), new Book("New Book #2", 2))); + + r.close(); + } + + private static Consumer<InboundSseEvent> collect(final Collection< Book > books) { + return event -> books.add(event.readData(Book.class, MediaType.APPLICATION_JSON_TYPE)); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/Book.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/Book.java b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/Book.java new file mode 100644 index 0000000..7deb5c0 --- /dev/null +++ b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/Book.java @@ -0,0 +1,71 @@ +/** + * 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.cxf.systest.jaxrs.sse; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class Book { + private String name; + private Integer id; + + public Book() { + } + + public Book(Integer id) { + this.id = id; + } + + public Book(String name, Integer id) { + this.name = name; + this.id = id; + } + + public void setName(String n) { + name = n; + } + + public String getName() { + return name; + } + + public void setId(Integer i) { + id = i; + } + + public Integer getId() { + return id; + } + + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } + + @Override + public boolean equals(Object obj) { + return EqualsBuilder.reflectionEquals(this, obj); + } + + @Override + public String toString() { + return ToStringBuilder.reflectionToString(this); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/BookStore.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/BookStore.java b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/BookStore.java new file mode 100644 index 0000000..c096713 --- /dev/null +++ b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/BookStore.java @@ -0,0 +1,136 @@ +/** + * 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.cxf.systest.jaxrs.sse; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.sse.OutboundSseEvent; +import javax.ws.rs.sse.OutboundSseEvent.Builder; +import javax.ws.rs.sse.Sse; +import javax.ws.rs.sse.SseBroadcaster; +import javax.ws.rs.sse.SseEventSink; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Path("/api/bookstore") +public class BookStore { + private static final Logger LOG = LoggerFactory.getLogger(BookStore.class); + + private final CountDownLatch latch = new CountDownLatch(2); + private Sse sse; + private SseBroadcaster broadcaster; + + @Context + public void setSse(Sse sse) { + this.sse = sse; + this.broadcaster = sse.newBroadcaster(); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Collection<Book> books() { + return Arrays.asList( + new Book("New Book #1", 1), + new Book("New Book #2", 2) + ); + } + + @GET + @Path("sse/{id}") + @Produces(MediaType.SERVER_SENT_EVENTS) + public void forBook(@Context SseEventSink sink, @PathParam("id") final String id, + @HeaderParam(HttpHeaders.LAST_EVENT_ID_HEADER) @DefaultValue("0") final String lastEventId) { + + new Thread() { + public void run() { + try { + final Integer id = Integer.valueOf(lastEventId); + final Builder builder = sse.newEventBuilder(); + + sink.send(createStatsEvent(builder.name("book"), id + 1)); + Thread.sleep(200); + sink.send(createStatsEvent(builder.name("book"), id + 2)); + Thread.sleep(200); + sink.send(createStatsEvent(builder.name("book"), id + 3)); + Thread.sleep(200); + sink.send(createStatsEvent(builder.name("book"), id + 4)); + Thread.sleep(200); + sink.close(); + } catch (final InterruptedException ex) { + LOG.error("Communication error", ex); + } + } + }.start(); + } + + @GET + @Path("broadcast/sse") + @Produces(MediaType.SERVER_SENT_EVENTS) + public void broadcast(@Context SseEventSink sink) { + try { + broadcaster.register(sink); + } finally { + latch.countDown(); + } + } + + @POST + @Path("broadcast/close") + public void stop() { + try { + // Await a least 2 clients to be broadcasted over + if (!latch.await(10, TimeUnit.SECONDS)) { + LOG.warn("Not enough clients have been connected, closing broadcaster anyway"); + } + + final Builder builder = sse.newEventBuilder(); + broadcaster.broadcast(createStatsEvent(builder.name("book"), 1000)); + broadcaster.broadcast(createStatsEvent(builder.name("book"), 2000)); + + } catch (final InterruptedException ex) { + LOG.error("Wait has been interrupted", ex); + } + + if (broadcaster != null) { + broadcaster.close(); + } + } + + private static OutboundSseEvent createStatsEvent(final OutboundSseEvent.Builder builder, final int eventId) { + return builder + .id(Integer.toString(eventId)) + .data(Book.class, new Book("New Book #" + eventId, eventId)) + .mediaType(MediaType.APPLICATION_JSON_TYPE) + .build(); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java new file mode 100644 index 0000000..a5eeb8e --- /dev/null +++ b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java @@ -0,0 +1,135 @@ +/** + * 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.cxf.systest.jaxrs.sse; + +import java.util.Arrays; +import java.util.Collection; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.sse.OutboundSseEvent; +import javax.ws.rs.sse.OutboundSseEvent.Builder; +import javax.ws.rs.sse.Sse; +import javax.ws.rs.sse.SseBroadcaster; +import javax.ws.rs.sse.SseEventSink; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Path("/api/bookstore") +public class BookStore2 { + private static final Logger LOG = LoggerFactory.getLogger(BookStore2.class); + + private final CountDownLatch latch = new CountDownLatch(2); + private Sse sse; + private SseBroadcaster broadcaster; + + public BookStore2(@Context Sse sse) { + this.sse = sse; + this.broadcaster = sse.newBroadcaster(); + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + public Collection<Book> books() { + return Arrays.asList( + new Book("New Book #1", 1), + new Book("New Book #2", 2) + ); + } + + @GET + @Path("sse/{id}") + @Produces(MediaType.SERVER_SENT_EVENTS) + public void forBook(@Context SseEventSink sink, @PathParam("id") final String id, + @HeaderParam(HttpHeaders.LAST_EVENT_ID_HEADER) @DefaultValue("0") final String lastEventId) { + + new Thread() { + public void run() { + try { + final Integer id = Integer.valueOf(lastEventId); + final Builder builder = sse.newEventBuilder(); + + sink.send(createStatsEvent(builder.name("book"), id + 1)); + Thread.sleep(200); + sink.send(createStatsEvent(builder.name("book"), id + 2)); + Thread.sleep(200); + sink.send(createStatsEvent(builder.name("book"), id + 3)); + Thread.sleep(200); + sink.send(createStatsEvent(builder.name("book"), id + 4)); + Thread.sleep(200); + sink.close(); + } catch (final InterruptedException ex) { + LOG.error("Communication error", ex); + } + } + }.start(); + } + + @GET + @Path("broadcast/sse") + @Produces(MediaType.SERVER_SENT_EVENTS) + public void broadcast(@Context SseEventSink sink) { + try { + broadcaster.register(sink); + } finally { + latch.countDown(); + } + } + + @POST + @Path("broadcast/close") + public void stop() { + try { + // Await a least 2 clients to be broadcasted over + if (!latch.await(10, TimeUnit.SECONDS)) { + LOG.warn("Not enough clients have been connected, closing broadcaster anyway"); + } + + final Builder builder = sse.newEventBuilder(); + broadcaster.broadcast(createStatsEvent(builder.name("book"), 1000)); + broadcaster.broadcast(createStatsEvent(builder.name("book"), 2000)); + + } catch (final InterruptedException ex) { + LOG.error("Wait has been interrupted", ex); + } + + if (broadcaster != null) { + broadcaster.close(); + } + } + + private static OutboundSseEvent createStatsEvent(final OutboundSseEvent.Builder builder, final int eventId) { + return builder + .id(Integer.toString(eventId)) + .data(Book.class, new Book("New Book #" + eventId, eventId)) + .mediaType(MediaType.APPLICATION_JSON_TYPE) + .build(); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java new file mode 100644 index 0000000..a4a4049 --- /dev/null +++ b/systests/rs-sse/rs-sse-base/src/main/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java @@ -0,0 +1,38 @@ +/** + * 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.cxf.systest.jaxrs.sse; + +import java.util.Collections; +import java.util.Set; + +import javax.ws.rs.core.Application; + +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; + +public class SseApplication extends Application { + @Override + public Set<Class<?>> getClasses() { + return Collections.singleton(BookStore2.class); + } + + @Override + public Set<Object> getSingletons() { + return Collections.singleton(new JacksonJsonProvider()); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-base/src/main/resources/META-INF/cxf/org.apache.cxf.Logger ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-base/src/main/resources/META-INF/cxf/org.apache.cxf.Logger b/systests/rs-sse/rs-sse-base/src/main/resources/META-INF/cxf/org.apache.cxf.Logger new file mode 100644 index 0000000..27dd788 --- /dev/null +++ b/systests/rs-sse/rs-sse-base/src/main/resources/META-INF/cxf/org.apache.cxf.Logger @@ -0,0 +1 @@ +org.apache.cxf.common.logging.Slf4jLogger \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-base/src/main/resources/jaxrs_sse/WEB-INF/web.xml ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-base/src/main/resources/jaxrs_sse/WEB-INF/web.xml b/systests/rs-sse/rs-sse-base/src/main/resources/jaxrs_sse/WEB-INF/web.xml new file mode 100644 index 0000000..64746acb --- /dev/null +++ b/systests/rs-sse/rs-sse-base/src/main/resources/jaxrs_sse/WEB-INF/web.xml @@ -0,0 +1,28 @@ +<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + + <servlet> + <servlet-name>CXFServlet</servlet-name> + <display-name>CXF Servlet</display-name> + <servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class> + <load-on-startup>1</load-on-startup> + <async-supported>true</async-supported> + <init-param> + <param-name>transportId</param-name> + <param-value>http://cxf.apache.org/transports/http/sse</param-value> + </init-param> + <init-param> + <param-name>javax.ws.rs.Application</param-name> + <param-value>org.apache.cxf.systest.jaxrs.sse.SseApplication</param-value> + </init-param> + <init-param> + <param-name>jaxrs.scope</param-name> + <param-value>singleton</param-value> + </init-param> + </servlet> + + <servlet-mapping> + <servlet-name>CXFServlet</servlet-name> + <url-pattern>/rest/*</url-pattern> + </servlet-mapping> +</web-app> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-base/src/main/resources/logback.xml ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-base/src/main/resources/logback.xml b/systests/rs-sse/rs-sse-base/src/main/resources/logback.xml new file mode 100644 index 0000000..430aa64 --- /dev/null +++ b/systests/rs-sse/rs-sse-base/src/main/resources/logback.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configuration scan="true" scanPeriod="5 seconds"> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>[%level] %d{yyyy-MM-dd HH:mm:ss.SSS} %logger{36} - [%X] %msg%n</pattern> + </encoder> + </appender> + + <root level="INFO"> + <appender-ref ref="STDOUT" /> + </root> +</configuration> http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-jetty/pom.xml ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-jetty/pom.xml b/systests/rs-sse/rs-sse-jetty/pom.xml new file mode 100644 index 0000000..c786a76 --- /dev/null +++ b/systests/rs-sse/rs-sse-jetty/pom.xml @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <parent> + <groupId>org.apache.cxf.systests</groupId> + <artifactId>cxf-systests-rs-sse</artifactId> + <version>3.2.0-SNAPSHOT</version> + <relativePath>../</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>cxf-systests-rs-sse-jetty</artifactId> + <name>Apache CXF SSE Integration System Tests for Jetty</name> + <description>Apache CXF SSE Integration System Tests for Jetty</description> + <url>http://cxf.apache.org</url> + <properties> + <cxf.jetty.version>${cxf.jetty9.version}</cxf.jetty.version> + </properties> + <dependencies> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-annotations</artifactId> + <version>${cxf.jetty.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-server</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-plus</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.websocket</groupId> + <artifactId>websocket-server</artifactId> + <version>${cxf.jetty.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty</groupId> + <artifactId>jetty-webapp</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.cxf.systests</groupId> + <artifactId>cxf-systests-rs-sse-base</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/AbstractJettyServer.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/AbstractJettyServer.java b/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/AbstractJettyServer.java new file mode 100644 index 0000000..a47c0c3 --- /dev/null +++ b/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/AbstractJettyServer.java @@ -0,0 +1,98 @@ +/** + * 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.cxf.systest.jaxrs.sse.jetty; + +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; + +import org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet; +import org.apache.cxf.systest.jaxrs.sse.BookStore; +import org.apache.cxf.testutil.common.AbstractBusTestServerBase; +import org.apache.cxf.transport.sse.SseHttpTransportFactory; +import org.eclipse.jetty.server.Handler; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.DefaultHandler; +import org.eclipse.jetty.server.handler.HandlerCollection; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.webapp.WebAppContext; + +public abstract class AbstractJettyServer extends AbstractBusTestServerBase { + + private org.eclipse.jetty.server.Server server; + private final String resourcePath; + private final String contextPath; + private final int port; + + protected AbstractJettyServer(final String contextPath, int portNumber) { + this(null, contextPath, portNumber); + } + + protected AbstractJettyServer(final String resourcePath, final String contextPath, int portNumber) { + this.resourcePath = resourcePath; + this.contextPath = contextPath; + this.port = portNumber; + } + + protected void run() { + server = new Server(port); + + try { + if (resourcePath == null) { + // Register and map the dispatcher servlet + final ServletHolder holder = new ServletHolder(new CXFNonSpringJaxrsServlet()); + holder.setInitParameter(CXFNonSpringJaxrsServlet.TRANSPORT_ID, SseHttpTransportFactory.TRANSPORT_ID); + holder.setInitParameter("jaxrs.serviceClasses", BookStore.class.getName()); + holder.setInitParameter("jaxrs.providers", JacksonJsonProvider.class.getName()); + final ServletContextHandler context = new ServletContextHandler(); + context.setContextPath(contextPath); + context.addServlet(holder, "/rest/*"); + server.setHandler(context); + } else { + final WebAppContext context = new WebAppContext(); + context.setContextPath(contextPath); + context.setWar(getClass().getResource(resourcePath).toURI().getPath()); + + HandlerCollection handlers = new HandlerCollection(); + handlers.setHandlers(new Handler[] {context, new DefaultHandler()}); + server.setHandler(handlers); + } + + configureServer(server); + server.start(); + } catch (final Exception ex) { + ex.printStackTrace(); + fail(ex.getMessage()); + } + } + + protected void configureServer(org.eclipse.jetty.server.Server theserver) throws Exception { + + } + + public void tearDown() throws Exception { + super.tearDown(); + + if (server != null) { + server.stop(); + server.destroy(); + server = null; + } + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/JettyEmbeddedTest.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/JettyEmbeddedTest.java b/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/JettyEmbeddedTest.java new file mode 100644 index 0000000..cafdeec --- /dev/null +++ b/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/JettyEmbeddedTest.java @@ -0,0 +1,49 @@ +/** + * 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.cxf.systest.jaxrs.sse.jetty; + +import org.apache.cxf.jaxrs.model.AbstractResourceInfo; +import org.apache.cxf.systest.jaxrs.sse.AbstractSseTest; +import org.junit.BeforeClass; +import org.junit.Ignore; + +public class JettyEmbeddedTest extends AbstractSseTest { + @Ignore + public static class EmbeddedJettyServer extends AbstractJettyServer { + public static final int PORT = allocatePortAsInt(EmbeddedJettyServer.class); + + public EmbeddedJettyServer() { + super("/", PORT); + } + } + + @BeforeClass + public static void startServers() throws Exception { + AbstractResourceInfo.clearAllMaps(); + //keep out of process due to stack traces testing failures + assertTrue("server did not launch correctly", launchServer(EmbeddedJettyServer.class, true)); + createStaticBus(); + } + + @Override + protected int getPort() { + return EmbeddedJettyServer.PORT; + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/JettyWarTest.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/JettyWarTest.java b/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/JettyWarTest.java new file mode 100644 index 0000000..10f435b --- /dev/null +++ b/systests/rs-sse/rs-sse-jetty/src/test/java/org/apache/cxf/systest/jaxrs/sse/jetty/JettyWarTest.java @@ -0,0 +1,48 @@ +/** + * 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.cxf.systest.jaxrs.sse.jetty; + +import org.apache.cxf.jaxrs.model.AbstractResourceInfo; +import org.apache.cxf.systest.jaxrs.sse.AbstractSseTest; +import org.junit.BeforeClass; +import org.junit.Ignore; + +public class JettyWarTest extends AbstractSseTest { + @Ignore + public static class EmbeddedJettyServer extends AbstractJettyServer { + public static final int PORT = allocatePortAsInt(EmbeddedJettyServer.class); + + public EmbeddedJettyServer() { + super("/jaxrs_sse", "/", PORT); + } + } + + @BeforeClass + public static void startServers() throws Exception { + AbstractResourceInfo.clearAllMaps(); + assertTrue("server did not launch correctly", launchServer(EmbeddedJettyServer.class, true)); + createStaticBus(); + } + + @Override + protected int getPort() { + return EmbeddedJettyServer.PORT; + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-tomcat/pom.xml ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-tomcat/pom.xml b/systests/rs-sse/rs-sse-tomcat/pom.xml new file mode 100644 index 0000000..e59a7b7 --- /dev/null +++ b/systests/rs-sse/rs-sse-tomcat/pom.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <parent> + <groupId>org.apache.cxf.systests</groupId> + <artifactId>cxf-systests-rs-sse</artifactId> + <version>3.2.0-SNAPSHOT</version> + <relativePath>../</relativePath> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>cxf-systests-rs-sse-tomcat</artifactId> + <name>Apache CXF SSE Integration System Tests for Tomcat</name> + <description>Apache CXF SSE Integration System Tests Tomcat</description> + <url>http://cxf.apache.org</url> + <properties> + <cxf.tomcat.version>8.0.32</cxf.tomcat.version> + </properties> + <dependencies> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-core</artifactId> + <version>${cxf.tomcat.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-logging-juli</artifactId> + <version>${cxf.tomcat.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-jasper</artifactId> + <version>${cxf.tomcat.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.cxf.systests</groupId> + <artifactId>cxf-systests-rs-sse-base</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.eclipse.jetty.websocket</groupId> + <artifactId>websocket-server</artifactId> + <version>${cxf.jetty.version}</version> + <scope>test</scope> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/AbstractTomcatServer.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/AbstractTomcatServer.java b/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/AbstractTomcatServer.java new file mode 100644 index 0000000..ded2a64 --- /dev/null +++ b/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/AbstractTomcatServer.java @@ -0,0 +1,111 @@ +/** + * 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.cxf.systest.jaxrs.sse.tomcat; + +import java.io.File; +import java.io.IOException; + +import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; + +import org.apache.catalina.Context; +import org.apache.catalina.Wrapper; +import org.apache.catalina.startup.Tomcat; +import org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet; +import org.apache.cxf.systest.jaxrs.sse.BookStore; +import org.apache.cxf.testutil.common.AbstractBusTestServerBase; +import org.apache.cxf.transport.sse.SseHttpTransportFactory; + +public abstract class AbstractTomcatServer extends AbstractBusTestServerBase { + + private Tomcat server; + private final String resourcePath; + private final String contextPath; + private final int port; + + protected AbstractTomcatServer(final String contextPath, int portNumber) { + this(null, contextPath, portNumber); + } + + protected AbstractTomcatServer(final String resourcePath, final String contextPath, int portNumber) { + this.resourcePath = resourcePath; + this.contextPath = contextPath; + this.port = portNumber; + } + + protected void run() { + server = new Tomcat(); + server.setPort(port); + + try { + final File base = createTemporaryDirectory(); + server.setBaseDir(base.getAbsolutePath()); + + if (resourcePath == null) { + final Context context = server.addContext("/", base.getAbsolutePath()); + final Wrapper cxfServlet = Tomcat.addServlet(context, "cxfServlet", new CXFNonSpringJaxrsServlet()); + cxfServlet.addInitParameter(CXFNonSpringJaxrsServlet.TRANSPORT_ID, + SseHttpTransportFactory.TRANSPORT_ID); + cxfServlet.addInitParameter("jaxrs.serviceClasses", BookStore.class.getName()); + cxfServlet.addInitParameter("jaxrs.providers", JacksonJsonProvider.class.getName()); + cxfServlet.setAsyncSupported(true); + context.addServletMapping("/rest/*", "cxfServlet"); + } else { + server.getHost().setAppBase(base.getAbsolutePath()); + server.getHost().setAutoDeploy(true); + server.getHost().setDeployOnStartup(true); + server.addWebapp(contextPath, getClass().getResource(resourcePath).toURI().getPath().toString()); + } + + server.start(); + } catch (final Exception ex) { + ex.printStackTrace(); + fail(ex.getMessage()); + } + } + + protected void configureServer(org.eclipse.jetty.server.Server theserver) throws Exception { + + } + + private static File createTemporaryDirectory() throws IOException { + final File base = File.createTempFile("tmp-", ""); + + if (!base.delete()) { + throw new IOException("Cannot (re)create base folder: " + base.getAbsolutePath()); + } + + if (!base.mkdir()) { + throw new IOException("Cannot create base folder: " + base.getAbsolutePath()); + } + + base.deleteOnExit(); + return base; + } + + public void tearDown() throws Exception { + super.tearDown(); + + if (server != null) { + server.stop(); + server.destroy(); + server = null; + } + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/TomcatEmbeddedTest.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/TomcatEmbeddedTest.java b/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/TomcatEmbeddedTest.java new file mode 100644 index 0000000..b96cc28 --- /dev/null +++ b/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/TomcatEmbeddedTest.java @@ -0,0 +1,49 @@ +/** + * 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.cxf.systest.jaxrs.sse.tomcat; + +import org.apache.cxf.jaxrs.model.AbstractResourceInfo; +import org.apache.cxf.systest.jaxrs.sse.AbstractSseTest; +import org.junit.BeforeClass; +import org.junit.Ignore; + +public class TomcatEmbeddedTest extends AbstractSseTest { + @Ignore + public static class EmbeddedTomcatServer extends AbstractTomcatServer { + public static final int PORT = allocatePortAsInt(EmbeddedTomcatServer.class); + + public EmbeddedTomcatServer() { + super("/", PORT); + } + } + + @BeforeClass + public static void startServers() throws Exception { + AbstractResourceInfo.clearAllMaps(); + assertTrue("server did not launch correctly", launchServer(EmbeddedTomcatServer.class, true)); + createStaticBus(); + } + + @Override + protected int getPort() { + return EmbeddedTomcatServer.PORT; + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/TomcatWarTest.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/TomcatWarTest.java b/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/TomcatWarTest.java new file mode 100644 index 0000000..102c1d1 --- /dev/null +++ b/systests/rs-sse/rs-sse-tomcat/src/test/java/org/apache/cxf/systest/jaxrs/sse/tomcat/TomcatWarTest.java @@ -0,0 +1,49 @@ +/** + * 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.cxf.systest.jaxrs.sse.tomcat; + +import org.apache.cxf.jaxrs.model.AbstractResourceInfo; +import org.apache.cxf.systest.jaxrs.sse.AbstractSseTest; +import org.junit.BeforeClass; +import org.junit.Ignore; + +public class TomcatWarTest extends AbstractSseTest { + @Ignore + public static class EmbeddedTomcatServer extends AbstractTomcatServer { + public static final int PORT = allocatePortAsInt(EmbeddedTomcatServer.class); + + public EmbeddedTomcatServer() { + super("/jaxrs_sse", "/", PORT); + } + } + + @BeforeClass + public static void startServers() throws Exception { + AbstractResourceInfo.clearAllMaps(); + assertTrue("server did not launch correctly", launchServer(EmbeddedTomcatServer.class, true)); + createStaticBus(); + } + + @Override + protected int getPort() { + return EmbeddedTomcatServer.PORT; + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractBroadcasterSseTest.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractBroadcasterSseTest.java b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractBroadcasterSseTest.java deleted file mode 100644 index 12a7ec7..0000000 --- a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractBroadcasterSseTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * 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.cxf.systest.jaxrs.sse; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; - -import com.fasterxml.jackson.core.JsonProcessingException; - -import org.junit.Test; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.hasItems; - -public abstract class AbstractBroadcasterSseTest extends AbstractSseBaseTest { - @Test - public void testBooksStreamIsBroadcasted() throws Exception { - final Collection<Future<Response>> results = new ArrayList<>(); - - for (int i = 0; i < 2; ++i) { - results.add( - createWebClient("/rest/api/bookstore/broadcast/sse").async().get() - ); - } - - createWebClient("/rest/api/bookstore/broadcast/close") - .async() - .post(null) - .get(10, TimeUnit.SECONDS) - .close(); - - for (final Future<Response> result: results) { - final Response r = result.get(3, TimeUnit.SECONDS); - assertEquals(Status.OK.getStatusCode(), r.getStatus()); - - final String response = r.readEntity(String.class); - assertThat(response, containsString("id: 1000")); - assertThat(response, containsString("data: " + toJson("New Book #1000", 1000))); - - assertThat(response, containsString("id: 2000")); - assertThat(response, containsString("data: " + toJson("New Book #2000", 2000))); - - r.close(); - } - } - - @Test - public void testBooksAreReturned() throws JsonProcessingException { - Response r = createWebClient("/rest/api/bookstore", MediaType.APPLICATION_JSON).get(); - assertEquals(Status.OK.getStatusCode(), r.getStatus()); - - final Book[] books = r.readEntity(Book[].class); - assertThat(Arrays.asList(books), hasItems(new Book("New Book #1", 1), new Book("New Book #2", 2))); - - r.close(); - } -} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseBaseTest.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseBaseTest.java b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseBaseTest.java deleted file mode 100644 index 87425b5..0000000 --- a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseBaseTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * 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.cxf.systest.jaxrs.sse; - -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; - -import org.apache.cxf.jaxrs.client.WebClient; -import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase; - -public abstract class AbstractSseBaseTest extends AbstractBusClientServerTestBase { - private final ObjectMapper mapper = new ObjectMapper(); - - protected String toJson(final String name, final Integer id) throws JsonProcessingException { - return mapper.writeValueAsString(new Book(name, id)); - } - - protected WebClient createWebClient(final String url, final String media) { - final List< ? > providers = Arrays.asList(new JacksonJsonProvider()); - - final WebClient wc = WebClient - .create("http://localhost:" + getPort() + url, providers) - .accept(media); - - WebClient.getConfig(wc).getHttpConduit().getClient().setReceiveTimeout(8000L); - return wc; - } - - protected WebClient createWebClient(final String url) { - return createWebClient(url, MediaType.SERVER_SENT_EVENTS); - } - - protected WebTarget createWebTarget(final String url) { - return ClientBuilder - .newClient() - .property("http.receive.timeout", 8000) - .register(JacksonJsonProvider.class) - .target("http://localhost:" + getPort() + url); - } - - protected void awaitEvents(long timeout, final Collection<?> events, int size) throws InterruptedException { - final long sleep = timeout / 10; - - for (int i = 0; i < timeout; i += sleep) { - if (events.size() == size) { - break; - } else { - Thread.sleep(sleep); - } - } - } - - protected abstract int getPort(); -} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseTest.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseTest.java b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseTest.java deleted file mode 100644 index 2f36914..0000000 --- a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/AbstractSseTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/** - * 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.cxf.systest.jaxrs.sse; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.function.Consumer; - -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.sse.InboundSseEvent; -import javax.ws.rs.sse.SseEventSource; - -import org.junit.Test; - -import static org.hamcrest.CoreMatchers.anyOf; -import static org.hamcrest.CoreMatchers.hasItem; -import static org.hamcrest.CoreMatchers.hasItems; - -public abstract class AbstractSseTest extends AbstractSseBaseTest { - @Test - public void testBooksStreamIsReturnedFromLastEventId() throws InterruptedException { - final WebTarget target = createWebTarget("/rest/api/bookstore/sse/1") - .property(HttpHeaders.LAST_EVENT_ID_HEADER, 150); - final Collection<Book> books = new ArrayList<>(); - - try (final SseEventSource eventSource = SseEventSource.target(target).build()) { - eventSource.register(collect(books), System.out::println); - eventSource.open(); - // Give the SSE stream some time to collect all events - awaitEvents(3000, books, 4); - } - - // Easing the test verification here, it does not work well for Atm + Jetty - assertThat(books, - anyOf( - hasItem(new Book("New Book #151", 151)), - hasItem(new Book("New Book #152", 152)), - hasItem(new Book("New Book #153", 153)), - hasItem(new Book("New Book #154", 154)) - ) - ); - } - - @Test - public void testBooksStreamIsReturnedFromInboundSseEvents() throws InterruptedException { - final WebTarget target = createWebTarget("/rest/api/bookstore/sse/0"); - final Collection<Book> books = new ArrayList<>(); - - try (final SseEventSource eventSource = SseEventSource.target(target).build()) { - eventSource.register(collect(books), System.out::println); - eventSource.open(); - // Give the SSE stream some time to collect all events - awaitEvents(3000, books, 4); - } - - assertThat(books, - hasItems( - new Book("New Book #1", 1), - new Book("New Book #2", 2), - new Book("New Book #3", 3), - new Book("New Book #4", 4) - ) - ); - } - - private static Consumer<InboundSseEvent> collect(final Collection< Book > books) { - return event -> books.add(event.readData(Book.class, MediaType.APPLICATION_JSON_TYPE)); - } -} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/Book.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/Book.java b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/Book.java deleted file mode 100644 index 7deb5c0..0000000 --- a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/Book.java +++ /dev/null @@ -1,71 +0,0 @@ -/** - * 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.cxf.systest.jaxrs.sse; - -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; -import org.apache.commons.lang3.builder.ToStringBuilder; - -public class Book { - private String name; - private Integer id; - - public Book() { - } - - public Book(Integer id) { - this.id = id; - } - - public Book(String name, Integer id) { - this.name = name; - this.id = id; - } - - public void setName(String n) { - name = n; - } - - public String getName() { - return name; - } - - public void setId(Integer i) { - id = i; - } - - public Integer getId() { - return id; - } - - @Override - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); - } - - @Override - public boolean equals(Object obj) { - return EqualsBuilder.reflectionEquals(this, obj); - } - - @Override - public String toString() { - return ToStringBuilder.reflectionToString(this); - } -} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore.java b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore.java deleted file mode 100644 index c096713..0000000 --- a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore.java +++ /dev/null @@ -1,136 +0,0 @@ -/** - * 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.cxf.systest.jaxrs.sse; - -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.ws.rs.DefaultValue; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.sse.OutboundSseEvent; -import javax.ws.rs.sse.OutboundSseEvent.Builder; -import javax.ws.rs.sse.Sse; -import javax.ws.rs.sse.SseBroadcaster; -import javax.ws.rs.sse.SseEventSink; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Path("/api/bookstore") -public class BookStore { - private static final Logger LOG = LoggerFactory.getLogger(BookStore.class); - - private final CountDownLatch latch = new CountDownLatch(2); - private Sse sse; - private SseBroadcaster broadcaster; - - @Context - public void setSse(Sse sse) { - this.sse = sse; - this.broadcaster = sse.newBroadcaster(); - } - - @GET - @Produces(MediaType.APPLICATION_JSON) - public Collection<Book> books() { - return Arrays.asList( - new Book("New Book #1", 1), - new Book("New Book #2", 2) - ); - } - - @GET - @Path("sse/{id}") - @Produces(MediaType.SERVER_SENT_EVENTS) - public void forBook(@Context SseEventSink sink, @PathParam("id") final String id, - @HeaderParam(HttpHeaders.LAST_EVENT_ID_HEADER) @DefaultValue("0") final String lastEventId) { - - new Thread() { - public void run() { - try { - final Integer id = Integer.valueOf(lastEventId); - final Builder builder = sse.newEventBuilder(); - - sink.send(createStatsEvent(builder.name("book"), id + 1)); - Thread.sleep(200); - sink.send(createStatsEvent(builder.name("book"), id + 2)); - Thread.sleep(200); - sink.send(createStatsEvent(builder.name("book"), id + 3)); - Thread.sleep(200); - sink.send(createStatsEvent(builder.name("book"), id + 4)); - Thread.sleep(200); - sink.close(); - } catch (final InterruptedException ex) { - LOG.error("Communication error", ex); - } - } - }.start(); - } - - @GET - @Path("broadcast/sse") - @Produces(MediaType.SERVER_SENT_EVENTS) - public void broadcast(@Context SseEventSink sink) { - try { - broadcaster.register(sink); - } finally { - latch.countDown(); - } - } - - @POST - @Path("broadcast/close") - public void stop() { - try { - // Await a least 2 clients to be broadcasted over - if (!latch.await(10, TimeUnit.SECONDS)) { - LOG.warn("Not enough clients have been connected, closing broadcaster anyway"); - } - - final Builder builder = sse.newEventBuilder(); - broadcaster.broadcast(createStatsEvent(builder.name("book"), 1000)); - broadcaster.broadcast(createStatsEvent(builder.name("book"), 2000)); - - } catch (final InterruptedException ex) { - LOG.error("Wait has been interrupted", ex); - } - - if (broadcaster != null) { - broadcaster.close(); - } - } - - private static OutboundSseEvent createStatsEvent(final OutboundSseEvent.Builder builder, final int eventId) { - return builder - .id(Integer.toString(eventId)) - .data(Book.class, new Book("New Book #" + eventId, eventId)) - .mediaType(MediaType.APPLICATION_JSON_TYPE) - .build(); - } -} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java deleted file mode 100644 index a5eeb8e..0000000 --- a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/BookStore2.java +++ /dev/null @@ -1,135 +0,0 @@ -/** - * 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.cxf.systest.jaxrs.sse; - -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import javax.ws.rs.DefaultValue; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.sse.OutboundSseEvent; -import javax.ws.rs.sse.OutboundSseEvent.Builder; -import javax.ws.rs.sse.Sse; -import javax.ws.rs.sse.SseBroadcaster; -import javax.ws.rs.sse.SseEventSink; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Path("/api/bookstore") -public class BookStore2 { - private static final Logger LOG = LoggerFactory.getLogger(BookStore2.class); - - private final CountDownLatch latch = new CountDownLatch(2); - private Sse sse; - private SseBroadcaster broadcaster; - - public BookStore2(@Context Sse sse) { - this.sse = sse; - this.broadcaster = sse.newBroadcaster(); - } - - @GET - @Produces(MediaType.APPLICATION_JSON) - public Collection<Book> books() { - return Arrays.asList( - new Book("New Book #1", 1), - new Book("New Book #2", 2) - ); - } - - @GET - @Path("sse/{id}") - @Produces(MediaType.SERVER_SENT_EVENTS) - public void forBook(@Context SseEventSink sink, @PathParam("id") final String id, - @HeaderParam(HttpHeaders.LAST_EVENT_ID_HEADER) @DefaultValue("0") final String lastEventId) { - - new Thread() { - public void run() { - try { - final Integer id = Integer.valueOf(lastEventId); - final Builder builder = sse.newEventBuilder(); - - sink.send(createStatsEvent(builder.name("book"), id + 1)); - Thread.sleep(200); - sink.send(createStatsEvent(builder.name("book"), id + 2)); - Thread.sleep(200); - sink.send(createStatsEvent(builder.name("book"), id + 3)); - Thread.sleep(200); - sink.send(createStatsEvent(builder.name("book"), id + 4)); - Thread.sleep(200); - sink.close(); - } catch (final InterruptedException ex) { - LOG.error("Communication error", ex); - } - } - }.start(); - } - - @GET - @Path("broadcast/sse") - @Produces(MediaType.SERVER_SENT_EVENTS) - public void broadcast(@Context SseEventSink sink) { - try { - broadcaster.register(sink); - } finally { - latch.countDown(); - } - } - - @POST - @Path("broadcast/close") - public void stop() { - try { - // Await a least 2 clients to be broadcasted over - if (!latch.await(10, TimeUnit.SECONDS)) { - LOG.warn("Not enough clients have been connected, closing broadcaster anyway"); - } - - final Builder builder = sse.newEventBuilder(); - broadcaster.broadcast(createStatsEvent(builder.name("book"), 1000)); - broadcaster.broadcast(createStatsEvent(builder.name("book"), 2000)); - - } catch (final InterruptedException ex) { - LOG.error("Wait has been interrupted", ex); - } - - if (broadcaster != null) { - broadcaster.close(); - } - } - - private static OutboundSseEvent createStatsEvent(final OutboundSseEvent.Builder builder, final int eventId) { - return builder - .id(Integer.toString(eventId)) - .data(Book.class, new Book("New Book #" + eventId, eventId)) - .mediaType(MediaType.APPLICATION_JSON_TYPE) - .build(); - } -} http://git-wip-us.apache.org/repos/asf/cxf/blob/76877054/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java ---------------------------------------------------------------------- diff --git a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java b/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java deleted file mode 100644 index a4a4049..0000000 --- a/systests/rs-sse/src/test/java/org/apache/cxf/systest/jaxrs/sse/SseApplication.java +++ /dev/null @@ -1,38 +0,0 @@ -/** - * 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.cxf.systest.jaxrs.sse; - -import java.util.Collections; -import java.util.Set; - -import javax.ws.rs.core.Application; - -import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; - -public class SseApplication extends Application { - @Override - public Set<Class<?>> getClasses() { - return Collections.singleton(BookStore2.class); - } - - @Override - public Set<Object> getSingletons() { - return Collections.singleton(new JacksonJsonProvider()); - } -}