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!\"#$%&'()*+,\\-./:;<=>?¡¿^{}\\\\\\[~\\]|"
+ + "\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 {};
+}