CAMEL-7619: Rest DSL - adding support for xml/json binding using Camel's data 
formats.


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

Branch: refs/heads/master
Commit: bca60fe04d19399db2b348c1eeb9c2fede2562db
Parents: 2e6347f
Author: Claus Ibsen <davscl...@apache.org>
Authored: Mon Jul 28 10:47:56 2014 +0200
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Mon Jul 28 10:50:49 2014 +0200

----------------------------------------------------------------------
 .../processor/binding/RestBindingProcessor.java | 108 ++++++++++---------
 .../RestRestletBindingModeAutoWithJsonTest.java |  61 +++++++++++
 .../RestRestletBindingModeAutoWithXmlTest.java  |  61 +++++++++++
 3 files changed, 182 insertions(+), 48 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/bca60fe0/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
 
b/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
index b6ecbb4..0ae78d8 100644
--- 
a/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
+++ 
b/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
@@ -43,8 +43,8 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
 
     private final AsyncProcessor jsonUnmarshal;
     private final AsyncProcessor xmlUnmarshal;
-    private final AsyncProcessor jsonMmarshal;
-    private final AsyncProcessor xmlMmarshal;
+    private final AsyncProcessor jsonMarshal;
+    private final AsyncProcessor xmlMarshal;
     private final String consumes;
     private final String produces;
     private final String bindingMode;
@@ -59,11 +59,11 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
             this.jsonUnmarshal = null;
         }
         if (outJsonDataFormat != null) {
-            this.jsonMmarshal = new MarshalProcessor(outJsonDataFormat);
+            this.jsonMarshal = new MarshalProcessor(outJsonDataFormat);
         } else if (jsonDataFormat != null) {
-            this.jsonMmarshal = new MarshalProcessor(jsonDataFormat);
+            this.jsonMarshal = new MarshalProcessor(jsonDataFormat);
         } else {
-            this.jsonMmarshal = null;
+            this.jsonMarshal = null;
         }
 
         if (xmlDataFormat != null) {
@@ -72,11 +72,11 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
             this.xmlUnmarshal = null;
         }
         if (outXmlDataFormat != null) {
-            this.xmlMmarshal = new MarshalProcessor(outXmlDataFormat);
+            this.xmlMarshal = new MarshalProcessor(outXmlDataFormat);
         } else if (xmlDataFormat != null) {
-            this.xmlMmarshal = new MarshalProcessor(xmlDataFormat);
+            this.xmlMarshal = new MarshalProcessor(xmlDataFormat);
         } else {
-            this.xmlMmarshal = null;
+            this.xmlMarshal = null;
         }
 
         this.consumes = consumes;
@@ -90,7 +90,6 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
     }
 
     // TODO: consumes/produces can be a list of media types, and prioritized 
1st to last.
-    // TODO: parsing body should only be done if really needed
 
     @Override
     public boolean process(Exchange exchange, final AsyncCallback callback) {
@@ -128,28 +127,37 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
             isJson = consumes != null && 
consumes.toLowerCase(Locale.US).contains("json");
         }
 
