add a blueprint version of websocket sample for karaf
Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/5ce68277 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/5ce68277 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/5ce68277 Branch: refs/heads/3.1.x-fixes Commit: 5ce682771ae91eab61e25eaa90ef416168eb4402 Parents: de9b793 Author: Akitoshi Yoshida <a...@apache.org> Authored: Tue Apr 5 10:38:42 2016 +0200 Committer: Akitoshi Yoshida <a...@apache.org> Committed: Tue Apr 5 13:36:58 2016 +0200 ---------------------------------------------------------------------- .../samples/jax_rs/websocket_osgi/README.txt | 94 +++++++ .../samples/jax_rs/websocket_osgi/pom.xml | 94 +++++++ .../main/java/demo/jaxrs/server/Customer.java | 43 +++ .../java/demo/jaxrs/server/CustomerService.java | 271 +++++++++++++++++++ .../src/main/java/demo/jaxrs/server/Order.java | 69 +++++ .../main/java/demo/jaxrs/server/Product.java | 43 +++ .../resources/OSGI-INF/blueprint/context.xml | 47 ++++ .../websocket_osgi/src/test/resources/client.js | 234 ++++++++++++++++ 8 files changed, 895 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/5ce68277/distribution/src/main/release/samples/jax_rs/websocket_osgi/README.txt ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/README.txt b/distribution/src/main/release/samples/jax_rs/websocket_osgi/README.txt new file mode 100644 index 0000000..60d7705 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/README.txt @@ -0,0 +1,94 @@ +JAX-RS WebSocket OSGi Blueprint Demo +================= + +This is an OSGi Blueprint version of JAX-RS WebSocket Demo. + +Building and running the demo using maven +--------------------------------------- + +From the base directory of this sample (i.e., where this README file is +located), the maven pom.xml file can be used to build and run the demo. + + +Using either UNIX or Windows: + + mvn install + +This will produce a war file in the target folder. + + +Starting Karaf (refer to http://karaf.apache.org/manual/latest-3.0.x/quick-start.html) + + bin/karaf + + + __ __ ____ + / //_/____ __________ _/ __/ + / ,< / __ `/ ___/ __ `/ /_ + / /| |/ /_/ / / / /_/ / __/ + /_/ |_|\__,_/_/ \__,_/_/ + + Apache Karaf (3.0.4) + + Hit '<tab>' for a list of available commands + and '[cmd] --help' for help on a specific command. + Hit '<ctrl-d>' or type 'system:shutdown' or 'logout' to shutdown Karaf. + + +In order to install CXF's features, you need to add the CXF's features repo using + + feature:repo-add cxf 3.n.m + + where 3.n.m corresponds to a valid CXF version number + +Install CXF's cxf-jaxrs and cxf-transports-websocket-server features that installs all the required bundles +for this demo bundle. + + feature:install cxf-jaxrs cxf-transports-websocket-server + +Install this demo bundle (using the appropriate bundle version number) + + install -s mvn:org.apache.cxf.samples/jax_rs_websocket_osgi/3.n.m + +And verify the bundles are installed. + +karaf@root()> feature:repo-add cxf 3.2.0-SNAPSHOT +Adding feature url mvn:org.apache.cxf.karaf/apache-cxf/3.2.0-SNAPSHOT/xml/features +karaf@root()> feature:install cxf-jaxrs cxf-transports-websocket-server +karaf@root()> list -t 0 | grep CXF + 80 | Active | 40 | 3.2.0.SNAPSHOT | Apache CXF Core + 81 | Active | 40 | 3.2.0.SNAPSHOT | Apache CXF Runtime Management +100 | Active | 40 | 3.2.0.SNAPSHOT | Apache CXF Runtime HTTP Transport +102 | Active | 40 | 3.2.0.SNAPSHOT | Apache CXF JAX-RS Extensions: Providers +103 | Active | 40 | 3.2.0.SNAPSHOT | Apache CXF JAX-RS Extensions: Search +104 | Active | 40 | 3.2.0.SNAPSHOT | Apache CXF JAX-RS Service Description +105 | Active | 40 | 3.2.0.SNAPSHOT | Apache CXF Runtime JAX-RS Frontend +106 | Active | 40 | 3.2.0.SNAPSHOT | Apache CXF JAX-RS Client +108 | Active | 40 | 3.2.0.SNAPSHOT | Apache CXF Runtime WebSocket Transport +karaf@root()> install -s mvn:org.apache.cxf.samples/jax_rs_websocket_osgi +Bundle ID: 109 +karaf@root()> list +START LEVEL 100 , List Threshold: 50 + ID | State | Lvl | Version | Name +--------------------------------------------------------------------- +107 | Active | 80 | 2.4.3 | atmosphere-runtime +109 | Active | 80 | 3.2.0.SNAPSHOT | JAX-RS WebSocket Blueprint Demo +karaf@root()> + + +Visit http://localhost:8181/cxf/ to see if this RESTful service is registered. + +Using Node.js client to test the service +-------- + +Go to samples/jax_rs/websocket_osgi/src/test/resources and at the console + +Assuming node (>=v4) and npm are installed, execute the following shell commands. + +% npm install atmosphere.js +% node client.js + +This client program supports websocket and sse and allows +you to choose your preferred protocol. + + http://git-wip-us.apache.org/repos/asf/cxf/blob/5ce68277/distribution/src/main/release/samples/jax_rs/websocket_osgi/pom.xml ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/pom.xml b/distribution/src/main/release/samples/jax_rs/websocket_osgi/pom.xml new file mode 100644 index 0000000..e0d1234 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/pom.xml @@ -0,0 +1,94 @@ +<?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"> + <modelVersion>4.0.0</modelVersion> + <artifactId>jax_rs_websocket_osgi</artifactId> + <packaging>bundle</packaging> + <name>JAX-RS WebSocket Blueprint Demo</name> + <description>JAX-RS WebSocket Demo</description> + + <parent> + <groupId>org.apache.cxf.samples</groupId> + <artifactId>cxf-samples</artifactId> + <version>3.2.0-SNAPSHOT</version> + <relativePath>../..</relativePath> + </parent> + <properties> + <cxf.version>${project.version}</cxf.version> + <!-- TODO remove these local entries after making the referenced dependency managed in parent/pom.xml --> + <cxf.atmosphere.version>2.4.3</cxf.atmosphere.version> + <cxf.jetty92.version>9.2.15.v20160210</cxf.jetty92.version> + <cxf.jetty93.version>9.3.5.v20151012</cxf.jetty93.version> + <cxf.jetty.version>${cxf.jetty93.version}</cxf.jetty.version> + </properties> + <build> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <extensions>true</extensions> + <configuration> + <instructions> + <Bundle-SymbolicName>${project.groupId}.${project.artifactId};blueprint.aries.xml-validation:=false</Bundle-SymbolicName> + <Import-Package> + javax.ws.rs, + javax.ws.rs.core, + org.apache.cxf.jaxrs.provider, + org.osgi.service.blueprint, + * + </Import-Package> + <Export-Package> + </Export-Package> + </instructions> + </configuration> + </plugin> + </plugins> + </build> + <dependencies> + <!-- cxt et al --> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-transports-http</artifactId> + <version>3.2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-transports-websocket</artifactId> + <version>3.2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.cxf</groupId> + <artifactId>cxf-rt-frontend-jaxrs</artifactId> + <version>3.2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>javax.ws.rs</groupId> + <artifactId>javax.ws.rs-api</artifactId> + </dependency> + + <!-- add atmosphere --> + <dependency> + <groupId>org.atmosphere</groupId> + <artifactId>atmosphere-runtime</artifactId> + <version>${cxf.atmosphere.version}</version> + </dependency> + + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/cxf/blob/5ce68277/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Customer.java ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Customer.java b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Customer.java new file mode 100644 index 0000000..44025f0 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Customer.java @@ -0,0 +1,43 @@ +/** + * 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 demo.jaxrs.server; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "Customer") +public class Customer { + private long id; + private String name; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/5ce68277/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/CustomerService.java ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/CustomerService.java b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/CustomerService.java new file mode 100644 index 0000000..f77f8aa --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/CustomerService.java @@ -0,0 +1,271 @@ +/** + * 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 demo.jaxrs.server; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.servlet.http.HttpServletResponse; + +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.StreamingOutput; + +import org.apache.cxf.transport.websocket.WebSocketConstants; + +@Path("/customerservice/") +@Produces("text/xml") +public class CustomerService { + private static final int MAX_ERROR_COUNT = 5; + private static ExecutorService executor = Executors.newSingleThreadExecutor(); + + long currentId = 123; + Map<Long, Customer> customers = new HashMap<Long, Customer>(); + Map<Long, Order> orders = new HashMap<Long, Order>(); + Map<String, WriterHolder<OutputStream>> monitors = new HashMap<String, WriterHolder<OutputStream>>(); + Map<String, WriterHolder<HttpServletResponse>> monitors2 = new HashMap<String, WriterHolder<HttpServletResponse>>(); + + public CustomerService() { + init(); + } + + @GET + @Path("/customers/{id}/") + public Customer getCustomer(@PathParam("id") String id) { + System.out.println("----invoking getCustomer, Customer id is: " + id); + long idNumber = Long.parseLong(id); + Customer customer = customers.get(idNumber); + if (customer != null) { + sendCustomerEvent("retrieved", customer); + } + return customer; + } + + @PUT + @Path("/customers/") + public Response updateCustomer(Customer customer) { + System.out.println("----invoking updateCustomer, Customer name is: " + customer.getName()); + Customer c = customers.get(customer.getId()); + Response r; + if (c != null) { + customers.put(customer.getId(), customer); + r = Response.ok().build(); + sendCustomerEvent("updated", customer); + } else { + r = Response.notModified().build(); + } + + return r; + } + + @POST + @Path("/customers/") + public Response addCustomer(Customer customer) { + System.out.println("----invoking addCustomer, Customer name is: " + customer.getName()); + customer.setId(++currentId); + + customers.put(customer.getId(), customer); + sendCustomerEvent("added", customer); + return Response.ok(customer).build(); + } + + @DELETE + @Path("/customers/{id}/") + public Response deleteCustomer(@PathParam("id") String id) { + System.out.println("----invoking deleteCustomer, Customer id is: " + id); + long idNumber = Long.parseLong(id); + Customer c = customers.get(idNumber); + + Response r; + if (c != null) { + r = Response.ok().build(); + Customer customer = customers.remove(idNumber); + if (customer != null) { + sendCustomerEvent("deleted", customer); + } + } else { + r = Response.notModified().build(); + } + + return r; + } + + @Path("/orders/{orderId}/") + public Order getOrder(@PathParam("orderId") String orderId) { + System.out.println("----invoking getOrder, Order id is: " + orderId); + long idNumber = Long.parseLong(orderId); + Order c = orders.get(idNumber); + return c; + } + + @GET + @Path("/monitor") + @Produces("text/*") + public StreamingOutput monitorCustomers( + @HeaderParam(WebSocketConstants.DEFAULT_REQUEST_ID_KEY) String reqid) { + final String key = reqid == null ? "*" : reqid; + return new StreamingOutput() { + public void write(final OutputStream out) throws IOException, WebApplicationException { + monitors.put(key, new WriterHolder(out, MAX_ERROR_COUNT)); + out.write(("Subscribed at " + new java.util.Date()).getBytes()); + } + + }; + } + + @GET + @Path("/monitor2") + @Produces("text/*") + public void monitorCustomers2( + final @javax.ws.rs.core.Context HttpServletResponse httpResponse, + @HeaderParam(WebSocketConstants.DEFAULT_REQUEST_ID_KEY) String reqid) { + final String key = reqid == null ? "*" : reqid; + monitors2.put(key, new WriterHolder(httpResponse, MAX_ERROR_COUNT)); + try { + httpResponse.getOutputStream().write(("Subscribed at " + new java.util.Date()).getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @GET + @Path("/unmonitor/{key}") + @Produces("text/*") + public String unmonitorCustomers(@PathParam("key") String key) { + return (monitors.remove(key) != null ? "Removed: " : "Already removed: ") + key; + } + + @GET + @Path("/unmonitor2/{key}") + @Produces("text/*") + public String unmonitorCustomers2(@PathParam("key") String key) { + return (monitors2.remove(key) != null ? "Removed: " : "Already removed: ") + key; + } + + private void sendCustomerEvent(final String msg, final Customer customer) { + executor.execute(new Runnable() { + public void run() { + try { + String t = msg + ": " + customer.getId() + "/" + customer.getName(); + for (Iterator<WriterHolder<OutputStream>> it = monitors.values().iterator(); it.hasNext();) { + WriterHolder<OutputStream> wh = it.next(); + try { + wh.getValue().write(t.getBytes()); + wh.getValue().flush(); + wh.reset(); + } catch (IOException e) { + System.out.println("----error writing to " + wh.getValue() + " " + wh.get()); + if (wh.increment()) { + // the max error count reached; purging the output resource + e.printStackTrace(); + try { + wh.getValue().close(); + } catch (IOException e2) { + // ignore; + } + it.remove(); + System.out.println("----purged " + wh.getValue()); + } + } + } + for (Iterator<WriterHolder<HttpServletResponse>> it = monitors2.values().iterator(); it.hasNext();) { + WriterHolder<HttpServletResponse> wh = it.next(); + try { + wh.getValue().getOutputStream().write(t.getBytes()); + wh.getValue().getOutputStream().flush(); + wh.reset(); + } catch (IOException e) { + System.out.println("----error writing to " + wh.getValue() + " " + wh.get()); + if (wh.increment()) { + // the max error count reached; purging the output resource + e.printStackTrace(); + try { + wh.getValue().getOutputStream().close(); + } catch (IOException e2) { + // ignore; + } + it.remove(); + System.out.println("----purged " + wh.getValue()); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + + } + final void init() { + Customer c = new Customer(); + c.setName("John"); + c.setId(123); + customers.put(c.getId(), c); + c = new Customer(); + c.setName("Homer"); + c.setId(235); + customers.put(c.getId(), c); + + Order o = new Order(); + o.setDescription("order 223"); + o.setId(223); + orders.put(o.getId(), o); + } + + private static class WriterHolder<T> { + final private T value; + final private int max; + final private AtomicInteger errorCount; + + public WriterHolder(T object, int max) { + this.value = object; + this.max = max; + this.errorCount = new AtomicInteger(); + } + + public T getValue() { + return value; + } + + public int get() { + return errorCount.get(); + } + public boolean increment() { + return max < errorCount.getAndIncrement(); + } + + public void reset() { + errorCount.getAndSet(0); + } + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/5ce68277/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Order.java ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Order.java b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Order.java new file mode 100644 index 0000000..a06b68b --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Order.java @@ -0,0 +1,69 @@ +/** + * 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 demo.jaxrs.server; + +import java.util.HashMap; +import java.util.Map; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "Order") +public class Order { + private long id; + private String description; + private Map<Long, Product> products = new HashMap<Long, Product>(); + + public Order() { + init(); + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String d) { + this.description = d; + } + + @GET + @Path("products/{productId}/") + public Product getProduct(@PathParam("productId")int productId) { + System.out.println("----invoking getProduct with id: " + productId); + Product p = products.get(new Long(productId)); + return p; + } + + final void init() { + Product p = new Product(); + p.setId(323); + p.setDescription("product 323"); + products.put(p.getId(), p); + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/5ce68277/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Product.java ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Product.java b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Product.java new file mode 100644 index 0000000..4452ec5 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/java/demo/jaxrs/server/Product.java @@ -0,0 +1,43 @@ +/** + * 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 demo.jaxrs.server; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "Product") +public class Product { + private long id; + private String description; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public void setDescription(String d) { + this.description = d; + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/5ce68277/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/resources/OSGI-INF/blueprint/context.xml ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/resources/OSGI-INF/blueprint/context.xml b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/resources/OSGI-INF/blueprint/context.xml new file mode 100644 index 0000000..9bd1cdf --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/main/resources/OSGI-INF/blueprint/context.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<!-- START SNIPPET: blueprint --> +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:cxf="http://cxf.apache.org/blueprint/core" + xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs" + + xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd + http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd + http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd"> + + + <!-- Application resources --> + <bean id="sampleResource" class="demo.jaxrs.server.CustomerService" /> + + <cxf:bus> + <cxf:features> + <cxf:logging /> + </cxf:features> + </cxf:bus> + + <jaxrs:server id="websocketSampleService" address="/websocketSample" transportId="http://cxf.apache.org/transports/websocket"> + <jaxrs:serviceBeans> + <ref component-id="sampleResource" /> + </jaxrs:serviceBeans> + </jaxrs:server> + +</blueprint> +<!-- END SNIPPET: blueprint --> http://git-wip-us.apache.org/repos/asf/cxf/blob/5ce68277/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/test/resources/client.js ---------------------------------------------------------------------- diff --git a/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/test/resources/client.js b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/test/resources/client.js new file mode 100644 index 0000000..492d520 --- /dev/null +++ b/distribution/src/main/release/samples/jax_rs/websocket_osgi/src/test/resources/client.js @@ -0,0 +1,234 @@ +/** + * client.js + * + * A client program to interact with samples/jax_rs/websocket_osgi service + * + * + */ + +"use strict"; + +// set the host url and path if the service runs at a different location +var HOST_URL = 'http://localhost:8181'; +var CONTEXT_PATH = "/cxf/websocketSample" + +var reader = require('readline'); +var prompt = reader.createInterface(process.stdin, process.stdout); + +var atmosphere = require('atmosphere.js'); + +var request = { url: HOST_URL + CONTEXT_PATH, + transport : 'websocket', + trackMessageLength: false, + dropHeaders: false, + reconnectInterval : 5000}; +var isopen = false; + +const TRANSPORT_NAMES = ["websocket", "sse"]; + +const COMMAND_LIST = + [["add name", "Add a new consumer and return the customer instance. (e.g., add green)"], + ["delete id", "Delete the customer. (e.g., delete 124)"], + ["get id", "Return the customere. (e.g., get 123)"], + ["quit", "Quit the application."], + ["subscribe", "Subscribe to the customer queries."], + ["unsubscribe", "Unsubscribe from the customer queries."], + ["update id name", "Update the customer. (e.g., update 125 red)"]]; + +function selectOption(c, opts) { + var i = parseInt(c); + if (!(i >= 0 && i < opts.length)) { + console.log('Invalid selection: ' + c + '; Using ' + opts[0]); + i = 0; + } + return opts[i]; +} + +function getArgs(name, msg) { + var sp = name.length; + if (msg.length > name.length && msg.charAt(name.length) != ' ') { + // remove the command suffix + sp = msg.indexOf(' ', name.length); + if (sp < 0) { + sp = msg.length; + } + } + return msg.substring(sp).trim().split(' '); +} + +function createAddCustomerPayload(name) { + return "<?xml version=\"1.0\"?>\n<Customer>\n <name>" + name + "</name>\n</Customer>\n"; +} + +function createUpdateCustomerPayload(id, name) { + return "<?xml version=\"1.0\"?>\n<Customer>\n <name>" + name + "</name>\n <id>" + id + "</id>\n</Customer>\n"; +} + +/// + +function doHelp() { + console.log('Available commands'); + for (var i = 0; i < COMMAND_LIST.length; i++) { + var c = COMMAND_LIST[i][0]; + console.log(c + " ".substring(0, 20 - c.length) + COMMAND_LIST[i][1]); + } +} + +function doAdd(v) { + var req; + if (transport == 'websocket') { + req = "POST " + CONTEXT_PATH + "/customerservice/customers\r\nContent-Type: text/xml; charset='utf-8'\r\nAccept: text/xml\r\n\r\n" + + createAddCustomerPayload(v[0]); + } else if (transport == 'sse') { + req = {"method": "POST", "url": HOST_URL + CONTEXT_PATH + "/customerservice/customers", "headers": {"content-type": "text/xml; charset=utf-8", "accept": "text/xml"}, "data": createAddCustomerPayload(v[0])} + } + console.log("TRACE: sending ", req); + subSocket.push(req); +} + +function doDelete(v) { + var req; + if (transport == 'websocket') { + req = "DELETE" + CONTEXT_PATH + "/customerservice/customers/" + v[0]; + } else if (transport == 'sse') { + req = {"method": "DELETE", "url": HOST_URL + CONTEXT_PATH + "/customerservice/customers/" + v[0]} + } + console.log("TRACE: sending ", req); + subSocket.push(req); +} + +function doGet(v) { + var req; + if (transport == 'websocket') { + req = "GET " + CONTEXT_PATH + "/customerservice/customers/" + v[0]; + } else if (transport == 'sse') { + req = {"method": "GET", "url": HOST_URL + CONTEXT_PATH + "/customerservice/customers/" + v[0]} + } + console.log("TRACE: sending ", req); + subSocket.push(req); +} + +function doSubscribe() { + var req; + if (transport == 'websocket') { + req = "GET " + CONTEXT_PATH + "/customerservice/monitor\r\nAccept: text/plain\r\n"; + } else if (transport == 'sse') { + req = {"method": "GET", "url": HOST_URL + CONTEXT_PATH + "/customerservice/monitor", "headers": {"accept": "text/plain"}} + } + console.log("TRACE: sending ", req); + subSocket.push(req); +} + +function doUnsubscribe() { + var req; + if (transport == 'websocket') { + req = "GET " + CONTEXT_PATH + "/customerservice/unmonitor/*\r\nAccept: text/plain\r\n"; + } else if (transport == 'sse') { + req = {"method": "GET", "url": HOST_URL + CONTEXT_PATH + "/customerservice/unmonitor/*", "headers": {"accept": "text/plain"}} + } + console.log("TRACE: sending ", req); + subSocket.push(req); +} + +function doUpdate(v) { + var req; + if (transport == 'websocket') { + req = "PUT " + CONTEXT_PATH + "/customerservice/customers\r\nContent-Type: text/xml; charset='utf-8'\r\nAccept: text/xml\r\n\r\n" + + createUpdateCustomerPayload(v[0], v[1]); + } else if (transport == 'sse') { + req = {"method": "PUT", "url": HOST_URL + CONTEXT_PATH + "/customerservice/customers", "headers": {"content-type": "text/xml; charset=utf-8", "accept": "text/xml"}, "data": createUpdateCustomerPayload(v[0], v[1])} + } + console.log("TRACE: sending ", req); + subSocket.push(req); +} + +function doQuit() { + subSocket.close(); + process.exit(0); +} + +/// + +request.onOpen = function(response) { + isopen = true; + console.log('Connected using ' + response.transport); + prompt.setPrompt("> ", 2); + prompt.prompt(); +}; + +request.onMessage = function (response) { + var message = response.responseBody; + console.log('Received: ', message); + console.log('------------------------------------------------------------------------'); + prompt.setPrompt("> ", 2); + prompt.prompt(); +}; + +request.onReconnect = function(response) { + console.log('Reconnecting ...'); +} + +request.onReopen = function(response) { + isopen = true; + console.log('Reconnected using ' + response.transport); + prompt.setPrompt("> ", 2); + prompt.prompt(); +} + +request.onClose = function(response) { + isopen = false; +} + +request.onError = function(response) { + console.log("Sorry, something went wrong: " + response.responseBody); +}; + +var transport = null; +var subSocket = null; +var author = null; + +console.log("Select transport ..."); +for (var i = 0; i < TRANSPORT_NAMES.length; i++) { + console.log(i + ": " + TRANSPORT_NAMES[i]); +} +prompt.setPrompt("select: ", 6); +prompt.prompt(); + +prompt. +on('line', function(line) { + var msg = line.trim(); + if (transport == null) { + transport = selectOption(msg, TRANSPORT_NAMES); + request.transport = transport; + subSocket = atmosphere.subscribe(request); + console.log("Connecting using " + transport); + setTimeout(function() { + if (!isopen) { + console.log("Unable to open a connection. Terminated."); + process.exit(0); + } + }, 3000); + } else if (msg.length == 0) { + doHelp(); + } else if (msg.indexOf("add") == 0) { + doAdd(getArgs("add", msg)); + } else if (msg.indexOf("del") == 0) { + doDelete(getArgs("del", msg)); + } else if (msg.indexOf("get") == 0) { + doGet(getArgs("get", msg)); + } else if (msg.indexOf("quit") == 0) { + doQuit(); + } else if (msg.indexOf("sub") == 0) { + doSubscribe(getArgs("sub", msg)); + } else if (msg.indexOf("unsub") == 0) { + doUnsubscribe(getArgs("unsub", msg)); + } else if (msg.indexOf("update") == 0) { + doUpdate(getArgs("update", msg)); + } + prompt.setPrompt("> ", 2); + prompt.prompt(); +}). +on('close', function() { + console.log("close"); + process.exit(0); +});