Repository: camel
Updated Branches:
  refs/heads/master 4cca8a864 -> cae408e0d


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


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

Branch: refs/heads/master
Commit: 2d38cd3044681d8c78577933b1b13cc60c8e32c8
Parents: 4cca8a8
Author: Claus Ibsen <davscl...@apache.org>
Authored: Fri Jul 25 10:41:28 2014 +0200
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Fri Jul 25 11:20:54 2014 +0200

----------------------------------------------------------------------
 .../camel/model/rest/RestBindingDefinition.java | 83 ++++++++++++++++++--
 .../apache/camel/model/rest/RestDefinition.java | 50 ++++++++++++
 .../apache/camel/model/rest/VerbDefinition.java | 48 +++++++++++
 .../processor/binding/RestBindingProcessor.java | 47 +++++++++--
 .../component/restlet/RestletComponent.java     | 11 +++
 .../restlet/RestRestletPojoInOutTest.java       |  2 +-
 .../restlet/SpringRestRestletPojoInOutTest.java | 53 +++++++++++++
 .../restlet/SpringRestRestletPojoInOutTest.xml  | 46 +++++++++++
 8 files changed, 328 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/2d38cd30/camel-core/src/main/java/org/apache/camel/model/rest/RestBindingDefinition.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/model/rest/RestBindingDefinition.java
 
b/camel-core/src/main/java/org/apache/camel/model/rest/RestBindingDefinition.java
index 229cf6f..5ffb068 100644
--- 
a/camel-core/src/main/java/org/apache/camel/model/rest/RestBindingDefinition.java
+++ 
b/camel-core/src/main/java/org/apache/camel/model/rest/RestBindingDefinition.java
@@ -26,7 +26,6 @@ import javax.xml.bind.annotation.XmlTransient;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Processor;
 import org.apache.camel.model.NoOutputDefinition;
-import org.apache.camel.model.ProcessorDefinition;
 import org.apache.camel.processor.binding.RestBindingProcessor;
 import org.apache.camel.spi.DataFormat;
 import org.apache.camel.spi.RouteContext;