-        // we have binding enabled, so we need to know if there body is empty 
or not\
-        // so force reading the body as a String which we can work with
-        String body = MessageHelper.extractBodyAsString(exchange.getIn());
-        if (body != null) {
-            exchange.getIn().setBody(body);
+        // only allow xml/json if the binding mode allows that
+        isXml &= bindingMode.equals("auto") || bindingMode.contains("xml");
+        isJson &= bindingMode.equals("auto") || bindingMode.contains("json");
+
+        // if we do not yet know if its xml or json, then use the binding mode 
to know the mode
+        if (!isJson && !isXml) {
+            isXml = bindingMode.equals("auto") || bindingMode.contains("xml");
+            isJson = bindingMode.equals("auto") || 
bindingMode.contains("json");
         }
 
-        // if we do not know if its xml/json then try check if the body is xml
-        if (!isXml && !isJson || isXml && isJson) {
+        // okay we have a binding mode, so need to check for empty body as 
that can cause the marshaller to fail
+        // as they assume a non-empty body
+        String body = null;
+        if (isXml || isJson) {
+            // we have binding enabled, so we need to know if there body is 
empty or not\
+            // so force reading the body as a String which we can work with
+            body = MessageHelper.extractBodyAsString(exchange.getIn());
             if (body != null) {
-                isXml = body.startsWith("<");
-                isJson = !isXml;
+                exchange.getIn().setBody(body);
+
+                if (isXml && isJson) {
+                    // we have still not determined between xml or json, so 
check the body if its xml based or not
+                    isXml = body.startsWith("<");
+                    isJson = !isXml;
+                }
             }
         }
 
-        // only allow xml/json if the binding mode allows that
-        isXml &= bindingMode.equals("auto") || bindingMode.contains("xml");
-        isJson &= bindingMode.equals("auto") || bindingMode.contains("json");
-
-        if (isXml && xmlUnmarshal != null) {
+       if (isXml && xmlUnmarshal != null) {
             // add reverse operation
-            exchange.addOnCompletion(new 
RestBindingMarshalOnCompletion(exchange.getFromRouteId(), jsonMmarshal, 
xmlMmarshal));
+            exchange.addOnCompletion(new 
RestBindingMarshalOnCompletion(exchange.getFromRouteId(), jsonMarshal, 
xmlMarshal, true));
             if (ObjectHelper.isNotEmpty(body)) {
                 return xmlUnmarshal.process(exchange, callback);
             } else {
@@ -158,7 +166,7 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
             }
         } else if (isJson && jsonUnmarshal != null) {
             // add reverse operation
-            exchange.addOnCompletion(new 
RestBindingMarshalOnCompletion(exchange.getFromRouteId(), jsonMmarshal, 
xmlMmarshal));
+            exchange.addOnCompletion(new 
RestBindingMarshalOnCompletion(exchange.getFromRouteId(), jsonMarshal, 
xmlMarshal, false));
             if (ObjectHelper.isNotEmpty(body)) {
                 return jsonUnmarshal.process(exchange, callback);
             } else {
@@ -204,14 +212,16 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
      */
     private final class RestBindingMarshalOnCompletion extends 
SynchronizationAdapter {
 
-        private final AsyncProcessor jsonMmarshal;
-        private final AsyncProcessor xmlMmarshal;
+        private final AsyncProcessor jsonMarshal;
+        private final AsyncProcessor xmlMarshal;
         private final String routeId;
+        private boolean wasXml;
 
-        private RestBindingMarshalOnCompletion(String routeId, AsyncProcessor 
jsonMmarshal, AsyncProcessor xmlMmarshal) {
+        private RestBindingMarshalOnCompletion(String routeId, AsyncProcessor 
jsonMarshal, AsyncProcessor xmlMarshal, boolean wasXml) {
             this.routeId = routeId;
-            this.jsonMmarshal = jsonMmarshal;
-            this.xmlMmarshal = xmlMmarshal;
+            this.jsonMarshal = jsonMarshal;
+            this.xmlMarshal = xmlMarshal;
+            this.wasXml = wasXml;
         }
 
         @Override
@@ -235,7 +245,7 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
             }
 
             // is there any marshaller at all
-            if (jsonMmarshal == null && xmlMmarshal == null) {
+            if (jsonMarshal == null && xmlMarshal == null) {
                 return;
             }
 
@@ -259,28 +269,30 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
                 isJson = produces != null && 
produces.toLowerCase(Locale.US).contains("json");
             }
 
-            // need to prepare exchange first
-            ExchangeHelper.prepareOutToIn(exchange);
-
-            // if we do not know explicit if its json or xml, then need to 
check the message body to be sure what it is
-            if (!isXml && !isJson || isXml && isJson) {
-                // read the content into memory so we can determine if its xml 
or json
-                String body = 
MessageHelper.extractBodyAsString(exchange.getIn());
-                if (body != null) {
-                    isXml = body.startsWith("<");
-                    isJson = !isXml;
-                }
-            }
-
             // only allow xml/json if the binding mode allows that
             isXml &= bindingMode.equals("auto") || bindingMode.contains("xml");
             isJson &= bindingMode.equals("auto") || 
bindingMode.contains("json");
 
+            // if we do not yet know if its xml or json, then use the binding 
mode to know the mode
+            if (!isJson && !isXml) {
+                isXml = bindingMode.equals("auto") || 
bindingMode.contains("xml");
+                isJson = bindingMode.equals("auto") || 
bindingMode.contains("json");
+            }
+
+            // in case we have not yet been able to determine if xml or json, 
then use the same as in the unmarshaller
+            if (isXml && isJson) {
+                isXml = wasXml;
+                isJson = !wasXml;
+            }
+
+            // need to prepare exchange first
+            ExchangeHelper.prepareOutToIn(exchange);
+
             try {
-                if (isXml && xmlMmarshal != null) {
-                    xmlMmarshal.process(exchange);
-                } else if (isJson && jsonMmarshal != null) {
-                    jsonMmarshal.process(exchange);
+                if (isXml && xmlMarshal != null) {
+                    xmlMarshal.process(exchange);
+                } else if (isJson && jsonMarshal != null) {
+                    jsonMarshal.process(exchange);
                 } else {
                     // we could not bind
                     if (bindingMode.equals("auto")) {

http://git-wip-us.apache.org/repos/asf/camel/blob/bca60fe0/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeAutoWithJsonTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeAutoWithJsonTest.java
 
b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeAutoWithJsonTest.java
new file mode 100644
index 0000000..33427c6
--- /dev/null
+++ 
b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeAutoWithJsonTest.java
@@ -0,0 +1,61 @@
+/**
+ * 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.restlet;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.junit.Test;
+
+/**
+ * @version 
+ */
+public class RestRestletBindingModeAutoWithJsonTest extends RestletTestSupport 
{
+
+    @Test
+    public void testBindingMode() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:input");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(UserPojo.class);
+
+        String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+        template.sendBody("http://localhost:"; + portNum + "/users/new", body);
+
+        assertMockEndpointsSatisfied();
+
+        UserPojo user = 
mock.getReceivedExchanges().get(0).getIn().getBody(UserPojo.class);
+        assertNotNull(user);
+        assertEquals(123, user.getId());
+        assertEquals("Donald Duck", user.getName());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // binding mode is json only
+                
restConfiguration().component("restlet").host("localhost").port(portNum).bindingMode(RestBindingMode.auto);
+
+                // use the rest DSL to define the rest services
+                rest("/users/")
+                    
.post("new").consumes("application/json").type(UserPojo.class)
+                        .to("mock:input");
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/bca60fe0/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeAutoWithXmlTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeAutoWithXmlTest.java
 
b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeAutoWithXmlTest.java
new file mode 100644
index 0000000..29779d5
--- /dev/null
+++ 
b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeAutoWithXmlTest.java
@@ -0,0 +1,61 @@
+/**
+ * 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.restlet;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.junit.Test;
+
+/**
+ * @version 
+ */
+public class RestRestletBindingModeAutoWithXmlTest extends RestletTestSupport {
+
+    @Test
+    public void testBindingMode() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:input");
+        mock.expectedMessageCount(1);
+        mock.message(0).body().isInstanceOf(UserJaxbPojo.class);
+
+        String body = "<user name=\"Donald Duck\" id=\"123\"></user>";
+        template.sendBody("http://localhost:"; + portNum + "/users/new", body);
+
+        assertMockEndpointsSatisfied();
+
+        UserJaxbPojo user = 
mock.getReceivedExchanges().get(0).getIn().getBody(UserJaxbPojo.class);
+        assertNotNull(user);
+        assertEquals(123, user.getId());
+        assertEquals("Donald Duck", user.getName());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // binding mode is json only
+                
restConfiguration().component("restlet").host("localhost").port(portNum).bindingMode(RestBindingMode.auto);
+
+                // use the rest DSL to define the rest services
+                rest("/users/")
+                    
.post("new").consumes("application/xml").type(UserJaxbPojo.class)
+                        .to("mock:input");
+            }
+        };
+    }
+}

Reply via email to