You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by co...@apache.org on 2019/04/30 13:56:34 UTC

[camel] branch master updated: CAMEL-13471 - Adding support for coap+tcp

This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/master by this push:
     new 420e9cd  CAMEL-13471 - Adding support for coap+tcp
420e9cd is described below

commit 420e9cd186c0aa773225dfd91e302baebc776f1c
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Tue Apr 30 14:55:26 2019 +0100

    CAMEL-13471 - Adding support for coap+tcp
---
 components/camel-coap/pom.xml                      |   5 +
 .../java/org/apache/camel/coap/CoAPComponent.java  |  10 +-
 .../java/org/apache/camel/coap/CoAPEndpoint.java   |   6 +-
 .../java/org/apache/camel/coap/CoAPProducer.java   |  14 ++-
 .../services/org/apache/camel/component/coaps      |  18 ---
 .../org/apache/camel/coap/CoAPComponentTest.java   |  28 ++++-
 .../camel/coap/CoAPRestComponentTCPTest.java       | 131 +++++++++++++++++++++
 .../springboot/CoAPComponentAutoConfiguration.java |   2 +-
 8 files changed, 190 insertions(+), 24 deletions(-)

diff --git a/components/camel-coap/pom.xml b/components/camel-coap/pom.xml
index badedf1..4f064de 100644
--- a/components/camel-coap/pom.xml
+++ b/components/camel-coap/pom.xml
@@ -51,6 +51,11 @@
             <artifactId>scandium</artifactId>
             <version>${californium-version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.eclipse.californium</groupId>
+            <artifactId>element-connector-tcp</artifactId>
+            <version>${californium-version}</version>
+        </dependency>
 
         <!-- logging -->
         <dependency>
diff --git a/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPComponent.java b/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPComponent.java
index 6c213ef..c36317f 100644
--- a/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPComponent.java
+++ b/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPComponent.java
@@ -37,6 +37,7 @@ import org.apache.camel.util.URISupport;
 import org.eclipse.californium.core.CoapServer;
 import org.eclipse.californium.core.network.CoapEndpoint;
 import org.eclipse.californium.core.network.config.NetworkConfig;
+import org.eclipse.californium.elements.tcp.TcpServerConnector;
 import org.eclipse.californium.scandium.DTLSConnector;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -44,7 +45,7 @@ import org.slf4j.LoggerFactory;
 /**
  * Represents the component that manages {@link CoAPEndpoint}.
  */
-@Component("coap")
+@Component("coap,coaps,coap+tcp,coaps+tcp")
 public class CoAPComponent extends DefaultComponent implements RestConsumerFactory {
     static final int DEFAULT_PORT = 5684;
     private static final Logger LOG = LoggerFactory.getLogger(CoAPComponent.class);
@@ -65,10 +66,15 @@ public class CoAPComponent extends DefaultComponent implements RestConsumerFacto
             InetSocketAddress address = new InetSocketAddress(port);
             coapBuilder.setNetworkConfig(config);
 
-            // Configure TLS
+            // Configure TLS and / or TCP
             if (CoAPEndpoint.enableTLS(endpoint.getUri())) {
                 DTLSConnector connector = endpoint.createDTLSConnector(address, false);
                 coapBuilder.setConnector(connector);
+            } else if (CoAPEndpoint.enableTCP(endpoint.getUri())) {
+                int tcpThreads = config.getInt(NetworkConfig.Keys.TCP_WORKER_THREADS);
+                int tcpIdleTimeout = config.getInt(NetworkConfig.Keys.TCP_CONNECTION_IDLE_TIMEOUT);
+                TcpServerConnector tcpConnector = new TcpServerConnector(address, tcpThreads, tcpIdleTimeout);
+                coapBuilder.setConnector(tcpConnector);
             } else {
                 coapBuilder.setInetSocketAddress(address);
             }
diff --git a/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPEndpoint.java b/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPEndpoint.java
index e169d8c..36954ca 100644
--- a/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPEndpoint.java
+++ b/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPEndpoint.java
@@ -49,7 +49,7 @@ import org.eclipse.californium.scandium.dtls.rpkstore.TrustedRpkStore;
 /**
  * The coap component is used for sending and receiving messages from COAP capable devices.
  */
-@UriEndpoint(firstVersion = "2.16.0", scheme = "coap", title = "CoAP", syntax = "coap:uri", label = "iot")
+@UriEndpoint(firstVersion = "2.16.0", scheme = "coap,coaps,coap+tcp,coaps+tcp", title = "CoAP", syntax = "coap:uri", label = "iot")
 public class CoAPEndpoint extends DefaultEndpoint {
     @UriPath
     private URI uri;
@@ -356,6 +356,10 @@ public class CoAPEndpoint extends DefaultEndpoint {
         return "coaps".equals(uri.getScheme());
     }
 
+    public static boolean enableTCP(URI uri) {
+        return uri.getScheme().endsWith("+tcp");
+    }
+
     public DTLSConnector createDTLSConnector(InetSocketAddress address, boolean client) {
 
         DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder();
diff --git a/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPProducer.java b/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPProducer.java
index d82852a..a764857 100644
--- a/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPProducer.java
+++ b/components/camel-coap/src/main/java/org/apache/camel/coap/CoAPProducer.java
@@ -25,6 +25,8 @@ import org.eclipse.californium.core.CoapClient;
 import org.eclipse.californium.core.CoapResponse;
 import org.eclipse.californium.core.coap.MediaTypeRegistry;
 import org.eclipse.californium.core.network.CoapEndpoint;
+import org.eclipse.californium.core.network.config.NetworkConfig;
+import org.eclipse.californium.elements.tcp.TcpClientConnector;
 import org.eclipse.californium.scandium.DTLSConnector;
 
 /**
@@ -94,13 +96,23 @@ public class CoAPProducer extends DefaultProducer {
             }
             client = new CoapClient(uri);
 
-            // Configure TLS
+            // Configure TLS and / or TCP
             if (CoAPEndpoint.enableTLS(uri)) {
                 DTLSConnector connector = endpoint.createDTLSConnector(null, true);
                 CoapEndpoint.Builder coapBuilder = new CoapEndpoint.Builder();
                 coapBuilder.setConnector(connector);
 
                 client.setEndpoint(coapBuilder.build());
+            } else if (CoAPEndpoint.enableTCP(endpoint.getUri())) {
+                NetworkConfig config = NetworkConfig.createStandardWithoutFile();
+                int tcpThreads = config.getInt(NetworkConfig.Keys.TCP_WORKER_THREADS);
+                int tcpConnectTimeout = config.getInt(NetworkConfig.Keys.TCP_CONNECT_TIMEOUT);
+                int tcpIdleTimeout = config.getInt(NetworkConfig.Keys.TCP_CONNECTION_IDLE_TIMEOUT);
+                TcpClientConnector tcpConnector = new TcpClientConnector(tcpThreads, tcpConnectTimeout, tcpIdleTimeout);
+                CoapEndpoint.Builder tcpBuilder = new CoapEndpoint.Builder();
+                tcpBuilder.setConnector(tcpConnector);
+
+                client.setEndpoint(tcpBuilder.build());
             }
 
         }
diff --git a/components/camel-coap/src/main/resources/META-INF/services/org/apache/camel/component/coaps b/components/camel-coap/src/main/resources/META-INF/services/org/apache/camel/component/coaps
deleted file mode 100644
index e0129bc..0000000
--- a/components/camel-coap/src/main/resources/META-INF/services/org/apache/camel/component/coaps
+++ /dev/null
@@ -1,18 +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.
-#
-
-class=org.apache.camel.coap.CoAPComponent
diff --git a/components/camel-coap/src/test/java/org/apache/camel/coap/CoAPComponentTest.java b/components/camel-coap/src/test/java/org/apache/camel/coap/CoAPComponentTest.java
index d4c8f49..aaad659 100644
--- a/components/camel-coap/src/test/java/org/apache/camel/coap/CoAPComponentTest.java
+++ b/components/camel-coap/src/test/java/org/apache/camel/coap/CoAPComponentTest.java
@@ -21,6 +21,7 @@ import org.apache.camel.Produce;
 import org.apache.camel.ProducerTemplate;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.AvailablePortFinder;
 import org.eclipse.californium.core.CoapClient;
 import org.eclipse.californium.core.CoapResponse;
 import org.eclipse.californium.core.coap.CoAP;
@@ -29,9 +30,14 @@ import org.junit.Test;
 
 public class CoAPComponentTest extends CoAPTestSupport {
 
+    protected static final int TCP_PORT = AvailablePortFinder.getNextAvailable();
+
     @Produce("direct:start")
     protected ProducerTemplate sender;
-    
+
+    @Produce("direct:starttcp")
+    protected ProducerTemplate tcpSender;
+
     @Test
     public void testCoAPComponent() throws Exception {
         CoapClient client = createClient("/TestResource");
@@ -47,6 +53,17 @@ public class CoAPComponentTest extends CoAPTestSupport {
         assertMockEndpointsSatisfied();
     }
 
+    @Test
+    public void testCoAPComponentTLS() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMinimumMessageCount(1);
+        mock.expectedBodiesReceived("Hello Camel CoAP");
+        mock.expectedHeaderReceived(Exchange.CONTENT_TYPE, MediaTypeRegistry.toString(MediaTypeRegistry.APPLICATION_OCTET_STREAM));
+        mock.expectedHeaderReceived(CoAPConstants.COAP_RESPONSE_CODE, CoAP.ResponseCode.CONTENT.toString());
+        tcpSender.sendBody("Camel CoAP");
+        assertMockEndpointsSatisfied();
+    }
+
     @Override
     protected RouteBuilder createRouteBuilder() throws Exception {
         return new RouteBuilder() {
@@ -56,10 +73,19 @@ public class CoAPComponentTest extends CoAPTestSupport {
                     .convertBodyTo(String.class)
                     .transform(body().prepend("Hello "));
 
+                fromF("coap+tcp://localhost:%d/TestResource", TCP_PORT)
+                    .convertBodyTo(String.class)
+                    .transform(body().prepend("Hello "));
+
                 from("direct:start")
                     .toF("coap://localhost:%d/TestResource", PORT)
                     .to("mock:result");
+
+                from("direct:starttcp")
+                    .toF("coap+tcp://localhost:%d/TestResource", TCP_PORT)
+                    .to("mock:result");
             }
         };
     }
+
 }
diff --git a/components/camel-coap/src/test/java/org/apache/camel/coap/CoAPRestComponentTCPTest.java b/components/camel-coap/src/test/java/org/apache/camel/coap/CoAPRestComponentTCPTest.java
new file mode 100644
index 0000000..bd85eec
--- /dev/null
+++ b/components/camel-coap/src/test/java/org/apache/camel/coap/CoAPRestComponentTCPTest.java
@@ -0,0 +1,131 @@
+/*
+ * 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.camel.coap;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.eclipse.californium.core.CoapClient;
+import org.eclipse.californium.core.CoapResponse;
+import org.eclipse.californium.core.coap.CoAP.ResponseCode;
+import org.eclipse.californium.core.coap.MediaTypeRegistry;
+import org.eclipse.californium.core.network.CoapEndpoint;
+import org.eclipse.californium.core.network.config.NetworkConfig;
+import org.eclipse.californium.elements.tcp.TcpClientConnector;
+import org.junit.Test;
+
+public class CoAPRestComponentTCPTest extends CamelTestSupport {
+    static int coapport = AvailablePortFinder.getNextAvailable();
+
+    @Test
+    public void testCoAP() throws Exception {
+        NetworkConfig.createStandardWithoutFile();
+        CoapClient client;
+        CoapResponse rsp;
+
+        client = new CoapClient("coap+tcp://localhost:" + coapport + "/TestResource/Ducky");
+        decorateWithTCP(client);
+        rsp = client.get();
+        assertEquals(ResponseCode.CONTENT, rsp.getCode());
+        assertEquals("Hello Ducky", rsp.getResponseText());
+        rsp = client.post("data", MediaTypeRegistry.TEXT_PLAIN);
+        assertEquals(ResponseCode.CONTENT, rsp.getCode());
+        assertEquals("Hello Ducky: data", rsp.getResponseText());
+
+        client = new CoapClient("coap+tcp://localhost:" + coapport + "/TestParams?id=Ducky");
+        decorateWithTCP(client);
+        client.setTimeout(1000000L);
+        rsp = client.get();
+        assertEquals(ResponseCode.CONTENT, rsp.getCode());
+        assertEquals("Hello Ducky", rsp.getResponseText());
+        rsp = client.post("data", MediaTypeRegistry.TEXT_PLAIN);
+        assertEquals(ResponseCode.CONTENT, rsp.getCode());
+        assertEquals("Hello Ducky: data", rsp.getResponseText());
+        assertEquals(MediaTypeRegistry.TEXT_PLAIN, rsp.getOptions().getContentFormat());
+    }
+
+    @Test
+    public void testCoAPMethodNotAllowedResponse() throws Exception {
+        NetworkConfig.createStandardWithoutFile();
+        CoapClient client = new CoapClient("coap+tcp://localhost:" + coapport + "/TestResource/Ducky");
+        decorateWithTCP(client);
+        client.setTimeout(1000000L);
+        CoapResponse rsp = client.delete();
+        assertEquals(ResponseCode.METHOD_NOT_ALLOWED, rsp.getCode());
+    }
+
+    @Test
+    public void testCoAPNotFoundResponse() throws Exception {
+        NetworkConfig.createStandardWithoutFile();
+        CoapClient client = new CoapClient("coap+tcp://localhost:" + coapport + "/foo/bar/cheese");
+        decorateWithTCP(client);
+        client.setTimeout(1000000L);
+        CoapResponse rsp = client.get();
+        assertEquals(ResponseCode.NOT_FOUND, rsp.getCode());
+    }
+    
+    private void decorateWithTCP(CoapClient client) {
+        NetworkConfig config = NetworkConfig.createStandardWithoutFile();
+        int tcpThreads = config.getInt(NetworkConfig.Keys.TCP_WORKER_THREADS);
+        int tcpConnectTimeout = config.getInt(NetworkConfig.Keys.TCP_CONNECT_TIMEOUT);
+        int tcpIdleTimeout = config.getInt(NetworkConfig.Keys.TCP_CONNECTION_IDLE_TIMEOUT);
+        TcpClientConnector tcpConnector = new TcpClientConnector(tcpThreads, tcpConnectTimeout, tcpIdleTimeout);
+        CoapEndpoint.Builder tcpBuilder = new CoapEndpoint.Builder();
+        tcpBuilder.setConnector(tcpConnector);
+
+        client.setEndpoint(tcpBuilder.build());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                restConfiguration("coap").scheme("coap+tcp").host("localhost").port(coapport);
+
+                rest("/TestParams")
+                    .get().to("direct:get1")
+                    .post().to("direct:post1");
+
+                rest("/TestResource")
+                    .get("/{id}").to("direct:get1")
+                    .post("/{id}").to("direct:post1");
+                
+                from("direct:get1").process(new Processor() {
+                    public void process(Exchange exchange) throws Exception {
+                        String id = exchange.getIn().getHeader("id", String.class);
+                        exchange.getOut().setBody("Hello " + id);
+                    }
+                });
+
+                from("direct:post1").process(new Processor() {
+                    public void process(Exchange exchange) throws Exception {
+                        String id = exchange.getIn().getHeader("id", String.class);
+                        String ct = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, String.class);
+                        if (!"text/plain".equals(ct)) {
+                            throw new Exception("No content type");
+                        }
+                        exchange.getOut().setBody("Hello " + id + ": " + exchange.getIn().getBody(String.class));
+                        exchange.getOut().setHeader(Exchange.CONTENT_TYPE, ct);
+                    }
+                });
+            }
+        };
+    }
+}
diff --git a/platforms/spring-boot/components-starter/camel-coap-starter/src/main/java/org/apache/camel/coap/springboot/CoAPComponentAutoConfiguration.java b/platforms/spring-boot/components-starter/camel-coap-starter/src/main/java/org/apache/camel/coap/springboot/CoAPComponentAutoConfiguration.java
index 028d594..dcfba25 100644
--- a/platforms/spring-boot/components-starter/camel-coap-starter/src/main/java/org/apache/camel/coap/springboot/CoAPComponentAutoConfiguration.java
+++ b/platforms/spring-boot/components-starter/camel-coap-starter/src/main/java/org/apache/camel/coap/springboot/CoAPComponentAutoConfiguration.java
@@ -75,7 +75,7 @@ public class CoAPComponentAutoConfiguration {
     }
 
     @Lazy
-    @Bean(name = "coap-component")
+    @Bean({"coap-component", "coap+tcp-component", "coaps-component", "coaps+tcp-component"})
     @ConditionalOnMissingBean(CoAPComponent.class)
     public CoAPComponent configureCoAPComponent() throws Exception {
         CoAPComponent component = new CoAPComponent();