@@ -64,6 +63,18 @@ public class RestBindingDefinition extends 
NoOutputDefinition {
     @XmlTransient
     private boolean useList;
 
+    @XmlAttribute
+    private String outType;
+
+    @XmlAttribute
+    private String outTypeList;
+
+    @XmlTransient
+    private Class<?> outClassType;
+
+    @XmlTransient
+    private boolean outUseList;
+
     @Override
     public String toString() {
         return "RestBinding";
@@ -85,14 +96,12 @@ public class RestBindingDefinition extends 
NoOutputDefinition {
 
         CamelContext context = routeContext.getCamelContext();
 
-        // the default binding mode can be overriden per rest verb
+        // the default binding mode can be overridden per rest verb
         String mode = context.getRestConfiguration().getBindingMode().name();
         if (bindingMode != null) {
             mode = bindingMode.name();
         }
 
-        // auto, off, json, xml, json_xml
-
         // setup json data format
         String name = jsonDataFormat;
         if (name == null) {
@@ -116,6 +125,19 @@ public class RestBindingDefinition extends 
NoOutputDefinition {
         }
         context.addService(json);
 
+        DataFormat outJson = context.resolveDataFormat(name);
+        if (outClassType == null && outType != null) {
+            outClassType = 
context.getClassResolver().resolveMandatoryClass(outType);
+        }
+        if (outClassType == null && outTypeList != null) {
+            outClassType = 
context.getClassResolver().resolveMandatoryClass(outTypeList);
+        }
+        if (outClassType != null) {
+            IntrospectionSupport.setProperty(context.getTypeConverter(), 
outJson, "unmarshalType", outClassType);
+            IntrospectionSupport.setProperty(context.getTypeConverter(), 
outJson, "useList", outUseList);
+        }
+        context.addService(outJson);
+
         // setup xml data format
         name = xmlDataFormat;
         if (name == null) {
@@ -138,7 +160,24 @@ public class RestBindingDefinition extends 
NoOutputDefinition {
         }
         context.addService(jaxb);
 
-        return new RestBindingProcessor(json, jaxb, consumes, produces, mode);
+        DataFormat outJaxb = context.resolveDataFormat(name);
+        if (outClassType == null && outType != null) {
+            outClassType = 
context.getClassResolver().resolveMandatoryClass(outType);
+        }
+        if (outClassType == null && outTypeList != null) {
+            outClassType = 
context.getClassResolver().resolveMandatoryClass(outTypeList);
+        }
+        if (outClassType != null) {
+            JAXBContext jc = JAXBContext.newInstance(outClassType);
+            IntrospectionSupport.setProperty(context.getTypeConverter(), 
outJaxb, "context", jc);
+        } else if (classType != null) {
+            // fallback and use the context from the input
+            JAXBContext jc = JAXBContext.newInstance(classType);
+            IntrospectionSupport.setProperty(context.getTypeConverter(), 
outJaxb, "context", jc);
+        }
+        context.addService(outJaxb);
+
+        return new RestBindingProcessor(json, jaxb, outJson, outJaxb, 
consumes, produces, mode);
     }
 
     public String getConsumes() {
@@ -215,4 +254,38 @@ public class RestBindingDefinition extends 
NoOutputDefinition {
         this.useList = useList;
     }
 
+    public String getOutType() {
+        return outType;
+    }
+
+    public void setOutType(String type) {
+        this.outType = type;
+        this.outUseList = false;
+    }
+
+    public String getOutTypeList() {
+        return outTypeList;
+    }
+
+    public void setOutTypeList(String typeList) {
+        this.outTypeList = typeList;
+        this.outUseList = true;
+    }
+
+    public Class<?> getOutClassType() {
+        return outClassType;
+    }
+
+    public void setOutClassType(Class<?> classType) {
+        this.outClassType = classType;
+    }
+
+    public boolean isOutUseList() {
+        return outUseList;
+    }
+
+    public void setOutUseList(boolean useList) {
+        this.outUseList = useList;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/2d38cd30/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java 
b/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java
index 52947a5..d81a564 100644
--- a/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java
@@ -189,6 +189,52 @@ public class RestDefinition {
         return this;
     }
 
+    public RestDefinition outType(String classType) {
+        // add to last verb
+        if (getVerbs().isEmpty()) {
+            throw new IllegalArgumentException("Must add verb first, such as 
get/post/delete");
+        }
+
+        VerbDefinition verb = getVerbs().get(getVerbs().size() - 1);
+        verb.setOutType(classType);
+        return this;
+    }
+
+    public RestDefinition outType(Class<?> classType) {
+        // add to last verb
+        if (getVerbs().isEmpty()) {
+            throw new IllegalArgumentException("Must add verb first, such as 
get/post/delete");
+        }
+
+        VerbDefinition verb = getVerbs().get(getVerbs().size() - 1);
+        verb.setOutClassType(classType);
+        verb.setOutType(classType.getCanonicalName());
+        return this;
+    }
+
+    public RestDefinition outTypeList(String classType) {
+        // add to last verb
+        if (getVerbs().isEmpty()) {
+            throw new IllegalArgumentException("Must add verb first, such as 
get/post/delete");
+        }
+
+        VerbDefinition verb = getVerbs().get(getVerbs().size() - 1);
+        verb.setOutTypeList(classType);
+        return this;
+    }
+
+    public RestDefinition outTypeList(Class<?> classType) {
+        // add to last verb
+        if (getVerbs().isEmpty()) {
+            throw new IllegalArgumentException("Must add verb first, such as 
get/post/delete");
+        }
+
+        VerbDefinition verb = getVerbs().get(getVerbs().size() - 1);
+        verb.setOutClassType(classType);
+        verb.setOutTypeList(classType.getCanonicalName());
+        return this;
+    }
+
     public RestDefinition bindingMode(RestBindingMode mode) {
         // add to last verb
         if (getVerbs().isEmpty()) {
@@ -298,6 +344,10 @@ public class RestDefinition {
                 binding.setTypeList(verb.getTypeList());
                 binding.setClassType(verb.getClassType());
                 binding.setUseList(verb.isUseList());
+                binding.setOutType(verb.getOutType());
+                binding.setOutTypeList(verb.getOutTypeList());
+                binding.setOutClassType(verb.getOutClassType());
+                binding.setOutUseList(verb.isOutUseList());
                 binding.setConsumes(verb.getConsumes());
                 binding.setProduces(verb.getProduces());
                 binding.setBindingMode(verb.getBindingMode());

http://git-wip-us.apache.org/repos/asf/camel/blob/2d38cd30/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
----------------------------------------------------------------------
diff --git 
a/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java 
b/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
index c2bc7fd..1032772 100644
--- a/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
@@ -53,12 +53,24 @@ public class VerbDefinition {
     @XmlAttribute
     private String typeList;
 
+    @XmlAttribute
+    private String outType;
+
+    @XmlAttribute
+    private String outTypeList;
+
     @XmlTransient
     private Class<?> classType;
 
     @XmlTransient
+    private Class<?> outClassType;
+
+    @XmlTransient
     private boolean useList;
 
+    @XmlTransient
+    private boolean outUseList;
+
     // used by XML DSL to either select a <to> or <route>
     // so we need to use the common type OptionalIdentifiedDefinition
     @XmlElements({
@@ -151,6 +163,42 @@ public class VerbDefinition {
         return useList;
     }
 
+    public String getOutType() {
+        return outType;
+    }
+
+    public void setOutType(String type) {
+        this.outType = type;
+        this.outUseList = false;
+    }
+
+    public String getOutTypeList() {
+        return outTypeList;
+    }
+
+    public void setOutTypeList(String typeList) {
+        this.outTypeList = typeList;
+        this.outUseList = true;
+    }
+
+    public Class<?> getOutClassType() {
+        return outClassType;
+    }
+
+    public void setOutClassType(Class<?> classType) {
+        this.outClassType = classType;
+        this.outUseList = false;
+    }
+
+    public void setOutListClassType(Class<?> classType) {
+        this.outClassType = classType;
+        this.outUseList = true;
+    }
+
+    public boolean isOutUseList() {
+        return outUseList;
+    }
+
     public RestDefinition getRest() {
         return rest;
     }

http://git-wip-us.apache.org/repos/asf/camel/blob/2d38cd30/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 630210b..7560348 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
@@ -47,11 +47,36 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
     private final String produces;
     private final String bindingMode;
 
-    public RestBindingProcessor(DataFormat jsonDataFormat, DataFormat 
xmlDataFormat, String consumes, String produces, String bindingMode) {
-        this.jsonUnmarshal = jsonDataFormat != null ? new 
UnmarshalProcessor(jsonDataFormat) : null;
-        this.jsonMmarshal = jsonDataFormat != null ? new 
MarshalProcessor(jsonDataFormat) : null;
-        this.xmlUnmarshal = xmlDataFormat != null ? new 
UnmarshalProcessor(xmlDataFormat) : null;
-        this.xmlMmarshal = xmlDataFormat != null ? new 
MarshalProcessor(xmlDataFormat) : null;
+    public RestBindingProcessor(DataFormat jsonDataFormat, DataFormat 
xmlDataFormat,
+                                DataFormat outJsonDataFormat, DataFormat 
outXmlDataFormat,
+                                String consumes, String produces, String 
bindingMode) {
+
+        if (jsonDataFormat != null) {
+            this.jsonUnmarshal = new UnmarshalProcessor(jsonDataFormat);
+        } else {
+            this.jsonUnmarshal = null;
+        }
+        if (outJsonDataFormat != null) {
+            this.jsonMmarshal = new MarshalProcessor(outJsonDataFormat);
+        } else if (jsonDataFormat != null) {
+            this.jsonMmarshal = new MarshalProcessor(jsonDataFormat);
+        } else {
+            this.jsonMmarshal = null;
+        }
+
+       if (xmlDataFormat != null) {
+            this.xmlUnmarshal = new UnmarshalProcessor(xmlDataFormat);
+        } else {
+            this.xmlUnmarshal = null;
+        }
+        if (outXmlDataFormat != null) {
+            this.xmlMmarshal = new MarshalProcessor(outXmlDataFormat);
+        } else if (xmlDataFormat != null) {
+            this.xmlMmarshal = new MarshalProcessor(xmlDataFormat);
+        } else {
+            this.xmlMmarshal = null;
+        }
+
         this.consumes = consumes;
         this.produces = produces;
         this.bindingMode = bindingMode;
@@ -163,7 +188,17 @@ public class RestBindingProcessor extends ServiceSupport 
implements AsyncProcess
 
         @Override
         public void onComplete(Exchange exchange) {
-            // only marshal if we succeeded
+            // only marshal if we succeeded (= onComplete)
+
+            if (bindingMode == null || "off".equals(bindingMode)) {
+                // binding is off
+                return;
+            }
+
+            // is there any marshaller at all
+            if (jsonMmarshal == null && xmlMmarshal == null) {
+                return;
+            }
 
             boolean isXml = false;
             boolean isJson = false;

http://git-wip-us.apache.org/repos/asf/camel/blob/2d38cd30/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletComponent.java
----------------------------------------------------------------------
diff --git 
a/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletComponent.java
 
b/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletComponent.java
index 4e50ea8..8707160 100644
--- 
a/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletComponent.java
+++ 
b/components/camel-restlet/src/main/java/org/apache/camel/component/restlet/RestletComponent.java
@@ -74,6 +74,7 @@ public class RestletComponent extends 
HeaderFilterStrategyComponent implements R
     private Boolean useForwardedForHeader;
     private Boolean reuseAddress;
     private boolean disableStreamCache;
+    private int port;
 
     public RestletComponent() {
         this(new Component());
@@ -108,6 +109,8 @@ public class RestletComponent extends 
HeaderFilterStrategyComponent implements R
         String host = u.getHost();
         if (u.getPort() > 0) {
             port = u.getPort();
+        } else {
+            port = this.port;
         }
 
         result.setProtocol(protocol);
@@ -489,6 +492,14 @@ public class RestletComponent extends 
HeaderFilterStrategyComponent implements R
         this.disableStreamCache = disableStreamCache;
     }
 
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
     @Override
     public Consumer createConsumer(CamelContext camelContext, Processor 
processor,
                                    String verb, String path, String consumes, 
Map<String, Object> parameters) throws Exception {

http://git-wip-us.apache.org/repos/asf/camel/blob/2d38cd30/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletPojoInOutTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletPojoInOutTest.java
 
b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletPojoInOutTest.java
index bb9e8ba..824e4e1 100644
--- 
a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletPojoInOutTest.java
+++ 
b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletPojoInOutTest.java
@@ -43,7 +43,7 @@ public class RestRestletPojoInOutTest extends 
RestletTestSupport {
 
                 // use the rest DSL to define the rest services
                 rest("/users/")
-                    .post("lives").type(UserPojo.class)
+                    
.post("lives").type(UserPojo.class).outType(CountryPojo.class)
                         .route()
                         .bean(new UserService(), "livesWhere");
             }

http://git-wip-us.apache.org/repos/asf/camel/blob/2d38cd30/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/SpringRestRestletPojoInOutTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/SpringRestRestletPojoInOutTest.java
 
b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/SpringRestRestletPojoInOutTest.java
new file mode 100644
index 0000000..d52099b
--- /dev/null
+++ 
b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/SpringRestRestletPojoInOutTest.java
@@ -0,0 +1,53 @@
+/**
+ * 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.test.AvailablePortFinder;
+import org.apache.camel.test.spring.CamelSpringTestSupport;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * @version 
+ */
+public class SpringRestRestletPojoInOutTest extends CamelSpringTestSupport {
+
+    protected static int portNum;
+
+    @BeforeClass
+    public static void initializePortNum() {
+        portNum = AvailablePortFinder.getNextAvailable();
+        System.getProperties().setProperty("test.port", "" + portNum);
+    }
+
+    @Override
+    protected AbstractApplicationContext createApplicationContext() {
+        return new 
ClassPathXmlApplicationContext("org/apache/camel/component/restlet/SpringRestRestletPojoInOutTest.xml");
+    }
+
+    @Test
+    public void testRestletPojoInOut() throws Exception {
+        String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+        String out = template.requestBody("http://localhost:"; + portNum + 
"/users/lives", body, String.class);
+
+        assertNotNull(out);
+        assertEquals("{\"iso\":\"EN\",\"country\":\"England\"}", out);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/2d38cd30/components/camel-restlet/src/test/resources/org/apache/camel/component/restlet/SpringRestRestletPojoInOutTest.xml
----------------------------------------------------------------------
diff --git 
a/components/camel-restlet/src/test/resources/org/apache/camel/component/restlet/SpringRestRestletPojoInOutTest.xml
 
b/components/camel-restlet/src/test/resources/org/apache/camel/component/restlet/SpringRestRestletPojoInOutTest.xml
new file mode 100644
index 0000000..5b2d6be
--- /dev/null
+++ 
b/components/camel-restlet/src/test/resources/org/apache/camel/component/restlet/SpringRestRestletPojoInOutTest.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+       <!--
+               Licensed to the Apache Software Foundation (ASF) under one or 
more
+               contributor license agreements. See the NOTICE file distributed 
with
+               this work for additional information regarding copyright 
ownership.
+               The ASF licenses this file to You under the Apache License, 
Version
+               2.0 (the "License"); you may not use this file except in 
compliance
+               with the License. You may obtain a copy of the License at
+               http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+               applicable law or agreed to in writing, software distributed 
under the
+               License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES 
OR
+               CONDITIONS OF ANY KIND, either express or implied. See the 
License for
+               the specific language governing permissions and limitations 
under the
+               License.
+       -->
+<beans xmlns="http://www.springframework.org/schema/beans";
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd
+
+      http://camel.apache.org/schema/spring 
http://camel.apache.org/schema/spring/camel-spring.xsd";>
+
+  <bean id="propertyPlaceholderConfigurer"
+        
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+    <property name="systemPropertiesModeName" 
value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
+    <property name="searchSystemEnvironment" value="true" />
+  </bean>
+
+  <bean id="restlet" 
class="org.apache.camel.component.restlet.RestletComponent">
+    <property name="port" value="${test.port}"/>
+  </bean>
+
+       <camelContext xmlns="http://camel.apache.org/schema/spring";>
+
+    <restConfiguration bindingMode="auto" component="restlet"/>
+
+    <rest uri="/users">
+      <post uri="/lives" type="org.apache.camel.component.restlet.UserPojo" 
outType="org.apache.camel.component.restlet.CountryPojo">
+        <route>
+          <bean beanType="org.apache.camel.component.restlet.UserService" 
method="livesWhere"/>
+        </route>
+      </post>
+    </rest>
+
+       </camelContext>
+
+</beans>
\ No newline at end of file

Reply via email to