Repository: camel Updated Branches: refs/heads/master c8f2e7ffb -> f8dd9c1c9
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/f8dd9c1c Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/f8dd9c1c Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/f8dd9c1c Branch: refs/heads/master Commit: f8dd9c1c98f11f0052430765ac6cac5d23584383 Parents: c8f2e7f Author: Claus Ibsen <davscl...@apache.org> Authored: Wed Jul 23 13:52:00 2014 +0200 Committer: Claus Ibsen <davscl...@apache.org> Committed: Wed Jul 23 13:52:00 2014 +0200 ---------------------------------------------------------------------- .../apache/camel/model/rest/RestDefinition.java | 4 +- .../processor/binding/RestBindingProcessor.java | 58 ++++++++++++++++++++ .../camel/component/restlet/CountryPojo.java | 39 +++++++++++++ .../restlet/RestRestletPojoInOutTest.java | 53 ++++++++++++++++++ .../camel/component/restlet/UserService.java | 33 +++++++++++ 5 files changed, 185 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/f8dd9c1c/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 dadd530..c163a1b 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 @@ -150,7 +150,7 @@ public class RestDefinition { VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); verb.setClassType(classType); - verb.setTypeList(classType.getCanonicalName()); + verb.setType(classType.getCanonicalName()); return this; } @@ -161,7 +161,7 @@ public class RestDefinition { } VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); - verb.setType(classType); + verb.setTypeList(classType); return this; } http://git-wip-us.apache.org/repos/asf/camel/blob/f8dd9c1c/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 a217c64..7bb9b39 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 @@ -21,21 +21,34 @@ import java.util.Locale; import org.apache.camel.AsyncCallback; import org.apache.camel.AsyncProcessor; import org.apache.camel.Exchange; +import org.apache.camel.processor.MarshalProcessor; import org.apache.camel.processor.UnmarshalProcessor; import org.apache.camel.spi.DataFormat; import org.apache.camel.support.ServiceSupport; +import org.apache.camel.support.SynchronizationAdapter; import org.apache.camel.util.AsyncProcessorHelper; import org.apache.camel.util.ExchangeHelper; import org.apache.camel.util.MessageHelper; +/** + * A {@link org.apache.camel.Processor} that binds the REST DSL incoming and outgoing messages + * from sources of json or xml to Java Objects. + * <p/> + * The binding uses {@link org.apache.camel.spi.DataFormat} for the actual work to transform + * from xml/json to Java Objects and reverse again. + */ public class RestBindingProcessor extends ServiceSupport implements AsyncProcessor { private final AsyncProcessor jsonUnmarshal; private final AsyncProcessor xmlUnmarshal; + private final AsyncProcessor jsonMmarshal; + private final AsyncProcessor xmlMmarshal; public RestBindingProcessor(DataFormat jsonDataFormat, DataFormat xmlDataFormat) { 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; } @Override @@ -56,8 +69,12 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess boolean isXml = contentType != null && contentType.toLowerCase(Locale.US).contains("xml"); boolean isJson = contentType != null && contentType.toLowerCase(Locale.US).contains("json"); if (isXml && xmlUnmarshal != null) { + // add reverse operation + exchange.addOnCompletion(new RestBindingMarshalOnCompletion(jsonMmarshal, xmlMmarshal, true)); return xmlUnmarshal.process(exchange, callback); } else if (isJson && jsonUnmarshal != null) { + // add reverse operation + exchange.addOnCompletion(new RestBindingMarshalOnCompletion(jsonMmarshal, xmlMmarshal, false)); return jsonUnmarshal.process(exchange, callback); } @@ -66,8 +83,12 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess isXml = body.startsWith("<") || body.contains("xml"); if (isXml && xmlUnmarshal != null) { + // add reverse operation + exchange.addOnCompletion(new RestBindingMarshalOnCompletion(jsonMmarshal, xmlMmarshal, true)); return xmlUnmarshal.process(exchange, callback); } else if (jsonUnmarshal != null) { + // add reverse operation + exchange.addOnCompletion(new RestBindingMarshalOnCompletion(jsonMmarshal, xmlMmarshal, false)); return jsonUnmarshal.process(exchange, callback); } else { // noop @@ -90,4 +111,41 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess protected void doStop() throws Exception { // noop } + + /** + * An {@link org.apache.camel.spi.Synchronization} that does the reverse operation + * of marshalling from POJO to json/xml + */ + private final class RestBindingMarshalOnCompletion extends SynchronizationAdapter { + + private final AsyncProcessor jsonMmarshal; + private final AsyncProcessor xmlMmarshal; + private final boolean wasXml; + + private RestBindingMarshalOnCompletion(AsyncProcessor jsonMmarshal, AsyncProcessor xmlMmarshal, boolean wasXml) { + this.jsonMmarshal = jsonMmarshal; + this.xmlMmarshal = xmlMmarshal; + this.wasXml = wasXml; + } + + @Override + public void onComplete(Exchange exchange) { + // only marshal if we succeeded + + // need to prepare exchange first + ExchangeHelper.prepareOutToIn(exchange); + + // TODO: add logic to detect what content-type is now + // also when we add support for @Produces then use that to determine if we should marshal to xml or json + try { + if (wasXml) { + xmlMmarshal.process(exchange); + } else { + jsonMmarshal.process(exchange); + } + } catch (Throwable e) { + exchange.setException(e); + } + } + } } http://git-wip-us.apache.org/repos/asf/camel/blob/f8dd9c1c/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/CountryPojo.java ---------------------------------------------------------------------- diff --git a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/CountryPojo.java b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/CountryPojo.java new file mode 100644 index 0000000..e20d3df --- /dev/null +++ b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/CountryPojo.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.restlet; + +public class CountryPojo { + + private String iso; + private String country; + + public String getIso() { + return iso; + } + + public void setIso(String iso) { + this.iso = iso; + } + + public String getCountry() { + return country; + } + + public void setCountry(String country) { + this.country = country; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/f8dd9c1c/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 new file mode 100644 index 0000000..bb9e8ba --- /dev/null +++ b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletPojoInOutTest.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.builder.RouteBuilder; +import org.junit.Test; + +/** + * @version + */ +public class RestRestletPojoInOutTest extends RestletTestSupport { + + @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); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + // configure to use restlet on localhost with the given port + restConfiguration().component("restlet").host("localhost").port(portNum); + + // use the rest DSL to define the rest services + rest("/users/") + .post("lives").type(UserPojo.class) + .route() + .bean(new UserService(), "livesWhere"); + } + }; + } + +} http://git-wip-us.apache.org/repos/asf/camel/blob/f8dd9c1c/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/UserService.java ---------------------------------------------------------------------- diff --git a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/UserService.java b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/UserService.java new file mode 100644 index 0000000..c1d8766 --- /dev/null +++ b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/UserService.java @@ -0,0 +1,33 @@ +/** + * 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; + +public class UserService { + + public CountryPojo livesWhere(UserPojo user) { + CountryPojo answer = new CountryPojo(); + if (user.getId() < 500) { + answer.setIso("EN"); + answer.setCountry("England"); + } else { + answer.setIso("SE"); + answer.setCountry("Sweden"); + } + return answer; + } + +}