You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2017/08/10 11:37:29 UTC

[1/7] camel git commit: Amend changes based on review.

Repository: camel
Updated Branches:
  refs/heads/master 239fde83c -> d6c829ac3


Amend changes based on review.

Signed-off-by: Jens Reimann <jr...@redhat.com>


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/59a4266a
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/59a4266a
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/59a4266a

Branch: refs/heads/master
Commit: 59a4266aafedc18d2907cdef1281f0111bbe9d6d
Parents: eb4f605
Author: Jens Reimann <jr...@redhat.com>
Authored: Thu Aug 10 10:02:30 2017 +0200
Committer: Andrea Cosentino <an...@gmail.com>
Committed: Thu Aug 10 12:20:18 2017 +0200

----------------------------------------------------------------------
 .../java/org/apache/camel/component/iec60870/ConnectionId.java | 2 +-
 components/readme.adoc                                         | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/59a4266a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ConnectionId.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ConnectionId.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ConnectionId.java
index 66dfc07..41dcb8f 100644
--- a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ConnectionId.java
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ConnectionId.java
@@ -29,7 +29,7 @@ public class ConnectionId {
         Objects.requireNonNull(host);
 
         if (port <= 0) {
-            throw new IllegalArgumentException(String.format("Port must be greater than 0"));
+            throw new IllegalArgumentException("Port must be greater than 0");
         }
 
         this.host = host;

http://git-wip-us.apache.org/repos/asf/camel/blob/59a4266a/components/readme.adoc
----------------------------------------------------------------------
diff --git a/components/readme.adoc b/components/readme.adoc
index 969911d..670f5b8 100644
--- a/components/readme.adoc
+++ b/components/readme.adoc
@@ -353,6 +353,12 @@ Number of Components: 278 in 191 JAR artifacts (17 deprecated)
 | link:camel-ibatis/src/main/docs/ibatis-component.adoc[iBatis] (camel-ibatis) +
 `ibatis:statement` | 1.2 | *deprecated* Performs a query poll insert update or delete in a relational database using Apache iBATIS.
 
+| link:camel-iec60870/src/main/docs/iec60870-client-component.adoc[IEC 60870 Client] (camel-iec60870) +
+`iec60870-client:endpoint` | 2.20 | A component which acts as client, allowing to remote control IEC 60870-5-104 capable devices.
+
+| link:camel-iec60870/src/main/docs/iec60870-client-component.adoc[IEC 60870 Client] (camel-iec60870) +
+`iec60870-server:endpoint` | 2.20 | A component which acts as server, offering remote control capabilities using IEC 60870-5-104.
+
 | link:camel-ignite/src/main/docs/ignite-cache-component.adoc[Ignite Cache] (camel-ignite) +
 `ignite-cache:cacheName` | 2.17 | The Ignite Cache endpoint is one of camel-ignite endpoints which allows you to interact with an Ignite Cache.
 


[5/7] camel git commit: Add the camel-iec60870 and camel-iec60870-starter

Posted by ac...@apache.org.
Add the camel-iec60870 and camel-iec60870-starter

This change adds the ne camel-iec6087 and camel-iec60870-starter
modules to a few build files.

Signed-off-by: Jens Reimann <jr...@redhat.com>


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/3ca4fe70
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/3ca4fe70
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/3ca4fe70

Branch: refs/heads/master
Commit: 3ca4fe70933820ededac051b3e8e9609e5e8a992
Parents: 59a4266
Author: Jens Reimann <jr...@redhat.com>
Authored: Thu Aug 10 10:21:14 2017 +0200
Committer: Andrea Cosentino <an...@gmail.com>
Committed: Thu Aug 10 12:20:19 2017 +0200

----------------------------------------------------------------------
 apache-camel/pom.xml                                      |  9 +++++++++
 apache-camel/src/main/descriptors/common-bin.xml          |  2 ++
 parent/pom.xml                                            |  5 +++++
 .../spring-boot-dm/camel-spring-boot-dependencies/pom.xml | 10 ++++++++++
 4 files changed, 26 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/3ca4fe70/apache-camel/pom.xml
----------------------------------------------------------------------
diff --git a/apache-camel/pom.xml b/apache-camel/pom.xml
index f16b001..d9e117e 100644
--- a/apache-camel/pom.xml
+++ b/apache-camel/pom.xml
@@ -460,6 +460,10 @@
     </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
+      <artifactId>camel-iec60870</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
       <artifactId>camel-ignite</artifactId>
     </dependency>
     <dependency>
@@ -1599,6 +1603,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
+      <artifactId>camel-iec60870-starter</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
       <artifactId>camel-ignite-starter</artifactId>
       <version>${project.version}</version>
     </dependency>

http://git-wip-us.apache.org/repos/asf/camel/blob/3ca4fe70/apache-camel/src/main/descriptors/common-bin.xml
----------------------------------------------------------------------
diff --git a/apache-camel/src/main/descriptors/common-bin.xml b/apache-camel/src/main/descriptors/common-bin.xml
index 276c795..4554ea5 100644
--- a/apache-camel/src/main/descriptors/common-bin.xml
+++ b/apache-camel/src/main/descriptors/common-bin.xml
@@ -125,6 +125,7 @@
         <include>org.apache.camel:camel-http4</include>
         <include>org.apache.camel:camel-ibatis</include>
         <include>org.apache.camel:camel-ical</include>
+        <include>org.apache.camel:camel-iec60870</include>
         <include>org.apache.camel:camel-infinispan</include>
         <include>org.apache.camel:camel-influxdb</include>
         <include>org.apache.camel:camel-ignite</include>
@@ -415,6 +416,7 @@
         <include>org.apache.camel:camel-http-starter</include>
         <include>org.apache.camel:camel-hystrix-starter</include>
         <include>org.apache.camel:camel-ical-starter</include>
+        <include>org.apache.camel:camel-iec60870-starter</include>
         <include>org.apache.camel:camel-ignite-starter</include>
         <include>org.apache.camel:camel-infinispan-starter</include>
         <include>org.apache.camel:camel-influxdb-starter</include>

http://git-wip-us.apache.org/repos/asf/camel/blob/3ca4fe70/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index 4faa687..4025825 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -2740,6 +2740,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-iec60870-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-ignite-starter</artifactId>
         <version>${project.version}</version>
       </dependency>

http://git-wip-us.apache.org/repos/asf/camel/blob/3ca4fe70/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml b/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
index 675a182..0f5f348 100644
--- a/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
+++ b/platforms/spring-boot/spring-boot-dm/camel-spring-boot-dependencies/pom.xml
@@ -1271,6 +1271,16 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-iec60870</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-iec60870-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-ignite</artifactId>
         <version>${project.version}</version>
       </dependency>


[7/7] camel git commit: Added camel-iec60870 to components POM

Posted by ac...@apache.org.
Added camel-iec60870 to components POM


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/d6c829ac
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/d6c829ac
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/d6c829ac

Branch: refs/heads/master
Commit: d6c829ac378ecbd163184b152e9dfc2ecee40013
Parents: cd6ed42
Author: Andrea Cosentino <an...@gmail.com>
Authored: Thu Aug 10 13:08:09 2017 +0200
Committer: Andrea Cosentino <an...@gmail.com>
Committed: Thu Aug 10 13:08:09 2017 +0200

----------------------------------------------------------------------
 components/pom.xml | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/d6c829ac/components/pom.xml
----------------------------------------------------------------------
diff --git a/components/pom.xml b/components/pom.xml
index 4a49e62..9412e0a 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -153,6 +153,7 @@
     <module>camel-hl7</module>
     <module>camel-ibatis</module>
     <module>camel-ical</module>
+    <module>camel-iec60870</module>
     <module>camel-ignite</module>
     <module>camel-infinispan</module>
     <module>camel-influxdb</module>


[6/7] camel git commit: Regen

Posted by ac...@apache.org.
Regen


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/cd6ed426
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/cd6ed426
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/cd6ed426

Branch: refs/heads/master
Commit: cd6ed426de2e0600440f83bdf6101d46e90d924c
Parents: 3ca4fe7
Author: Andrea Cosentino <an...@gmail.com>
Authored: Thu Aug 10 13:04:41 2017 +0200
Committer: Andrea Cosentino <an...@gmail.com>
Committed: Thu Aug 10 13:04:41 2017 +0200

----------------------------------------------------------------------
 components/readme.adoc                                  | 12 +++++-------
 docs/user-manual/en/SUMMARY.md                          |  2 ++
 .../spring-boot-dm/camel-spring-boot-bom/pom.xml        |  5 +++++
 3 files changed, 12 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/cd6ed426/components/readme.adoc
----------------------------------------------------------------------
diff --git a/components/readme.adoc b/components/readme.adoc
index 670f5b8..9717e8e 100644
--- a/components/readme.adoc
+++ b/components/readme.adoc
@@ -2,7 +2,7 @@ Components
 ^^^^^^^^^^
 
 // components: START
-Number of Components: 278 in 191 JAR artifacts (17 deprecated)
+Number of Components: 280 in 192 JAR artifacts (17 deprecated)
 
 [width="100%",cols="4,1,5",options="header"]
 |=======================================================================
@@ -354,10 +354,10 @@ Number of Components: 278 in 191 JAR artifacts (17 deprecated)
 `ibatis:statement` | 1.2 | *deprecated* Performs a query poll insert update or delete in a relational database using Apache iBATIS.
 
 | link:camel-iec60870/src/main/docs/iec60870-client-component.adoc[IEC 60870 Client] (camel-iec60870) +
-`iec60870-client:endpoint` | 2.20 | A component which acts as client, allowing to remote control IEC 60870-5-104 capable devices.
+`iec60870-client:endpointUri` | 2.20 | Camel IEC 60870-5-104 support
 
-| link:camel-iec60870/src/main/docs/iec60870-client-component.adoc[IEC 60870 Client] (camel-iec60870) +
-`iec60870-server:endpoint` | 2.20 | A component which acts as server, offering remote control capabilities using IEC 60870-5-104.
+| link:camel-iec60870/src/main/docs/iec60870-server-component.adoc[IEC 60870-5-104 server] (camel-iec60870) +
+`iec60870-server:endpointUri` | 2.20 | Camel IEC 60870-5-104 support
 
 | link:camel-ignite/src/main/docs/ignite-cache-component.adoc[Ignite Cache] (camel-ignite) +
 `ignite-cache:cacheName` | 2.17 | The Ignite Cache endpoint is one of camel-ignite endpoints which allows you to interact with an Ignite Cache.
@@ -1024,7 +1024,7 @@ Miscellaneous Components
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
 // others: START
-Number of Miscellaneous Components: 38 in 38 JAR artifacts (14 deprecated)
+Number of Miscellaneous Components: 37 in 37 JAR artifacts (13 deprecated)
 
 [width="100%",cols="4,1,5",options="header"]
 |=======================================================================
@@ -1080,8 +1080,6 @@ Number of Miscellaneous Components: 38 in 38 JAR artifacts (14 deprecated)
 
 | link:camel-spring-cloud-netflix/src/main/docs/spring-cloud-netflix.adoc[Spring Cloud Netflix] (camel-spring-cloud-netflix) | 2.19 | Camel Cloud integration with Spring Cloud Netflix
 
-| link:camel-spring-dm/src/main/docs/spring-dm.adoc[Spring DM] (camel-spring-dm) | 2.18 | *deprecated* Camel SpringDM (OSGi) XML DSL
-
 | link:camel-spring-javaconfig/src/main/docs/spring-javaconfig.adoc[Spring Java Configuration] (camel-spring-javaconfig) | 2.0 | Using Camel with Spring Java Configuration
 
 | link:camel-spring-security/src/main/docs/spring-security.adoc[Spring Security] (camel-spring-security) | 2.3 | Security using Spring Security

http://git-wip-us.apache.org/repos/asf/camel/blob/cd6ed426/docs/user-manual/en/SUMMARY.md
----------------------------------------------------------------------
diff --git a/docs/user-manual/en/SUMMARY.md b/docs/user-manual/en/SUMMARY.md
index 34bb690..8cbbb55 100644
--- a/docs/user-manual/en/SUMMARY.md
+++ b/docs/user-manual/en/SUMMARY.md
@@ -229,6 +229,8 @@
 	* [HTTP](http-component.adoc)
 	* [HTTP4](http4-component.adoc)
 	* [iBatis](ibatis-component.adoc)
+	* [IEC 60870 Client](iec60870-client-component.adoc)
+	* [IEC 60870-5-104 server](iec60870-server-component.adoc)
 	* [Ignite Cache](ignite-cache-component.adoc)
 	* [Ignite Compute](ignite-compute-component.adoc)
 	* [Ignite Events](ignite-events-component.adoc)

http://git-wip-us.apache.org/repos/asf/camel/blob/cd6ed426/platforms/spring-boot/spring-boot-dm/camel-spring-boot-bom/pom.xml
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/spring-boot-dm/camel-spring-boot-bom/pom.xml b/platforms/spring-boot/spring-boot-dm/camel-spring-boot-bom/pom.xml
index feda875..b6210ba 100644
--- a/platforms/spring-boot/spring-boot-dm/camel-spring-boot-bom/pom.xml
+++ b/platforms/spring-boot/spring-boot-dm/camel-spring-boot-bom/pom.xml
@@ -547,6 +547,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-iec60870-starter</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-ignite-starter</artifactId>
         <version>${project.version}</version>
       </dependency>


[3/7] camel git commit: Import of the IEC 60870 component

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerComponent.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerComponent.java
new file mode 100644
index 0000000..521d2a2
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerComponent.java
@@ -0,0 +1,83 @@
+/**
+ * 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.component.iec60870.server;
+
+import java.net.UnknownHostException;
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.iec60870.AbstractIecComponent;
+import org.apache.camel.component.iec60870.ConnectionId;
+import org.apache.camel.component.iec60870.Constants;
+import org.apache.camel.component.iec60870.ObjectAddress;
+import org.eclipse.neoscada.protocol.iec60870.server.data.DataModuleOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServerComponent extends AbstractIecComponent<ServerConnectionMultiplexor, ServerOptions> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ServerComponent.class);
+
+    public ServerComponent(final CamelContext context) {
+        super(ServerOptions.class, new ServerOptions(), context, ServerEndpoint.class);
+    }
+
+    public ServerComponent() {
+        super(ServerOptions.class, new ServerOptions(), ServerEndpoint.class);
+    }
+
+    @Override
+    protected void applyDataModuleOptions(final ServerOptions options, final Map<String, Object> parameters) {
+        if (parameters.get(Constants.PARAM_DATA_MODULE_OPTIONS) instanceof DataModuleOptions) {
+            options.setDataModuleOptions((DataModuleOptions)parameters.get(Constants.PARAM_DATA_MODULE_OPTIONS));
+        }
+    }
+
+    @Override
+    protected ServerConnectionMultiplexor createConnection(final ConnectionId id, final ServerOptions options) {
+        LOG.debug("Create new server - id: {}", id);
+
+        try {
+            return new ServerConnectionMultiplexor(new ServerInstance(id.getHost(), id.getPort(), options));
+        } catch (final UnknownHostException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    protected Endpoint createEndpoint(final String uri, final ServerConnectionMultiplexor connection, final ObjectAddress address) {
+        return new ServerEndpoint(uri, this, connection, address);
+    }
+
+    /**
+     * Default connection options
+     *
+     * @param defaultConnectionOptions the new default connection options, must
+     *            not be {@code null}
+     */
+    @Override
+    public void setDefaultConnectionOptions(final ServerOptions defaultConnectionOptions) {
+        super.setDefaultConnectionOptions(defaultConnectionOptions);
+    }
+
+    @Override
+    public ServerOptions getDefaultConnectionOptions() {
+        return super.getDefaultConnectionOptions();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerConnectionMultiplexor.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerConnectionMultiplexor.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerConnectionMultiplexor.java
new file mode 100644
index 0000000..43c80a4
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerConnectionMultiplexor.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 org.apache.camel.component.iec60870.server;
+
+import org.apache.camel.component.iec60870.AbstractConnectionMultiplexor;
+
+public class ServerConnectionMultiplexor extends AbstractConnectionMultiplexor {
+
+    private final ServerInstance server;
+
+    public ServerConnectionMultiplexor(final ServerInstance server) {
+        this.server = server;
+    }
+
+    @Override
+    protected void performStart() throws Exception {
+        this.server.start();
+    }
+
+    @Override
+    protected void performStop() throws Exception {
+        this.server.stop();
+    }
+
+    public ServerInstance getServer() {
+        return this.server;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerConsumer.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerConsumer.java
new file mode 100644
index 0000000..a947340
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerConsumer.java
@@ -0,0 +1,110 @@
+/**
+ * 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.component.iec60870.server;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.component.iec60870.ObjectAddress;
+import org.apache.camel.impl.DefaultConsumer;
+import org.apache.camel.impl.DefaultMessage;
+import org.eclipse.neoscada.protocol.iec60870.server.data.model.WriteModel.Request;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServerConsumer extends DefaultConsumer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ServerConsumer.class);
+
+    private final ServerInstance server;
+    private final ServerEndpoint endpoint;
+
+    public ServerConsumer(final ServerEndpoint endpoint, final Processor processor, final ServerInstance server) {
+        super(endpoint, processor);
+        this.endpoint = endpoint;
+        this.server = server;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        this.server.setListener(this.endpoint.getAddress(), this::updateValue);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        this.server.setListener(this.endpoint.getAddress(), null);
+        super.doStop();
+    }
+
+    private CompletionStage<Void> updateValue(final Request<?> value) {
+        try {
+            // create exchange
+
+            final Exchange exchange = getEndpoint().createExchange();
+            exchange.setIn(mapMessage(value));
+
+            // create new future
+
+            final CompletableFuture<Void> result = new CompletableFuture<>();
+
+            // process and map async callback to our future
+
+            getAsyncProcessor().process(exchange, doneSync -> result.complete(null));
+
+            // return future
+
+            return result;
+
+        } catch (final Exception e) {
+
+            // we failed triggering the process
+
+            LOG.debug("Failed to process message", e);
+
+            // create a future
+
+            final CompletableFuture<Void> result = new CompletableFuture<>();
+
+            // complete it right away
+
+            result.completeExceptionally(e);
+
+            // return it
+
+            return result;
+        }
+    }
+
+    private Message mapMessage(final Request<?> request) {
+        final DefaultMessage message = new DefaultMessage(this.endpoint.getCamelContext());
+
+        message.setBody(request);
+
+        message.setHeader("address", ObjectAddress.valueOf(request.getHeader().getAsduAddress(), request.getAddress()));
+        message.setHeader("value", request.getValue());
+        message.setHeader("informationObjectAddress", request.getAddress());
+        message.setHeader("asduHeader", request.getHeader());
+        message.setHeader("type", request.getType());
+        message.setHeader("execute", request.isExecute());
+
+        return message;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerEndpoint.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerEndpoint.java
new file mode 100644
index 0000000..ebee197
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerEndpoint.java
@@ -0,0 +1,60 @@
+/**
+ * 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.component.iec60870.server;
+
+import static java.util.Objects.requireNonNull;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.component.iec60870.AbstractIecEndpoint;
+import org.apache.camel.component.iec60870.ObjectAddress;
+import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+
+@UriEndpoint(firstVersion = "2.20.0", scheme = "iec60870-server", syntax = "iec60870-server:endpointUri", title = "IEC 60870-5-104 server", consumerClass = ServerConsumer.class, label = "iot")
+public class ServerEndpoint extends AbstractIecEndpoint<ServerConnectionMultiplexor> {
+
+    /**
+     * Filter out all requests which don't have the execute bit set
+     */
+    @UriParam(defaultValue = "true")
+    private boolean filterNonExecute = true;
+
+    public ServerEndpoint(final String uri, final DefaultComponent component, final ServerConnectionMultiplexor connection, final ObjectAddress address) {
+        super(uri, component, requireNonNull(connection), address);
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        return new ServerProducer(this, getConnection().getServer());
+    }
+
+    @Override
+    public Consumer createConsumer(final Processor processor) throws Exception {
+        return new ServerConsumer(this, processor, getConnection().getServer());
+    }
+
+    public void setFilterNonExecute(final boolean filterNonExecute) {
+        this.filterNonExecute = filterNonExecute;
+    }
+
+    public boolean isFilterNonExecute() {
+        return this.filterNonExecute;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerInstance.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerInstance.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerInstance.java
new file mode 100644
index 0000000..403ceb4
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerInstance.java
@@ -0,0 +1,190 @@
+/**
+ * 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.component.iec60870.server;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static java.util.Arrays.asList;
+
+import org.apache.camel.component.iec60870.DiscardAckModule;
+import org.apache.camel.component.iec60870.ObjectAddress;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.ASDUAddress;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.InformationObjectAddress;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.Value;
+import org.eclipse.neoscada.protocol.iec60870.server.Server;
+import org.eclipse.neoscada.protocol.iec60870.server.data.DataModule;
+import org.eclipse.neoscada.protocol.iec60870.server.data.model.BackgroundModel;
+import org.eclipse.neoscada.protocol.iec60870.server.data.model.ChangeDataModel;
+import org.eclipse.neoscada.protocol.iec60870.server.data.model.ChangeModel;
+import org.eclipse.neoscada.protocol.iec60870.server.data.model.WriteModel;
+import org.eclipse.neoscada.protocol.iec60870.server.data.model.WriteModel.Action;
+import org.eclipse.neoscada.protocol.iec60870.server.data.model.WriteModel.Request;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServerInstance {
+    private static final Logger LOG = LoggerFactory.getLogger(ServerInstance.class);
+
+    private final ServerOptions options;
+
+    private final class DataModelImpl extends ChangeDataModel {
+        private DataModelImpl() {
+            super("Camel/IEC60870/DataModel");
+        }
+
+        @Override
+        protected ChangeModel createChangeModel() {
+            if (ServerInstance.this.options.getBufferingPeriod() != null && ServerInstance.this.options.getBufferingPeriod() > 0) {
+                LOG.info("Creating buffering change model: {} ms", ServerInstance.this.options.getBufferingPeriod());
+                return makeBufferingChangeModel(ServerInstance.this.options.getBufferingPeriod());
+            } else {
+                LOG.info("Creating instant change model");
+                return makeInstantChangeModel();
+            }
+        }
+
+        @Override
+        protected WriteModel createWriteModel() {
+            return new WriteModel() {
+
+                @Override
+                public Action prepareCommand(final Request<Boolean> request) {
+                    return prepareAction(request);
+                }
+
+                @Override
+                public Action prepareSetpointFloat(final Request<Float> request) {
+                    return prepareAction(request);
+                }
+
+                @Override
+                public Action prepareSetpointScaled(final Request<Short> request) {
+                    return prepareAction(request);
+                }
+            };
+        }
+
+        @Override
+        protected BackgroundModel createBackgroundModel() {
+            if (ServerInstance.this.options.getBackgroundScanPeriod() > 0) {
+                LOG.info("Creating background scan model: {} ms", ServerInstance.this.options.getBackgroundScanPeriod());
+                return makeDefaultBackgroundModel();
+            }
+            LOG.info("Not creating background scan model");
+            return null;
+        }
+
+        @Override
+        public void notifyDataChange(final ASDUAddress asduAddress, final InformationObjectAddress informationObjectAddress, final Value<?> value, final boolean notify) {
+            super.notifyDataChange(asduAddress, informationObjectAddress, value, notify);
+        }
+    }
+
+    @FunctionalInterface
+    public interface ServerObjectListener {
+        CompletionStage<Void> execute(Request<?> request);
+    }
+
+    private final DataModelImpl dataModel = new DataModelImpl();
+
+    private Server server;
+    private DataModule dataModule;
+    private final InetSocketAddress address;
+    private final Map<ObjectAddress, ServerObjectListener> listeners = new ConcurrentHashMap<>();
+
+    public ServerInstance(final String host, final int port, final ServerOptions options) throws UnknownHostException {
+        this.options = options;
+        this.address = new InetSocketAddress(InetAddress.getByName(host), port);
+    }
+
+    public void start() {
+        this.dataModel.start();
+        this.dataModule = new DataModule(this.options.getDataModuleOptions(), this.dataModel);
+        this.server = new Server(this.address, this.options.getProtocolOptions(), asList(this.dataModule, new DiscardAckModule()));
+    }
+
+    public void stop() {
+        final LinkedList<Exception> ex = new LinkedList<>();
+
+        if (this.server != null) {
+            try {
+                this.server.close();
+            } catch (final Exception e) {
+                ex.add(e);
+            }
+            this.server = null;
+        }
+        if (this.dataModule != null) {
+            try {
+                this.dataModule.dispose();
+            } catch (final Exception e) {
+                ex.add(e);
+            }
+            this.dataModule = null;
+        }
+
+        // handle all exceptions
+
+        final Exception e = ex.pollFirst();
+        if (e != null) {
+            RuntimeException re;
+            if (e instanceof RuntimeException) {
+                re = (RuntimeException)e;
+            } else {
+                re = new RuntimeException(e);
+            }
+            ex.forEach(re::addSuppressed);
+            throw re;
+        }
+    }
+
+    private Action prepareAction(final Request<?> request) {
+        final ObjectAddress address = ObjectAddress.valueOf(request.getHeader().getAsduAddress(), request.getAddress());
+        final ServerObjectListener listener = this.listeners.get(address);
+
+        if (listener == null) {
+            // no one is listening
+            return null;
+        }
+
+        return () -> listener.execute(request);
+    }
+
+    public void setListener(final ObjectAddress address, final ServerObjectListener listener) {
+        Objects.requireNonNull(address);
+
+        if (listener != null) {
+            this.listeners.put(address, listener);
+        } else {
+            this.listeners.remove(address);
+        }
+    }
+
+    public void notifyValue(final ObjectAddress address, final Value<?> value) {
+        Objects.requireNonNull(address);
+        Objects.requireNonNull(value);
+
+        this.dataModel.notifyDataChange(address.getASDUAddress(), address.getInformationObjectAddress(), value, true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerOptions.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerOptions.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerOptions.java
new file mode 100644
index 0000000..021838b
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerOptions.java
@@ -0,0 +1,152 @@
+/**
+ * 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.component.iec60870.server;
+
+import java.util.Objects;
+
+import org.apache.camel.component.iec60870.BaseOptions;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.eclipse.neoscada.protocol.iec60870.ProtocolOptions;
+import org.eclipse.neoscada.protocol.iec60870.server.data.DataModuleOptions;
+
+@UriParams
+public class ServerOptions extends BaseOptions<ServerOptions> {
+
+    /**
+     * Data module options
+     */
+    @UriParam(javaType = "DataModuleOptions", label = "data")
+    private DataModuleOptions.Builder dataModuleOptions;
+
+    /**
+     * A time period in "ms" the protocol layer will buffer change events in
+     * order to send out aggregated change messages
+     */
+    @UriParam(label = "data")
+    private Integer bufferingPeriod;
+
+    // dummy for doc generation
+    /**
+     * Send booleans with timestamps
+     */
+    @UriParam(label = "data", defaultValue = "true")
+    private boolean booleansWithTimestamp;
+
+    // dummy for doc generation
+    /**
+     * Send floats with timestamps
+     */
+    @UriParam(label = "data", defaultValue = "true")
+    private boolean floatsWithTimestamp;
+
+    // dummy for doc generation
+    /**
+     * Number of spontaneous events to keep in the buffer.
+     * <p>
+     * When there are more than this number of spontaneous in events in the
+     * buffer, then events will be dropped in order to maintain the buffer size.
+     * </p>
+     */
+    @UriParam(label = "data", defaultValue = "10")
+    private int spontaneousDuplicates;
+
+    // dummy for doc generation
+    /**
+     * The period in "ms" between background transmission cycles.
+     * <p>
+     * If this is set to zero or less, background transmissions will be
+     * disabled.
+     * </p>
+     */
+    @UriParam(label = "data", defaultValue = "60000")
+    private int backgroundScanPeriod;
+
+    public ServerOptions() {
+        this.dataModuleOptions = new DataModuleOptions.Builder();
+    }
+
+    public ServerOptions(final ServerOptions other) {
+        this(other.getProtocolOptions(), other.getDataModuleOptions());
+    }
+
+    public ServerOptions(final ProtocolOptions protocolOptions, final DataModuleOptions dataModuleOptions) {
+        super(protocolOptions);
+
+        Objects.requireNonNull(dataModuleOptions);
+
+        this.dataModuleOptions = new DataModuleOptions.Builder(dataModuleOptions);
+    }
+
+    @Override
+    public ServerOptions copy() {
+        return new ServerOptions(this);
+    }
+
+    public void setDataModuleOptions(final DataModuleOptions dataModuleOptions) {
+        Objects.requireNonNull(dataModuleOptions);
+
+        this.dataModuleOptions = new DataModuleOptions.Builder(dataModuleOptions);
+    }
+
+    public void setBufferingPeriod(final Integer bufferingPeriod) {
+        this.bufferingPeriod = bufferingPeriod;
+    }
+
+    public Integer getBufferingPeriod() {
+        return this.bufferingPeriod;
+    }
+
+    // wrapper methods - DataModuleOptions
+
+    public DataModuleOptions getDataModuleOptions() {
+        return this.dataModuleOptions.build();
+    }
+
+    public void setBooleansWithTimestamp(final boolean booleansWithTimestamp) {
+        this.dataModuleOptions.setBooleansWithTimestamp(booleansWithTimestamp);
+    }
+
+    public boolean isBooleansWithTimestamp() {
+        return this.dataModuleOptions.isBooleansWithTimestamp();
+    }
+
+    public void setFloatsWithTimestamp(final boolean floatsWithTimestamp) {
+        this.dataModuleOptions.setFloatsWithTimestamp(floatsWithTimestamp);
+    }
+
+    public boolean isFloatsWithTimestamp() {
+        return this.dataModuleOptions.isFloatsWithTimestamp();
+    }
+
+    public void setSpontaneousDuplicates(final int spontaneousDuplicates) {
+        this.dataModuleOptions.setSpontaneousDuplicates(spontaneousDuplicates);
+    }
+
+    public int getSpontaneousDuplicates() {
+        return this.dataModuleOptions.getSpontaneousDuplicates();
+    }
+
+    public void setBackgroundScanPeriod(final int backgroundScanPeriod) {
+        this.dataModuleOptions.setBackgroundScanPeriod(backgroundScanPeriod);
+    }
+
+    public int getBackgroundScanPeriod() {
+        return this.dataModuleOptions.getBackgroundScanPeriod();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerProducer.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerProducer.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerProducer.java
new file mode 100644
index 0000000..d8ae1e5
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/server/ServerProducer.java
@@ -0,0 +1,68 @@
+/**
+ * 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.component.iec60870.server;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.impl.DefaultProducer;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.Value;
+
+public class ServerProducer extends DefaultProducer {
+
+    private final ServerEndpoint endpoint;
+    private final ServerInstance server;
+
+    public ServerProducer(final ServerEndpoint endpoint, final ServerInstance server) {
+        super(endpoint);
+        this.endpoint = endpoint;
+        this.server = server;
+    }
+
+    @Override
+    public void process(final Exchange exchange) throws Exception {
+        final Value<?> value = mapToCommand(exchange);
+        this.server.notifyValue(this.endpoint.getAddress(), value);
+    }
+
+    private Value<?> mapToCommand(final Exchange exchange) {
+        final Object body = exchange.getIn().getBody();
+
+        if (body instanceof Value<?>) {
+            return (Value<?>)body;
+        }
+
+        if (body instanceof Float || body instanceof Double) {
+            return Value.ok(((Number)body).floatValue());
+        }
+
+        if (body instanceof Boolean) {
+            return Value.ok((Boolean)body);
+        }
+
+        if (body instanceof Short || body instanceof Byte || body instanceof Integer || body instanceof Long) {
+            return convertToShort(((Number)body).longValue());
+        }
+
+        throw new IllegalArgumentException("Unable to map body to a value: " + body);
+    }
+
+    private Value<?> convertToShort(final long value) {
+        if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
+            throw new IllegalArgumentException(String.format("Value must be between %s and %s", Short.MIN_VALUE, Short.MAX_VALUE));
+        }
+        return Value.ok((short)value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/resources/META-INF/LICENSE.txt
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/resources/META-INF/LICENSE.txt b/components/camel-iec60870/src/main/resources/META-INF/LICENSE.txt
new file mode 100755
index 0000000..6b0b127
--- /dev/null
+++ b/components/camel-iec60870/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/resources/META-INF/NOTICE.txt
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/resources/META-INF/NOTICE.txt b/components/camel-iec60870/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/components/camel-iec60870/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/resources/META-INF/services/org/apache/camel/component/iec60870-client
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/resources/META-INF/services/org/apache/camel/component/iec60870-client b/components/camel-iec60870/src/main/resources/META-INF/services/org/apache/camel/component/iec60870-client
new file mode 100644
index 0000000..4194ef0
--- /dev/null
+++ b/components/camel-iec60870/src/main/resources/META-INF/services/org/apache/camel/component/iec60870-client
@@ -0,0 +1,18 @@
+#
+# 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.component.iec60870.client.ClientComponent
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/resources/META-INF/services/org/apache/camel/component/iec60870-server
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/resources/META-INF/services/org/apache/camel/component/iec60870-server b/components/camel-iec60870/src/main/resources/META-INF/services/org/apache/camel/component/iec60870-server
new file mode 100644
index 0000000..25afe0d
--- /dev/null
+++ b/components/camel-iec60870/src/main/resources/META-INF/services/org/apache/camel/component/iec60870-server
@@ -0,0 +1,18 @@
+#
+# 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.component.iec60870.server.ServerComponent
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/ConnectionIdTest.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/ConnectionIdTest.java b/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/ConnectionIdTest.java
new file mode 100644
index 0000000..c0f0b8e
--- /dev/null
+++ b/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/ConnectionIdTest.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.camel.component.iec60870;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ConnectionIdTest {
+    @Test
+    public void testNotEqual1() {
+        ConnectionId id1 = new ConnectionId("host", 1202, "id1");
+        ConnectionId id2 = new ConnectionId("host", 1202, "id2");
+        Assert.assertFalse("Must be different", id1.equals(id2));
+    }
+
+    @Test
+    public void testNotEqual2() {
+        ConnectionId id1 = new ConnectionId("host1", 1202, "id");
+        ConnectionId id2 = new ConnectionId("host2", 1202, "id");
+        Assert.assertFalse("Must be different", id1.equals(id2));
+    }
+
+    @Test
+    public void testNotEqual3() {
+        ConnectionId id1 = new ConnectionId("host", 1202_1, "id");
+        ConnectionId id2 = new ConnectionId("host", 1202_2, "id");
+        Assert.assertFalse("Must be different", id1.equals(id2));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testIllegal1() {
+        new ConnectionId("host", -1, "id");
+    }
+
+    @Test
+    public void testGetters() {
+        ConnectionId id = new ConnectionId("host", 1202, "id");
+        Assert.assertEquals("host", id.getHost());
+        Assert.assertEquals(1202, id.getPort());
+        Assert.assertEquals("id", id.getConnectionId());
+    }
+
+    @Test
+    public void testEqual1() {
+        ConnectionId id1 = new ConnectionId("host", 1202, "id");
+        ConnectionId id2 = new ConnectionId("host", 1202, "id");
+        Assert.assertTrue("Must be equal", id1.equals(id2));
+    }
+
+    @Test
+    public void testEqual2() {
+        ConnectionId id1 = new ConnectionId("host", 1202, "id");
+        ConnectionId id2 = new ConnectionId("host", 1202, "id");
+
+        Assert.assertTrue("Hash code must be equal", id1.hashCode() == id2.hashCode());
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/ConnectionTest.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/ConnectionTest.java b/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/ConnectionTest.java
new file mode 100644
index 0000000..81d79b7
--- /dev/null
+++ b/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/ConnectionTest.java
@@ -0,0 +1,171 @@
+/**
+ * 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.component.iec60870;
+
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.RoutesBuilder;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.AssertionClause;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.Value;
+import org.eclipse.neoscada.protocol.iec60870.server.data.model.WriteModel.Request;
+import org.junit.Test;
+
+public class ConnectionTest extends CamelTestSupport {
+
+    private static final String DIRECT_SEND_S_1 = "direct:sendServer1";
+
+    private static final String DIRECT_SEND_C_1 = "direct:sendClient1";
+
+    private static final String MOCK_CLIENT_1 = "mock:testClient1";
+
+    private static final String MOCK_CLIENT_2 = "mock:testClient2";
+
+    private static final String MOCK_SERVER_1 = "mock:testServer1";
+
+    @Produce(uri = DIRECT_SEND_S_1)
+    protected ProducerTemplate producerServer1;
+
+    @Produce(uri = DIRECT_SEND_C_1)
+    protected ProducerTemplate producerClient1;
+
+    @EndpointInject(uri = MOCK_CLIENT_1)
+    protected MockEndpoint testClient1Endpoint;
+
+    @EndpointInject(uri = MOCK_CLIENT_2)
+    protected MockEndpoint testClient2Endpoint;
+
+    @EndpointInject(uri = MOCK_SERVER_1)
+    protected MockEndpoint testServer1Endpoint;
+
+    @Override
+    protected RoutesBuilder createRouteBuilder() throws Exception {
+
+        final int port = Ports.pickServerPort();
+
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from(DIRECT_SEND_S_1).toF("iec60870-server:localhost:%s/00-00-00-00-01", port);
+                fromF("iec60870-client:localhost:%s/00-00-00-00-01", port).to(MOCK_CLIENT_1);
+                fromF("iec60870-client:localhost:%s/00-00-00-00-02", port).to(MOCK_CLIENT_2);
+
+                from(DIRECT_SEND_C_1).toF("iec60870-client:localhost:%s/00-00-00-01-01", port);
+                fromF("iec60870-server:localhost:%s/00-00-00-01-01", port).to(MOCK_SERVER_1);
+            }
+        };
+    }
+
+    @Test
+    public void testFloat1() throws InterruptedException {
+        this.producerServer1.sendBody(1.23f);
+
+        // expect - count
+
+        this.testClient1Endpoint.setExpectedCount(1);
+        this.testClient2Endpoint.setExpectedCount(0);
+
+        // expect
+
+        expectValue(testClient1Endpoint.message(0), assertGoodValue(1.23f));
+
+        // assert
+
+        assertMockEndpointsSatisfied(1_000, TimeUnit.MILLISECONDS);
+    }
+
+    @Test
+    public void testBoolean1() throws InterruptedException {
+        this.producerServer1.sendBody(true);
+
+        // expect - count
+
+        this.testClient1Endpoint.setExpectedCount(1);
+        this.testClient2Endpoint.setExpectedCount(0);
+
+        // expect
+
+        expectValue(testClient1Endpoint.message(0), assertGoodValue(true));
+
+        // assert
+
+        assertMockEndpointsSatisfied(1_000, TimeUnit.MILLISECONDS);
+    }
+
+    @Test
+    public void testCommand1() throws InterruptedException {
+
+        Thread.sleep(1_000);
+
+        this.producerClient1.sendBody(true);
+
+        // expect - count
+
+        this.testServer1Endpoint.setExpectedCount(1);
+
+        // expect
+
+        expectRequest(testServer1Endpoint.message(0), expectRequest(true));
+
+        // assert
+
+        assertMockEndpointsSatisfied(2_000, TimeUnit.MILLISECONDS);
+        System.out.println(testServer1Endpoint.getExchanges().get(0).getIn().getBody());
+
+    }
+
+    private <T> void expectValue(AssertionClause message, Consumer<Value<?>> consumer) {
+        message.predicate(exchange -> {
+            final Value<?> body = exchange.getIn().getBody(Value.class);
+            consumer.accept(body);
+            return true;
+        });
+    }
+
+    private <T> void expectRequest(AssertionClause message, Consumer<Request<?>> consumer) {
+        message.predicate(exchange -> {
+            final Request<?> body = exchange.getIn().getBody(Request.class);
+            consumer.accept(body);
+            return true;
+        });
+    }
+
+    public static Consumer<Value<?>> assertGoodValue(final Object expectedValue) {
+        return value -> {
+            assertNotNull(value);
+            assertEquals(expectedValue, value.getValue());
+            assertTrue(value.getQualityInformation().isValid());
+            assertTrue(value.getQualityInformation().isTopical());
+            assertFalse(value.getQualityInformation().isBlocked());
+            assertFalse(value.getQualityInformation().isSubstituted());
+        };
+    }
+
+    private Consumer<Request<?>> expectRequest(final Object expectedValue) {
+        return value -> {
+            assertNotNull(value);
+            assertEquals(expectedValue, value.getValue());
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/Ports.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/Ports.java b/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/Ports.java
new file mode 100644
index 0000000..7b30b71
--- /dev/null
+++ b/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/Ports.java
@@ -0,0 +1,32 @@
+/**
+ * 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.component.iec60870;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+
+public final class Ports {
+
+    private Ports() {
+    }
+
+    public static int pickServerPort() throws IOException {
+        try (ServerSocket socket = new ServerSocket(0)) {
+            return socket.getLocalPort();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/testing/ExampleApplication1.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/testing/ExampleApplication1.java b/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/testing/ExampleApplication1.java
new file mode 100644
index 0000000..1d144fb
--- /dev/null
+++ b/components/camel-iec60870/src/test/java/org/apache/camel/component/iec60870/testing/ExampleApplication1.java
@@ -0,0 +1,76 @@
+/**
+ * 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.component.iec60870.testing;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.DefaultCamelContext;
+
+public class ExampleApplication1 {
+    public static void main(final String[] args) throws Exception {
+        new ExampleApplication1().run();
+    }
+
+    private void run() throws Exception {
+        final CamelContext context = new DefaultCamelContext();
+
+        context.addRoutes(new RouteBuilder() {
+
+            @Override
+            public void configure() throws Exception {
+
+                from("timer:foo") //
+                    .setBody(simple("${random(10)}"))//
+                    .convertBodyTo(Float.class) //
+                    .to("iec60870-client:localhost:2404/0-1-2-3-4") //
+                    .to("iec60870-client:localhost:2405/0-1-2-3-4") //
+                    .setBody(simple("Timer: ${body}")) //
+                    .to("stream:err");
+
+                from("iec60870-server:localhost:2404/0-1-2-3-4") //
+                    .setBody(simple("${body.value}")) //
+                    .to("iec60870-server:localhost:2404/0-1-2-3-4") //
+                    .setBody(simple("Server 1: ${body}")) //
+                    .to("stream:err");
+
+                from("iec60870-server:localhost:2405/0-1-2-3-4") //
+                    .setBody(simple("${body.value}")) //
+                    .to("iec60870-server:localhost:2405/0-1-2-3-4") //
+                    .setBody(simple("Server 2: ${body}")) //
+                    .to("stream:err");
+
+                from("iec60870-client:localhost:2404/0-1-2-3-4") //
+                    .setBody(simple("From 1: ${body}")) //
+                    .to("stream:err");
+
+                from("iec60870-client:localhost:2405/0-1-2-3-4") //
+                    .setBody(simple("From 2: ${body}")) //
+                    .to("stream:err");
+            }
+        });
+
+        // start
+
+        context.start();
+
+        // sleep
+
+        while (true) {
+            Thread.sleep(Long.MAX_VALUE);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/test/resources/log4j2.properties
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/test/resources/log4j2.properties b/components/camel-iec60870/src/test/resources/log4j2.properties
new file mode 100644
index 0000000..8534003
--- /dev/null
+++ b/components/camel-iec60870/src/test/resources/log4j2.properties
@@ -0,0 +1,28 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+appender.file.type = File
+appender.file.name = file
+appender.file.fileName = target/camel-iec60870-test.log
+appender.file.layout.type = PatternLayout
+appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+appender.out.type = Console
+appender.out.name = out
+appender.out.layout.type = PatternLayout
+appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n
+rootLogger.level = INFO
+rootLogger.appenderRef.file.ref = file

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/readme.adoc
----------------------------------------------------------------------
diff --git a/components/readme.adoc b/components/readme.adoc
index 3edbf09..969911d 100644
--- a/components/readme.adoc
+++ b/components/readme.adoc
@@ -1018,7 +1018,7 @@ Miscellaneous Components
 ^^^^^^^^^^^^^^^^^^^^^^^^
 
 // others: START
-Number of Miscellaneous Components: 37 in 37 JAR artifacts (13 deprecated)
+Number of Miscellaneous Components: 38 in 38 JAR artifacts (14 deprecated)
 
 [width="100%",cols="4,1,5",options="header"]
 |=======================================================================
@@ -1074,6 +1074,8 @@ Number of Miscellaneous Components: 37 in 37 JAR artifacts (13 deprecated)
 
 | link:camel-spring-cloud-netflix/src/main/docs/spring-cloud-netflix.adoc[Spring Cloud Netflix] (camel-spring-cloud-netflix) | 2.19 | Camel Cloud integration with Spring Cloud Netflix
 
+| link:camel-spring-dm/src/main/docs/spring-dm.adoc[Spring DM] (camel-spring-dm) | 2.18 | *deprecated* Camel SpringDM (OSGi) XML DSL
+
 | link:camel-spring-javaconfig/src/main/docs/spring-javaconfig.adoc[Spring Java Configuration] (camel-spring-javaconfig) | 2.0 | Using Camel with Spring Java Configuration
 
 | link:camel-spring-security/src/main/docs/spring-security.adoc[Spring Security] (camel-spring-security) | 2.3 | Security using Spring Security

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index 4a3cf0e..4faa687 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -508,6 +508,7 @@
     <narayana-version>5.6.4.Final</narayana-version>
     <neethi-bundle-version>3.0.1</neethi-bundle-version>
     <nekohtml-version>1.9.22</nekohtml-version>
+    <neoscada-version>0.4.0</neoscada-version>
     <netty3-version>3.10.6.Final</netty3-version>
     <netty-version>4.1.14.Final</netty-version>
     <netty40-version>4.0.50.Final</netty40-version>
@@ -1335,6 +1336,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.camel</groupId>
+        <artifactId>camel-iec60870</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.camel</groupId>
         <artifactId>camel-infinispan</artifactId>
         <version>${project.version}</version>
       </dependency>

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/platforms/spring-boot/components-starter/camel-iec60870-starter/pom.xml
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-iec60870-starter/pom.xml b/platforms/spring-boot/components-starter/camel-iec60870-starter/pom.xml
new file mode 100644
index 0000000..0208573
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-iec60870-starter/pom.xml
@@ -0,0 +1,53 @@
+<?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.
+
+-->
+<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>
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>components-starter</artifactId>
+    <version>2.20.0-SNAPSHOT</version>
+  </parent>
+  <artifactId>camel-iec60870-starter</artifactId>
+  <packaging>jar</packaging>
+  <name>Spring-Boot Starter :: Camel :: IEC 60870</name>
+  <description>Spring-Boot Starter for Camel IEC 60870-5-104 support</description>
+  <dependencies>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+      <version>${spring-boot-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-iec60870</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <!--START OF GENERATED CODE-->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core-starter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-spring-boot-starter</artifactId>
+    </dependency>
+    <!--END OF GENERATED CODE-->
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/client/springboot/ClientComponentAutoConfiguration.java
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/client/springboot/ClientComponentAutoConfiguration.java b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/client/springboot/ClientComponentAutoConfiguration.java
new file mode 100644
index 0000000..731a1ec
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/client/springboot/ClientComponentAutoConfiguration.java
@@ -0,0 +1,128 @@
+/**
+ * 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.component.iec60870.client.springboot;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Generated;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.iec60870.client.ClientComponent;
+import org.apache.camel.spi.ComponentCustomizer;
+import org.apache.camel.spi.HasId;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.spring.boot.ComponentConfigurationProperties;
+import org.apache.camel.spring.boot.util.ConditionalOnCamelContextAndAutoConfigurationBeans;
+import org.apache.camel.spring.boot.util.GroupCondition;
+import org.apache.camel.spring.boot.util.HierarchicalPropertiesEvaluator;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+
+/**
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.SpringBootAutoConfigurationMojo")
+@Configuration
+@Conditional({ConditionalOnCamelContextAndAutoConfigurationBeans.class,
+        ClientComponentAutoConfiguration.GroupConditions.class})
+@AutoConfigureAfter(CamelAutoConfiguration.class)
+@EnableConfigurationProperties({ComponentConfigurationProperties.class,
+        ClientComponentConfiguration.class})
+public class ClientComponentAutoConfiguration {
+
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(ClientComponentAutoConfiguration.class);
+    @Autowired
+    private ApplicationContext applicationContext;
+    @Autowired
+    private CamelContext camelContext;
+    @Autowired
+    private ClientComponentConfiguration configuration;
+    @Autowired(required = false)
+    private List<ComponentCustomizer<ClientComponent>> customizers;
+
+    static class GroupConditions extends GroupCondition {
+        public GroupConditions() {
+            super("camel.component", "camel.component.iec60870-client");
+        }
+    }
+
+    @Lazy
+    @Bean(name = "iec60870-client-component")
+    @ConditionalOnMissingBean(ClientComponent.class)
+    public ClientComponent configureClientComponent() throws Exception {
+        ClientComponent component = new ClientComponent();
+        component.setCamelContext(camelContext);
+        Map<String, Object> parameters = new HashMap<>();
+        IntrospectionSupport.getProperties(configuration, parameters, null,
+                false);
+        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
+            Object value = entry.getValue();
+            Class<?> paramClass = value.getClass();
+            if (paramClass.getName().endsWith("NestedConfiguration")) {
+                Class nestedClass = null;
+                try {
+                    nestedClass = (Class) paramClass.getDeclaredField(
+                            "CAMEL_NESTED_CLASS").get(null);
+                    HashMap<String, Object> nestedParameters = new HashMap<>();
+                    IntrospectionSupport.getProperties(value, nestedParameters,
+                            null, false);
+                    Object nestedProperty = nestedClass.newInstance();
+                    IntrospectionSupport.setProperties(camelContext,
+                            camelContext.getTypeConverter(), nestedProperty,
+                            nestedParameters);
+                    entry.setValue(nestedProperty);
+                } catch (NoSuchFieldException e) {
+                }
+            }
+        }
+        IntrospectionSupport.setProperties(camelContext,
+                camelContext.getTypeConverter(), component, parameters);
+        if (ObjectHelper.isNotEmpty(customizers)) {
+            for (ComponentCustomizer<ClientComponent> customizer : customizers) {
+                boolean useCustomizer = (customizer instanceof HasId)
+                        ? HierarchicalPropertiesEvaluator.evaluate(
+                                applicationContext.getEnvironment(),
+                                "camel.component.customizer",
+                                "camel.component.iec60870-client.customizer",
+                                ((HasId) customizer).getId())
+                        : HierarchicalPropertiesEvaluator.evaluate(
+                                applicationContext.getEnvironment(),
+                                "camel.component.customizer",
+                                "camel.component.iec60870-client.customizer");
+                if (useCustomizer) {
+                    LOGGER.debug("Configure component {}, with customizer {}",
+                            component, customizer);
+                    customizer.customize(component);
+                }
+            }
+        }
+        return component;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/client/springboot/ClientComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/client/springboot/ClientComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/client/springboot/ClientComponentConfiguration.java
new file mode 100644
index 0000000..beaa2a9
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/client/springboot/ClientComponentConfiguration.java
@@ -0,0 +1,87 @@
+/**
+ * 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.component.iec60870.client.springboot;
+
+import javax.annotation.Generated;
+import org.apache.camel.spring.boot.ComponentConfigurationPropertiesCommon;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Camel IEC 60870-5-104 support
+ * 
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.SpringBootAutoConfigurationMojo")
+@ConfigurationProperties(prefix = "camel.component.iec60870-client")
+public class ClientComponentConfiguration
+        extends
+            ComponentConfigurationPropertiesCommon {
+
+    /**
+     * Default connection options
+     */
+    private ClientOptionsNestedConfiguration defaultConnectionOptions;
+    /**
+     * Whether the component should resolve property placeholders on itself when
+     * starting. Only properties which are of String type can use property
+     * placeholders.
+     */
+    private Boolean resolvePropertyPlaceholders = true;
+
+    public ClientOptionsNestedConfiguration getDefaultConnectionOptions() {
+        return defaultConnectionOptions;
+    }
+
+    public void setDefaultConnectionOptions(
+            ClientOptionsNestedConfiguration defaultConnectionOptions) {
+        this.defaultConnectionOptions = defaultConnectionOptions;
+    }
+
+    public Boolean getResolvePropertyPlaceholders() {
+        return resolvePropertyPlaceholders;
+    }
+
+    public void setResolvePropertyPlaceholders(
+            Boolean resolvePropertyPlaceholders) {
+        this.resolvePropertyPlaceholders = resolvePropertyPlaceholders;
+    }
+
+    public static class ClientOptionsNestedConfiguration {
+        public static final Class CAMEL_NESTED_CLASS = org.apache.camel.component.iec60870.client.ClientOptions.class;
+        private Byte causeSourceAddress;
+        /**
+         * Whether background scan transmissions should be ignored.
+         */
+        private Boolean ignoreBackgroundScan = true;
+
+        public Byte getCauseSourceAddress() {
+            return causeSourceAddress;
+        }
+
+        public void setCauseSourceAddress(Byte causeSourceAddress) {
+            this.causeSourceAddress = causeSourceAddress;
+        }
+
+        public Boolean getIgnoreBackgroundScan() {
+            return ignoreBackgroundScan;
+        }
+
+        public void setIgnoreBackgroundScan(Boolean ignoreBackgroundScan) {
+            this.ignoreBackgroundScan = ignoreBackgroundScan;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/server/springboot/ServerComponentAutoConfiguration.java
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/server/springboot/ServerComponentAutoConfiguration.java b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/server/springboot/ServerComponentAutoConfiguration.java
new file mode 100644
index 0000000..ac6a0c5
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/server/springboot/ServerComponentAutoConfiguration.java
@@ -0,0 +1,128 @@
+/**
+ * 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.component.iec60870.server.springboot;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Generated;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.iec60870.server.ServerComponent;
+import org.apache.camel.spi.ComponentCustomizer;
+import org.apache.camel.spi.HasId;
+import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.apache.camel.spring.boot.ComponentConfigurationProperties;
+import org.apache.camel.spring.boot.util.ConditionalOnCamelContextAndAutoConfigurationBeans;
+import org.apache.camel.spring.boot.util.GroupCondition;
+import org.apache.camel.spring.boot.util.HierarchicalPropertiesEvaluator;
+import org.apache.camel.util.IntrospectionSupport;
+import org.apache.camel.util.ObjectHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+
+/**
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.SpringBootAutoConfigurationMojo")
+@Configuration
+@Conditional({ConditionalOnCamelContextAndAutoConfigurationBeans.class,
+        ServerComponentAutoConfiguration.GroupConditions.class})
+@AutoConfigureAfter(CamelAutoConfiguration.class)
+@EnableConfigurationProperties({ComponentConfigurationProperties.class,
+        ServerComponentConfiguration.class})
+public class ServerComponentAutoConfiguration {
+
+    private static final Logger LOGGER = LoggerFactory
+            .getLogger(ServerComponentAutoConfiguration.class);
+    @Autowired
+    private ApplicationContext applicationContext;
+    @Autowired
+    private CamelContext camelContext;
+    @Autowired
+    private ServerComponentConfiguration configuration;
+    @Autowired(required = false)
+    private List<ComponentCustomizer<ServerComponent>> customizers;
+
+    static class GroupConditions extends GroupCondition {
+        public GroupConditions() {
+            super("camel.component", "camel.component.iec60870-server");
+        }
+    }
+
+    @Lazy
+    @Bean(name = "iec60870-server-component")
+    @ConditionalOnMissingBean(ServerComponent.class)
+    public ServerComponent configureServerComponent() throws Exception {
+        ServerComponent component = new ServerComponent();
+        component.setCamelContext(camelContext);
+        Map<String, Object> parameters = new HashMap<>();
+        IntrospectionSupport.getProperties(configuration, parameters, null,
+                false);
+        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
+            Object value = entry.getValue();
+            Class<?> paramClass = value.getClass();
+            if (paramClass.getName().endsWith("NestedConfiguration")) {
+                Class nestedClass = null;
+                try {
+                    nestedClass = (Class) paramClass.getDeclaredField(
+                            "CAMEL_NESTED_CLASS").get(null);
+                    HashMap<String, Object> nestedParameters = new HashMap<>();
+                    IntrospectionSupport.getProperties(value, nestedParameters,
+                            null, false);
+                    Object nestedProperty = nestedClass.newInstance();
+                    IntrospectionSupport.setProperties(camelContext,
+                            camelContext.getTypeConverter(), nestedProperty,
+                            nestedParameters);
+                    entry.setValue(nestedProperty);
+                } catch (NoSuchFieldException e) {
+                }
+            }
+        }
+        IntrospectionSupport.setProperties(camelContext,
+                camelContext.getTypeConverter(), component, parameters);
+        if (ObjectHelper.isNotEmpty(customizers)) {
+            for (ComponentCustomizer<ServerComponent> customizer : customizers) {
+                boolean useCustomizer = (customizer instanceof HasId)
+                        ? HierarchicalPropertiesEvaluator.evaluate(
+                                applicationContext.getEnvironment(),
+                                "camel.component.customizer",
+                                "camel.component.iec60870-server.customizer",
+                                ((HasId) customizer).getId())
+                        : HierarchicalPropertiesEvaluator.evaluate(
+                                applicationContext.getEnvironment(),
+                                "camel.component.customizer",
+                                "camel.component.iec60870-server.customizer");
+                if (useCustomizer) {
+                    LOGGER.debug("Configure component {}, with customizer {}",
+                            component, customizer);
+                    customizer.customize(component);
+                }
+            }
+        }
+        return component;
+    }
+}
\ No newline at end of file


[4/7] camel git commit: Import of the IEC 60870 component

Posted by ac...@apache.org.
Import of the IEC 60870 component

This change adds an IEC 60870 camel component based on the
IEC 60870 implementation of Eclipse NeoSCADA.

Signed-off-by: Jens Reimann <jr...@redhat.com>


Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/eb4f6059
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/eb4f6059
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/eb4f6059

Branch: refs/heads/master
Commit: eb4f6059cdfa5e363afdc57d258ea51775a59b88
Parents: 239fde8
Author: Jens Reimann <jr...@redhat.com>
Authored: Wed Aug 9 14:32:26 2017 +0200
Committer: Andrea Cosentino <an...@gmail.com>
Committed: Thu Aug 10 12:20:18 2017 +0200

----------------------------------------------------------------------
 components/camel-iec60870/pom.xml               | 146 ++++++++++++
 .../main/docs/iec60870-client-component.adoc    | 127 +++++++++++
 .../main/docs/iec60870-server-component.adoc    | 111 +++++++++
 .../iec60870/AbstractConnectionMultiplexor.java |  88 ++++++++
 .../iec60870/AbstractIecComponent.java          | 174 +++++++++++++++
 .../component/iec60870/AbstractIecEndpoint.java | 109 +++++++++
 .../camel/component/iec60870/BaseOptions.java   | 223 +++++++++++++++++++
 .../camel/component/iec60870/ConnectionId.java  |  94 ++++++++
 .../camel/component/iec60870/Constants.java     |  25 +++
 .../iec60870/DiscardAckChannelHandler.java      |  54 +++++
 .../component/iec60870/DiscardAckModule.java    |  44 ++++
 .../camel/component/iec60870/ObjectAddress.java | 114 ++++++++++
 .../iec60870/client/ClientComponent.java        |  78 +++++++
 .../iec60870/client/ClientConnection.java       | 132 +++++++++++
 .../client/ClientConnectionMultiplexor.java     |  43 ++++
 .../iec60870/client/ClientConsumer.java         |  79 +++++++
 .../iec60870/client/ClientEndpoint.java         |  46 ++++
 .../iec60870/client/ClientOptions.java          |  91 ++++++++
 .../iec60870/client/ClientProducer.java         |  89 ++++++++
 .../iec60870/server/ServerComponent.java        |  83 +++++++
 .../server/ServerConnectionMultiplexor.java     |  43 ++++
 .../iec60870/server/ServerConsumer.java         | 110 +++++++++
 .../iec60870/server/ServerEndpoint.java         |  60 +++++
 .../iec60870/server/ServerInstance.java         | 190 ++++++++++++++++
 .../iec60870/server/ServerOptions.java          | 152 +++++++++++++
 .../iec60870/server/ServerProducer.java         |  68 ++++++
 .../src/main/resources/META-INF/LICENSE.txt     | 203 +++++++++++++++++
 .../src/main/resources/META-INF/NOTICE.txt      |  11 +
 .../org/apache/camel/component/iec60870-client  |  18 ++
 .../org/apache/camel/component/iec60870-server  |  18 ++
 .../component/iec60870/ConnectionIdTest.java    |  71 ++++++
 .../component/iec60870/ConnectionTest.java      | 171 ++++++++++++++
 .../apache/camel/component/iec60870/Ports.java  |  32 +++
 .../iec60870/testing/ExampleApplication1.java   |  76 +++++++
 .../src/test/resources/log4j2.properties        |  28 +++
 components/readme.adoc                          |   4 +-
 parent/pom.xml                                  |   6 +
 .../camel-iec60870-starter/pom.xml              |  53 +++++
 .../ClientComponentAutoConfiguration.java       | 128 +++++++++++
 .../ClientComponentConfiguration.java           |  87 ++++++++
 .../ServerComponentAutoConfiguration.java       | 128 +++++++++++
 .../ServerComponentConfiguration.java           | 136 +++++++++++
 .../src/main/resources/META-INF/LICENSE.txt     | 203 +++++++++++++++++
 .../src/main/resources/META-INF/NOTICE.txt      |  11 +
 .../main/resources/META-INF/spring.factories    |  21 ++
 .../src/main/resources/META-INF/spring.provides |  17 ++
 .../spring-boot/components-starter/pom.xml      |   1 +
 47 files changed, 3995 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/pom.xml b/components/camel-iec60870/pom.xml
new file mode 100644
index 0000000..6102479
--- /dev/null
+++ b/components/camel-iec60870/pom.xml
@@ -0,0 +1,146 @@
+<?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.
+
+-->
+<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>
+
+  <parent>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>components</artifactId>
+    <version>2.20.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-iec60870</artifactId>
+  <packaging>jar</packaging>
+  <name>Camel :: IEC 60870</name>
+  <description>Camel IEC 60870-5-104 support</description>
+
+  <properties>
+    <camel.osgi.export.pkg>
+      !*.internal.*,
+      org.apache.camel.component.iec60870.*
+    </camel.osgi.export.pkg>
+    <camel.osgi.export.service>
+      org.apache.camel.spi.ComponentResolver;component=iec60870-client,
+      org.apache.camel.spi.ComponentResolver;component=iec60870-server
+    </camel.osgi.export.service>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.eclipse.neoscada.protocols</groupId>
+      <artifactId>org.eclipse.neoscada.protocol.iec60870</artifactId>
+      <version>${neoscada-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.neoscada.protocols</groupId>
+      <artifactId>org.eclipse.neoscada.protocol.iec60870.client</artifactId>
+      <version>${neoscada-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.neoscada.protocols</groupId>
+      <artifactId>org.eclipse.neoscada.protocol.iec60870.client.data</artifactId>
+      <version>${neoscada-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.neoscada.protocols</groupId>
+      <artifactId>org.eclipse.neoscada.protocol.iec60870.server</artifactId>
+      <version>${neoscada-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.neoscada.protocols</groupId>
+      <artifactId>org.eclipse.neoscada.protocol.iec60870.server.data</artifactId>
+      <version>${neoscada-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.eclipse.neoscada.utils</groupId>
+      <artifactId>org.eclipse.scada.utils</artifactId>
+      <version>${neoscada-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-buffer</artifactId>
+      <version>${netty-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec</artifactId>
+      <version>${netty-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-common</artifactId>
+      <version>${netty-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-handler</artifactId>
+      <version>${netty-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-transport</artifactId>
+      <version>${netty-version}</version>
+    </dependency>
+
+    <!-- testing -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-api</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.logging.log4j</groupId>
+      <artifactId>log4j-slf4j-impl</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/docs/iec60870-client-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/docs/iec60870-client-component.adoc b/components/camel-iec60870/src/main/docs/iec60870-client-component.adoc
new file mode 100644
index 0000000..60367ec
--- /dev/null
+++ b/components/camel-iec60870/src/main/docs/iec60870-client-component.adoc
@@ -0,0 +1,127 @@
+## IEC 60870 Client Component
+
+*Available as of Camel version 2.20*
+
+### IEC 60870-5-104 Client Component
+
+*Available as of Camel 2.20*
+
+The *IEC 60870-5-104 Client* component provides access to IEC 60870 servers using the
+http://eclipse.org/eclipsescada[Eclipse NeoSCADAâ„¢] implementation.
+
+*Java 8*: This component requires Java 8 at runtime. 
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-iec60870</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+------------------------------------------------------------
+
+// component options: START
+The IEC 60870 Client component supports 2 options which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|=======================================================================
+| Name | Description | Default | Type
+| **defaultConnection Options** (common) | Default connection options |  | ClientOptions
+| **resolveProperty Placeholders** (advanced) | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | boolean
+|=======================================================================
+// component options: END
+
+
+
+
+
+### URI format
+
+The URI syntax of the endpoint is: 
+
+[source]
+------------------------
+iec60870-client:host:port/00-01-02-03-04
+------------------------
+
+The information object address is encoded in the path in the syntax shows above. Please
+note that always the full, 5 octet address format is being used. Unused octets have to be filled
+with zero.
+
+### URI options
+
+
+// endpoint options: START
+The IEC 60870 Client endpoint is configured using URI syntax:
+
+    iec60870-client:endpointUri
+
+with the following path and query parameters:
+
+#### Path Parameters (1 parameters):
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|=======================================================================
+| Name | Description | Default | Type
+| **uriPath** | *Required* The object information address |  | ObjectAddress
+|=======================================================================
+
+#### Query Parameters (18 parameters):
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|=======================================================================
+| Name | Description | Default | Type
+| **dataModuleOptions** (common) | Data module options |  | DataModuleOptions
+| **protocolOptions** (common) | Protocol options |  | ProtocolOptions
+| **bridgeErrorHandler** (consumer) | Allows for bridging the consumer to the Camel routing Error Handler which mean any exceptions occurred while the consumer is trying to pickup incoming messages or the likes will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions that will be logged at WARN or ERROR level and ignored. | false | boolean
+| **exceptionHandler** (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this options is not in use. By default the consumer will deal with exceptions that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
+| **exchangePattern** (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
+| **synchronous** (advanced) | Sets whether synchronous processing should be strictly used or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+| **acknowledgeWindow** (connection) | Parameter W - Acknowledgment window. | 10 | short
+| **adsuAddressType** (connection) | The common ASDU address size. May be either SIZE_1 or SIZE_2. |  | ASDUAddressType
+| **causeOfTransmissionType** (connection) | The cause of transmission type. May be either SIZE_1 or SIZE_2. |  | CauseOfTransmission Type
+| **informationObjectAddress Type** (connection) | The information address size. May be either SIZE_1 SIZE_2 or SIZE_3. |  | InformationObject AddressType
+| **maxUnacknowledged** (connection) | Parameter K - Maximum number of un-acknowledged messages. | 15 | short
+| **timeout1** (connection) | Timeout T1 in milliseconds. | 15000 | int
+| **timeout2** (connection) | Timeout T2 in milliseconds. | 10000 | int
+| **timeout3** (connection) | Timeout T3 in milliseconds. | 20000 | int
+| **ignoreBackgroundScan** (data) | Whether background scan transmissions should be ignored. | true | boolean
+| **ignoreDaylightSavingTime** (data) | Whether to ignore or respect DST | false | boolean
+| **timeZone** (data) | The timezone to use. May be any Java time zone string | UTC | TimeZone
+| **connectionId** (id) | An identifier grouping connection instances |  | String
+|=======================================================================
+// endpoint options: END
+
+
+
+A connection instance if identified by the host and port part of the URI, plus all parameters in the "id" group.
+If a new connection id is encountered the connection options will be evaluated and the connection instance
+is created with those options.
+
+
+NOTE: If two URIs specify the same connection (host, port, …) but different connection options, then it is
+undefined which of those connection options will be used. 
+
+
+The final connection options will be evaluated in the following order:
+
+* If present, the +connectionOptions+ parameter will be used
+* Otherwise the +defaultConnectionOptions+ instance is copied and customized in the following steps
+* Apply +protocolOptions+ if present
+* Apply +dataModuleOptions+ if present
+* Apply all explicit connection parameters (e.g. +timeZone+)
+
+
+
+### See Also
+
+* link:configuring-camel.html[Configuring Camel]
+* link:component.html[Component]
+* link:endpoint.html[Endpoint]
+* link:getting-started.html[Getting Started]

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/docs/iec60870-server-component.adoc
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/docs/iec60870-server-component.adoc b/components/camel-iec60870/src/main/docs/iec60870-server-component.adoc
new file mode 100644
index 0000000..338e8d7
--- /dev/null
+++ b/components/camel-iec60870/src/main/docs/iec60870-server-component.adoc
@@ -0,0 +1,111 @@
+## IEC 60870-5-104 server Component
+
+*Available as of Camel version 2.20*
+
+### IEC 60870-5-104 Server Component
+
+*Available as of Camel 2.20*
+
+The *IEC 60870-5-104 Server* component provides access to IEC 60870 servers using the
+http://eclipse.org/eclipsescada[Eclipse NeoSCADAâ„¢] implementation.
+
+*Java 8*: This component requires Java 8 at runtime. 
+
+Maven users will need to add the following dependency to their `pom.xml`
+for this component:
+
+[source,xml]
+------------------------------------------------------------
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-iec60870</artifactId>
+    <version>x.x.x</version>
+    <!-- use the same version as your Camel core version -->
+</dependency>
+------------------------------------------------------------
+
+
+// component options: START
+The IEC 60870-5-104 server component supports 2 options which are listed below.
+
+
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|=======================================================================
+| Name | Description | Default | Type
+| **defaultConnection Options** (common) | Default connection options |  | ServerOptions
+| **resolveProperty Placeholders** (advanced) | Whether the component should resolve property placeholders on itself when starting. Only properties which are of String type can use property placeholders. | true | boolean
+|=======================================================================
+// component options: END
+
+
+
+
+
+### URI format
+
+The URI syntax of the endpoint is: 
+
+[source]
+------------------------
+iec60870-server:host:port/00-01-02-03-04
+------------------------
+
+The information object address is encoded in the path in the syntax shows above. Please
+note that always the full, 5 octet address format is being used. Unused octets have to be filled
+with zero.
+
+### URI options
+
+
+
+
+// endpoint options: START
+The IEC 60870-5-104 server endpoint is configured using URI syntax:
+
+    iec60870-server:endpointUri
+
+with the following path and query parameters:
+
+#### Path Parameters (1 parameters):
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|=======================================================================
+| Name | Description | Default | Type
+| **uriPath** | *Required* The object information address |  | ObjectAddress
+|=======================================================================
+
+#### Query Parameters (19 parameters):
+
+[width="100%",cols="2,5,^1,2",options="header"]
+|=======================================================================
+| Name | Description | Default | Type
+| **dataModuleOptions** (common) | Data module options |  | DataModuleOptions
+| **filterNonExecute** (common) | Filter out all requests which don't have the execute bit set | true | boolean
+| **protocolOptions** (common) | Protocol options |  | ProtocolOptions
+| **bridgeErrorHandler** (consumer) | Allows for bridging the consumer to the Camel routing Error Handler which mean any exceptions occurred while the consumer is trying to pickup incoming messages or the likes will now be processed as a message and handled by the routing Error Handler. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions that will be logged at WARN or ERROR level and ignored. | false | boolean
+| **exceptionHandler** (consumer) | To let the consumer use a custom ExceptionHandler. Notice if the option bridgeErrorHandler is enabled then this options is not in use. By default the consumer will deal with exceptions that will be logged at WARN or ERROR level and ignored. |  | ExceptionHandler
+| **exchangePattern** (consumer) | Sets the exchange pattern when the consumer creates an exchange. |  | ExchangePattern
+| **synchronous** (advanced) | Sets whether synchronous processing should be strictly used or Camel is allowed to use asynchronous processing (if supported). | false | boolean
+| **acknowledgeWindow** (connection) | Parameter W - Acknowledgment window. | 10 | short
+| **adsuAddressType** (connection) | The common ASDU address size. May be either SIZE_1 or SIZE_2. |  | ASDUAddressType
+| **causeOfTransmissionType** (connection) | The cause of transmission type. May be either SIZE_1 or SIZE_2. |  | CauseOfTransmission Type
+| **informationObjectAddress Type** (connection) | The information address size. May be either SIZE_1 SIZE_2 or SIZE_3. |  | InformationObject AddressType
+| **maxUnacknowledged** (connection) | Parameter K - Maximum number of un-acknowledged messages. | 15 | short
+| **timeout1** (connection) | Timeout T1 in milliseconds. | 15000 | int
+| **timeout2** (connection) | Timeout T2 in milliseconds. | 10000 | int
+| **timeout3** (connection) | Timeout T3 in milliseconds. | 20000 | int
+| **ignoreBackgroundScan** (data) | Whether background scan transmissions should be ignored. | true | boolean
+| **ignoreDaylightSavingTime** (data) | Whether to ignore or respect DST | false | boolean
+| **timeZone** (data) | The timezone to use. May be any Java time zone string | UTC | TimeZone
+| **connectionId** (id) | An identifier grouping connection instances |  | String
+|=======================================================================
+// endpoint options: END
+
+
+### See Also
+
+* link:configuring-camel.html[Configuring Camel]
+* link:component.html[Component]
+* link:endpoint.html[Endpoint]
+* link:getting-started.html[Getting Started]

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractConnectionMultiplexor.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractConnectionMultiplexor.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractConnectionMultiplexor.java
new file mode 100644
index 0000000..18fa1bf
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractConnectionMultiplexor.java
@@ -0,0 +1,88 @@
+/**
+ * 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.component.iec60870;
+
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractConnectionMultiplexor {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractConnectionMultiplexor.class);
+
+    public interface Handle {
+        void unregister() throws Exception;
+    }
+
+    private final class HandleImplementation implements Handle {
+        @Override
+        public void unregister() throws Exception {
+            AbstractConnectionMultiplexor.this.unregister(this);
+        }
+    }
+
+    private final Set<HandleImplementation> handles = new CopyOnWriteArraySet<>();
+
+    public synchronized Handle register() throws Exception {
+        final HandleImplementation handle = new HandleImplementation();
+
+        final boolean needStart = this.handles.isEmpty();
+        this.handles.add(handle);
+
+        if (needStart) {
+            LOG.info("Calling performStart()");
+            performStart();
+        }
+
+        return handle;
+    }
+
+    private synchronized void unregister(final HandleImplementation handle) throws Exception {
+        if (!this.handles.remove(handle)) {
+            return;
+        }
+
+        if (this.handles.isEmpty()) {
+            LOG.info("Calling performStop()");
+            performStop();
+        }
+    }
+
+    public synchronized void dispose() {
+
+        LOG.info("Disposing");
+        if (this.handles.isEmpty()) {
+            LOG.debug("Disposing - not started");
+            return;
+        }
+
+        LOG.debug("Disposing - calling performStop()");
+
+        this.handles.clear();
+        try {
+            performStop();
+        } catch (final Exception e) {
+            throw new RuntimeException("Failed to stop on dispose", e);
+        }
+    }
+
+    protected abstract void performStart() throws Exception;
+
+    protected abstract void performStop() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractIecComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractIecComponent.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractIecComponent.java
new file mode 100644
index 0000000..93ca36c
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractIecComponent.java
@@ -0,0 +1,174 @@
+/**
+ * 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.component.iec60870;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+import static java.util.Objects.requireNonNull;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.iec60870.client.ClientOptions;
+import org.apache.camel.impl.DefaultComponent;
+import org.eclipse.neoscada.protocol.iec60870.ProtocolOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AbstractIecComponent<T1, T2 extends BaseOptions<T2>> extends DefaultComponent {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractIecComponent.class);
+
+    private final Map<ConnectionId, T1> connections = new HashMap<>();
+
+    private final Class<T2> connectionOptionsClazz;
+
+    private T2 defaultConnectionOptions;
+
+    public AbstractIecComponent(final Class<T2> connectionOptionsClazz, final T2 defaultConnectionOptions, final Class<? extends Endpoint> endpointClass) {
+        this.connectionOptionsClazz = connectionOptionsClazz;
+        this.defaultConnectionOptions = defaultConnectionOptions;
+    }
+
+    public AbstractIecComponent(final Class<T2> connectionOptionsClazz, final T2 defaultConnectionOptions, final CamelContext context,
+                                final Class<? extends Endpoint> endpointClass) {
+        super(context);
+        this.connectionOptionsClazz = connectionOptionsClazz;
+        this.defaultConnectionOptions = defaultConnectionOptions;
+    }
+
+    protected abstract T1 createConnection(ConnectionId id, T2 options);
+
+    /**
+     * Default connection options
+     *
+     * @param defaultConnectionOptions the new default connection options, must
+     *            not be {@code null}
+     */
+    protected void setDefaultConnectionOptions(final T2 defaultConnectionOptions) {
+        this.defaultConnectionOptions = requireNonNull(defaultConnectionOptions);
+    }
+
+    /**
+     * Get the default connection options
+     *
+     * @return the default connect options, never returns {@code null}
+     */
+    protected T2 getDefaultConnectionOptions() {
+        return this.defaultConnectionOptions;
+    }
+
+    @Override
+    protected Endpoint createEndpoint(final String uri, final String remaining, final Map<String, Object> parameters) throws Exception {
+
+        LOG.info("Create endpoint - uri: {}, remaining: {}, parameters: {}", uri, remaining, parameters);
+
+        final T1 connection = lookupConnection(uri, parameters);
+        final ObjectAddress address = parseAddress(uri);
+
+        return createEndpoint(uri, connection, address);
+    }
+
+    protected abstract Endpoint createEndpoint(String uri, T1 connection, ObjectAddress address);
+
+    protected T2 parseOptions(final ConnectionId id, final Map<String, Object> parameters) throws Exception {
+
+        // test for provided connection options
+
+        final Object connectionOptions = parameters.get(Constants.PARAM_CONNECTION_OPTIONS);
+        if (connectionOptions != null) {
+            try {
+                return this.connectionOptionsClazz.cast(connectionOptions);
+            } catch (final ClassCastException e) {
+                throw new IllegalArgumentException(String.format("'%s' must by of type %s", Constants.PARAM_CONNECTION_OPTIONS, ClientOptions.class.getName()), e);
+            }
+        }
+
+        // construct new default set
+
+        final T2 options = this.defaultConnectionOptions.copy();
+
+        // apply protocolOptions
+
+        if (parameters.get(Constants.PARAM_PROTOCOL_OPTIONS) instanceof ProtocolOptions) {
+            options.setProtocolOptions((ProtocolOptions)parameters.get(Constants.PARAM_PROTOCOL_OPTIONS));
+        }
+
+        // apply dataModuleOptions
+
+        applyDataModuleOptions(options, parameters);
+
+        // apply parameters to connection options
+
+        setProperties(options, parameters);
+
+        // return result
+
+        return options;
+    }
+
+    protected abstract void applyDataModuleOptions(T2 options, Map<String, Object> parameters);
+
+    private T1 lookupConnection(final String fullUri, final Map<String, Object> parameters) throws Exception {
+
+        LOG.debug("parse connection - '{}'", fullUri);
+
+        if (fullUri == null || fullUri.isEmpty()) {
+            throw new IllegalArgumentException("Invalid URI: " + fullUri);
+        }
+
+        final ConnectionId id = parseConnectionId(fullUri, parameters);
+
+        LOG.debug("parse connection - fullUri: {} -> {}", fullUri, id);
+
+        synchronized (this) {
+            LOG.debug("Locating connection - {}", id);
+
+            T1 connection = this.connections.get(id);
+
+            LOG.debug("Result - {} -> {}", id, connection);
+
+            if (connection == null) {
+                final T2 options = parseOptions(id, parameters);
+                LOG.debug("Creating new connection: {}", options);
+
+                connection = createConnection(id, options);
+                this.connections.put(id, connection);
+            }
+            return connection;
+        }
+    }
+
+    private static ConnectionId parseConnectionId(final String fullUri, final Map<String, Object> parameters) {
+        final URI uri = URI.create(fullUri);
+
+        final Object connectionId = parameters.get("connectionId");
+
+        return new ConnectionId(uri.getHost(), uri.getPort(), connectionId instanceof String ? (String)connectionId : null);
+    }
+
+    private static ObjectAddress parseAddress(final String fullUri) {
+        final URI uri = URI.create(fullUri);
+
+        String path = uri.getPath();
+        path = path.replaceAll("^\\/+", "");
+
+        return ObjectAddress.valueOf(path);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractIecEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractIecEndpoint.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractIecEndpoint.java
new file mode 100644
index 0000000..98fd48c
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/AbstractIecEndpoint.java
@@ -0,0 +1,109 @@
+/**
+ * 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.component.iec60870;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+import static java.util.Objects.requireNonNull;
+
+import org.apache.camel.component.iec60870.AbstractConnectionMultiplexor.Handle;
+import org.apache.camel.component.iec60870.client.ClientOptions;
+import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriPath;
+import org.eclipse.neoscada.protocol.iec60870.ProtocolOptions;
+import org.eclipse.neoscada.protocol.iec60870.client.data.DataModuleOptions;
+
+public abstract class AbstractIecEndpoint<T extends AbstractConnectionMultiplexor> extends DefaultEndpoint {
+
+    /**
+     * The object information address
+     */
+    @UriPath(name = "uriPath")
+    @Metadata(required = "true")
+    private final ObjectAddress address;
+
+    // dummy for doc generation
+    /**
+     * A full set of connection options
+     */
+    @UriParam
+    private ClientOptions connectionOptions;
+
+    // dummy for doc generation
+    /**
+     * A set of protocol options
+     */
+    @UriParam
+    private ProtocolOptions protocolOptions;
+
+    // dummy for doc generation
+    /**
+     * A set of data module options
+     */
+    @UriParam
+    private DataModuleOptions dataModuleOptions;
+
+    // dummy for doc generation
+    /**
+     * An identifier grouping connection instances
+     */
+    @UriParam(label = "id")
+    private String connectionId;
+
+    private final T connection;
+
+    private final AtomicReference<Handle> connectionHandle = new AtomicReference<>();
+
+    public AbstractIecEndpoint(final String uri, final DefaultComponent component, final T connection, final ObjectAddress address) {
+        super(uri, component);
+
+        this.connection = requireNonNull(connection);
+        this.address = requireNonNull(address);
+    }
+
+    public ObjectAddress getAddress() {
+        return this.address;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        this.connectionHandle.set(this.connection.register());
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        final Handle connectionHandle = this.connectionHandle.getAndSet(null);
+        if (connectionHandle != null) {
+            connectionHandle.unregister();
+        }
+        super.doStop();
+    }
+
+    protected T getConnection() {
+        return this.connection;
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/BaseOptions.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/BaseOptions.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/BaseOptions.java
new file mode 100644
index 0000000..e7e63c3
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/BaseOptions.java
@@ -0,0 +1,223 @@
+/**
+ * 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.component.iec60870;
+
+import java.util.Objects;
+import java.util.TimeZone;
+
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.eclipse.neoscada.protocol.iec60870.ASDUAddressType;
+import org.eclipse.neoscada.protocol.iec60870.CauseOfTransmissionType;
+import org.eclipse.neoscada.protocol.iec60870.InformationObjectAddressType;
+import org.eclipse.neoscada.protocol.iec60870.ProtocolOptions;
+
+@UriParams
+public abstract class BaseOptions<T extends BaseOptions<T>> {
+
+    /**
+     * Protocol options
+     */
+    @UriParam(javaType = "ProtocolOptions")
+    private ProtocolOptions.Builder protocolOptions;
+
+    // dummy for doc generation
+    /**
+     * The common ASDU address size.
+     * <p>
+     * May be either {@code SIZE_1} or {@code SIZE_2}.
+     * </p>
+     */
+    @UriParam(enums = "SIZE_1, SIZE_2", label = "connection")
+    private ASDUAddressType adsuAddressType;
+
+    // dummy for doc generation
+    /**
+     * The information address size.
+     * <p>
+     * May be either {@code SIZE_1}, {@code SIZE_2} or {@code SIZE_3}.
+     * </p>
+     */
+    @UriParam(enums = "SIZE_1, SIZE_2, SIZE_3", label = "connection")
+    private InformationObjectAddressType informationObjectAddressType;
+
+    // dummy for doc generation
+    /**
+     * The cause of transmission type.
+     * <p>
+     * May be either {@code SIZE_1} or {@code SIZE_2}.
+     * </p>
+     */
+    @UriParam(enums = "SIZE_1, SIZE_2", label = "connection")
+    private CauseOfTransmissionType causeOfTransmissionType;
+
+    // dummy for doc generation
+    /**
+     * The timezone to use.
+     * <p>
+     * May be any Java time zone string
+     * </p>
+     */
+    @UriParam(label = "data", defaultValue = "UTC")
+    private TimeZone timeZone;
+
+    // dummy for doc generation
+    /**
+     * Whether to ignore or respect DST
+     */
+    @UriParam(label = "data")
+    private boolean ignoreDaylightSavingTime;
+
+    // dummy for doc generation
+    /**
+     * Timeout T1 in milliseconds.
+     */
+    @UriParam(label = "connection", defaultValue = "15000")
+    private int timeout1;
+
+    // dummy for doc generation
+    /**
+     * Timeout T2 in milliseconds.
+     */
+    @UriParam(label = "connection", defaultValue = "10000")
+    private int timeout2;
+
+    // dummy for doc generation
+    /**
+     * Timeout T3 in milliseconds.
+     */
+    @UriParam(label = "connection", defaultValue = "20000")
+    private int timeout3;
+
+    // dummy for doc generation
+    /**
+     * Parameter "K" - Maximum number of un-acknowledged messages.
+     */
+    @UriParam(label = "connection", defaultValue = "15")
+    private short maxUnacknowledged;
+
+    // dummy for doc generation
+    /**
+     * Parameter "W" - Acknowledgment window.
+     */
+    @UriParam(label = "connection", defaultValue = "10")
+    private short acknowledgeWindow;
+
+    public BaseOptions() {
+        this.protocolOptions = new ProtocolOptions.Builder();
+    }
+
+    public BaseOptions(final ProtocolOptions protocolOptions) {
+        Objects.requireNonNull(protocolOptions);
+        this.protocolOptions = new ProtocolOptions.Builder(protocolOptions);
+    }
+
+    public void setProtocolOptions(final ProtocolOptions protocolOptions) {
+        Objects.requireNonNull(protocolOptions);
+
+        this.protocolOptions = new ProtocolOptions.Builder(protocolOptions);
+    }
+
+    public ProtocolOptions getProtocolOptions() {
+        return this.protocolOptions.build();
+    }
+
+    public abstract T copy();
+
+    // wrapper methods - ProtocolOptions
+
+    public int getTimeout1() {
+        return this.protocolOptions.getTimeout1();
+    }
+
+    public void setTimeout1(final int timeout1) {
+        this.protocolOptions.setTimeout1(timeout1);
+    }
+
+    public int getTimeout2() {
+        return this.protocolOptions.getTimeout2();
+    }
+
+    public void setTimeout2(final int timeout2) {
+        this.protocolOptions.setTimeout2(timeout2);
+    }
+
+    public int getTimeout3() {
+        return this.protocolOptions.getTimeout3();
+    }
+
+    public void setTimeout3(final int timeout3) {
+        this.protocolOptions.setTimeout3(timeout3);
+    }
+
+    public short getAcknowledgeWindow() {
+        return this.protocolOptions.getAcknowledgeWindow();
+    }
+
+    public void setAcknowledgeWindow(final short acknowledgeWindow) {
+        this.protocolOptions.setAcknowledgeWindow(acknowledgeWindow);
+    }
+
+    public short getMaxUnacknowledged() {
+        return this.protocolOptions.getMaxUnacknowledged();
+    }
+
+    public void setMaxUnacknowledged(final short maxUnacknowledged) {
+        this.protocolOptions.setMaxUnacknowledged(maxUnacknowledged);
+    }
+
+    public ASDUAddressType getAdsuAddressType() {
+        return this.protocolOptions.getAdsuAddressType();
+    }
+
+    public void setAdsuAddressType(final ASDUAddressType adsuAddressType) {
+        this.protocolOptions.setAdsuAddressType(adsuAddressType);
+    }
+
+    public InformationObjectAddressType getInformationObjectAddressType() {
+        return this.protocolOptions.getInformationObjectAddressType();
+    }
+
+    public void setInformationObjectAddressType(final InformationObjectAddressType informationObjectAddressType) {
+        this.protocolOptions.setInformationObjectAddressType(informationObjectAddressType);
+    }
+
+    public CauseOfTransmissionType getCauseOfTransmissionType() {
+        return this.protocolOptions.getCauseOfTransmissionType();
+    }
+
+    public void setCauseOfTransmissionType(final CauseOfTransmissionType causeOfTransmissionType) {
+        this.protocolOptions.setCauseOfTransmissionType(causeOfTransmissionType);
+    }
+
+    public TimeZone getTimeZone() {
+        return this.protocolOptions.getTimeZone();
+    }
+
+    public void setTimeZone(final TimeZone timeZone) {
+        this.protocolOptions.setTimeZone(timeZone);
+    }
+
+    public void setIgnoreDaylightSavingTime(final boolean ignoreDaylightSavingTime) {
+        this.protocolOptions.setIgnoreDaylightSavingTime(ignoreDaylightSavingTime);
+    }
+
+    public boolean isIgnoreDaylightSavingTime() {
+        return this.protocolOptions.isIgnoreDaylightSavingTime();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ConnectionId.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ConnectionId.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ConnectionId.java
new file mode 100644
index 0000000..66dfc07
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ConnectionId.java
@@ -0,0 +1,94 @@
+/**
+ * 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.component.iec60870;
+
+import java.util.Objects;
+
+public class ConnectionId {
+    private final String host;
+
+    private final int port;
+
+    private final String connectionId;
+
+    public ConnectionId(final String host, final int port, final String connectionId) {
+        Objects.requireNonNull(host);
+
+        if (port <= 0) {
+            throw new IllegalArgumentException(String.format("Port must be greater than 0"));
+        }
+
+        this.host = host;
+        this.port = port;
+        this.connectionId = connectionId;
+    }
+
+    public String getHost() {
+        return this.host;
+    }
+
+    public int getPort() {
+        return this.port;
+    }
+
+    public String getConnectionId() {
+        return this.connectionId;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (this.connectionId == null ? 0 : this.connectionId.hashCode());
+        result = prime * result + (this.host == null ? 0 : this.host.hashCode());
+        result = prime * result + this.port;
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final ConnectionId other = (ConnectionId)obj;
+        if (this.connectionId == null) {
+            if (other.connectionId != null) {
+                return false;
+            }
+        } else if (!this.connectionId.equals(other.connectionId)) {
+            return false;
+        }
+        if (this.host == null) {
+            if (other.host != null) {
+                return false;
+            }
+        } else if (!this.host.equals(other.host)) {
+            return false;
+        }
+        if (this.port != other.port) {
+            return false;
+        }
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/Constants.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/Constants.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/Constants.java
new file mode 100644
index 0000000..f2f5a60
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/Constants.java
@@ -0,0 +1,25 @@
+/**
+ * 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.component.iec60870;
+
+public interface Constants {
+    String PARAM_DATA_MODULE_OPTIONS = "dataModuleOptions";
+
+    String PARAM_PROTOCOL_OPTIONS = "protocolOptions";
+
+    String PARAM_CONNECTION_OPTIONS = "connectionOptions";
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/DiscardAckChannelHandler.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/DiscardAckChannelHandler.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/DiscardAckChannelHandler.java
new file mode 100644
index 0000000..32cbd69
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/DiscardAckChannelHandler.java
@@ -0,0 +1,54 @@
+/**
+ * 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.component.iec60870;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import org.eclipse.neoscada.protocol.iec60870.asdu.message.AbstractMessage;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.Cause;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.StandardCause;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DiscardAckChannelHandler extends ChannelInboundHandlerAdapter {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DiscardAckChannelHandler.class);
+
+    private final Set<Cause> discards = new HashSet<>();
+
+    public DiscardAckChannelHandler() {
+        this.discards.add(StandardCause.ACTIVATION_CONFIRM);
+        this.discards.add(StandardCause.ACTIVATION_TERMINATION);
+        this.discards.add(StandardCause.DEACTIVATION_CONFIRM);
+    }
+
+    @Override
+    public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
+        if (msg instanceof AbstractMessage) {
+            final AbstractMessage amsg = (AbstractMessage)msg;
+            final Cause cause = amsg.getHeader().getCauseOfTransmission().getCause();
+            if (this.discards.contains(cause)) {
+                LOG.debug("Discarding: {}", cause);
+                return;
+            }
+        }
+        super.channelRead(ctx, msg);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/DiscardAckModule.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/DiscardAckModule.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/DiscardAckModule.java
new file mode 100644
index 0000000..4fb9c6d
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/DiscardAckModule.java
@@ -0,0 +1,44 @@
+/**
+ * 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.component.iec60870;
+
+import io.netty.channel.socket.SocketChannel;
+import org.eclipse.neoscada.protocol.iec60870.apci.MessageChannel;
+import org.eclipse.neoscada.protocol.iec60870.asdu.MessageManager;
+import org.eclipse.neoscada.protocol.iec60870.client.Client;
+import org.eclipse.neoscada.protocol.iec60870.client.ClientModule;
+import org.eclipse.neoscada.protocol.iec60870.server.Server;
+import org.eclipse.neoscada.protocol.iec60870.server.ServerModule;
+
+public class DiscardAckModule implements ClientModule, ServerModule {
+    @Override
+    public void initializeChannel(final SocketChannel channel, final MessageChannel messageChannel) {
+        channel.pipeline().addLast(new DiscardAckChannelHandler());
+    }
+
+    @Override
+    public void dispose() {
+    }
+
+    @Override
+    public void initializeClient(final Client client, final MessageManager manager) {
+    }
+
+    @Override
+    public void initializeServer(final Server server, final MessageManager manager) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ObjectAddress.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ObjectAddress.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ObjectAddress.java
new file mode 100644
index 0000000..232a506
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/ObjectAddress.java
@@ -0,0 +1,114 @@
+/**
+ * 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.component.iec60870;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.ASDUAddress;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.InformationObjectAddress;
+
+public class ObjectAddress {
+    int[] address;
+
+    private ObjectAddress(final int[] address) {
+        this.address = address;
+    }
+
+    public ObjectAddress(final int a1, final int a2, final int a3, final int a4, final int a5) {
+        this.address = new int[] {a1, a2, a3, a4, a5};
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%02d-%02d-%02d-%02d-%02d", this.address[0], this.address[1], this.address[2], this.address[3], this.address[4]);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(this.address);
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final ObjectAddress other = (ObjectAddress)obj;
+        if (!Arrays.equals(this.address, other.address)) {
+            return false;
+        }
+        return true;
+    }
+
+    public static ObjectAddress valueOf(final ASDUAddress asduAddress, final InformationObjectAddress address) {
+        Objects.requireNonNull(asduAddress);
+        Objects.requireNonNull(address);
+
+        final int[] a = asduAddress.toArray();
+        final int[] b = address.toArray();
+
+        return new ObjectAddress(a[0], a[1], b[0], b[1], b[2]);
+    }
+
+    public static ObjectAddress valueOf(final String address) {
+        if (address == null || address.isEmpty()) {
+            return null;
+        }
+
+        final String[] toks = address.split("-");
+        if (toks.length != 5) {
+            throw new IllegalArgumentException("Invalid address. Must have 5 octets.");
+        }
+
+        final int[] a = new int[toks.length];
+
+        for (int i = 0; i < toks.length; i++) {
+            final int v;
+            try {
+                v = Integer.parseInt(toks[i]);
+            } catch (final NumberFormatException e) {
+                throw new IllegalArgumentException("Address segment must be numeric", e);
+            }
+
+            if (v < 0 || v > 255) {
+                throw new IllegalArgumentException(String.format("Address segment must be an octet, between 0 and 255 (is %s)", v));
+            }
+
+            a[i] = v;
+        }
+
+        return new ObjectAddress(a);
+    }
+
+    public ASDUAddress getASDUAddress() {
+        return ASDUAddress.fromArray(new int[] {this.address[0], this.address[1]});
+    }
+
+    public InformationObjectAddress getInformationObjectAddress() {
+        return InformationObjectAddress.fromArray(new int[] {this.address[2], this.address[3], this.address[4]});
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientComponent.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientComponent.java
new file mode 100644
index 0000000..1609ed1
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientComponent.java
@@ -0,0 +1,78 @@
+/**
+ * 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.component.iec60870.client;
+
+import java.util.Map;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.component.iec60870.AbstractIecComponent;
+import org.apache.camel.component.iec60870.ConnectionId;
+import org.apache.camel.component.iec60870.Constants;
+import org.apache.camel.component.iec60870.ObjectAddress;
+import org.eclipse.neoscada.protocol.iec60870.client.data.DataModuleOptions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClientComponent extends AbstractIecComponent<ClientConnectionMultiplexor, ClientOptions> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClientComponent.class);
+
+    public ClientComponent(final CamelContext context) {
+        super(ClientOptions.class, new ClientOptions(), context, ClientEndpoint.class);
+    }
+
+    public ClientComponent() {
+        super(ClientOptions.class, new ClientOptions(), ClientEndpoint.class);
+    }
+
+    @Override
+    protected void applyDataModuleOptions(final ClientOptions options, final Map<String, Object> parameters) {
+        if (parameters.get(Constants.PARAM_DATA_MODULE_OPTIONS) instanceof DataModuleOptions) {
+            options.setDataModuleOptions((DataModuleOptions)parameters.get(Constants.PARAM_DATA_MODULE_OPTIONS));
+        }
+    }
+
+    @Override
+    protected Endpoint createEndpoint(final String uri, final ClientConnectionMultiplexor connection, final ObjectAddress address) {
+        return new ClientEndpoint(uri, this, connection, address);
+    }
+
+    @Override
+    protected ClientConnectionMultiplexor createConnection(final ConnectionId id, final ClientOptions options) {
+        LOG.debug("Create new connection - id: {}", id);
+
+        return new ClientConnectionMultiplexor(new ClientConnection(id.getHost(), id.getPort(), options));
+    }
+
+    /**
+     * Default connection options
+     *
+     * @param defaultConnectionOptions the new default connection options, must
+     *            not be {@code null}
+     */
+    @Override
+    public void setDefaultConnectionOptions(final ClientOptions defaultConnectionOptions) {
+        super.setDefaultConnectionOptions(defaultConnectionOptions);
+    }
+
+    @Override
+    public ClientOptions getDefaultConnectionOptions() {
+        return super.getDefaultConnectionOptions();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConnection.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConnection.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConnection.java
new file mode 100644
index 0000000..c4c47c7
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConnection.java
@@ -0,0 +1,132 @@
+/**
+ * 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.component.iec60870.client;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import io.netty.channel.ChannelHandlerContext;
+import org.apache.camel.component.iec60870.DiscardAckModule;
+import org.apache.camel.component.iec60870.ObjectAddress;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.ASDUAddress;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.InformationObjectAddress;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.QualifierOfInterrogation;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.Value;
+import org.eclipse.neoscada.protocol.iec60870.client.AutoConnectClient;
+import org.eclipse.neoscada.protocol.iec60870.client.AutoConnectClient.ModulesFactory;
+import org.eclipse.neoscada.protocol.iec60870.client.AutoConnectClient.State;
+import org.eclipse.neoscada.protocol.iec60870.client.AutoConnectClient.StateListener;
+import org.eclipse.neoscada.protocol.iec60870.client.data.AbstractDataProcessor;
+import org.eclipse.neoscada.protocol.iec60870.client.data.DataHandler;
+import org.eclipse.neoscada.protocol.iec60870.client.data.DataModule;
+import org.eclipse.neoscada.protocol.iec60870.client.data.DataModuleContext;
+
+public class ClientConnection {
+
+    @FunctionalInterface
+    public interface ValueListener {
+        void update(ObjectAddress address, Value<?> value);
+    }
+
+    private final StateListener stateListener = new StateListener() {
+
+        @Override
+        public void stateChanged(final State state, final Throwable e) {
+        }
+    };
+
+    private final DataHandler dataHandler = new AbstractDataProcessor() {
+
+        /**
+         * Called when the connection was established
+         */
+        @Override
+        public void activated(final DataModuleContext dataModuleContext, final ChannelHandlerContext ctx) {
+            dataModuleContext.requestStartData();
+            dataModuleContext.startInterrogation(ASDUAddress.BROADCAST, QualifierOfInterrogation.GLOBAL);
+        }
+
+        /**
+         * Called when the start data was accepted
+         */
+        @Override
+        public void started() {
+        }
+
+        /**
+         * Called when the connection broke
+         */
+        @Override
+        public void disconnected() {
+        }
+
+        @Override
+        protected void fireEntry(final ASDUAddress asduAddress, final InformationObjectAddress address, final Value<?> value) {
+            ClientConnection.this.handleData(ObjectAddress.valueOf(asduAddress, address), value);
+        }
+    };
+
+    private final Map<ObjectAddress, Value<?>> lastValue = new HashMap<>();
+    private final Map<ObjectAddress, ValueListener> listeners = new HashMap<>();
+
+    private final String host;
+    private final int port;
+    private final ClientOptions options;
+
+    private AutoConnectClient client;
+
+    public ClientConnection(final String host, final int port, final ClientOptions options) {
+        this.host = host;
+        this.port = port;
+        this.options = options;
+    }
+
+    public void start() {
+        final DataModule dataModule = new DataModule(this.dataHandler, this.options.getDataModuleOptions());
+        final ModulesFactory factory = () -> Arrays.asList(dataModule, new DiscardAckModule());
+        this.client = new AutoConnectClient(this.host, this.port, this.options.getProtocolOptions(), factory, this.stateListener);
+    }
+
+    public void stop() throws Exception {
+        this.client.close();
+    }
+
+    protected synchronized void handleData(final ObjectAddress address, final Value<?> value) {
+        this.lastValue.put(address, value);
+        final ValueListener listener = this.listeners.get(address);
+        if (listener != null) {
+            listener.update(address, value);
+        }
+    }
+
+    public synchronized void setListener(final ObjectAddress address, final ValueListener listener) {
+        if (listener != null) {
+            this.listeners.put(address, listener);
+            final Value<?> last = this.lastValue.get(address);
+            if (last != null) {
+                listener.update(address, last);
+            }
+        } else {
+            this.listeners.remove(address);
+        }
+    }
+
+    public boolean executeCommand(final Object command) {
+        return this.client.writeCommand(command);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConnectionMultiplexor.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConnectionMultiplexor.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConnectionMultiplexor.java
new file mode 100644
index 0000000..9805a0b
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConnectionMultiplexor.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 org.apache.camel.component.iec60870.client;
+
+import org.apache.camel.component.iec60870.AbstractConnectionMultiplexor;
+
+public class ClientConnectionMultiplexor extends AbstractConnectionMultiplexor {
+
+    private final ClientConnection connection;
+
+    public ClientConnectionMultiplexor(final ClientConnection connection) {
+        this.connection = connection;
+    }
+
+    @Override
+    protected void performStart() throws Exception {
+        this.connection.start();
+    }
+
+    @Override
+    protected void performStop() throws Exception {
+        this.connection.stop();
+    }
+
+    public ClientConnection getConnection() {
+        return this.connection;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConsumer.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConsumer.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConsumer.java
new file mode 100644
index 0000000..f947f29
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientConsumer.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.camel.component.iec60870.client;
+
+import java.time.Instant;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.Processor;
+import org.apache.camel.component.iec60870.ObjectAddress;
+import org.apache.camel.impl.DefaultConsumer;
+import org.apache.camel.impl.DefaultMessage;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.Value;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClientConsumer extends DefaultConsumer {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClientConsumer.class);
+
+    private final ClientConnection connection;
+    private final ClientEndpoint endpoint;
+
+    public ClientConsumer(final ClientEndpoint endpoint, final Processor processor, final ClientConnection connection) {
+        super(endpoint, processor);
+        this.endpoint = endpoint;
+        this.connection = connection;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        this.connection.setListener(this.endpoint.getAddress(), this::updateValue);
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        this.connection.setListener(this.endpoint.getAddress(), null);
+        super.doStop();
+    }
+
+    private void updateValue(final ObjectAddress address, final Value<?> value) {
+        // Note: we hold the sync lock for the connection
+        try {
+            final Exchange exchange = getEndpoint().createExchange();
+            exchange.setIn(mapMessage(value));
+            getAsyncProcessor().process(exchange);
+        } catch (final Exception e) {
+            LOG.debug("Failed to process message", e);
+        }
+    }
+
+    private Message mapMessage(final Value<?> value) {
+        final DefaultMessage message = new DefaultMessage(this.endpoint.getCamelContext());
+
+        message.setBody(value);
+
+        message.setHeader("value", value.getValue());
+        message.setHeader("timestamp", Instant.ofEpochMilli(value.getTimestamp()));
+        message.setHeader("quality", value.getQualityInformation());
+        message.setHeader("overflow", value.isOverflow());
+
+        return message;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientEndpoint.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientEndpoint.java
new file mode 100644
index 0000000..e554a4f
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientEndpoint.java
@@ -0,0 +1,46 @@
+/**
+ * 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.component.iec60870.client;
+
+import static java.util.Objects.requireNonNull;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.component.iec60870.AbstractIecEndpoint;
+import org.apache.camel.component.iec60870.ObjectAddress;
+import org.apache.camel.impl.DefaultComponent;
+import org.apache.camel.spi.UriEndpoint;
+
+@UriEndpoint(firstVersion = "2.20.0", scheme = "iec60870-client", syntax = "iec60870-client:endpointUri", title = "IEC 60870 Client", consumerClass = ClientConsumer.class, label = "iot")
+public class ClientEndpoint extends AbstractIecEndpoint<ClientConnectionMultiplexor> {
+
+    public ClientEndpoint(final String uri, final DefaultComponent component, final ClientConnectionMultiplexor connection, final ObjectAddress address) {
+        super(uri, component, requireNonNull(connection), address);
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+        return new ClientProducer(this, getConnection().getConnection());
+    }
+
+    @Override
+    public Consumer createConsumer(final Processor processor) throws Exception {
+        return new ClientConsumer(this, processor, getConnection().getConnection());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientOptions.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientOptions.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientOptions.java
new file mode 100644
index 0000000..86cdb9e
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientOptions.java
@@ -0,0 +1,91 @@
+/**
+ * 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.component.iec60870.client;
+
+import java.util.Objects;
+
+import org.apache.camel.component.iec60870.BaseOptions;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+import org.eclipse.neoscada.protocol.iec60870.ProtocolOptions;
+import org.eclipse.neoscada.protocol.iec60870.client.data.DataModuleOptions;
+
+@UriParams
+public class ClientOptions extends BaseOptions<ClientOptions> {
+
+    /**
+     * Data module options
+     */
+    @UriParam(javaType = "DataModuleOptions")
+    private DataModuleOptions.Builder dataModuleOptions;
+
+    // dummy for doc generation
+    /**
+     * Whether background scan transmissions should be ignored.
+     */
+    @UriParam(label = "data", defaultValue = "true")
+    private boolean ignoreBackgroundScan;
+
+    public ClientOptions() {
+        this.dataModuleOptions = new DataModuleOptions.Builder();
+    }
+
+    public ClientOptions(final ClientOptions other) {
+        this(other.getProtocolOptions(), other.getDataModuleOptions());
+    }
+
+    public ClientOptions(final ProtocolOptions protocolOptions, final DataModuleOptions dataOptions) {
+        super(protocolOptions);
+
+        Objects.requireNonNull(dataOptions);
+
+        this.dataModuleOptions = new DataModuleOptions.Builder(dataOptions);
+    }
+
+    public void setDataModuleOptions(final DataModuleOptions dataModuleOptions) {
+        Objects.requireNonNull(dataModuleOptions);
+
+        this.dataModuleOptions = new DataModuleOptions.Builder(dataModuleOptions);
+    }
+
+    public DataModuleOptions getDataModuleOptions() {
+        return this.dataModuleOptions.build();
+    }
+
+    @Override
+    public ClientOptions copy() {
+        return new ClientOptions(this);
+    }
+
+    // wrapper methods - DataModuleOptions
+
+    public void setCauseSourceAddress(final Byte causeSourceAddress) {
+        this.dataModuleOptions.setCauseSourceAddress(causeSourceAddress);
+    }
+
+    public Byte getCauseSourceAddress() {
+        return this.dataModuleOptions.getCauseSourceAddress();
+    }
+
+    public void setIgnoreBackgroundScan(final boolean ignoreBackgroundScan) {
+        this.dataModuleOptions.setIgnoreBackgroundScan(ignoreBackgroundScan);
+    }
+
+    public boolean isIgnoreBackgroundScan() {
+        return this.dataModuleOptions.isIgnoreBackgroundScan();
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientProducer.java
----------------------------------------------------------------------
diff --git a/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientProducer.java b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientProducer.java
new file mode 100644
index 0000000..de7c36d
--- /dev/null
+++ b/components/camel-iec60870/src/main/java/org/apache/camel/component/iec60870/client/ClientProducer.java
@@ -0,0 +1,89 @@
+/**
+ * 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.component.iec60870.client;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.iec60870.ObjectAddress;
+import org.apache.camel.impl.DefaultProducer;
+import org.eclipse.neoscada.protocol.iec60870.asdu.ASDUHeader;
+import org.eclipse.neoscada.protocol.iec60870.asdu.message.SetPointCommandScaledValue;
+import org.eclipse.neoscada.protocol.iec60870.asdu.message.SetPointCommandShortFloatingPoint;
+import org.eclipse.neoscada.protocol.iec60870.asdu.message.SingleCommand;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.CauseOfTransmission;
+import org.eclipse.neoscada.protocol.iec60870.asdu.types.InformationObjectAddress;
+
+public class ClientProducer extends DefaultProducer {
+
+    private final ClientConnection connection;
+    private final ASDUHeader header;
+    private final InformationObjectAddress address;
+
+    public ClientProducer(final ClientEndpoint endpoint, final ClientConnection connection) {
+        super(endpoint);
+        this.connection = connection;
+
+        final ObjectAddress address = endpoint.getAddress();
+        this.header = new ASDUHeader(CauseOfTransmission.ACTIVATED, address.getASDUAddress());
+        this.address = address.getInformationObjectAddress();
+    }
+
+    @Override
+    public void process(final Exchange exchange) throws Exception {
+        final Object command = mapToCommand(exchange);
+
+        if (command != null) {
+            if (!this.connection.executeCommand(command)) {
+                throw new IllegalStateException("Failed to send command. Not connected.");
+            }
+        }
+    }
+
+    private Object mapToCommand(final Exchange exchange) {
+        final Object body = exchange.getIn().getBody();
+
+        if (body instanceof Float || body instanceof Double) {
+            return makeFloatCommand(((Number)body).floatValue());
+        }
+
+        if (body instanceof Boolean) {
+            return makeBooleanCommand((Boolean)body);
+        }
+
+        if (body instanceof Integer || body instanceof Short || body instanceof Byte || body instanceof Long) {
+            return makeIntCommand(((Number)body).longValue());
+        }
+
+        throw new IllegalArgumentException("Unable to map value to a command: " + body);
+    }
+
+    private Object makeBooleanCommand(final Boolean state) {
+        return new SingleCommand(this.header, this.address, state);
+    }
+
+    private Object makeIntCommand(final long value) {
+
+        if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
+            throw new IllegalArgumentException(String.format("Integer value is outside of range - min: %s, max: %s", Short.MIN_VALUE, Short.MAX_VALUE));
+        }
+
+        return new SetPointCommandScaledValue(this.header, this.address, (short)value);
+    }
+
+    private Object makeFloatCommand(final float value) {
+        return new SetPointCommandShortFloatingPoint(this.header, this.address, value);
+    }
+}


[2/7] camel git commit: Import of the IEC 60870 component

Posted by ac...@apache.org.
http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/server/springboot/ServerComponentConfiguration.java
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/server/springboot/ServerComponentConfiguration.java b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/server/springboot/ServerComponentConfiguration.java
new file mode 100644
index 0000000..c58ac3f
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/java/org/apache/camel/component/iec60870/server/springboot/ServerComponentConfiguration.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.camel.component.iec60870.server.springboot;
+
+import javax.annotation.Generated;
+import org.apache.camel.spring.boot.ComponentConfigurationPropertiesCommon;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Camel IEC 60870-5-104 support
+ * 
+ * Generated by camel-package-maven-plugin - do not edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.SpringBootAutoConfigurationMojo")
+@ConfigurationProperties(prefix = "camel.component.iec60870-server")
+public class ServerComponentConfiguration
+        extends
+            ComponentConfigurationPropertiesCommon {
+
+    /**
+     * Default connection options
+     */
+    private ServerOptionsNestedConfiguration defaultConnectionOptions;
+    /**
+     * Whether the component should resolve property placeholders on itself when
+     * starting. Only properties which are of String type can use property
+     * placeholders.
+     */
+    private Boolean resolvePropertyPlaceholders = true;
+
+    public ServerOptionsNestedConfiguration getDefaultConnectionOptions() {
+        return defaultConnectionOptions;
+    }
+
+    public void setDefaultConnectionOptions(
+            ServerOptionsNestedConfiguration defaultConnectionOptions) {
+        this.defaultConnectionOptions = defaultConnectionOptions;
+    }
+
+    public Boolean getResolvePropertyPlaceholders() {
+        return resolvePropertyPlaceholders;
+    }
+
+    public void setResolvePropertyPlaceholders(
+            Boolean resolvePropertyPlaceholders) {
+        this.resolvePropertyPlaceholders = resolvePropertyPlaceholders;
+    }
+
+    public static class ServerOptionsNestedConfiguration {
+        public static final Class CAMEL_NESTED_CLASS = org.apache.camel.component.iec60870.server.ServerOptions.class;
+        /**
+         * A time period in "ms" the protocol layer will buffer change events in
+         * order to send out aggregated change messages
+         */
+        private Integer bufferingPeriod;
+        /**
+         * Send booleans with timestamps
+         */
+        private Boolean booleansWithTimestamp;
+        /**
+         * Send floats with timestamps
+         */
+        private Boolean floatsWithTimestamp;
+        /**
+         * Number of spontaneous events to keep in the buffer.
+         * <p>
+         * When there are more than this number of spontaneous in events in the
+         * buffer, then events will be dropped in order to maintain the buffer
+         * size.
+         * </p>
+         */
+        private Integer spontaneousDuplicates;
+        /**
+         * The period in "ms" between background transmission cycles.
+         * <p>
+         * If this is set to zero or less, background transmissions will be
+         * disabled.
+         * </p>
+         */
+        private Integer backgroundScanPeriod;
+
+        public Integer getBufferingPeriod() {
+            return bufferingPeriod;
+        }
+
+        public void setBufferingPeriod(Integer bufferingPeriod) {
+            this.bufferingPeriod = bufferingPeriod;
+        }
+
+        public Boolean getBooleansWithTimestamp() {
+            return booleansWithTimestamp;
+        }
+
+        public void setBooleansWithTimestamp(Boolean booleansWithTimestamp) {
+            this.booleansWithTimestamp = booleansWithTimestamp;
+        }
+
+        public Boolean getFloatsWithTimestamp() {
+            return floatsWithTimestamp;
+        }
+
+        public void setFloatsWithTimestamp(Boolean floatsWithTimestamp) {
+            this.floatsWithTimestamp = floatsWithTimestamp;
+        }
+
+        public Integer getSpontaneousDuplicates() {
+            return spontaneousDuplicates;
+        }
+
+        public void setSpontaneousDuplicates(Integer spontaneousDuplicates) {
+            this.spontaneousDuplicates = spontaneousDuplicates;
+        }
+
+        public Integer getBackgroundScanPeriod() {
+            return backgroundScanPeriod;
+        }
+
+        public void setBackgroundScanPeriod(Integer backgroundScanPeriod) {
+            this.backgroundScanPeriod = backgroundScanPeriod;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/LICENSE.txt
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/LICENSE.txt b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/LICENSE.txt
new file mode 100644
index 0000000..6b0b127
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/LICENSE.txt
@@ -0,0 +1,203 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed 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.
+

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/NOTICE.txt
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/NOTICE.txt b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/NOTICE.txt
new file mode 100644
index 0000000..2e215bf
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/NOTICE.txt
@@ -0,0 +1,11 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Apache Camel distribution.                    ==
+   =========================================================================
+
+   This product includes software developed by
+   The Apache Software Foundation (http://www.apache.org/).
+
+   Please read the different LICENSE files present in the licenses directory of
+   this distribution.

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/spring.factories
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/spring.factories b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/spring.factories
new file mode 100644
index 0000000..f4b173b
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,21 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+org.apache.camel.component.iec60870.client.springboot.ClientComponentAutoConfiguration,\
+org.apache.camel.component.iec60870.server.springboot.ServerComponentAutoConfiguration
+

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/spring.provides
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/spring.provides b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/spring.provides
new file mode 100644
index 0000000..422d995
--- /dev/null
+++ b/platforms/spring-boot/components-starter/camel-iec60870-starter/src/main/resources/META-INF/spring.provides
@@ -0,0 +1,17 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+provides: camel-iec60870

http://git-wip-us.apache.org/repos/asf/camel/blob/eb4f6059/platforms/spring-boot/components-starter/pom.xml
----------------------------------------------------------------------
diff --git a/platforms/spring-boot/components-starter/pom.xml b/platforms/spring-boot/components-starter/pom.xml
index bbc2ed6..670bdf7 100644
--- a/platforms/spring-boot/components-starter/pom.xml
+++ b/platforms/spring-boot/components-starter/pom.xml
@@ -169,6 +169,7 @@
     <module>camel-http4-starter</module>
     <module>camel-hystrix-starter</module>
     <module>camel-ical-starter</module>
+    <module>camel-iec60870-starter</module>
     <module>camel-ignite-starter</module>
     <module>camel-infinispan-starter</module>
     <module>camel-influxdb-starter</module>