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:26 UTC

[06/23] camel git commit: camel-cm component added following the steps in http://camel.apache.org/add-new-component-guide.html

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NoMessageException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NoMessageException.java b/components/camel-cm/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/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/c70e9db8/components/camel-cm/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NotPhoneNumberFoundException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/NotPhoneNumberFoundException.java b/components/camel-cm/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/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/c70e9db8/components/camel-cm/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnknownErrorException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnknownErrorException.java b/components/camel-cm/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/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/c70e9db8/components/camel-cm/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnroutableMessageException.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/main/java/org/apache/camel/component/cm/exceptions/cmresponse/UnroutableMessageException.java b/components/camel-cm/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/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/c70e9db8/components/camel-cm/src/main/java/org/apache/camel/component/cm/validation/constraints/E164.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/main/java/org/apache/camel/component/cm/validation/constraints/E164.java b/components/camel-cm/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/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 {};
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/main/java/org/apache/camel/component/cm/validation/constraints/E164Validator.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/main/java/org/apache/camel/component/cm/validation/constraints/E164Validator.java b/components/camel-cm/src/main/java/org/apache/camel/component/cm/validation/constraints/E164Validator.java
new file mode 100644
index 0000000..d8160f7
--- /dev/null
+++ b/components/camel-cm/src/main/java/org/apache/camel/component/cm/validation/constraints/E164Validator.java
@@ -0,0 +1,66 @@
+/**
+ * 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 javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+
+/**
+ * Checks that a given character sequence (e.g. string) is a valid E164 formatted phonenumber. https://www.cmtelecom.com/newsroom/how-to-format-international-telephone- numbers
+ * https://github.com/googlei18n/libphonenumber
+ */
+public class E164Validator implements ConstraintValidator<E164, String> {
+
+    private final PhoneNumberUtil pnu = PhoneNumberUtil.getInstance();
+
+    @Override
+    public void initialize(final E164 constraintAnnotation) {
+    }
+
+    @Override
+    public boolean isValid(final String value, final ConstraintValidatorContext context) {
+
+        if (value == null) {
+            return false;
+        }
+        try {
+
+            final PhoneNumber parsingResult = pnu.parse(value, null);
+            if (!pnu.format(parsingResult, PhoneNumberFormat.E164).equals(value)) {
+                return false;
+            }
+            return true;
+        } catch (final NumberParseException t) {
+            // Errors when parsing phonenumber
+            return false;
+        }
+
+        // CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN
+        // log.debug("Phone Number: {}", value);
+        // log.debug("Country code: {}", numberProto.getCountryCode());
+        // log.debug("National Number: {}", numberProto.getNationalNumber());
+        // log.debug("E164 format: {}", pnu.format(numberProto,
+        // PhoneNumberFormat.E164));
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/main/resources/META-INF/services/org/apache/camel/component/cm
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/main/resources/META-INF/services/org/apache/camel/component/cm b/components/camel-cm/src/main/resources/META-INF/services/org/apache/camel/component/cm
new file mode 100644
index 0000000..bf9d84b
--- /dev/null
+++ b/components/camel-cm/src/main/resources/META-INF/services/org/apache/camel/component/cm
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class=org.apache.camel.component.cm.CMComponent

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/main/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/main/resources/log4j.properties b/components/camel-cm/src/main/resources/log4j.properties
new file mode 100644
index 0000000..8c6ec38
--- /dev/null
+++ b/components/camel-cm/src/main/resources/log4j.properties
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+log4j.rootLogger=error, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+
+# Print the date in ISO 8601 format
+log4j.appender.stdout.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
+
+log4j.appender.R=org.apache.log4j.RollingFileAppender
+log4j.appender.R.File=application.log
+
+log4j.appender.R.MaxFileSize=100KB
+# Keep one backup file
+log4j.appender.R.MaxBackupIndex=1
+
+log4j.appender.R.layout=org.apache.log4j.PatternLayout
+log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
+
+# LOGGERS
+log4j.logger.org.apache=INFO
+log4j.logger.org.apache.camel.cm=TRACE

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMConfigurationTest.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMConfigurationTest.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMConfigurationTest.java
new file mode 100644
index 0000000..beafa33
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMConfigurationTest.java
@@ -0,0 +1,142 @@
+/**
+ * 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.test;
+
+import java.util.Set;
+import java.util.UUID;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validator;
+
+import org.apache.camel.component.cm.CMConfiguration;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.Assert;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { ValidatorConfiguration.class })
+// @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
+// @DisableJmx(false)
+// @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class CMConfigurationTest extends AbstractJUnit4SpringContextTests {
+
+    @Autowired
+    private Validator validator;
+
+    @Before
+    public void beforeTest() throws Exception {
+    }
+
+    // @After
+    // public void afterTest() {
+
+    @Test
+    public void testNullProductToken() throws Exception {
+
+        final CMConfiguration configuration = new CMConfiguration();
+
+        // length: 1-11
+        configuration.setDefaultFrom("DefaultFrom");
+        configuration.setProductTokenAsUUID(null);
+        configuration.setDefaultMaxNumberOfParts(8);
+        configuration.setTestConnectionOnStartup(false);
+
+        final Set<ConstraintViolation<CMConfiguration>> constraintViolations = validator.validate(configuration);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testNullDefaultFrom() throws Exception {
+
+        final CMConfiguration configuration = new CMConfiguration();
+
+        // length: 1-11
+        configuration.setDefaultFrom(null);
+
+        configuration.setProductTokenAsUUID(UUID.randomUUID());
+        configuration.setDefaultMaxNumberOfParts(8);
+        configuration.setTestConnectionOnStartup(false);
+
+        final Set<ConstraintViolation<CMConfiguration>> constraintViolations = validator.validate(configuration);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testDefaultFromFieldMaxLength() throws Exception {
+
+        final CMConfiguration configuration = new CMConfiguration();
+
+        // length: 1-11
+        configuration.setDefaultFrom("123456789012");
+
+        configuration.setProductTokenAsUUID(UUID.randomUUID());
+        configuration.setDefaultMaxNumberOfParts(8);
+        configuration.setTestConnectionOnStartup(false);
+
+        final Set<ConstraintViolation<CMConfiguration>> constraintViolations = validator.validate(configuration);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testDefaultFromFieldZeroLength() throws Exception {
+
+        final CMConfiguration configuration = new CMConfiguration();
+
+        // length: 1-11
+        configuration.setDefaultFrom("");
+
+        configuration.setProductTokenAsUUID(UUID.randomUUID());
+        configuration.setDefaultMaxNumberOfParts(8);
+        configuration.setTestConnectionOnStartup(false);
+
+        final Set<ConstraintViolation<CMConfiguration>> constraintViolations = validator.validate(configuration);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testMaxNumberOfParts() throws Exception {
+
+        final CMConfiguration configuration = new CMConfiguration();
+
+        configuration.setProductTokenAsUUID(UUID.randomUUID());
+        configuration.setDefaultFrom("DefaultFrom");
+        configuration.setDefaultMaxNumberOfParts(9);
+        configuration.setTestConnectionOnStartup(false);
+
+        final Set<ConstraintViolation<CMConfiguration>> constraintViolations = validator.validate(configuration);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testMaxNumberOfPartsZero() throws Exception {
+
+        final CMConfiguration configuration = new CMConfiguration();
+
+        configuration.setProductTokenAsUUID(UUID.randomUUID());
+        configuration.setDefaultFrom("DefaultFrom");
+        configuration.setDefaultMaxNumberOfParts(0);
+        configuration.setTestConnectionOnStartup(false);
+
+        final Set<ConstraintViolation<CMConfiguration>> constraintViolations = validator.validate(configuration);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMMessageTest.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMMessageTest.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMMessageTest.java
new file mode 100644
index 0000000..9eacecb
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMMessageTest.java
@@ -0,0 +1,323 @@
+/**
+ * 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.test;
+
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
+import org.apache.camel.component.cm.CMConstants;
+import org.apache.camel.component.cm.CMMessage;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.Assert;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = { ValidatorConfiguration.class })
+// @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
+// @DisableJmx(false)
+// @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class CMMessageTest extends AbstractJUnit4SpringContextTests {
+
+    private final PhoneNumberUtil pnu = PhoneNumberUtil.getInstance();
+    private String validNumber;
+
+    @Before
+    public void beforeTest() throws Exception {
+        validNumber = pnu.format(pnu.getExampleNumber("ES"), PhoneNumberFormat.E164);
+    }
+
+    // @After
+    // public void afterTest() {
+
+    /*
+     * GSM0338
+     */
+
+    @Test
+    public void testGSM338AndLTMAXGSMMESSAGELENGTH() throws Exception {
+
+        // 0338 and less than 160 char -> 1 part
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < CMConstants.MAX_GSM_MESSAGE_LENGTH; index++) {
+            message.append("a");
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 1);
+        Assert.isTrue(!cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testGSM338AndEQMAXGSMMESSAGELENGTH() throws Exception {
+        // 0338 and length is exactly 160 -> 1 part
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < CMConstants.MAX_GSM_MESSAGE_LENGTH; index++) {
+            message.append("a");
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 1);
+        Assert.isTrue(!cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testGSM338AndGTMAXGSMMESSAGELENGTH() throws Exception {
+
+        // 0338 and length is exactly 161 -> 2 part
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < CMConstants.MAX_GSM_MESSAGE_LENGTH + 1; index++) {
+            message.append("a");
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 2);
+        Assert.isTrue(!cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testGSM338AndLT2MAXGSMMESSAGELENGTH() throws Exception {
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < (2 * CMConstants.MAX_GSM_MESSAGE_LENGTH_PER_PART_IF_MULTIPART - 1); index++) {
+            message.append("a");
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 2);
+        Assert.isTrue(!cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testGSM338AndEQ2MAXGSMMESSAGELENGTH() throws Exception {
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < (2 * CMConstants.MAX_GSM_MESSAGE_LENGTH_PER_PART_IF_MULTIPART); index++) {
+            message.append("a");
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 2);
+        Assert.isTrue(!cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testGSM338AndGT2MAXGSMMESSAGELENGTH() throws Exception {
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < (2 * CMConstants.MAX_GSM_MESSAGE_LENGTH_PER_PART_IF_MULTIPART + 1); index++) {
+            message.append("a");
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 3);
+        Assert.isTrue(!cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testGSM338AndEQ8MAXGSMMESSAGELENGTH() throws Exception {
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < (8 * CMConstants.MAX_GSM_MESSAGE_LENGTH_PER_PART_IF_MULTIPART); index++) {
+            message.append("a");
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 8);
+        Assert.isTrue(!cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testGSM338AndGT8MAXGSMMESSAGELENGTH() throws Exception {
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < (8 * CMConstants.MAX_GSM_MESSAGE_LENGTH_PER_PART_IF_MULTIPART + 1); index++) {
+            message.append("a");
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 8);
+        Assert.isTrue(!cmMessage.isUnicode());
+    }
+
+    /*
+     * Unicode Messages
+     */
+
+    @Test
+    public void testUnicodeAndLTMAXGSMMESSAGELENGTH() throws Exception {
+
+        String ch = "\uF400";
+
+        // 0338 and less than 160 char -> 1 part
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < CMConstants.MAX_UNICODE_MESSAGE_LENGTH; index++) {
+            message.append(ch);
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 1);
+        Assert.isTrue(cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testUnicodeAndEQMAXGSMMESSAGELENGTH() throws Exception {
+        // 0338 and length is exactly 160 -> 1 part
+
+        String ch = "\uF400";
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < CMConstants.MAX_UNICODE_MESSAGE_LENGTH; index++) {
+            message.append(ch);
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 1);
+        Assert.isTrue(cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testUnicodeAndGTMAXGSMMESSAGELENGTH() throws Exception {
+
+        // 0338 and length is exactly 161 -> 2 part
+
+        String ch = "\uF400";
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < CMConstants.MAX_UNICODE_MESSAGE_LENGTH + 1; index++) {
+            message.append(ch);
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 2);
+        Assert.isTrue(cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testUnicodeAndLT2MAXGSMMESSAGELENGTH() throws Exception {
+
+        String ch = "\uF400";
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < (2 * CMConstants.MAX_UNICODE_MESSAGE_LENGTH_PER_PART_IF_MULTIPART - 1); index++) {
+            message.append(ch);
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 2);
+        Assert.isTrue(cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testUnicodeAndEQ2MAXGSMMESSAGELENGTH() throws Exception {
+
+        String ch = "\uF400";
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < (2 * CMConstants.MAX_UNICODE_MESSAGE_LENGTH_PER_PART_IF_MULTIPART); index++) {
+            message.append(ch);
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 2);
+        Assert.isTrue(cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testUnicodeAndGT2MAXGSMMESSAGELENGTH() throws Exception {
+
+        String ch = "\uF400";
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < (2 * CMConstants.MAX_UNICODE_MESSAGE_LENGTH_PER_PART_IF_MULTIPART + 1); index++) {
+            message.append(ch);
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 3);
+        Assert.isTrue(cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testUnicodeAndEQ8MAXGSMMESSAGELENGTH() throws Exception {
+
+        String ch = "\uF400";
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < (8 * CMConstants.MAX_UNICODE_MESSAGE_LENGTH_PER_PART_IF_MULTIPART); index++) {
+            message.append(ch);
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 8);
+        Assert.isTrue(cmMessage.isUnicode());
+    }
+
+    @Test
+    public void testUnicodeAndGT8MAXGSMMESSAGELENGTH() throws Exception {
+
+        String ch = "\uF400";
+
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < (8 * CMConstants.MAX_GSM_MESSAGE_LENGTH_PER_PART_IF_MULTIPART + 1); index++) {
+            message.append(ch);
+        }
+
+        final CMMessage cmMessage = new CMMessage(validNumber, message.toString());
+        cmMessage.setUnicodeAndMultipart(CMConstants.DEFAULT_MULTIPARTS);
+
+        Assert.isTrue(cmMessage.getMultiparts() == 8);
+        Assert.isTrue(cmMessage.isUnicode());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMProxy.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMProxy.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMProxy.java
new file mode 100644
index 0000000..45b88bd
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMProxy.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.test;
+
+import org.apache.camel.component.cm.client.SMSMessage;
+
+/**
+ * Regular interface used to proxy a producer sending to the Route out to CM Direct {@link http://camel.apache.org/using-camelproxy.html}
+ */
+public interface CMProxy {
+    void send(SMSMessage smsMessage);
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMTest.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMTest.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMTest.java
new file mode 100644
index 0000000..aac110e
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CMTest.java
@@ -0,0 +1,407 @@
+/**
+ * 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.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Produce;
+import org.apache.camel.ResolveEndpointFailedException;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.Service;
+import org.apache.camel.component.cm.CMEndpoint;
+import org.apache.camel.component.cm.client.SMSMessage;
+import org.apache.camel.component.cm.exceptions.HostUnavailableException;
+import org.apache.camel.component.cm.exceptions.InvalidPayloadException;
+import org.apache.camel.component.cm.exceptions.InvalidURLException;
+import org.apache.camel.component.cm.exceptions.InvalidUriEndpointException;
+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.InvalidMSISDNException;
+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.NoMessageException;
+import org.apache.camel.component.cm.exceptions.cmresponse.NotPhoneNumberFoundException;
+import org.apache.camel.component.cm.exceptions.cmresponse.UnknownErrorException;
+import org.apache.camel.component.cm.exceptions.cmresponse.UnroutableMessageException;
+import org.apache.camel.component.cm.test.mocks.cmsender.CMResponseExceptionSender;
+import org.apache.camel.component.cm.test.mocks.cmsender.InsufficientBalanceExceptionSender;
+import org.apache.camel.component.cm.test.mocks.cmsender.InvalidMSISDNExceptionSender;
+import org.apache.camel.component.cm.test.mocks.cmsender.InvalidProductTokenExceptionSender;
+import org.apache.camel.component.cm.test.mocks.cmsender.NoAccountFoundForProductTokenExceptionSender;
+import org.apache.camel.component.cm.test.mocks.cmsender.NoMessageExceptionSender;
+import org.apache.camel.component.cm.test.mocks.cmsender.NotPhoneNumberFoundExceptionSender;
+import org.apache.camel.component.cm.test.mocks.cmsender.UnknownErrorExceptionSender;
+import org.apache.camel.component.cm.test.mocks.cmsender.UnroutableMessageExceptionSender;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.spring.CamelSpringDelegatingTestContextLoader;
+import org.apache.camel.test.spring.CamelSpringJUnit4ClassRunner;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+import org.springframework.util.Assert;
+
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
+
+@RunWith(CamelSpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = {
+        CamelTestConfiguration.class }, loader = CamelSpringDelegatingTestContextLoader.class)
+// @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
+// @DisableJmx(false)
+// @MockEndpoints
+// @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class CMTest extends AbstractJUnit4SpringContextTests {
+
+    // dependency: camel-spring-javaconfig
+
+    @Autowired
+    private CamelContext camelContext;
+
+    private SecureRandom random = new SecureRandom();
+
+    private final PhoneNumberUtil pnu = PhoneNumberUtil.getInstance();
+    private String validNumber;
+
+    @Produce(uri = "direct:sms")
+    private CMProxy cmProxy;
+
+    @EndpointInject(uri = "mock:test")
+    private MockEndpoint mock;
+
+    // private StopWatch stopWatch = new StopWatch(getClass().getSimpleName());
+
+    @Before
+    public void beforeTest() throws Exception {
+        mock.reset();
+        camelContext.startRoute(CamelTestConfiguration.SIMPLE_ROUTE_ID);
+        validNumber = pnu.format(pnu.getExampleNumber("ES"),
+                PhoneNumberFormat.E164);
+    }
+
+    @After
+    public void afterTest() {
+
+        try {
+            camelContext.stopRoute(CamelTestConfiguration.SIMPLE_ROUTE_ID);
+        } catch (Exception e) {
+            logger.error("Exception trying to stop de routes", e);
+        }
+
+        // Stop all routes
+        // for (Route route : camelContext.getRoutes()) {
+        // try {
+        // camelContext.stopRoute(route.getId());
+        // } catch (Exception e) {
+        // logger.error("Exception trying to stop de routes", e);
+        // }
+        // }
+    }
+
+    /*
+     * 1. Invalid URI
+     */
+
+    @Test(expected = InvalidUriEndpointException.class)
+    public void testNotRequiredProductToken() throws Throwable {
+        try {
+            String schemedUri = "cm://sgw01.cm.nl/gateway.ashx?defaultFrom=MyBusiness&defaultMaxNumberOfParts=8&testConnectionOnStartup=true";
+            camelContext.getEndpoint(schemedUri).start();
+        } catch (Throwable t) {
+            throw t.getCause();
+        }
+
+    }
+
+    @Test(expected = InvalidUriEndpointException.class)
+    public void testNotRequiredDefaultFrom() throws Throwable {
+        try {
+            String schemedUri = "cm://sgw01.cm.nl/gateway.ashx?defaultFrom=MyBusiness&defaultMaxNumberOfParts=8&testConnectionOnStartup=true";
+            camelContext.getEndpoint(schemedUri).start();
+        } catch (Throwable t) {
+            throw t.getCause();
+        }
+
+    }
+
+    @Test(expected = HostUnavailableException.class)
+    public void testHostUnavailableException() throws Throwable {
+        // cm://sgw01.cm.nl/gateway.ashx?defaultFrom=MyBusiness&defaultMaxNumberOfParts=8&productToken=ea723fd7-da81-4826-89bc-fa7144e71c40&testConnectionOnStartup=true
+        String schemedUri = "cm://dummy.sgw01.cm.nl/gateway.ashx?defaultFrom=MyBusiness&defaultMaxNumberOfParts=8&productToken=ea723fd7-da81-4826-89bc-fa7144e71c40&testConnectionOnStartup=true";
+        Service service = camelContext.getEndpoint(schemedUri).createProducer();
+        service.start();
+    }
+
+    @Test(expected = InvalidURLException.class)
+    public void testInvalidHostDuplicateScheme() throws Throwable {
+        // cm://sgw01.cm.nl/gateway.ashx?defaultFrom=MyBusiness&defaultMaxNumberOfParts=8&productToken=ea723fd7-da81-4826-89bc-fa7144e71c40&testConnectionOnStartup=true
+        try {
+            String schemedUri = "cm://https://demo.com";
+            camelContext.getEndpoint(schemedUri);
+        } catch (Throwable t) {
+            throw t.getCause();
+        }
+    }
+
+    @Test(expected = ResolveEndpointFailedException.class)
+    public void testInvalidUriEndpoint() throws Throwable {
+        // cm://sgw01.cm.nl/gateway.ashx?defaultFrom=MyBusiness&defaultMaxNumberOfParts=8&productToken=ea723fd7-da81-4826-89bc-fa7144e71c40&testConnectionOnStartup=true
+        String noHostUri = "cm://gateway.ashx?defaultFrom=MyBusiness&defaultMaxNumberOfParts=8&productToken=ea723fd7-da81-4826-89bc-fa7144e71c40&testConnectionOnStartup=true";
+        camelContext.getEndpoint(noHostUri);
+    }
+
+    /*
+     * 2. Invalid Payload
+     */
+
+    @Test(expected = RuntimeException.class)
+    public void testNullPayload() throws Throwable {
+        cmProxy.send(null);
+    }
+
+    // @DirtiesContext
+    @Test(expected = NoAccountFoundForProductTokenException.class)
+    public void testAsPartOfARoute() throws Exception {
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateUnicodeMessage(), validNumber, null);
+        cmProxy.send(smsMessage);
+    }
+
+    @Test(expected = NoAccountFoundForProductTokenException.class)
+    public void testNoAccountFoundForProductTokenException() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        endpoint.getProducer()
+                .setSender(new NoAccountFoundForProductTokenExceptionSender());
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateGSM0338Message(), validNumber, null);
+        cmProxy.send(smsMessage);
+    }
+
+    /*
+     * 3. CM Responses (Faking Exceptions)
+     */
+
+    @Test(expected = CMResponseException.class)
+    public void testCMResponseException() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        endpoint.getProducer().setSender(new CMResponseExceptionSender());
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateUnicodeMessage(), validNumber, null);
+        cmProxy.send(smsMessage);
+    }
+
+    @Test(expected = InsufficientBalanceException.class)
+    public void testInsufficientBalanceException() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        endpoint.getProducer()
+                .setSender(new InsufficientBalanceExceptionSender());
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateGSM0338Message(), validNumber, null);
+        cmProxy.send(smsMessage);
+    }
+
+    @Test(expected = InvalidMSISDNException.class)
+    public void testInvalidMSISDNException() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        endpoint.getProducer().setSender(new InvalidMSISDNExceptionSender());
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateUnicodeMessage(), validNumber, null);
+        cmProxy.send(smsMessage);
+    }
+
+    @Test(expected = InvalidProductTokenException.class)
+    public void testInvalidProductTokenException() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        endpoint.getProducer()
+                .setSender(new InvalidProductTokenExceptionSender());
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateUnicodeMessage(), validNumber, null);
+        cmProxy.send(smsMessage);
+    }
+
+    @Test(expected = NoMessageException.class)
+    public void testNoMessageException() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        endpoint.getProducer().setSender(new NoMessageExceptionSender());
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateGSM0338Message(), validNumber, null);
+        cmProxy.send(smsMessage);
+    }
+
+    @Test(expected = NotPhoneNumberFoundException.class)
+    public void testNotPhoneNumberFoundException() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        endpoint.getProducer()
+                .setSender(new NotPhoneNumberFoundExceptionSender());
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateUnicodeMessage(), validNumber, null);
+        cmProxy.send(smsMessage);
+    }
+
+    @Test(expected = UnknownErrorException.class)
+    public void testUnknownErrorException() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        endpoint.getProducer().setSender(new UnknownErrorExceptionSender());
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateGSM0338Message(), validNumber, null);
+        cmProxy.send(smsMessage);
+    }
+
+    @Test(expected = UnroutableMessageException.class)
+    public void testUnroutableMessageException() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        endpoint.getProducer()
+                .setSender(new UnroutableMessageExceptionSender());
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateUnicodeMessage(), validNumber, null);
+        cmProxy.send(smsMessage);
+    }
+
+    @Test(expected = RuntimeCamelException.class)
+    public void testCMEndpointIsForProducing() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        endpoint.createConsumer(null);
+    }
+
+    @Test
+    public void testCMEndpointGetHost() throws Exception {
+
+        // Change sending strategy
+        CMEndpoint endpoint = (CMEndpoint) camelContext
+                .getEndpoint(applicationContext
+                        .getBean(CamelTestConfiguration.class).getUri());
+        Assert.isTrue(endpoint.getHost().equals(applicationContext
+                .getEnvironment().getRequiredProperty("cm.url")));
+    }
+
+    @Test(expected = InvalidPayloadException.class)
+    public void testSendInvalidPayload() throws Exception {
+
+        // Body
+        final SMSMessage smsMessage = new SMSMessage(generateIdAsString(),
+                generateGSM0338Message(), null, null);
+        cmProxy.send(smsMessage);
+    }
+
+    /*
+     * CMMessages
+     */
+
+    // @Test(expected = RuntimeException.class)
+    // public void testSkel() throws Exception {
+
+    // mock.expectedMessageCount(1);
+    //
+    // // Body
+    // final SMSMessage smsMessage = new SMSMessage("Hello CM", validNumber);
+    // cmProxy.send(smsMessage);
+    //
+    // mock.assertIsSatisfied();
+    // }
+
+    private String generateUnicodeMessage() {
+        String ch = "\uF400";
+        return generateRandomLengthMessageByChar(ch);
+    }
+
+    private String generateGSM0338Message() {
+        String ch = "a";
+        return generateRandomLengthMessageByChar(ch);
+    }
+
+    private String generateRandomLengthMessageByChar(String ch) {
+        // random Length
+        int msgLength = (int) (Math.random() * 2000);
+        StringBuffer message = new StringBuffer();
+        for (int index = 0; index < msgLength; index++) {
+            message.append(ch);
+        }
+        return message.toString();
+    }
+
+    //
+    private String generateIdAsString() {
+        return new BigInteger(130, random).toString(32);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CamelTestConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CamelTestConfiguration.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CamelTestConfiguration.java
new file mode 100644
index 0000000..b6a136d
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/CamelTestConfiguration.java
@@ -0,0 +1,100 @@
+/**
+ * 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.test;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.spring.javaconfig.SingleRouteCamelConfiguration;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.util.Assert;
+import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
+
+/**
+ * Builds a SimpleRoute to send a message to CM GW and CM Uri is built based on properties in a file.
+ */
+@Configuration("cmConfig")
+@PropertySource("classpath:/cm-smsgw.properties")
+public class CamelTestConfiguration extends SingleRouteCamelConfiguration {
+
+    public static final String SIMPLE_ROUTE_ID = "simple-route";
+
+    private String uri;
+
+    @Override
+    public RouteBuilder route() {
+        return new RouteBuilder() {
+
+            @Override
+            public void configure() throws Exception {
+
+                Assert.hasLength(uri);
+
+                log.info("\nCM Component is an URI based component\nCM URI: {}", uri);
+
+                // Route definition
+                from("direct:sms").to(uri).to("mock:test").routeId(SIMPLE_ROUTE_ID).autoStartup(true);
+
+            }
+        };
+    }
+
+    @Bean
+    public LocalValidatorFactoryBean getValidatorFactory() {
+        final LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
+        localValidatorFactoryBean.getValidationPropertyMap().put("hibernate.validator.fail_fast", "true");
+        return localValidatorFactoryBean;
+    }
+
+    /**
+     * Build the URI of the CM Component based on Environmental properties
+     */
+    @Override
+    public final void setApplicationContext(final ApplicationContext applicationContext) {
+
+        super.setApplicationContext(applicationContext);
+
+        final Environment env = applicationContext.getEnvironment();
+
+        final String host = env.getRequiredProperty("cm.url");
+        final String productTokenString = env.getRequiredProperty("cm.product-token");
+        final String sender = env.getRequiredProperty("cm.default-sender");
+
+        final StringBuffer cmUri = new StringBuffer("cm:" + host).append("?productToken=").append(productTokenString);
+        if (sender != null && !sender.isEmpty()) {
+            cmUri.append("&defaultFrom=").append(sender);
+        }
+
+        // Defaults to false
+        final Boolean testConnectionOnStartup = Boolean.parseBoolean(env.getProperty("cm.testConnectionOnStartup", "false"));
+        if (testConnectionOnStartup) {
+            cmUri.append("&testConnectionOnStartup=").append(testConnectionOnStartup.toString());
+        }
+
+        // Defaults to 8
+        final Integer defaultMaxNumberOfParts = Integer.parseInt(env.getProperty("defaultMaxNumberOfParts", "8"));
+        cmUri.append("&defaultMaxNumberOfParts=").append(defaultMaxNumberOfParts.toString());
+
+        uri = cmUri.toString();
+    }
+
+    public String getUri() {
+        return uri;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/SMSMessageTest.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/SMSMessageTest.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/SMSMessageTest.java
new file mode 100644
index 0000000..63bfced
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/SMSMessageTest.java
@@ -0,0 +1,183 @@
+/**
+ * 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.test;
+
+import java.util.Set;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Validator;
+
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber.CountryCodeSource;
+import org.apache.camel.component.cm.client.SMSMessage;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.Assert;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes = {ValidatorConfiguration.class })
+// @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
+// @DisableJmx(false)
+// @FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class SMSMessageTest extends AbstractJUnit4SpringContextTests {
+
+    @Autowired
+    private Validator validator;
+
+    private final PhoneNumberUtil pnu = PhoneNumberUtil.getInstance();
+    private String validNumber;
+
+    @Before
+    public void beforeTest() throws Exception {
+
+        validNumber = pnu.format(pnu.getExampleNumber("ES"), PhoneNumberFormat.E164);
+    }
+
+    // @After
+    // public void afterTest() {
+
+    @Test
+    public void testSMSMessageConstructor() throws Throwable {
+
+        // Coverage ;)
+        SMSMessage message = new SMSMessage(null, null);
+        Assert.isNull(message.getMessage());
+        Assert.isNull(message.getPhoneNumber());
+
+        message = new SMSMessage("idAsString", null, null, "MySelf");
+        Assert.isTrue(message.getId().equals("idAsString"));
+        Assert.isTrue(message.getFrom().equals("MySelf"));
+    }
+
+    @Test
+    public void testNullMessageField() throws Exception {
+
+        final SMSMessage m = new SMSMessage(null, validNumber);
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testNullPhoneNumber() throws Exception {
+
+        final SMSMessage m = new SMSMessage("Hello world!", null);
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testDynamicFromFieldMaxLength() throws Exception {
+
+        String dynamicFrom = "messagelengthgreaterthan12";
+
+        final SMSMessage m = new SMSMessage("idAsString", "Hello World", validNumber, dynamicFrom);
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testDynamicFromFieldZeroLength() throws Exception {
+
+        String zeroLengthDynamicFrom = "";
+
+        final SMSMessage m = new SMSMessage("idAsString", "Hello World", validNumber, zeroLengthDynamicFrom);
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testIdAsStringMaxLength() throws Exception {
+
+        String idAsString = "thisistheidastringlengthgreaterthan32";
+
+        final SMSMessage m = new SMSMessage(idAsString, "Hello World", validNumber, "MySelf");
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testIdAsStringFieldZeroLength() throws Exception {
+
+        String zeroLengthIdAsString = "";
+
+        final SMSMessage m = new SMSMessage(zeroLengthIdAsString, "Hello World", validNumber, "MySelf");
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testE164NullNumberIsInValid() throws Exception {
+
+        final String phoneNumber = null;
+        final SMSMessage m = new SMSMessage("Hello world!", phoneNumber);
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testE164IsValid() throws Exception {
+
+        final SMSMessage m = new SMSMessage("Hello world!", validNumber);
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(0 == constraintViolations.size());
+    }
+
+    @Test
+    public void testE164NoPlusSignedNumberIsInvalid() throws Exception {
+
+        final String phoneNumber = "34600000000";
+        final SMSMessage m = new SMSMessage("Hello world!", phoneNumber);
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testE164NoPlusSignedNumberBut00IsInvalid() throws Exception {
+
+        final String phoneNumber = new PhoneNumber().setCountryCodeSource(CountryCodeSource.FROM_NUMBER_WITHOUT_PLUS_SIGN).setNationalNumber(0034600000000).toString();
+        final SMSMessage m = new SMSMessage("Hello world!", phoneNumber);
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+
+    @Test
+    public void testE164NumberWithPlusSignIsInvalid() throws Exception {
+
+        final String phoneNumber = "+34 600 00 00 00";
+        final SMSMessage m = new SMSMessage("Hello world!", phoneNumber);
+
+        final Set<ConstraintViolation<SMSMessage>> constraintViolations = validator.validate(m);
+        Assert.isTrue(1 == constraintViolations.size());
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/ValidatorConfiguration.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/ValidatorConfiguration.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/ValidatorConfiguration.java
new file mode 100644
index 0000000..9e8779e
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/ValidatorConfiguration.java
@@ -0,0 +1,35 @@
+/**
+ * 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.test;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
+
+/**
+ * Builds a SimpleRoute to send a message to CM GW and CM Uri is built based on properties in a file.
+ */
+@Configuration("smsConfig")
+public class ValidatorConfiguration {
+
+    @Bean
+    public LocalValidatorFactoryBean getValidatorFactory() {
+        final LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
+        localValidatorFactoryBean.getValidationPropertyMap().put("hibernate.validator.fail_fast", "true");
+        return localValidatorFactoryBean;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/CMResponseExceptionSender.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/CMResponseExceptionSender.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/CMResponseExceptionSender.java
new file mode 100644
index 0000000..f116f28
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/CMResponseExceptionSender.java
@@ -0,0 +1,31 @@
+/**
+ * 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.test.mocks.cmsender;
+
+import org.apache.camel.component.cm.CMMessage;
+import org.apache.camel.component.cm.CMSender;
+import org.apache.camel.component.cm.exceptions.MessagingException;
+import org.apache.camel.component.cm.exceptions.cmresponse.CMResponseException;
+
+public class CMResponseExceptionSender implements CMSender {
+
+    @Override
+    public void send(CMMessage cmMessage) throws MessagingException {
+        throw new CMResponseException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InsufficientBalanceExceptionSender.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InsufficientBalanceExceptionSender.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InsufficientBalanceExceptionSender.java
new file mode 100644
index 0000000..03f940d
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InsufficientBalanceExceptionSender.java
@@ -0,0 +1,31 @@
+/**
+ * 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.test.mocks.cmsender;
+
+import org.apache.camel.component.cm.CMMessage;
+import org.apache.camel.component.cm.CMSender;
+import org.apache.camel.component.cm.exceptions.MessagingException;
+import org.apache.camel.component.cm.exceptions.cmresponse.InsufficientBalanceException;
+
+public class InsufficientBalanceExceptionSender implements CMSender {
+
+    @Override
+    public void send(CMMessage cmMessage) throws MessagingException {
+        throw new InsufficientBalanceException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InvalidMSISDNExceptionSender.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InvalidMSISDNExceptionSender.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InvalidMSISDNExceptionSender.java
new file mode 100644
index 0000000..b45d113
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InvalidMSISDNExceptionSender.java
@@ -0,0 +1,31 @@
+/**
+ * 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.test.mocks.cmsender;
+
+import org.apache.camel.component.cm.CMMessage;
+import org.apache.camel.component.cm.CMSender;
+import org.apache.camel.component.cm.exceptions.MessagingException;
+import org.apache.camel.component.cm.exceptions.cmresponse.InvalidMSISDNException;
+
+public class InvalidMSISDNExceptionSender implements CMSender {
+
+    @Override
+    public void send(CMMessage cmMessage) throws MessagingException {
+        throw new InvalidMSISDNException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InvalidProductTokenExceptionSender.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InvalidProductTokenExceptionSender.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InvalidProductTokenExceptionSender.java
new file mode 100644
index 0000000..7ff256c
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/InvalidProductTokenExceptionSender.java
@@ -0,0 +1,31 @@
+/**
+ * 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.test.mocks.cmsender;
+
+import org.apache.camel.component.cm.CMMessage;
+import org.apache.camel.component.cm.CMSender;
+import org.apache.camel.component.cm.exceptions.MessagingException;
+import org.apache.camel.component.cm.exceptions.cmresponse.InvalidProductTokenException;
+
+public class InvalidProductTokenExceptionSender implements CMSender {
+
+    @Override
+    public void send(CMMessage cmMessage) throws MessagingException {
+        throw new InvalidProductTokenException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NoAccountFoundForProductTokenExceptionSender.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NoAccountFoundForProductTokenExceptionSender.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NoAccountFoundForProductTokenExceptionSender.java
new file mode 100644
index 0000000..8b57406
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NoAccountFoundForProductTokenExceptionSender.java
@@ -0,0 +1,31 @@
+/**
+ * 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.test.mocks.cmsender;
+
+import org.apache.camel.component.cm.CMMessage;
+import org.apache.camel.component.cm.CMSender;
+import org.apache.camel.component.cm.exceptions.MessagingException;
+import org.apache.camel.component.cm.exceptions.cmresponse.NoAccountFoundForProductTokenException;
+
+public class NoAccountFoundForProductTokenExceptionSender implements CMSender {
+
+    @Override
+    public void send(CMMessage cmMessage) throws MessagingException {
+        throw new NoAccountFoundForProductTokenException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NoMessageExceptionSender.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NoMessageExceptionSender.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NoMessageExceptionSender.java
new file mode 100644
index 0000000..9520934
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NoMessageExceptionSender.java
@@ -0,0 +1,31 @@
+/**
+ * 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.test.mocks.cmsender;
+
+import org.apache.camel.component.cm.CMMessage;
+import org.apache.camel.component.cm.CMSender;
+import org.apache.camel.component.cm.exceptions.MessagingException;
+import org.apache.camel.component.cm.exceptions.cmresponse.NoMessageException;
+
+public class NoMessageExceptionSender implements CMSender {
+
+    @Override
+    public void send(CMMessage cmMessage) throws MessagingException {
+        throw new NoMessageException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NotPhoneNumberFoundExceptionSender.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NotPhoneNumberFoundExceptionSender.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NotPhoneNumberFoundExceptionSender.java
new file mode 100644
index 0000000..a85639b
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/NotPhoneNumberFoundExceptionSender.java
@@ -0,0 +1,31 @@
+/**
+ * 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.test.mocks.cmsender;
+
+import org.apache.camel.component.cm.CMMessage;
+import org.apache.camel.component.cm.CMSender;
+import org.apache.camel.component.cm.exceptions.MessagingException;
+import org.apache.camel.component.cm.exceptions.cmresponse.NotPhoneNumberFoundException;
+
+public class NotPhoneNumberFoundExceptionSender implements CMSender {
+
+    @Override
+    public void send(CMMessage cmMessage) throws MessagingException {
+        throw new NotPhoneNumberFoundException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/UnknownErrorExceptionSender.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/UnknownErrorExceptionSender.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/UnknownErrorExceptionSender.java
new file mode 100644
index 0000000..d20723f
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/UnknownErrorExceptionSender.java
@@ -0,0 +1,31 @@
+/**
+ * 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.test.mocks.cmsender;
+
+import org.apache.camel.component.cm.CMMessage;
+import org.apache.camel.component.cm.CMSender;
+import org.apache.camel.component.cm.exceptions.MessagingException;
+import org.apache.camel.component.cm.exceptions.cmresponse.UnknownErrorException;
+
+public class UnknownErrorExceptionSender implements CMSender {
+
+    @Override
+    public void send(CMMessage cmMessage) throws MessagingException {
+        throw new UnknownErrorException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/UnroutableMessageExceptionSender.java
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/UnroutableMessageExceptionSender.java b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/UnroutableMessageExceptionSender.java
new file mode 100644
index 0000000..3b6af1e
--- /dev/null
+++ b/components/camel-cm/src/test/java/org/apache/camel/component/cm/test/mocks/cmsender/UnroutableMessageExceptionSender.java
@@ -0,0 +1,31 @@
+/**
+ * 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.test.mocks.cmsender;
+
+import org.apache.camel.component.cm.CMMessage;
+import org.apache.camel.component.cm.CMSender;
+import org.apache.camel.component.cm.exceptions.MessagingException;
+import org.apache.camel.component.cm.exceptions.cmresponse.UnroutableMessageException;
+
+public class UnroutableMessageExceptionSender implements CMSender {
+
+    @Override
+    public void send(CMMessage cmMessage) throws MessagingException {
+        throw new UnroutableMessageException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/camel-cm/src/test/resources/cm-smsgw.properties
----------------------------------------------------------------------
diff --git a/components/camel-cm/src/test/resources/cm-smsgw.properties b/components/camel-cm/src/test/resources/cm-smsgw.properties
new file mode 100644
index 0000000..9393fa9
--- /dev/null
+++ b/components/camel-cm/src/test/resources/cm-smsgw.properties
@@ -0,0 +1,28 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# DefaultSender
+cm.default-sender=MyBusiness
+
+# CM URL
+# https://dashboard.onlinesmsgateway.com/docs#send-a-message-send-a-message
+cm.url=sgw01.cm.nl/gateway.ashx
+
+# UUID as STRING
+cm.product-token=ea723fd7-da81-4826-89bc-fa7144e71c40
+
+cm.testConnectionOnStartup=true
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/components/pom.xml
----------------------------------------------------------------------
diff --git a/components/pom.xml b/components/pom.xml
index 4fdb948..1cc2241 100644
--- a/components/pom.xml
+++ b/components/pom.xml
@@ -81,6 +81,7 @@
     <module>camel-castor</module>
     <module>camel-cdi</module>
     <module>camel-chunk</module>
+	<module>camel-cm</module>
     <module>camel-cmis</module>
     <module>camel-coap</module>
     <module>camel-cometd</module>

http://git-wip-us.apache.org/repos/asf/camel/blob/c70e9db8/parent/pom.xml
----------------------------------------------------------------------
diff --git a/parent/pom.xml b/parent/pom.xml
index 9475392..dca9b67 100644
--- a/parent/pom.xml
+++ b/parent/pom.xml
@@ -125,6 +125,8 @@
     <commons-net-version>3.3</commons-net-version>
     <commons-pool-version>1.6</commons-pool-version>
     <commons-pool2-version>2.4.2</commons-pool2-version>
+    <commons-pool2-version>2.4.1</commons-pool2-version>
+	<commons-validator-version>1.5.0</commons-validator-version>
     <commons-vfs2-version>2.0</commons-vfs2-version>
     <compress-lzf-version>1.0.3</compress-lzf-version>
     <concurrentlinkedhashmap.version>1.4.2</concurrentlinkedhashmap.version>
@@ -335,6 +337,7 @@
     <json-path-version>2.1.0</json-path-version>
     <json-simple-version>1.1.1</json-simple-version>
     <json-smart-version>2.2.1</json-smart-version>
+	<jsoup-version>1.8.3</jsoup-version>
     <jsp-api-2.1-version>1.0.1</jsp-api-2.1-version>
     <jsr311-api-version>1.1.1</jsr311-api-version>
     <jsmpp-bundle-version>2.1.0_4</jsmpp-bundle-version>
@@ -358,6 +361,7 @@
     <kubernetes-model-version>1.0.43</kubernetes-model-version>
     <kxml2-bundle-version>2.3.0_3</kxml2-bundle-version>
     <leveldbjni-version>1.8</leveldbjni-version>
+	<libphonenumber-version>7.2.7</libphonenumber-version>
     <!-- virtual dependency only used by Eclipse m2e -->
     <lifecycle-mapping-version>1.0.0</lifecycle-mapping-version>
     <log4j-version>1.2.17</log4j-version>