You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2016/03/23 19:59:42 UTC

[22/23] camel git commit: Polished

Polished


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

Branch: refs/heads/master
Commit: 585154511947c0ddf2674e1e44fc0f85db7f9311
Parents: 1c79846
Author: Claus Ibsen <da...@apache.org>
Authored: Wed Mar 23 19:41:18 2016 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Wed Mar 23 19:41:18 2016 +0100

----------------------------------------------------------------------
 apache-camel/pom.xml                            |   4 +
 .../src/main/descriptors/common-bin.xml         |   1 +
 components/camel-cm-sms/README.md               |  32 ++
 components/camel-cm-sms/pom.xml                 | 106 ++++++
 .../apache/camel/component/cm/CMComponent.java  |  96 +++++
 .../camel/component/cm/CMConfiguration.java     |  89 +++++
 .../apache/camel/component/cm/CMConstants.java  |  44 +++
 .../apache/camel/component/cm/CMEndpoint.java   | 109 ++++++
 .../apache/camel/component/cm/CMMessage.java    | 153 ++++++++
 .../apache/camel/component/cm/CMProducer.java   | 149 ++++++++
 .../org/apache/camel/component/cm/CMSender.java |  28 ++
 .../component/cm/CMSenderOneMessageImpl.java    | 254 +++++++++++++
 .../org/apache/camel/component/cm/CMUtils.java  |  30 ++
 .../camel/component/cm/client/SMSMessage.java   | 114 ++++++
 .../camel/component/cm/client/Translator.java   |  23 ++
 .../cm/exceptions/CMDirectException.java        |  40 ++
 .../cm/exceptions/HostUnavailableException.java |  39 ++
 .../cm/exceptions/XMLConstructionException.java |  39 ++
 .../cmresponse/CMResponseException.java         |  41 ++
 .../InsufficientBalanceException.java           |  26 ++
 .../cmresponse/InvalidMSISDNException.java      |  23 ++
 .../InvalidProductTokenException.java           |  26 ++
 .../NoAccountFoundForProductTokenException.java |  28 ++
 .../cmresponse/NoMessageException.java          |  23 ++
 .../NotPhoneNumberFoundException.java           |  23 ++
 .../cmresponse/UnknownErrorException.java       |  26 ++
 .../cmresponse/UnroutableMessageException.java  |  23 ++
 .../cm/validation/constraints/E164.java         |  41 ++
 .../validation/constraints/E164Validator.java   |  66 ++++
 .../services/org/apache/camel/component/cm-sms  |  18 +
 .../src/main/resources/log4j.properties         |  41 ++
 .../component/cm/test/CMConfigurationTest.java  | 142 +++++++
 .../camel/component/cm/test/CMMessageTest.java  | 323 ++++++++++++++++
 .../apache/camel/component/cm/test/CMProxy.java |  26 ++
 .../apache/camel/component/cm/test/CMTest.java  | 375 +++++++++++++++++++
 .../cm/test/CamelTestConfiguration.java         | 110 ++++++
 .../camel/component/cm/test/SMSMessageTest.java | 183 +++++++++
 .../cm/test/ValidatorConfiguration.java         |  35 ++
 .../cmsender/CMResponseExceptionSender.java     |  30 ++
 .../InsufficientBalanceExceptionSender.java     |  30 ++
 .../cmsender/InvalidMSISDNExceptionSender.java  |  30 ++
 .../InvalidProductTokenExceptionSender.java     |  30 ++
 ...ountFoundForProductTokenExceptionSender.java |  30 ++
 .../cmsender/NoMessageExceptionSender.java      |  30 ++
 .../NotPhoneNumberFoundExceptionSender.java     |  30 ++
 .../cmsender/UnknownErrorExceptionSender.java   |  30 ++
 .../UnroutableMessageExceptionSender.java       |  30 ++
 .../src/test/resources/cm-smsgw.properties      |  28 ++
 components/camel-cm/README.md                   |  32 --
 components/camel-cm/pom.xml                     | 105 ------
 .../apache/camel/component/cm/CMComponent.java  |  99 -----
 .../camel/component/cm/CMConfiguration.java     |  92 -----
 .../apache/camel/component/cm/CMConstants.java  |  44 ---
 .../apache/camel/component/cm/CMEndpoint.java   | 141 -------
 .../apache/camel/component/cm/CMMessage.java    | 153 --------
 .../apache/camel/component/cm/CMProducer.java   | 149 --------
 .../org/apache/camel/component/cm/CMSender.java |  28 --
 .../component/cm/CMSenderOneMessageImpl.java    | 254 -------------
 .../org/apache/camel/component/cm/CMUtils.java  |  30 --
 .../camel/component/cm/client/SMSMessage.java   | 114 ------
 .../camel/component/cm/client/Translator.java   |  23 --
 .../cm/exceptions/CMDirectException.java        |  40 --
 .../cm/exceptions/HostUnavailableException.java |  39 --
 .../cm/exceptions/XMLConstructionException.java |  39 --
 .../cmresponse/CMResponseException.java         |  41 --
 .../InsufficientBalanceException.java           |  26 --
 .../cmresponse/InvalidMSISDNException.java      |  23 --
 .../InvalidProductTokenException.java           |  26 --
 .../NoAccountFoundForProductTokenException.java |  28 --
 .../cmresponse/NoMessageException.java          |  23 --
 .../NotPhoneNumberFoundException.java           |  23 --
 .../cmresponse/UnknownErrorException.java       |  26 --
 .../cmresponse/UnroutableMessageException.java  |  23 --
 .../cm/validation/constraints/E164.java         |  41 --
 .../validation/constraints/E164Validator.java   |  66 ----
 .../services/org/apache/camel/component/cm      |  18 -
 .../src/main/resources/log4j.properties         |  37 --
 .../component/cm/test/CMConfigurationTest.java  | 142 -------
 .../camel/component/cm/test/CMMessageTest.java  | 323 ----------------
 .../apache/camel/component/cm/test/CMProxy.java |  26 --
 .../apache/camel/component/cm/test/CMTest.java  | 363 ------------------
 .../cm/test/CamelTestConfiguration.java         | 112 ------
 .../camel/component/cm/test/SMSMessageTest.java | 183 ---------
 .../cm/test/ValidatorConfiguration.java         |  35 --
 .../cmsender/CMResponseExceptionSender.java     |  30 --
 .../InsufficientBalanceExceptionSender.java     |  30 --
 .../cmsender/InvalidMSISDNExceptionSender.java  |  30 --
 .../InvalidProductTokenExceptionSender.java     |  30 --
 ...ountFoundForProductTokenExceptionSender.java |  30 --
 .../cmsender/NoMessageExceptionSender.java      |  30 --
 .../NotPhoneNumberFoundExceptionSender.java     |  30 --
 .../cmsender/UnknownErrorExceptionSender.java   |  30 --
 .../UnroutableMessageExceptionSender.java       |  30 --
 .../src/test/resources/cm-smsgw.properties      |  28 --
 components/pom.xml                              |   2 +-
 parent/pom.xml                                  |   5 +
 96 files changed, 3253 insertions(+), 3266 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/apache-camel/pom.xml
----------------------------------------------------------------------
diff --git a/apache-camel/pom.xml b/apache-camel/pom.xml
index db97d20..b92593e 100644
--- a/apache-camel/pom.xml
+++ b/apache-camel/pom.xml
@@ -153,6 +153,10 @@
     </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
+      <artifactId>camel-cm-sms</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
       <artifactId>camel-cmis</artifactId>
     </dependency>
     <dependency>

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/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 3f43a8e..ae2c879 100644
--- a/apache-camel/src/main/descriptors/common-bin.xml
+++ b/apache-camel/src/main/descriptors/common-bin.xml
@@ -49,6 +49,7 @@
         <include>org.apache.camel:camel-castor</include>
         <include>org.apache.camel:camel-cdi</include>
         <include>org.apache.camel:camel-chunk</include>
+        <include>org.apache.camel:camel-cm-sms</include>
         <include>org.apache.camel:camel-cmis</include>
         <include>org.apache.camel:camel-core</include>
         <include>org.apache.camel:camel-core-osgi</include>

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/README.md
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/README.md b/components/camel-cm-sms/README.md
new file mode 100644
index 0000000..63f9059
--- /dev/null
+++ b/components/camel-cm-sms/README.md
@@ -0,0 +1,32 @@
+# camel-cm
+
+[Camel component](http://camel.apache.org/components.html) for the [CM SMS Gateway](https://www.cmtelecom.com). 
+
+It allows to integrate [CM SMS API](https://dashboard.onlinesmsgateway.com/docs) in an application as a camel component. 
+
+You must have a valid account.  More information are available at [CM Telecom](https://www.cmtelecom.com/support).
+
+### URI Format
+
+```
+cm://sgw01.cm.nl/gateway.ashx?defaultFrom=DefaultSender&defaultMaxNumberOfParts=8&productToken=2fb82162-754c-4c1b-806d-9cb7efd677f4
+```
+
+
+### Endpoint Options
+
+CM endpoints act like a **producer** and support the following options.
+
+| Name  | Default Value | Description |
+| ------------- | ------------- | ------------- |
+| productToken  |*none* |**Required**. UUID as String. This is the product token that was sent to you by email. Example: 'de7c7df3-81ca-4d1e-863d-95a252120321'|
+| defaultFrom  | *none* |**Required**. This is the default sender name, to be included in each SMSMessage instance not providing one. The maximum length is 11 characters.|
+| defaultMaxNumberOfParts  | 8 | If it is a [multipart message](https://dashboard.onlinesmsgateway.com/docs#send-a-message-multipart) forces the max number of parts to be sent. <p>The gateway will first check if a message is larger than 160 characters, if so, the message will be cut into multiple 153 characters parts limited by these parameters whether the message is [GSM 0038 encodeable](https://en.wikipedia.org/wiki/GSM_03.38). <p>Otherwise, The gateway will check if a message is larger than 70 characters, if so, the message will be cut into multiple 67 characters parts to a maximum of this parameter.|
+| testConnectionOnStartup | false | This ensures that Camel is not started with failed connections cause an exception is thrown on startup. | 
+
+### Tests
+
+Tests provided so far show a valid [Spring Configuration](https://github.com/oalles/camel-cm/blob/master/src/test/java/org/apache/camel/component/cm/test/TestConfiguration.java). Notice that CM Component URI is built from properties in a [file](https://github.com/oalles/camel-cm/blob/master/src/test/resources/cm-smsgw.properties). 
+
+### Sample of Usage
+You can try [this project](https://github.com/oalles/camel-cm-sample) to see how camel-cm can be integrated in a camel route. 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/pom.xml b/components/camel-cm-sms/pom.xml
new file mode 100644
index 0000000..4200180
--- /dev/null
+++ b/components/camel-cm-sms/pom.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!--
+	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.18-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>camel-cm-sms</artifactId>
+  <packaging>bundle</packaging>
+
+  <name>Camel :: CM SMS</name>
+  <description>Camel CM SMS Gateway Component</description>
+
+  <properties>
+    <camel.osgi.export.pkg>org.apache.camel.component.cm.*</camel.osgi.export.pkg>
+    <camel.osgi.export.service>org.apache.camel.spi.ComponentResolver;component=cm-sms</camel.osgi.export.service>
+  </properties>
+
+  <dependencies>
+
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-core</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>com.googlecode.libphonenumber</groupId>
+      <artifactId>libphonenumber</artifactId>
+      <version>${libphonenumber-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient-osgi</artifactId>
+      <version>${httpclient4-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jsoup</groupId>
+      <artifactId>jsoup</artifactId>
+      <version>${jsoup-version}</version>
+    </dependency>
+
+    <dependency>
+      <groupId>javax.validation</groupId>
+      <artifactId>validation-api</artifactId>
+      <version>${validation-api-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>javax.el</groupId>
+      <artifactId>javax.el-api</artifactId>
+      <version>${javax.el-api-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-validator</groupId>
+      <artifactId>commons-validator</artifactId>
+      <version>${commons-validator-version}</version>
+    </dependency>
+
+    <!-- test dependencies -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-test-spring</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-spring-javaconfig</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-log4j12</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.hibernate</groupId>
+      <artifactId>hibernate-validator</artifactId>
+      <version>${hibernate-validator-version}</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMComponent.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMComponent.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMComponent.java
new file mode 100644
index 0000000..73d1250
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMComponent.java
@@ -0,0 +1,96 @@
+/**
+ * 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.cm;
+
+import java.util.Map;
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validator;
+
+import org.apache.camel.BeanInject;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Endpoint;
+import org.apache.camel.ResolveEndpointFailedException;
+import org.apache.camel.impl.UriEndpointComponent;
+import org.apache.camel.util.URISupport;
+import org.apache.commons.validator.routines.UrlValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Represents the component that manages {@link CMEndpoint}s.
+ */
+public class CMComponent extends UriEndpointComponent {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CMComponent.class);
+
+    // TODO: Must not rely on dependency injection as it should work out of the box
+    @BeanInject
+    private Validator validator;
+
+    public CMComponent(final CamelContext context) {
+        super(context, CMEndpoint.class);
+    }
+
+    /**
+     * Endpoints factory
+     */
+    @Override
+    protected Endpoint createEndpoint(final String uri, final String remaining, final Map<String, Object> parameters) throws Exception {
+
+        LOG.debug("Creating CM Endpoint ... ");
+
+        final String url = CMConstants.DEFAULT_SCHEME + remaining;
+        if (!UrlValidator.getInstance().isValid(url)) {
+            throw new ResolveEndpointFailedException(uri, String.format("HOST provided: %s seem to be invalid. Remember SCHEME has to be excluded.", url));
+        }
+
+        LOG.debug("Uri=[{}], path=[{}], parameters=[{}]", new Object[] {URISupport.sanitizeUri(uri), URISupport.sanitizePath(remaining), parameters });
+
+        // Set configuration based on uri parameters
+        final CMConfiguration config = new CMConfiguration();
+        setProperties(config, parameters);
+
+        // Validate configuration
+        LOG.debug("Validating uri based configuration");
+        final Set<ConstraintViolation<CMConfiguration>> constraintViolations = validator.validate(config);
+        if (constraintViolations.size() > 0) {
+            final StringBuffer msg = new StringBuffer();
+            for (final ConstraintViolation<CMConfiguration> cv : constraintViolations) {
+                msg.append(String.format("- Invalid value for %s: %s", cv.getPropertyPath().toString(), cv.getMessage()));
+            }
+            throw new ResolveEndpointFailedException(uri, msg.toString());
+        }
+        LOG.debug("CMConfiguration - OK!");
+
+        // Component is an Endpoint factory. So far, just one Endpoint type.
+        // Endpoint construction and configuration.
+
+        LOG.debug("Creating CMEndpoint");
+        final CMEndpoint endpoint = new CMEndpoint(uri, this);
+        endpoint.setConfiguration(config);
+        endpoint.setHost(remaining);
+
+        return endpoint;
+    }
+
+    public Validator getValidator() {
+        return validator;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMConfiguration.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMConfiguration.java
new file mode 100644
index 0000000..74d75b0
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMConfiguration.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.cm;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriParams;
+
+@UriParams
+public class CMConfiguration {
+
+    @UriParam @Metadata(required = "true")
+    @NotNull
+    private String productToken;
+    @UriParam
+    @NotNull @Size(min = 1, max = 11)
+    private String defaultFrom;
+    @UriParam(defaultValue = "8")
+    @Min(1) @Max(8)
+    private int defaultMaxNumberOfParts = 8;
+    @UriParam
+    private boolean testConnectionOnStartup;
+
+    public String getProductToken() {
+        return productToken;
+    }
+
+    /**
+     * The unique token to use
+     */
+    public void setProductToken(String productToken) {
+        this.productToken = productToken;
+    }
+
+    public String getDefaultFrom() {
+        return defaultFrom;
+    }
+
+    /**
+     * This is the sender name. The maximum length is 11 characters.
+     */
+    public void setDefaultFrom(final String defaultFrom) {
+        this.defaultFrom = defaultFrom;
+    }
+
+    public int getDefaultMaxNumberOfParts() {
+        return defaultMaxNumberOfParts;
+    }
+
+    /**
+     * If it is a multipart message forces the max number. Message can be truncated.
+     * Technically the gateway will first check if a message is larger than 160 characters,
+     * if so, the message will be cut into multiple 153 characters parts limited by these parameters.
+     */
+    public void setDefaultMaxNumberOfParts(final int defaultMaxNumberOfParts) {
+        this.defaultMaxNumberOfParts = defaultMaxNumberOfParts;
+    }
+
+    public boolean isTestConnectionOnStartup() {
+        return testConnectionOnStartup;
+    }
+
+    /**
+     * Whether to test the connection to the SMS Gateway on startup
+     */
+    public void setTestConnectionOnStartup(final boolean testConnectionOnStartup) {
+        this.testConnectionOnStartup = testConnectionOnStartup;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMConstants.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMConstants.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMConstants.java
new file mode 100644
index 0000000..afe8fde
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMConstants.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.cm;
+
+public interface CMConstants {
+
+    String DEFAULT_SCHEME = "https://";
+
+    int DEFAULT_MULTIPARTS = 8;
+
+    int MAX_UNICODE_MESSAGE_LENGTH = 70;
+    int MAX_GSM_MESSAGE_LENGTH = 160;
+    int MAX_UNICODE_MESSAGE_LENGTH_PER_PART_IF_MULTIPART = 67;
+    int MAX_GSM_MESSAGE_LENGTH_PER_PART_IF_MULTIPART = 153;
+
+    // status code 200 - Error substrings - check it contains.
+    String ERROR_UNKNOWN = "Unknown error";
+    String ERROR_NO_ACCOUNT = "No account found";
+    String ERROR_INSUFICIENT_BALANCE = "Insufficient balance";
+    String ERROR_UNROUTABLE_MESSAGE = "Message is unroutable";
+    String ERROR_INVALID_PRODUCT_TOKEN = "Invalid product token";
+
+    // TODO: Review this pattern.
+    // or it should be foundnd an alternative to jcharset to check if a message is GSM 03.38 encodable
+    // See:
+    // https://en.wikipedia.org/wiki/GSM_03.38
+    // http://frightanic.com/software-development/regex-for-gsm-03-38-7bit-character-set/
+    String GSM_0338_REGEX = "^[A-Za-z0-9 \\r\\n@£$\u0394_\u03A6\u0393\u039B\u03A9\u03A0\u03A8\u03A3\u0398\u039E!\"#$%&amp;'()*+,\\-./:;&lt;=&gt;?¡¿^{}\\\\\\[~\\]|"
+                            + "\u20AC\u00a5\u00e8\u00e9\u00f9\u00ec\u00f2\u00c7\u00d8\u00f8\u00c5\u00e5\u00c6\u00e6\u00df\u00c9\u00c4\u00d6\u00d1\u00dc\u00a7\u00e4\u00f6\u00f1\u00fc\u00e0]*$";
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMEndpoint.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMEndpoint.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMEndpoint.java
new file mode 100644
index 0000000..b290801
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMEndpoint.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.cm;
+
+import java.util.UUID;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.ExchangePattern;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.spi.Metadata;
+import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
+import org.apache.camel.spi.UriPath;
+import org.apache.camel.util.ObjectHelper;
+
+@UriEndpoint(scheme = "cm-sms", title = "CM SMS Gateway", syntax = "cm-sms:host", label = "mobile", producerOnly = true)
+public class CMEndpoint extends DefaultEndpoint {
+
+    @UriPath
+    @Metadata(required = "true")
+    private String host;
+    @UriParam
+    private CMConfiguration configuration;
+
+    public CMEndpoint(final String uri, final CMComponent component) {
+        super(uri, component);
+        setExchangePattern(ExchangePattern.InOut);
+    }
+
+    /**
+     * Provides a channel on which clients can send Messages to a CM Endpoint
+     */
+    @Override
+    public CMProducer createProducer() throws Exception {
+        final CMConfiguration config = getConfiguration();
+
+        // This is the camel exchange processor. Allows to send messages to CM
+        // API.
+        // TODO: Should i provide a CMSender factory? Dynamically choose
+        // CMSender implementation? Sending strategy?
+        // Consider:
+        // 1. single - Single Message strategy.
+        // 2. Multi - CM Api supports to 1000 messages per call.
+        // 3. sliding - sliding window? 1000 messages or time thresold?
+        // 4. mocked - in order to fake cm responses
+
+        // CMConstants.DEFAULT_SCHEME + host is a valid URL. It was previously checked
+
+        String token = config.getProductToken();
+        ObjectHelper.notEmpty(token, "productToken");
+
+        UUID uuid = UUID.fromString(token);
+        return new CMProducer(this, new CMSenderOneMessageImpl(getCMUrl(), uuid));
+    }
+
+    @Override
+    public Consumer createConsumer(final Processor processor) throws Exception {
+        throw new UnsupportedOperationException("Consumer not supported");
+    }
+
+    public CMConfiguration getConfiguration() {
+        return configuration;
+    }
+
+    public void setConfiguration(final CMConfiguration configuration) {
+        this.configuration = configuration;
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return true;
+    }
+
+    public String getCMUrl() {
+        return CMConstants.DEFAULT_SCHEME + host;
+    }
+
+    @Override
+    public CMComponent getComponent() {
+        return (CMComponent) super.getComponent();
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    /**
+     * SMS Provider HOST with scheme
+     */
+    public void setHost(final String host) {
+        this.host = host;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMMessage.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMMessage.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMMessage.java
new file mode 100644
index 0000000..2f98936
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMMessage.java
@@ -0,0 +1,153 @@
+/**
+ * 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.cm;
+
+/**
+ * Valid message to be serialized and sent to CM Endpoints. If the message only uses GSM 7-bit characters, then 160 characters will fit in 1 SMS part, and 153*n characters will fit in n SMS parts for
+ * n>1. If the message contains other characters, then only 70 characters will fit in 1 SMS part, and 67*n characters will fit in n SMS parts for n>1. <br>
+ * <br>
+ * {@link https://dashboard.onlinesmsgateway.com/docs} <br>
+ * {@link http://support.telerivet.com/customer/portal/articles/1957426-multipart-unicode-sms-messages}
+ */
+public class CMMessage {
+
+    /**
+     * Restrictions: 1 - 32 alphanumeric characters and reference will not work for demo accounts
+     */
+    // TODO: use a ID generator?
+    private String idAsString;
+
+    private String phoneNumber;
+    private String message;
+
+    private String sender;
+
+    private boolean unicode;
+    private int multipart = 1;
+
+    public CMMessage(final String phoneNumber, final String message) {
+        this.message = message;
+        this.phoneNumber = phoneNumber;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(final String message) {
+        this.message = message;
+    }
+
+    public String getPhoneNumber() {
+        return phoneNumber;
+    }
+
+    public void setPhoneNumber(final String phoneNumber) {
+        this.phoneNumber = phoneNumber;
+    }
+
+    public String getSender() {
+        return sender;
+    }
+
+    public void setSender(final String sender) {
+        this.sender = sender;
+    }
+
+    public String getIdAsString() {
+        return idAsString;
+    }
+
+    public void setIdAsString(final String idAsString) {
+        this.idAsString = idAsString;
+    }
+
+    public boolean isUnicode() {
+        return unicode;
+    }
+
+    public void setUnicode(final boolean unicode) {
+        this.unicode = unicode;
+    }
+
+    public boolean isMultipart() {
+        return multipart > 1;
+    }
+
+    /**
+     * For a CMMessage instance
+     *
+     * @param defaultMaxNumberOfParts
+     */
+    public void setUnicodeAndMultipart(int defaultMaxNumberOfParts) {
+
+        // Set UNICODE and MULTIPART
+        final String msg = getMessage();
+        if (CMUtils.isGsm0338Encodeable(msg)) {
+
+            // Not Unicode is Multipart?
+            if (msg.length() > CMConstants.MAX_GSM_MESSAGE_LENGTH) {
+
+                // Multiparts. 153 caracteres max per part
+                int parts = msg.length() / CMConstants.MAX_GSM_MESSAGE_LENGTH_PER_PART_IF_MULTIPART;
+                if (msg.length() % CMConstants.MAX_GSM_MESSAGE_LENGTH_PER_PART_IF_MULTIPART != 0) {
+                    parts++;
+                }
+
+                setMultiparts((parts > defaultMaxNumberOfParts) ? defaultMaxNumberOfParts : parts);
+            } else { // Otherwise multipart = 1
+                setMultiparts(1);
+            }
+        } else {
+            // Unicode Message
+            setUnicode(true);
+
+            if (msg.length() > CMConstants.MAX_UNICODE_MESSAGE_LENGTH) {
+
+                // Multiparts. 67 caracteres max per part
+                int parts = msg.length() / CMConstants.MAX_UNICODE_MESSAGE_LENGTH_PER_PART_IF_MULTIPART;
+                if (msg.length() % CMConstants.MAX_UNICODE_MESSAGE_LENGTH_PER_PART_IF_MULTIPART != 0) {
+                    parts++;
+                }
+
+                setMultiparts((parts > defaultMaxNumberOfParts) ? defaultMaxNumberOfParts : parts);
+            } else { // Otherwise multipart = 1
+                setMultiparts(1);
+            }
+        }
+    }
+
+    public void setMultiparts(final int multipart) {
+        this.multipart = multipart;
+    }
+
+    public int getMultiparts() {
+        return multipart;
+    }
+
+    @Override
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer(" {phoneNumber: " + phoneNumber + ", message: " + message + ", sender=" + sender + ", unicode: " + unicode + ", multipart: " + multipart);
+        if (idAsString != null && !idAsString.isEmpty()) {
+            sb.append(", idAsString=" + idAsString);
+        }
+        sb.append(" }");
+        return sb.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMProducer.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMProducer.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMProducer.java
new file mode 100644
index 0000000..e4f5722
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMProducer.java
@@ -0,0 +1,149 @@
+/**
+ * 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.cm;
+
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validator;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadRuntimeException;
+import org.apache.camel.component.cm.client.SMSMessage;
+import org.apache.camel.component.cm.exceptions.HostUnavailableException;
+import org.apache.camel.impl.DefaultProducer;
+import org.apache.http.client.methods.HttpHead;
+import org.apache.http.impl.client.HttpClientBuilder;
+
+/**
+ * is the exchange processor. Sends a validated sms message to CM Endpoints.
+ */
+public class CMProducer extends DefaultProducer {
+
+    private Validator validator;
+
+    /**
+     * sends a valid message to CM endpoints.
+     */
+    private CMSender sender;
+
+    public CMProducer(final CMEndpoint endpoint, final CMSender sender) {
+        super(endpoint);
+        this.sender = sender;
+    }
+
+    /**
+     * Producer is a exchange processor. This process is built in several steps. 1. Validate message receive from client 2. Send validated message to CM endpoints. 3. Process response from CM
+     * endpoints.
+     */
+    @Override
+    public void process(final Exchange exchange) throws Exception {
+
+        // Immutable message receive from clients. Throws camel ' s
+        // InvalidPayloadException
+        final SMSMessage smsMessage = exchange.getIn().getMandatoryBody(SMSMessage.class);
+
+        // Validates Payload - SMSMessage
+        log.trace("Validating SMSMessage instance provided: {}", smsMessage.toString());
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = getValidator().validate(smsMessage);
+        if (constraintViolations.size() > 0) {
+            final StringBuffer msg = new StringBuffer();
+            for (final ConstraintViolation<SMSMessage> cv : constraintViolations) {
+                msg.append(String.format("- Invalid value for %s: %s", cv.getPropertyPath().toString(), cv.getMessage()));
+            }
+            log.debug(msg.toString());
+            throw new InvalidPayloadRuntimeException(exchange, SMSMessage.class);
+        }
+        log.trace("SMSMessage instance is valid: {}", smsMessage.toString());
+
+        // We have a valid (immutable) SMSMessage instance, lets extend to
+        // CMMessage
+        // This is the instance we will use to build the XML document to be
+        // sent to CM SMS GW.
+        final CMMessage cmMessage = new CMMessage(smsMessage.getPhoneNumber(), smsMessage.getMessage());
+        log.debug("CMMessage instance build from valid SMSMessage instance");
+
+        if (smsMessage.getFrom() == null || smsMessage.getFrom().isEmpty()) {
+            String df = getConfiguration().getDefaultFrom();
+            cmMessage.setSender(df);
+            log.debug("Dynamic sender is set to default dynamic sender: {}", df);
+        }
+
+        // Remember, this can be null.
+        cmMessage.setIdAsString(smsMessage.getId());
+
+        // Unicode and multipart
+        cmMessage.setUnicodeAndMultipart(getConfiguration().getDefaultMaxNumberOfParts());
+
+        // 2. Send a validated sms message to CM endpoints
+        //  for abnormal situations.
+        sender.send(cmMessage);
+
+        log.debug("Request accepted by CM Host: {}", cmMessage.toString());
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+
+        // log at debug level for singletons, for prototype scoped log at trace
+        // level to not spam logs
+
+        log.debug("Starting CMProducer");
+
+        final CMConfiguration configuration = getConfiguration();
+
+        if (configuration.isTestConnectionOnStartup()) {
+            try {
+                log.debug("Checking connection - {}", getEndpoint().getCMUrl());
+                HttpClientBuilder.create().build().execute(new HttpHead(getEndpoint().getCMUrl()));
+                log.debug("Connection to {}: OK", getEndpoint().getCMUrl());
+            } catch (final Exception e) {
+                throw new HostUnavailableException(String.format("Connection to %s: NOT AVAILABLE", getEndpoint().getCMUrl()), e);
+            }
+        }
+
+        // keep starting
+        super.doStart();
+
+        log.debug("CMProducer started");
+    }
+
+    @Override
+    public CMEndpoint getEndpoint() {
+        return (CMEndpoint) super.getEndpoint();
+    }
+
+    public CMConfiguration getConfiguration() {
+        return getEndpoint().getConfiguration();
+    }
+
+    public Validator getValidator() {
+        if (validator == null) {
+            validator = getEndpoint().getComponent().getValidator();
+        }
+        return validator;
+    }
+
+    public CMSender getSender() {
+        return sender;
+    }
+
+    public void setSender(CMSender sender) {
+        this.sender = sender;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSender.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSender.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSender.java
new file mode 100644
index 0000000..661f4dd
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSender.java
@@ -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.
+ */
+package org.apache.camel.component.cm;
+
+/**
+ * Sends a validated sms message to CM endpoints
+ */
+public interface CMSender {
+
+    /**
+     * Sends a validated sms message to CM Endpoints.
+     */
+    void send(CMMessage cmMessage);
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSenderOneMessageImpl.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSenderOneMessageImpl.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSenderOneMessageImpl.java
new file mode 100644
index 0000000..07e0e14
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMSenderOneMessageImpl.java
@@ -0,0 +1,254 @@
+/**
+ * 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.cm;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.util.UUID;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+import org.apache.camel.component.cm.exceptions.CMDirectException;
+import org.apache.camel.component.cm.exceptions.XMLConstructionException;
+import org.apache.camel.component.cm.exceptions.cmresponse.CMResponseException;
+import org.apache.camel.component.cm.exceptions.cmresponse.InsufficientBalanceException;
+import org.apache.camel.component.cm.exceptions.cmresponse.InvalidProductTokenException;
+import org.apache.camel.component.cm.exceptions.cmresponse.NoAccountFoundForProductTokenException;
+import org.apache.camel.component.cm.exceptions.cmresponse.UnknownErrorException;
+import org.apache.camel.component.cm.exceptions.cmresponse.UnroutableMessageException;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CMSenderOneMessageImpl implements CMSender {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CMSenderOneMessageImpl.class);
+
+    private final String url;
+    private final UUID productToken;
+
+    public CMSenderOneMessageImpl(final String url, final UUID productToken) {
+
+        this.url = url;
+        this.productToken = productToken;
+    }
+
+    /**
+     * Sends a message to CM endpoints. 1. CMMessage instance is going to be marshalled to xml. 2. Post request xml string to CMEndpoint.
+     */
+    @Override
+    public void send(final CMMessage cmMessage) {
+
+        // See: Check https://dashboard.onlinesmsgateway.com/docs for responses
+
+        // 1.Construct XML. Throws XMLConstructionException
+        final String xml = createXml(cmMessage);
+
+        // 2. Try to send to CM SMS Provider ...Throws CMResponseException
+        doHttpPost(url, xml);
+    }
+
+    private String createXml(final CMMessage message) {
+
+        try {
+
+            final ByteArrayOutputStream xml = new ByteArrayOutputStream();
+            final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            factory.setNamespaceAware(true);
+
+            // Get the DocumentBuilder
+            final DocumentBuilder docBuilder = factory.newDocumentBuilder();
+
+            // Create blank DOM Document
+            final DOMImplementation impl = docBuilder.getDOMImplementation();
+            final Document doc = impl.createDocument(null, "MESSAGES", null);
+
+            // ROOT Element es MESSAGES
+            final Element root = doc.getDocumentElement();
+
+            // AUTHENTICATION element
+            final Element authenticationElement = doc.createElement("AUTHENTICATION");
+            final Element productTokenElement = doc.createElement("PRODUCTTOKEN");
+            authenticationElement.appendChild(productTokenElement);
+            final Text productTokenValue = doc.createTextNode("" + productToken);
+            productTokenElement.appendChild(productTokenValue);
+            root.appendChild(authenticationElement);
+
+            // MSG Element
+            final Element msgElement = doc.createElement("MSG");
+            root.appendChild(msgElement);
+
+            // <FROM>VALUE</FROM>
+            final Element fromElement = doc.createElement("FROM");
+            fromElement.appendChild(doc.createTextNode(message.getSender()));
+            msgElement.appendChild(fromElement);
+
+            // <BODY>VALUE</BODY>
+            final Element bodyElement = doc.createElement("BODY");
+            bodyElement.appendChild(doc.createTextNode(message.getMessage()));
+            msgElement.appendChild(bodyElement);
+
+            // <TO>VALUE</TO>
+            final Element toElement = doc.createElement("TO");
+            toElement.appendChild(doc.createTextNode(message.getPhoneNumber()));
+            msgElement.appendChild(toElement);
+
+            // <DCS>VALUE</DCS> - if UNICODE - messageOut.isGSM338Enc
+            // false
+            if (message.isUnicode()) {
+                final Element dcsElement = doc.createElement("DCS");
+                dcsElement.appendChild(doc.createTextNode("8"));
+                msgElement.appendChild(dcsElement);
+            }
+
+            // <REFERENCE>VALUE</REFERENCE> -Alfanum
+            final String id = message.getIdAsString();
+            if (id != null && !id.isEmpty()) {
+                final Element refElement = doc.createElement("REFERENCE");
+                refElement.appendChild(doc.createTextNode("" + message.getIdAsString()));
+                msgElement.appendChild(refElement);
+            }
+
+            // <MINIMUMNUMBEROFMESSAGEPARTS>1</MINIMUMNUMBEROFMESSAGEPARTS>
+            // <MAXIMUMNUMBEROFMESSAGEPARTS>8</MAXIMUMNUMBEROFMESSAGEPARTS>
+            if (message.isMultipart()) {
+                final Element minMessagePartsElement = doc.createElement("MINIMUMNUMBEROFMESSAGEPARTS");
+                minMessagePartsElement.appendChild(doc.createTextNode("1"));
+                msgElement.appendChild(minMessagePartsElement);
+
+                final Element maxMessagePartsElement = doc.createElement("MAXIMUMNUMBEROFMESSAGEPARTS");
+                maxMessagePartsElement.appendChild(doc.createTextNode(Integer.toString(message.getMultiparts())));
+                msgElement.appendChild(maxMessagePartsElement);
+            }
+
+            // Creatate XML as String
+            final Transformer aTransformer = TransformerFactory.newInstance().newTransformer();
+            aTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            final Source src = new DOMSource(doc);
+            final Result dest = new StreamResult(xml);
+            aTransformer.transform(src, dest);
+            return xml.toString();
+        } catch (final TransformerException e) {
+            throw new XMLConstructionException(String.format("Cant serialize CMMessage %s", message), e);
+        } catch (final ParserConfigurationException e) {
+            throw new XMLConstructionException(String.format("Cant serialize CMMessage %s", message), e);
+        }
+    }
+
+    private void doHttpPost(final String urlString, final String requestString) {
+
+        final HttpClient client = HttpClientBuilder.create().build();
+        final HttpPost post = new HttpPost(urlString);
+        post.setEntity(new StringEntity(requestString, Charset.forName("UTF-8")));
+
+        try {
+
+            final HttpResponse response = client.execute(post);
+
+            final int statusCode = response.getStatusLine().getStatusCode();
+
+            LOG.debug("Response Code : {}", statusCode);
+
+            if (statusCode == 400) {
+                throw new CMDirectException("CM Component and CM API show some kind of inconsistency. "
+                                            + "CM is complaining about not using a post method for the request. And this component only uses POST requests. What happens?");
+            }
+
+            if (statusCode != 200) {
+                throw new CMDirectException("CM Component and CM API show some kind of inconsistency. The component expects the status code to be 200 or 400. New api released? ");
+            }
+
+            // So we have 200 status code...
+
+            // The response type is 'text/plain' and contains the actual
+            // result of the request processing.
+
+            // We obtaing the result text
+            final BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
+
+            final StringBuffer result = new StringBuffer();
+            String line = null;
+            while ((line = rd.readLine()) != null) {
+                result.append(line);
+            }
+
+            // ... and process it
+
+            line = result.toString();
+            if (!line.isEmpty()) {
+
+                // Line is not empty = error
+                LOG.debug("Result of the request processing: FAILED\n{}", line);
+
+                // The response text contains the error description. We will
+                // throw a custom exception for each.
+
+                if (line.contains(CMConstants.ERROR_UNKNOWN)) {
+                    throw new UnknownErrorException();
+                } else if (line.contains(CMConstants.ERROR_NO_ACCOUNT)) {
+                    throw new NoAccountFoundForProductTokenException();
+                } else if (line.contains(CMConstants.ERROR_INSUFICIENT_BALANCE)) {
+                    throw new InsufficientBalanceException();
+                } else if (line.contains(CMConstants.ERROR_UNROUTABLE_MESSAGE)) {
+                    throw new UnroutableMessageException();
+                } else if (line.contains(CMConstants.ERROR_INVALID_PRODUCT_TOKEN)) {
+                    throw new InvalidProductTokenException();
+                } else {
+
+                    // SO FAR i would expect other kind of ERROR.
+
+                    // MSISDN correctness and message validity is client
+                    // responsibility
+                    throw new CMResponseException("CHECK ME. I am not expecting this. ");
+                }
+            }
+
+            // Ok. Line is EMPTY - successfully submitted
+            LOG.debug("Result of the request processing: Successfully submited");
+        } catch (final IOException io) {
+            throw new CMDirectException(io);
+        } catch (Throwable t) {
+            if (!(t instanceof CMDirectException)) {
+                // Chain it
+                t = new CMDirectException(t);
+            }
+            throw (CMDirectException) t;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMUtils.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMUtils.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMUtils.java
new file mode 100644
index 0000000..f0581da
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/CMUtils.java
@@ -0,0 +1,30 @@
+/**
+ * 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.cm;
+
+public final class CMUtils {
+
+    private CMUtils() {
+    }
+
+    public static boolean isGsm0338Encodeable(final String message) {
+        return message.matches(CMConstants.GSM_0338_REGEX);
+    }
+
+    // TODO: Have a look at
+    // https:// github.com/apache/camel/blob/master/components/camel-smpp/src/main/java/org/apache/camel/component/smpp/SmppUtils.java
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/client/SMSMessage.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/client/SMSMessage.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/client/SMSMessage.java
new file mode 100644
index 0000000..869c9f8
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/client/SMSMessage.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.cm.client;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
+import org.apache.camel.component.cm.validation.constraints.E164;
+
+/**
+ * Immutable. The message instance provided by the client.
+ */
+public class SMSMessage {
+
+    /**
+     * Required MSISDN. E164 value. The destination phone number. Format with a '+' and country code.
+     *
+     * @see <a href="https://en.wikipedia.org/wiki/E.164">https://en.wikipedia.org/wiki/E.164</a>
+     */
+    @E164
+    private final String phoneNumber;
+
+    /**
+     * This is the message to be sent. 2 options:
+     * <ul>
+     * <li>If the message is GSM 0038 encodeable the gateway will first check if a message is larger than 160 characters, if so, the message will be cut into multiple 153 characters parts limited by
+     * defaultMaxNumberOfParts set in the component uri.</li>
+     * <li>Otherwise, the gateway will check if a message is larger than 70 characters, if so, the message will be cut into multiple 67 characters parts to a maximum of defaultMaxNumberOfParts set in
+     * the component uri.</li>
+     * </ul>
+     *
+     * @see <a href="https://en.wikipedia.org/wiki/GSM_03.38">E.164</a>
+     */
+    @NotNull
+    private final String message;
+
+    /**
+     * This is an optional dynamic sender name.
+     * <p>
+     * 1 - 11 alphanumeric characters and + char. Not Empty Strings. This field has a maximum length of 11 characters. If it is not set the defaultFrom required to configure the component will be set.
+     */
+    @Size(min = 1, max = 11)
+    @Pattern(regexp = "^[A-Za-z0-9]+$")
+    private final String from;
+
+    /**
+     * Unique identifier for a message.
+     * <p>
+     * 1 - 32 alphanumeric characters. Not Empty Strings. Will not work for demo accounts. This field corresponds to REFERENCE parameter in CM Api.
+     */
+    @Size(min = 1, max = 32)
+    @Pattern(regexp = "^[A-Za-z0-9]+$")
+    private final String id;
+
+    public SMSMessage(final String message, final String phoneNumber) {
+        this(null, message, phoneNumber, null);
+    }
+
+    public SMSMessage(String id, final String message, final String phoneNumber) {
+        this(id, message, phoneNumber, null);
+    }
+
+    public SMSMessage(final String id, final String message, final String phoneNumber, final String from) {
+        this.id = id;
+        this.message = message;
+        this.phoneNumber = phoneNumber;
+        this.from = from;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public String getPhoneNumber() {
+        return phoneNumber;
+    }
+
+    public String getFrom() {
+        return from;
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer toS = new StringBuffer("{phoneNumber: " + phoneNumber + ", message: " + message);
+        if (from != null && !from.isEmpty()) {
+            toS.append(", from: " + from);
+        }
+        if (id != null && !id.isEmpty()) {
+            toS.append(", id: " + id);
+        }
+        toS.append(" }");
+        return toS.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/client/Translator.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/client/Translator.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/client/Translator.java
new file mode 100644
index 0000000..4c6e9e9
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/client/Translator.java
@@ -0,0 +1,23 @@
+/**
+ * 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.cm.client;
+
+public interface Translator<T> {
+
+    SMSMessage translate(T t);
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/CMDirectException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/CMDirectException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/CMDirectException.java
new file mode 100644
index 0000000..70912ff
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/CMDirectException.java
@@ -0,0 +1,40 @@
+/**
+ * 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.cm.exceptions;
+
+public class CMDirectException extends RuntimeException {
+
+    public CMDirectException() {
+    }
+
+    public CMDirectException(final String message) {
+        super(message);
+    }
+
+    public CMDirectException(final Throwable cause) {
+        super(cause);
+    }
+
+    public CMDirectException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    public CMDirectException(final String message, final Throwable cause,
+            final boolean enableSuppression, final boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/HostUnavailableException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/HostUnavailableException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/HostUnavailableException.java
new file mode 100644
index 0000000..73bf0d0
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/HostUnavailableException.java
@@ -0,0 +1,39 @@
+/**
+ * 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.cm.exceptions;
+
+public class HostUnavailableException extends CMDirectException {
+
+    public HostUnavailableException() {
+    }
+
+    public HostUnavailableException(final String message) {
+        super(message);
+    }
+
+    public HostUnavailableException(final Throwable cause) {
+        super(cause);
+    }
+
+    public HostUnavailableException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    public HostUnavailableException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/XMLConstructionException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/XMLConstructionException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/XMLConstructionException.java
new file mode 100644
index 0000000..5086e70
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/XMLConstructionException.java
@@ -0,0 +1,39 @@
+/**
+ * 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.cm.exceptions;
+
+public class XMLConstructionException extends CMDirectException {
+
+    public XMLConstructionException() {
+    }
+
+    public XMLConstructionException(final String message) {
+        super(message);
+    }
+
+    public XMLConstructionException(final Throwable cause) {
+        super(cause);
+    }
+
+    public XMLConstructionException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    public XMLConstructionException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/CMResponseException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/CMResponseException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/CMResponseException.java
new file mode 100644
index 0000000..4ed4f6e
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/CMResponseException.java
@@ -0,0 +1,41 @@
+/**
+ * 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.cm.exceptions.cmresponse;
+
+import org.apache.camel.component.cm.exceptions.CMDirectException;
+
+public class CMResponseException extends CMDirectException {
+
+    public CMResponseException() {
+    }
+
+    public CMResponseException(final String message) {
+        super(message);
+    }
+
+    public CMResponseException(final Throwable cause) {
+        super(cause);
+    }
+
+    public CMResponseException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    public CMResponseException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) {
+        super(message, cause, enableSuppression, writableStackTrace);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InsufficientBalanceException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InsufficientBalanceException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InsufficientBalanceException.java
new file mode 100644
index 0000000..bb73cc5
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InsufficientBalanceException.java
@@ -0,0 +1,26 @@
+/**
+ * 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.cm.exceptions.cmresponse;
+
+/**
+ * You are out of trial messages. Order new messages via your dashboard.
+ */
+public class InsufficientBalanceException extends CMResponseException {
+
+    public InsufficientBalanceException() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InvalidMSISDNException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InvalidMSISDNException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InvalidMSISDNException.java
new file mode 100644
index 0000000..c80fbdd
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InvalidMSISDNException.java
@@ -0,0 +1,23 @@
+/**
+ * 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.cm.exceptions.cmresponse;
+
+public class InvalidMSISDNException extends CMResponseException {
+
+    public InvalidMSISDNException() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InvalidProductTokenException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InvalidProductTokenException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InvalidProductTokenException.java
new file mode 100644
index 0000000..ce81bcb
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/InvalidProductTokenException.java
@@ -0,0 +1,26 @@
+/**
+ * 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.cm.exceptions.cmresponse;
+
+/**
+ * Invalid or missing
+ */
+public class InvalidProductTokenException extends CMResponseException {
+
+    public InvalidProductTokenException() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NoAccountFoundForProductTokenException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NoAccountFoundForProductTokenException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NoAccountFoundForProductTokenException.java
new file mode 100644
index 0000000..a718ff3
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NoAccountFoundForProductTokenException.java
@@ -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.
+ */
+package org.apache.camel.component.cm.exceptions.cmresponse;
+
+/**
+ * No account found for the provided product token.
+ *
+ * @author Omar
+ */
+public class NoAccountFoundForProductTokenException extends CMResponseException {
+
+    public NoAccountFoundForProductTokenException() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NoMessageException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NoMessageException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NoMessageException.java
new file mode 100644
index 0000000..4398219
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NoMessageException.java
@@ -0,0 +1,23 @@
+/**
+ * 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.cm.exceptions.cmresponse;
+
+public class NoMessageException extends CMResponseException {
+
+    public NoMessageException() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NotPhoneNumberFoundException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NotPhoneNumberFoundException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NotPhoneNumberFoundException.java
new file mode 100644
index 0000000..877b972
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NotPhoneNumberFoundException.java
@@ -0,0 +1,23 @@
+/**
+ * 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.cm.exceptions.cmresponse;
+
+public class NotPhoneNumberFoundException extends CMResponseException {
+
+    public NotPhoneNumberFoundException() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnknownErrorException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnknownErrorException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnknownErrorException.java
new file mode 100644
index 0000000..bb0951a
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnknownErrorException.java
@@ -0,0 +1,26 @@
+/**
+ * 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.cm.exceptions.cmresponse;
+
+/**
+ * An unexpected error occurred. Check the provided values. Contact CM for support.
+ */
+public class UnknownErrorException extends CMResponseException {
+
+    public UnknownErrorException() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnroutableMessageException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnroutableMessageException.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnroutableMessageException.java
new file mode 100644
index 0000000..ec07c1f
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnroutableMessageException.java
@@ -0,0 +1,23 @@
+/**
+ * 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.cm.exceptions.cmresponse;
+
+public class UnroutableMessageException extends CMResponseException {
+
+    public UnroutableMessageException() {
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/58515451/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/validation/constraints/E164.java
----------------------------------------------------------------------
diff --git a/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/validation/constraints/E164.java b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/validation/constraints/E164.java
new file mode 100644
index 0000000..3d7dd95
--- /dev/null
+++ b/components/camel-cm-sms/src/main/java/org/apache/camel/component/cm/validation/constraints/E164.java
@@ -0,0 +1,41 @@
+/**
+ * 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.cm.validation.constraints;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
+        ElementType.ANNOTATION_TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Constraint(validatedBy = E164Validator.class)
+@Documented
+public @interface E164 {
+
+    // String message() default "{e164.message}";
+    String message() default "E164 format expected for that phone number";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}