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 2017/02/14 12:21:22 UTC
[1/3] camel git commit: CAMEL-10532 Convert
RestConsumerBindingProcessor into processor advice so it works fine with
contract advice together
Repository: camel
Updated Branches:
refs/heads/master 605710dd2 -> 8c9184b6f
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeJsonWithContractTest.java
----------------------------------------------------------------------
diff --git a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeJsonWithContractTest.java b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeJsonWithContractTest.java
new file mode 100644
index 0000000..b25aabd
--- /dev/null
+++ b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeJsonWithContractTest.java
@@ -0,0 +1,91 @@
+/**
+ * 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 java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestDefinition;
+import org.junit.Test;
+
+public class RestRestletBindingModeJsonWithContractTest extends RestletTestSupport {
+
+ @Test
+ public void testBindingModeJsonWithContract() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:input");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(UserPojoEx.class);
+
+ String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+ Object answer = template.requestBody("http://localhost:" + portNum + "/users/new", body);
+ assertNotNull(answer);
+ BufferedReader reader = new BufferedReader(new InputStreamReader((InputStream)answer));
+ String line;
+ String answerString = "";
+ while ((line = reader.readLine()) != null) {
+ answerString += line;
+ }
+ assertTrue("Unexpected response: " + answerString, answerString.contains("\"active\":true"));
+
+ assertMockEndpointsSatisfied();
+
+ Object obj = mock.getReceivedExchanges().get(0).getIn().getBody();
+ assertEquals(UserPojoEx.class, obj.getClass());
+ UserPojoEx user = (UserPojoEx)obj;
+ assertNotNull(user);
+ assertEquals(123, user.getId());
+ assertEquals("Donald Duck", user.getName());
+ assertEquals(true, user.isActive());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ context.getTypeConverterRegistry().addTypeConverters(new MyTypeConverters());
+ restConfiguration().component("restlet").host("localhost").port(portNum).bindingMode(RestBindingMode.json);
+
+ rest("/users/")
+ // REST binding converts from JSON to UserPojo
+ .post("new").type(UserPojo.class)
+ .route()
+ // then contract advice converts from UserPojo to UserPojoEx
+ .inputType(UserPojoEx.class)
+ .to("mock:input");
+ }
+ };
+ }
+
+ public static class MyTypeConverters implements TypeConverters {
+ @Converter
+ public UserPojoEx toEx(UserPojo user) {
+ UserPojoEx ex = new UserPojoEx();
+ ex.setId(user.getId());
+ ex.setName(user.getName());
+ ex.setActive(true);
+ return ex;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeOffWithContractTest.java
----------------------------------------------------------------------
diff --git a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeOffWithContractTest.java b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeOffWithContractTest.java
new file mode 100644
index 0000000..98bae98
--- /dev/null
+++ b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletBindingModeOffWithContractTest.java
@@ -0,0 +1,98 @@
+/**
+ * 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 java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.dataformat.JsonDataFormat;
+import org.apache.camel.model.dataformat.JsonLibrary;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestDefinition;
+import org.junit.Test;
+
+public class RestRestletBindingModeOffWithContractTest extends RestletTestSupport {
+
+ @Test
+ public void testBindingModeOffWithContract() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:input");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(UserPojoEx.class);
+
+ String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+ Object answer = template.requestBodyAndHeader("http://localhost:" + portNum + "/users/new", body, Exchange.CONTENT_TYPE, "application/json");
+ assertNotNull(answer);
+ BufferedReader reader = new BufferedReader(new InputStreamReader((InputStream)answer));
+ String line;
+ String answerString = "";
+ while ((line = reader.readLine()) != null) {
+ answerString += line;
+ }
+ assertTrue("Unexpected response: " + answerString, answerString.contains("\"active\":true"));
+
+ assertMockEndpointsSatisfied();
+
+ Object obj = mock.getReceivedExchanges().get(0).getIn().getBody();
+ assertEquals(UserPojoEx.class, obj.getClass());
+ UserPojoEx user = (UserPojoEx)obj;
+ assertNotNull(user);
+ assertEquals(123, user.getId());
+ assertEquals("Donald Duck", user.getName());
+ assertEquals(true, user.isActive());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ restConfiguration().component("restlet").host("localhost").port(portNum).bindingMode(RestBindingMode.off);
+
+ JsonDataFormat jsondf = new JsonDataFormat();
+ jsondf.setLibrary(JsonLibrary.Jackson);
+ jsondf.setAllowUnmarshallType(true);
+ jsondf.setUnmarshalType(UserPojoEx.class);
+ transformer()
+ .fromType("json")
+ .toType(UserPojoEx.class)
+ .withDataFormat(jsondf);
+ transformer()
+ .fromType(UserPojoEx.class)
+ .toType("json")
+ .withDataFormat(jsondf);
+ rest("/users/")
+ // REST binding does nothing
+ .post("new")
+ .route()
+ // contract advice converts betweeen JSON and UserPojoEx directly
+ .inputType(UserPojoEx.class)
+ .outputType("json")
+ .process(ex -> {
+ ex.getIn().getBody(UserPojoEx.class).setActive(true);
+ })
+ .to("mock:input");
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletCustomDataFormatInvalidTest.java
----------------------------------------------------------------------
diff --git a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletCustomDataFormatInvalidTest.java b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletCustomDataFormatInvalidTest.java
index e75c291..751ea9c 100644
--- a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletCustomDataFormatInvalidTest.java
+++ b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/RestRestletCustomDataFormatInvalidTest.java
@@ -62,7 +62,7 @@ public class RestRestletCustomDataFormatInvalidTest extends RestletTestSupport {
context.start();
fail("Should have thrown exception");
} catch (FailedToCreateRouteException e) {
- assertEquals("JsonDataFormat name: bla must not be an existing bean instance from the registry", e.getCause().getMessage());
+ assertTrue(e.getCause().getMessage().contains("JsonDataFormat name: bla must not be an existing bean instance from the registry"));
}
}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/UserPojoEx.java
----------------------------------------------------------------------
diff --git a/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/UserPojoEx.java b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/UserPojoEx.java
new file mode 100644
index 0000000..eabc2aa
--- /dev/null
+++ b/components/camel-restlet/src/test/java/org/apache/camel/component/restlet/UserPojoEx.java
@@ -0,0 +1,48 @@
+/**
+ * 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 UserPojoEx {
+
+ private int id;
+ private String name;
+ private boolean active;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletBindingModeJsonWithContractTest.java
----------------------------------------------------------------------
diff --git a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletBindingModeJsonWithContractTest.java b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletBindingModeJsonWithContractTest.java
new file mode 100644
index 0000000..8e91d66
--- /dev/null
+++ b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletBindingModeJsonWithContractTest.java
@@ -0,0 +1,92 @@
+/**
+ * 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.servlet.rest;
+
+import java.io.ByteArrayInputStream;
+
+import com.meterware.httpunit.PostMethodWebRequest;
+import com.meterware.httpunit.WebRequest;
+import com.meterware.httpunit.WebResponse;
+import com.meterware.servletunit.ServletUnitClient;
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.servlet.ServletCamelRouterTestSupport;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestDefinition;
+import org.junit.Test;
+
+public class RestServletBindingModeJsonWithContractTest extends ServletCamelRouterTestSupport {
+
+ @Test
+ public void testBindingModeJsonWithContract() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:input");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(UserPojoEx.class);
+
+ String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+ WebRequest req = new PostMethodWebRequest(CONTEXT_URL + "/services/users/new", new ByteArrayInputStream(body.getBytes()), "application/json");
+ ServletUnitClient client = newClient();
+ client.setExceptionsThrownOnErrorStatus(false);
+ WebResponse response = client.getResponse(req);
+ assertEquals(200, response.getResponseCode());
+ String answer = response.getText();
+ assertTrue("Unexpected response: " + answer, answer.contains("\"active\":true"));
+
+ assertMockEndpointsSatisfied();
+
+ Object obj = mock.getReceivedExchanges().get(0).getIn().getBody();
+ assertEquals(UserPojoEx.class, obj.getClass());
+ UserPojoEx user = (UserPojoEx)obj;
+ assertNotNull(user);
+ assertEquals(123, user.getId());
+ assertEquals("Donald Duck", user.getName());
+ assertEquals(true, user.isActive());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ context.getTypeConverterRegistry().addTypeConverters(new MyTypeConverters());
+ restConfiguration().component("servlet").bindingMode(RestBindingMode.json);
+
+ rest("/users/")
+ // REST binding converts from JSON to UserPojo
+ .post("new").type(UserPojo.class)
+ .route()
+ // then contract advice converts from UserPojo to UserPojoEx
+ .inputType(UserPojoEx.class)
+ .to("mock:input");
+ }
+ };
+ }
+
+ public static class MyTypeConverters implements TypeConverters {
+ @Converter
+ public UserPojoEx toEx(UserPojo user) {
+ UserPojoEx ex = new UserPojoEx();
+ ex.setId(user.getId());
+ ex.setName(user.getName());
+ ex.setActive(true);
+ return ex;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletBindingModeOffWithContractTest.java
----------------------------------------------------------------------
diff --git a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletBindingModeOffWithContractTest.java b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletBindingModeOffWithContractTest.java
new file mode 100644
index 0000000..fa481be
--- /dev/null
+++ b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletBindingModeOffWithContractTest.java
@@ -0,0 +1,99 @@
+/**
+ * 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.servlet.rest;
+
+import java.io.ByteArrayInputStream;
+
+import com.meterware.httpunit.PostMethodWebRequest;
+import com.meterware.httpunit.WebRequest;
+import com.meterware.httpunit.WebResponse;
+import com.meterware.servletunit.ServletUnitClient;
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.servlet.ServletCamelRouterTestSupport;
+import org.apache.camel.model.dataformat.JsonDataFormat;
+import org.apache.camel.model.dataformat.JsonLibrary;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestDefinition;
+import org.junit.Test;
+
+public class RestServletBindingModeOffWithContractTest extends ServletCamelRouterTestSupport {
+
+ @Test
+ public void testBindingModeOffWithContract() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:input");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(UserPojoEx.class);
+
+ String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+ WebRequest req = new PostMethodWebRequest(CONTEXT_URL + "/services/users/new", new ByteArrayInputStream(body.getBytes()), "application/json");
+ ServletUnitClient client = newClient();
+ client.setExceptionsThrownOnErrorStatus(false);
+ WebResponse response = client.getResponse(req);
+ assertEquals(200, response.getResponseCode());
+ String answer = response.getText();
+ assertTrue("Unexpected response: " + answer, answer.contains("\"active\":true"));
+
+ assertMockEndpointsSatisfied();
+
+ Object obj = mock.getReceivedExchanges().get(0).getIn().getBody();
+ assertEquals(UserPojoEx.class, obj.getClass());
+ UserPojoEx user = (UserPojoEx)obj;
+ assertNotNull(user);
+ assertEquals(123, user.getId());
+ assertEquals("Donald Duck", user.getName());
+ assertEquals(true, user.isActive());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ restConfiguration().component("servlet").bindingMode(RestBindingMode.off);
+
+ JsonDataFormat jsondf = new JsonDataFormat();
+ jsondf.setLibrary(JsonLibrary.Jackson);
+ jsondf.setAllowUnmarshallType(true);
+ jsondf.setUnmarshalType(UserPojoEx.class);
+ transformer()
+ .fromType("json")
+ .toType(UserPojoEx.class)
+ .withDataFormat(jsondf);
+ transformer()
+ .fromType(UserPojoEx.class)
+ .toType("json")
+ .withDataFormat(jsondf);
+ rest("/users/")
+ // REST binding does nothing
+ .post("new")
+ .route()
+ // contract advice converts betweeen JSON and UserPojoEx directly
+ .inputType(UserPojoEx.class)
+ .outputType("json")
+ .process(ex -> {
+ ex.getIn().getBody(UserPojoEx.class).setActive(true);
+ })
+ .to("mock:input");
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/UserPojoEx.java
----------------------------------------------------------------------
diff --git a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/UserPojoEx.java b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/UserPojoEx.java
new file mode 100644
index 0000000..7b1b218
--- /dev/null
+++ b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/UserPojoEx.java
@@ -0,0 +1,48 @@
+/**
+ * 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.servlet.rest;
+
+public class UserPojoEx {
+
+ private int id;
+ private String name;
+ private boolean active;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/component/rest/FromRestGetEmbeddedRouteTest.java
----------------------------------------------------------------------
diff --git a/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/component/rest/FromRestGetEmbeddedRouteTest.java b/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/component/rest/FromRestGetEmbeddedRouteTest.java
index c9cafe8..ed9a579 100644
--- a/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/component/rest/FromRestGetEmbeddedRouteTest.java
+++ b/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/component/rest/FromRestGetEmbeddedRouteTest.java
@@ -41,7 +41,7 @@ public class FromRestGetEmbeddedRouteTest extends CamelBlueprintTestSupport {
assertNotNull(rest);
assertEquals("/say/hello", rest.getPath());
assertEquals(1, rest.getVerbs().size());
- ToDefinition to = assertIsInstanceOf(ToDefinition.class, rest.getVerbs().get(0).getRoute().getOutputs().get(1));
+ ToDefinition to = assertIsInstanceOf(ToDefinition.class, rest.getVerbs().get(0).getRoute().getOutputs().get(0));
assertEquals("mock:hello", to.getUri());
rest = context.getRestDefinitions().get(1);
@@ -49,7 +49,7 @@ public class FromRestGetEmbeddedRouteTest extends CamelBlueprintTestSupport {
assertEquals("/say/bye", rest.getPath());
assertEquals(2, rest.getVerbs().size());
assertEquals("application/json", rest.getVerbs().get(0).getConsumes());
- to = assertIsInstanceOf(ToDefinition.class, rest.getVerbs().get(0).getRoute().getOutputs().get(1));
+ to = assertIsInstanceOf(ToDefinition.class, rest.getVerbs().get(0).getRoute().getOutputs().get(0));
assertEquals("mock:bye", to.getUri());
// the rest becomes routes and the input is a seda endpoint created by the DummyRestConsumerFactory
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/component/rest/FromRestGetInterceptTest.java
----------------------------------------------------------------------
diff --git a/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/component/rest/FromRestGetInterceptTest.java b/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/component/rest/FromRestGetInterceptTest.java
index ce766b4..6b72368 100644
--- a/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/component/rest/FromRestGetInterceptTest.java
+++ b/components/camel-test-blueprint/src/test/java/org/apache/camel/test/blueprint/component/rest/FromRestGetInterceptTest.java
@@ -30,7 +30,7 @@ public class FromRestGetInterceptTest extends CamelBlueprintTestSupport {
public void testFromRestModel() throws Exception {
getMockEndpoint("mock:hello").expectedMessageCount(1);
getMockEndpoint("mock:bar").expectedMessageCount(1);
- getMockEndpoint("mock:intercept").expectedMessageCount(4);
+ getMockEndpoint("mock:intercept").expectedMessageCount(3);
String out = template.requestBody("seda:get-say-hello", "I was here", String.class);
assertEquals("Bye World", out);
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpBindingModeJsonWithContractTest.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpBindingModeJsonWithContractTest.java b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpBindingModeJsonWithContractTest.java
new file mode 100644
index 0000000..df293dd
--- /dev/null
+++ b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpBindingModeJsonWithContractTest.java
@@ -0,0 +1,83 @@
+/**
+ * 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.undertow.rest;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.undertow.BaseUndertowTest;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestDefinition;
+import org.junit.Test;
+
+public class RestUndertowHttpBindingModeJsonWithContractTest extends BaseUndertowTest {
+
+ @Test
+ public void testBindingModeJsonWithContract() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:input");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(UserPojoEx.class);
+
+ String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+ Object answer = template.requestBody("undertow:http://localhost:{{port}}/users/new", body);
+ assertNotNull(answer);
+ String answerString = new String((byte[])answer);
+ assertTrue("Unexpected response: " + answerString, answerString.contains("\"active\":true"));
+
+ assertMockEndpointsSatisfied();
+
+ Object obj = mock.getReceivedExchanges().get(0).getIn().getBody();
+ assertEquals(UserPojoEx.class, obj.getClass());
+ UserPojoEx user = (UserPojoEx)obj;
+ assertNotNull(user);
+ assertEquals(123, user.getId());
+ assertEquals("Donald Duck", user.getName());
+ assertEquals(true, user.isActive());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ context.getTypeConverterRegistry().addTypeConverters(new MyTypeConverters());
+ restConfiguration().component("undertow").host("localhost").port(getPort()).bindingMode(RestBindingMode.json);
+
+ rest("/users/")
+ // REST binding converts from JSON to UserPojo
+ .post("new").type(UserPojo.class)
+ .route()
+ // then contract advice converts from UserPojo to UserPojoEx
+ .inputType(UserPojoEx.class)
+ .to("mock:input");
+ }
+ };
+ }
+
+ public static class MyTypeConverters implements TypeConverters {
+ @Converter
+ public UserPojoEx toEx(UserPojo user) {
+ UserPojoEx ex = new UserPojoEx();
+ ex.setId(user.getId());
+ ex.setName(user.getName());
+ ex.setActive(true);
+ return ex;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpBindingModeOffWithContractTest.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpBindingModeOffWithContractTest.java b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpBindingModeOffWithContractTest.java
new file mode 100644
index 0000000..432c986
--- /dev/null
+++ b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/RestUndertowHttpBindingModeOffWithContractTest.java
@@ -0,0 +1,90 @@
+/**
+ * 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.undertow.rest;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.undertow.BaseUndertowTest;
+import org.apache.camel.model.dataformat.JsonDataFormat;
+import org.apache.camel.model.dataformat.JsonLibrary;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestDefinition;
+import org.junit.Test;
+
+public class RestUndertowHttpBindingModeOffWithContractTest extends BaseUndertowTest {
+
+ @Test
+ public void testBindingModeOffWithContract() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:input");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(UserPojoEx.class);
+
+ String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+ Object answer = template.requestBodyAndHeader("undertow:http://localhost:{{port}}/users/new", body, Exchange.CONTENT_TYPE, "application/json");
+ assertNotNull(answer);
+ String answerString = new String((byte[])answer);
+ assertTrue("Unexpected response: " + answerString, answerString.contains("\"active\":true"));
+
+ assertMockEndpointsSatisfied();
+
+ Object obj = mock.getReceivedExchanges().get(0).getIn().getBody();
+ assertEquals(UserPojoEx.class, obj.getClass());
+ UserPojoEx user = (UserPojoEx)obj;
+ assertNotNull(user);
+ assertEquals(123, user.getId());
+ assertEquals("Donald Duck", user.getName());
+ assertEquals(true, user.isActive());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ restConfiguration().component("undertow").host("localhost").port(getPort()).bindingMode(RestBindingMode.off);
+
+ JsonDataFormat jsondf = new JsonDataFormat();
+ jsondf.setLibrary(JsonLibrary.Jackson);
+ jsondf.setAllowUnmarshallType(true);
+ jsondf.setUnmarshalType(UserPojoEx.class);
+ transformer()
+ .fromType("json")
+ .toType(UserPojoEx.class)
+ .withDataFormat(jsondf);
+ transformer()
+ .fromType(UserPojoEx.class)
+ .toType("json")
+ .withDataFormat(jsondf);
+ rest("/users/")
+ // REST binding does nothing
+ .post("new")
+ .route()
+ // contract advice converts betweeen JSON and UserPojoEx directly
+ .inputType(UserPojoEx.class)
+ .outputType("json")
+ .process(ex -> {
+ ex.getIn().getBody(UserPojoEx.class).setActive(true);
+ })
+ .to("mock:input");
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/UserPojoEx.java
----------------------------------------------------------------------
diff --git a/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/UserPojoEx.java b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/UserPojoEx.java
new file mode 100644
index 0000000..974778c
--- /dev/null
+++ b/components/camel-undertow/src/test/java/org/apache/camel/component/undertow/rest/UserPojoEx.java
@@ -0,0 +1,48 @@
+/**
+ * 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.undertow.rest;
+
+public class UserPojoEx {
+
+ private int id;
+ private String name;
+ private boolean active;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+}
[2/3] camel git commit: CAMEL-10532 Convert
RestConsumerBindingProcessor into processor advice so it works fine with
contract advice together
Posted by da...@apache.org.
CAMEL-10532 Convert RestConsumerBindingProcessor into processor advice so it works fine with contract advice together
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/8c9184b6
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/8c9184b6
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/8c9184b6
Branch: refs/heads/master
Commit: 8c9184b6f2d75ebbab90a5cb42eb51e114fec42b
Parents: 25b2ba2
Author: Tomohisa Igarashi <tm...@gmail.com>
Authored: Thu Feb 9 17:48:16 2017 +0900
Committer: Tomohisa Igarashi <tm...@gmail.com>
Committed: Tue Feb 14 20:43:46 2017 +0900
----------------------------------------------------------------------
.../rest/RestConsumerBindingProcessor.java | 461 -------------------
.../apache/camel/impl/DefaultRouteContext.java | 23 +-
.../org/apache/camel/model/RouteDefinition.java | 23 +-
.../camel/model/rest/RestBindingDefinition.java | 18 +-
.../apache/camel/model/rest/RestDefinition.java | 2 +-
.../apache/camel/processor/ContractAdvice.java | 34 +-
.../camel/processor/RestBindingAdvice.java | 418 +++++++++++++++++
.../java/org/apache/camel/spi/DataType.java | 2 +-
.../java/org/apache/camel/spi/RouteContext.java | 5 -
.../rest/FromRestGetEmbeddedRouteTest.java | 4 +-
.../component/rest/FromRestGetEndPathTest.java | 2 +-
.../rest/FromRestGetInterceptTest.java | 2 +-
.../ManagedTransformerRegistryTest.java | 4 +-
...estJettyBindingModeJsonWithContractTest.java | 92 ++++
...RestJettyBindingModeOffWithContractTest.java | 99 ++++
.../camel/component/jetty/rest/UserPojoEx.java | 48 ++
...ettyHttpBindingModeJsonWithContractTest.java | 83 ++++
...NettyHttpBindingModeOffWithContractTest.java | 90 ++++
.../component/netty4/http/rest/UserPojoEx.java | 48 ++
...tRestletBindingModeJsonWithContractTest.java | 91 ++++
...stRestletBindingModeOffWithContractTest.java | 98 ++++
.../RestRestletCustomDataFormatInvalidTest.java | 2 +-
.../camel/component/restlet/UserPojoEx.java | 48 ++
...tServletBindingModeJsonWithContractTest.java | 92 ++++
...stServletBindingModeOffWithContractTest.java | 99 ++++
.../component/servlet/rest/UserPojoEx.java | 48 ++
.../rest/FromRestGetEmbeddedRouteTest.java | 4 +-
.../rest/FromRestGetInterceptTest.java | 2 +-
...rtowHttpBindingModeJsonWithContractTest.java | 83 ++++
...ertowHttpBindingModeOffWithContractTest.java | 90 ++++
.../component/undertow/rest/UserPojoEx.java | 48 ++
31 files changed, 1657 insertions(+), 506 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/main/java/org/apache/camel/component/rest/RestConsumerBindingProcessor.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/component/rest/RestConsumerBindingProcessor.java b/camel-core/src/main/java/org/apache/camel/component/rest/RestConsumerBindingProcessor.java
deleted file mode 100644
index 888fc2f..0000000
--- a/camel-core/src/main/java/org/apache/camel/component/rest/RestConsumerBindingProcessor.java
+++ /dev/null
@@ -1,461 +0,0 @@
-/**
- * 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.rest;
-
-import java.util.Locale;
-import java.util.Map;
-
-import org.apache.camel.AsyncCallback;
-import org.apache.camel.AsyncProcessor;
-import org.apache.camel.CamelContext;
-import org.apache.camel.CamelContextAware;
-import org.apache.camel.Exchange;
-import org.apache.camel.Message;
-import org.apache.camel.Route;
-import org.apache.camel.processor.MarshalProcessor;
-import org.apache.camel.processor.UnmarshalProcessor;
-import org.apache.camel.processor.binding.BindingException;
-import org.apache.camel.spi.DataFormat;
-import org.apache.camel.spi.RestConfiguration;
-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;
-import org.apache.camel.util.ObjectHelper;
-import org.apache.camel.util.ServiceHelper;
-
-/**
- * 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 RestConsumerBindingProcessor extends ServiceSupport implements AsyncProcessor {
-
- private final CamelContext camelContext;
- private final AsyncProcessor jsonUnmarshal;
- private final AsyncProcessor xmlUnmarshal;
- private final AsyncProcessor jsonMarshal;
- private final AsyncProcessor xmlMarshal;
- private final String consumes;
- private final String produces;
- private final String bindingMode;
- private final boolean skipBindingOnErrorCode;
- private final boolean enableCORS;
- private final Map<String, String> corsHeaders;
- private final Map<String, String> queryDefaultValues;
-
- public RestConsumerBindingProcessor(CamelContext camelContext, DataFormat jsonDataFormat, DataFormat xmlDataFormat,
- DataFormat outJsonDataFormat, DataFormat outXmlDataFormat,
- String consumes, String produces, String bindingMode,
- boolean skipBindingOnErrorCode, boolean enableCORS,
- Map<String, String> corsHeaders,
- Map<String, String> queryDefaultValues) {
-
- this.camelContext = camelContext;
-
- if (jsonDataFormat != null) {
- this.jsonUnmarshal = new UnmarshalProcessor(jsonDataFormat);
- } else {
- this.jsonUnmarshal = null;
- }
- if (outJsonDataFormat != null) {
- this.jsonMarshal = new MarshalProcessor(outJsonDataFormat);
- } else if (jsonDataFormat != null) {
- this.jsonMarshal = new MarshalProcessor(jsonDataFormat);
- } else {
- this.jsonMarshal = null;
- }
-
- if (xmlDataFormat != null) {
- this.xmlUnmarshal = new UnmarshalProcessor(xmlDataFormat);
- } else {
- this.xmlUnmarshal = null;
- }
- if (outXmlDataFormat != null) {
- this.xmlMarshal = new MarshalProcessor(outXmlDataFormat);
- } else if (xmlDataFormat != null) {
- this.xmlMarshal = new MarshalProcessor(xmlDataFormat);
- } else {
- this.xmlMarshal = null;
- }
-
- this.consumes = consumes;
- this.produces = produces;
- this.bindingMode = bindingMode;
- this.skipBindingOnErrorCode = skipBindingOnErrorCode;
- this.enableCORS = enableCORS;
- this.corsHeaders = corsHeaders;
- this.queryDefaultValues = queryDefaultValues;
- }
-
- @Override
- public void process(Exchange exchange) throws Exception {
- AsyncProcessorHelper.process(this, exchange);
- }
-
- @Override
- public boolean process(Exchange exchange, final AsyncCallback callback) {
- if (enableCORS) {
- exchange.addOnCompletion(new RestConsumerBindingCORSOnCompletion(corsHeaders));
- }
-
- String method = exchange.getIn().getHeader(Exchange.HTTP_METHOD, String.class);
- if ("OPTIONS".equalsIgnoreCase(method)) {
- // for OPTIONS methods then we should not route at all as its part of CORS
- exchange.setProperty(Exchange.ROUTE_STOP, true);
- callback.done(true);
- return true;
- }
-
- boolean isXml = false;
- boolean isJson = false;
-
- String contentType = ExchangeHelper.getContentType(exchange);
- if (contentType != null) {
- isXml = contentType.toLowerCase(Locale.ENGLISH).contains("xml");
- isJson = contentType.toLowerCase(Locale.ENGLISH).contains("json");
- }
- // if content type could not tell us if it was json or xml, then fallback to if the binding was configured with
- // that information in the consumes
- if (!isXml && !isJson) {
- isXml = consumes != null && consumes.toLowerCase(Locale.ENGLISH).contains("xml");
- isJson = consumes != null && consumes.toLowerCase(Locale.ENGLISH).contains("json");
- }
-
- // 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");
- }
-
- String accept = exchange.getIn().getHeader("Accept", String.class);
-
- String body = null;
- if (exchange.getIn().getBody() != null) {
-
- // 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
- 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) {
- 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;
- }
- }
- }
- }
-
- // add missing default values which are mapped as headers
- if (queryDefaultValues != null) {
- for (Map.Entry<String, String> entry : queryDefaultValues.entrySet()) {
- if (exchange.getIn().getHeader(entry.getKey()) == null) {
- exchange.getIn().setHeader(entry.getKey(), entry.getValue());
- }
- }
- }
-
- // favor json over xml
- if (isJson && jsonUnmarshal != null) {
- // add reverse operation
- exchange.addOnCompletion(new RestConsumerBindingMarshalOnCompletion(exchange.getFromRouteId(), jsonMarshal, xmlMarshal, false, accept));
- if (ObjectHelper.isNotEmpty(body)) {
- return jsonUnmarshal.process(exchange, callback);
- } else {
- callback.done(true);
- return true;
- }
- } else if (isXml && xmlUnmarshal != null) {
- // add reverse operation
- exchange.addOnCompletion(new RestConsumerBindingMarshalOnCompletion(exchange.getFromRouteId(), jsonMarshal, xmlMarshal, true, accept));
- if (ObjectHelper.isNotEmpty(body)) {
- return xmlUnmarshal.process(exchange, callback);
- } else {
- callback.done(true);
- return true;
- }
- }
-
- // we could not bind
- if ("off".equals(bindingMode) || bindingMode.equals("auto")) {
- // okay for auto we do not mind if we could not bind
- exchange.addOnCompletion(new RestConsumerBindingMarshalOnCompletion(exchange.getFromRouteId(), jsonMarshal, xmlMarshal, false, accept));
- callback.done(true);
- return true;
- } else {
- if (bindingMode.contains("xml")) {
- exchange.setException(new BindingException("Cannot bind to xml as message body is not xml compatible", exchange));
- } else {
- exchange.setException(new BindingException("Cannot bind to json as message body is not json compatible", exchange));
- }
- callback.done(true);
- return true;
- }
- }
-
- @Override
- public String toString() {
- return "RestConsumerBindingProcessor";
- }
-
- @Override
- protected void doStart() throws Exception {
- // inject CamelContext before starting
- if (jsonMarshal instanceof CamelContextAware) {
- ((CamelContextAware) jsonMarshal).setCamelContext(camelContext);
- }
- if (jsonUnmarshal instanceof CamelContextAware) {
- ((CamelContextAware) jsonUnmarshal).setCamelContext(camelContext);
- }
- if (xmlMarshal instanceof CamelContextAware) {
- ((CamelContextAware) xmlMarshal).setCamelContext(camelContext);
- }
- if (xmlUnmarshal instanceof CamelContextAware) {
- ((CamelContextAware) xmlUnmarshal).setCamelContext(camelContext);
- }
- ServiceHelper.startServices(jsonMarshal, jsonUnmarshal, xmlMarshal, xmlUnmarshal);
- }
-
- @Override
- protected void doStop() throws Exception {
- ServiceHelper.stopServices(jsonMarshal, jsonUnmarshal, xmlMarshal, xmlUnmarshal);
- }
-
- /**
- * An {@link org.apache.camel.spi.Synchronization} that does the reverse operation
- * of marshalling from POJO to json/xml
- */
- private final class RestConsumerBindingMarshalOnCompletion extends SynchronizationAdapter {
-
- private final AsyncProcessor jsonMarshal;
- private final AsyncProcessor xmlMarshal;
- private final String routeId;
- private boolean wasXml;
- private String accept;
-
- private RestConsumerBindingMarshalOnCompletion(String routeId, AsyncProcessor jsonMarshal, AsyncProcessor xmlMarshal, boolean wasXml, String accept) {
- this.routeId = routeId;
- this.jsonMarshal = jsonMarshal;
- this.xmlMarshal = xmlMarshal;
- this.wasXml = wasXml;
- this.accept = accept;
- }
-
- @Override
- public void onAfterRoute(Route route, Exchange exchange) {
- // we use the onAfterRoute callback, to ensure the data has been marshalled before
- // the consumer writes the response back
-
- // only trigger when it was the 1st route that was done
- if (!routeId.equals(route.getId())) {
- return;
- }
-
- // only marshal if there was no exception
- if (exchange.getException() != null) {
- return;
- }
-
- if (skipBindingOnErrorCode) {
- Integer code = exchange.hasOut() ? exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class) : exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
- // if there is a custom http error code then skip binding
- if (code != null && code >= 300) {
- return;
- }
- }
-
- boolean isXml = false;
- boolean isJson = false;
-
- // accept takes precedence
- if (accept != null) {
- isXml = accept.toLowerCase(Locale.ENGLISH).contains("xml");
- isJson = accept.toLowerCase(Locale.ENGLISH).contains("json");
- }
- // fallback to content type if still undecided
- if (!isXml && !isJson) {
- String contentType = ExchangeHelper.getContentType(exchange);
- if (contentType != null) {
- isXml = contentType.toLowerCase(Locale.ENGLISH).contains("xml");
- isJson = contentType.toLowerCase(Locale.ENGLISH).contains("json");
- }
- }
- // if content type could not tell us if it was json or xml, then fallback to if the binding was configured with
- // that information in the consumes
- if (!isXml && !isJson) {
- isXml = produces != null && produces.toLowerCase(Locale.ENGLISH).contains("xml");
- isJson = produces != null && produces.toLowerCase(Locale.ENGLISH).contains("json");
- }
-
- // only allow xml/json if the binding mode allows that (when off we still want to know if its xml or json)
- if (bindingMode != null) {
- isXml &= bindingMode.equals("off") || bindingMode.equals("auto") || bindingMode.contains("xml");
- isJson &= bindingMode.equals("off") || 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);
-
- // ensure there is a content type header (even if binding is off)
- ensureHeaderContentType(produces, isXml, isJson, exchange);
-
- if (bindingMode == null || "off".equals(bindingMode)) {
- // binding is off, so no message body binding
- return;
- }
-
- // is there any marshaller at all
- if (jsonMarshal == null && xmlMarshal == null) {
- return;
- }
-
- // is the body empty
- if ((exchange.hasOut() && exchange.getOut().getBody() == null) || (!exchange.hasOut() && exchange.getIn().getBody() == null)) {
- return;
- }
-
- String contentType = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, String.class);
- // need to lower-case so the contains check below can match if using upper case
- contentType = contentType.toLowerCase(Locale.US);
- try {
- // favor json over xml
- if (isJson && jsonMarshal != null) {
- // only marshal if its json content type
- if (contentType.contains("json")) {
- jsonMarshal.process(exchange);
- }
- } else if (isXml && xmlMarshal != null) {
- // only marshal if its xml content type
- if (contentType.contains("xml")) {
- xmlMarshal.process(exchange);
- }
- } else {
- // we could not bind
- if (bindingMode.equals("auto")) {
- // okay for auto we do not mind if we could not bind
- } else {
- if (bindingMode.contains("xml")) {
- exchange.setException(new BindingException("Cannot bind to xml as message body is not xml compatible", exchange));
- } else {
- exchange.setException(new BindingException("Cannot bind to json as message body is not json compatible", exchange));
- }
- }
- }
- } catch (Throwable e) {
- exchange.setException(e);
- }
- }
-
- private void ensureHeaderContentType(String contentType, boolean isXml, boolean isJson, Exchange exchange) {
- // favor given content type
- if (contentType != null) {
- String type = ExchangeHelper.getContentType(exchange);
- if (type == null) {
- exchange.getIn().setHeader(Exchange.CONTENT_TYPE, contentType);
- }
- }
-
- // favor json over xml
- if (isJson) {
- // make sure there is a content-type with json
- String type = ExchangeHelper.getContentType(exchange);
- if (type == null) {
- exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
- }
- } else if (isXml) {
- // make sure there is a content-type with xml
- String type = ExchangeHelper.getContentType(exchange);
- if (type == null) {
- exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/xml");
- }
- }
- }
-
- @Override
- public String toString() {
- return "RestConsumerBindingMarshalOnCompletion";
- }
- }
-
- private final class RestConsumerBindingCORSOnCompletion extends SynchronizationAdapter {
-
- private final Map<String, String> corsHeaders;
-
- private RestConsumerBindingCORSOnCompletion(Map<String, String> corsHeaders) {
- this.corsHeaders = corsHeaders;
- }
-
- @Override
- public void onAfterRoute(Route route, Exchange exchange) {
- // add the CORS headers after routing, but before the consumer writes the response
- Message msg = exchange.hasOut() ? exchange.getOut() : exchange.getIn();
-
- // use default value if none has been configured
- String allowOrigin = corsHeaders != null ? corsHeaders.get("Access-Control-Allow-Origin") : null;
- if (allowOrigin == null) {
- allowOrigin = RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_ORIGIN;
- }
- String allowMethods = corsHeaders != null ? corsHeaders.get("Access-Control-Allow-Methods") : null;
- if (allowMethods == null) {
- allowMethods = RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_METHODS;
- }
- String allowHeaders = corsHeaders != null ? corsHeaders.get("Access-Control-Allow-Headers") : null;
- if (allowHeaders == null) {
- allowHeaders = RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_HEADERS;
- }
- String maxAge = corsHeaders != null ? corsHeaders.get("Access-Control-Max-Age") : null;
- if (maxAge == null) {
- maxAge = RestConfiguration.CORS_ACCESS_CONTROL_MAX_AGE;
- }
-
- msg.setHeader("Access-Control-Allow-Origin", allowOrigin);
- msg.setHeader("Access-Control-Allow-Methods", allowMethods);
- msg.setHeader("Access-Control-Allow-Headers", allowHeaders);
- msg.setHeader("Access-Control-Max-Age", maxAge);
- }
-
- @Override
- public String toString() {
- return "RestConsumerBindingCORSOnCompletion";
- }
- }
-
-}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
index 328dae9..fbb3673 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
@@ -37,6 +37,7 @@ import org.apache.camel.model.RouteDefinition;
import org.apache.camel.processor.CamelInternalProcessor;
import org.apache.camel.processor.ContractAdvice;
import org.apache.camel.processor.Pipeline;
+import org.apache.camel.processor.RestBindingAdvice;
import org.apache.camel.spi.Contract;
import org.apache.camel.spi.InterceptStrategy;
import org.apache.camel.spi.RouteContext;
@@ -70,7 +71,6 @@ public class DefaultRouteContext implements RouteContext {
private List<RoutePolicy> routePolicyList = new ArrayList<RoutePolicy>();
private ShutdownRoute shutdownRoute;
private ShutdownRunningTask shutdownRunningTask;
- private Contract contract;
public DefaultRouteContext(CamelContext camelContext, RouteDefinition route, FromDefinition from, Collection<Route> routes) {
this.camelContext = camelContext;
@@ -194,8 +194,24 @@ public class DefaultRouteContext implements RouteContext {
// wrap in route lifecycle
internal.addAdvice(new CamelInternalProcessor.RouteLifecycleAdvice());
+ // wrap in REST binding
+ if (route.getRestBindingDefinition() != null) {
+ try {
+ internal.addAdvice(route.getRestBindingDefinition().createRestBindingAdvice(this));
+ } catch (Exception e) {
+ throw ObjectHelper.wrapRuntimeCamelException(e);
+ }
+ }
+
// wrap in contract
- if (contract != null) {
+ if (route.getInputType() != null || route.getOutputType() != null) {
+ Contract contract = new Contract();
+ if (route.getInputType() != null) {
+ contract.setInputType(route.getInputType().getUrn());
+ }
+ if (route.getOutputType() != null) {
+ contract.setOutputType(route.getOutputType().getUrn());
+ }
internal.addAdvice(new ContractAdvice(contract));
}
@@ -409,7 +425,4 @@ public class DefaultRouteContext implements RouteContext {
return routePolicyList;
}
- public void setContract(Contract contract) {
- this.contract = contract;
- }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java b/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
index 76b4ec3..97078dd 100644
--- a/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/RouteDefinition.java
@@ -44,6 +44,7 @@ import org.apache.camel.builder.AdviceWithTask;
import org.apache.camel.builder.ErrorHandlerBuilderRef;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultRouteContext;
+import org.apache.camel.model.rest.RestBindingDefinition;
import org.apache.camel.model.rest.RestDefinition;
import org.apache.camel.processor.interceptor.HandleFault;
import org.apache.camel.spi.Contract;
@@ -88,6 +89,7 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
private boolean contextScopedErrorHandler = true;
private Boolean rest;
private RestDefinition restDefinition;
+ private RestBindingDefinition restBindingDefinition;
private InputTypeDefinition inputType;
private OutputTypeDefinition outputType;
@@ -966,6 +968,15 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
this.restDefinition = restDefinition;
}
+ public RestBindingDefinition getRestBindingDefinition() {
+ return restBindingDefinition;
+ }
+
+ @XmlTransient
+ public void setRestBindingDefinition(RestBindingDefinition restBindingDefinition) {
+ this.restBindingDefinition = restBindingDefinition;
+ }
+
@SuppressWarnings("deprecation")
public boolean isContextScopedErrorHandler(CamelContext context) {
if (!contextScopedErrorHandler) {
@@ -1127,18 +1138,6 @@ public class RouteDefinition extends ProcessorDefinition<RouteDefinition> {
throw new FailedToCreateRouteException(route.getId(), route.toString(), at, cause);
}
- // add data type contract
- if (inputType != null || outputType != null) {
- Contract contract = new Contract();
- if (inputType != null) {
- contract.setInputType(inputType.getUrn());
- }
- if (outputType != null) {
- contract.setOutputType(outputType.getUrn());
- }
- routeContext.setContract(contract);
- }
-
List<ProcessorDefinition<?>> list = new ArrayList<ProcessorDefinition<?>>(outputs);
for (ProcessorDefinition<?> output : list) {
try {
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/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 a376442..8c1c291 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
@@ -27,8 +27,8 @@ import javax.xml.bind.annotation.XmlTransient;
import org.apache.camel.CamelContext;
import org.apache.camel.Processor;
-import org.apache.camel.component.rest.RestConsumerBindingProcessor;
-import org.apache.camel.model.NoOutputDefinition;
+import org.apache.camel.model.OptionalIdentifiedDefinition;
+import org.apache.camel.processor.RestBindingAdvice;
import org.apache.camel.spi.DataFormat;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.RestConfiguration;
@@ -42,7 +42,7 @@ import org.apache.camel.util.IntrospectionSupport;
@Metadata(label = "rest")
@XmlRootElement(name = "restBinding")
@XmlAccessorType(XmlAccessType.FIELD)
-public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinition> {
+public class RestBindingDefinition extends OptionalIdentifiedDefinition<RestBindingDefinition> {
@XmlTransient
private Map<String, String> defaultValues;
@@ -80,8 +80,7 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
return "RestBinding";
}
- @Override
- public Processor createProcessor(RouteContext routeContext) throws Exception {
+ public RestBindingAdvice createRestBindingAdvice(RouteContext routeContext) throws Exception {
CamelContext context = routeContext.getCamelContext();
RestConfiguration config = context.getRestConfiguration(component, true);
@@ -105,7 +104,7 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
if (mode == null || "off".equals(mode)) {
// binding mode is off, so create a off mode binding processor
- return new RestConsumerBindingProcessor(context, null, null, null, null, consumes, produces, mode, skip, cors, corsHeaders, defaultValues);
+ return new RestBindingAdvice(context, null, null, null, null, consumes, produces, mode, skip, cors, corsHeaders, defaultValues);
}
// setup json data format
@@ -200,7 +199,7 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
setAdditionalConfiguration(config, context, outJaxb, "xml.out.");
}
- return new RestConsumerBindingProcessor(context, json, jaxb, outJson, outJaxb, consumes, produces, mode, skip, cors, corsHeaders, defaultValues);
+ return new RestBindingAdvice(context, json, jaxb, outJson, outJaxb, consumes, produces, mode, skip, cors, corsHeaders, defaultValues);
}
private void setAdditionalConfiguration(RestConfiguration config, CamelContext context,
@@ -351,4 +350,9 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
public void setEnableCORS(Boolean enableCORS) {
this.enableCORS = enableCORS;
}
+
+ @Override
+ public String getLabel() {
+ return "";
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/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 68deb66..3cd6b2c 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
@@ -736,7 +736,7 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
}
}
- route.getOutputs().add(0, binding);
+ route.setRestBindingDefinition(binding);
// create the from endpoint uri which is using the rest component
String from = "rest:" + verb.asVerb() + ":" + buildUri(verb);
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java b/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
index 15a3d61..a3dad33 100644
--- a/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
+++ b/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
@@ -1,3 +1,19 @@
+/**
+ * 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.processor;
import org.apache.camel.CamelContext;
@@ -40,12 +56,15 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
@Override
public void after(Exchange exchange, Object data) throws Exception {
Message target = exchange.hasOut() ? exchange.getOut() : exchange.getIn();
- DataType from = getCurrentType(exchange, exchange.hasOut() ? Exchange.OUTPUT_TYPE : Exchange.INPUT_TYPE);
+ if (!exchange.hasOut() && exchange.getProperty(Exchange.OUTPUT_TYPE) == null) {
+ exchange.setProperty(Exchange.OUTPUT_TYPE, exchange.getProperty(Exchange.INPUT_TYPE));
+ }
+ DataType from = getCurrentType(exchange, Exchange.OUTPUT_TYPE);
DataType to = contract.getOutputType();
if (to != null && !to.equals(from)) {
LOG.debug("Looking for transformer for OUTPUT: from='{}', to='{}'", from, to);
doTransform(target, from, to);
- exchange.setProperty(exchange.hasOut() ? Exchange.OUTPUT_TYPE : Exchange.INPUT_TYPE, to);
+ exchange.setProperty(Exchange.OUTPUT_TYPE, to);
}
}
@@ -61,7 +80,8 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
// Java->Java transformation just relies on TypeConverter if no explicit transformer
return;
} else if (from == null) {
- // {undefined}->Other transformation - assuming it's already in expected shape
+ // use body class as a from type, or do nothing with assuming it's already in expected shape
+ applyTransformerByClass(message, to);
return;
} else if (applyTransformerByToModel(message, from, to)) {
// Java->Other transformation - found a transformer supports 'to' data model
@@ -85,8 +105,8 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
private boolean convertIfRequired(Message message, DataType type) throws Exception {
// TODO for better performance it may be better to add TypeConveterTransformer
// into transformer registry automatically to avoid unnecessary scan in transformer registry
- CamelContext context = message.getExchange().getContext();
if (type != null && type.isJavaType() && type.getName() != null) {
+ CamelContext context = message.getExchange().getContext();
Class<?> typeJava = getClazz(type.getName(), context);
if (!typeJava.isAssignableFrom(message.getBody().getClass())) {
LOG.debug("Converting to '{}'", typeJava.getName());
@@ -110,6 +130,12 @@ public class ContractAdvice implements CamelInternalProcessorAdvice {
return applyTransformer(transformer, message, from, to);
}
+ private boolean applyTransformerByClass(Message message, DataType to) throws Exception {
+ DataType from = new DataType(message.getBody().getClass());
+ Transformer transformer = message.getExchange().getContext().resolveTransformer(from, to);
+ return applyTransformer(transformer, message, from, to);
+ }
+
private boolean applyTransformerByToModel(Message message, DataType from, DataType to) throws Exception {
Transformer transformer = message.getExchange().getContext().resolveTransformer(to.getModel());
return applyTransformer(transformer, message, from, to);
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/processor/RestBindingAdvice.java b/camel-core/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
new file mode 100644
index 0000000..7b81a19
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/processor/RestBindingAdvice.java
@@ -0,0 +1,418 @@
+/**
+ * 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.processor;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.camel.AsyncProcessor;
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.processor.binding.BindingException;
+import org.apache.camel.spi.Contract;
+import org.apache.camel.spi.DataFormat;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.RestConfiguration;
+import org.apache.camel.spi.Transformer;
+import org.apache.camel.util.ExchangeHelper;
+import org.apache.camel.util.MessageHelper;
+import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ServiceHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A {@link org.apache.camel.processor.CamelInternalProcessorAdvice} 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.
+ *
+ * @see CamelInternalProcessor, CamelInternalProcessorAdvice
+ */
+public class RestBindingAdvice implements CamelInternalProcessorAdvice<Map<String, Object>> {
+ private static final String STATE_KEY_DO_MARSHAL = "doMarshal";
+ private static final String STATE_KEY_ACCEPT = "accept";
+ private static final String STATE_JSON = "json";
+ private static final String STATE_XML = "xml";
+
+ private final AsyncProcessor jsonUnmarshal;
+ private final AsyncProcessor xmlUnmarshal;
+ private final AsyncProcessor jsonMarshal;
+ private final AsyncProcessor xmlMarshal;
+ private final String consumes;
+ private final String produces;
+ private final String bindingMode;
+ private final boolean skipBindingOnErrorCode;
+ private final boolean enableCORS;
+ private final Map<String, String> corsHeaders;
+ private final Map<String, String> queryDefaultValues;
+
+ public RestBindingAdvice(CamelContext camelContext, DataFormat jsonDataFormat, DataFormat xmlDataFormat,
+ DataFormat outJsonDataFormat, DataFormat outXmlDataFormat,
+ String consumes, String produces, String bindingMode,
+ boolean skipBindingOnErrorCode, boolean enableCORS,
+ Map<String, String> corsHeaders,
+ Map<String, String> queryDefaultValues) throws Exception {
+
+ if (jsonDataFormat != null) {
+ this.jsonUnmarshal = new UnmarshalProcessor(jsonDataFormat);
+ } else {
+ this.jsonUnmarshal = null;
+ }
+ if (outJsonDataFormat != null) {
+ this.jsonMarshal = new MarshalProcessor(outJsonDataFormat);
+ } else if (jsonDataFormat != null) {
+ this.jsonMarshal = new MarshalProcessor(jsonDataFormat);
+ } else {
+ this.jsonMarshal = null;
+ }
+
+ if (xmlDataFormat != null) {
+ this.xmlUnmarshal = new UnmarshalProcessor(xmlDataFormat);
+ } else {
+ this.xmlUnmarshal = null;
+ }
+ if (outXmlDataFormat != null) {
+ this.xmlMarshal = new MarshalProcessor(outXmlDataFormat);
+ } else if (xmlDataFormat != null) {
+ this.xmlMarshal = new MarshalProcessor(xmlDataFormat);
+ } else {
+ this.xmlMarshal = null;
+ }
+
+ if (jsonMarshal != null) {
+ camelContext.addService(jsonMarshal, true);
+ }
+ if (jsonUnmarshal != null) {
+ camelContext.addService(jsonUnmarshal, true);
+ }
+ if (xmlMarshal instanceof CamelContextAware) {
+ camelContext.addService(xmlMarshal, true);
+ }
+ if (xmlUnmarshal instanceof CamelContextAware) {
+ camelContext.addService(xmlUnmarshal, true);
+ }
+
+ this.consumes = consumes;
+ this.produces = produces;
+ this.bindingMode = bindingMode;
+ this.skipBindingOnErrorCode = skipBindingOnErrorCode;
+ this.enableCORS = enableCORS;
+ this.corsHeaders = corsHeaders;
+ this.queryDefaultValues = queryDefaultValues;
+
+ }
+
+ @Override
+ public Map<String, Object> before(Exchange exchange) throws Exception {
+ Map<String, Object> state = new HashMap<>();
+ if (isOptionsMethod(exchange, state)) {
+ return state;
+ }
+ unmarshal(exchange, state);
+ return state;
+ }
+
+ @Override
+ public void after(Exchange exchange, Map<String, Object> state) throws Exception {
+ if (enableCORS) {
+ setCORSHeaders(exchange, state);
+ }
+ if (state.get(STATE_KEY_DO_MARSHAL) != null) {
+ marshal(exchange, state);
+ }
+ }
+
+ private boolean isOptionsMethod(Exchange exchange, Map<String, Object> state) {
+ String method = exchange.getIn().getHeader(Exchange.HTTP_METHOD, String.class);
+ if ("OPTIONS".equalsIgnoreCase(method)) {
+ // for OPTIONS methods then we should not route at all as its part of CORS
+ exchange.setProperty(Exchange.ROUTE_STOP, true);
+ return true;
+ }
+ return false;
+ }
+
+ private void unmarshal(Exchange exchange, Map<String, Object> state) throws Exception {
+ boolean isXml = false;
+ boolean isJson = false;
+
+ String contentType = ExchangeHelper.getContentType(exchange);
+ if (contentType != null) {
+ isXml = contentType.toLowerCase(Locale.ENGLISH).contains("xml");
+ isJson = contentType.toLowerCase(Locale.ENGLISH).contains("json");
+ }
+ // if content type could not tell us if it was json or xml, then fallback to if the binding was configured with
+ // that information in the consumes
+ if (!isXml && !isJson) {
+ isXml = consumes != null && consumes.toLowerCase(Locale.ENGLISH).contains("xml");
+ isJson = consumes != null && consumes.toLowerCase(Locale.ENGLISH).contains("json");
+ }
+
+ // set the INPUT_TYPE to indicate body type
+ if (isJson) {
+ exchange.setProperty(Exchange.INPUT_TYPE, new DataType("json"));
+ } else if (isXml) {
+ exchange.setProperty(Exchange.INPUT_TYPE, new DataType("xml"));
+ }
+
+ // 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");
+ }
+
+ state.put(STATE_KEY_ACCEPT, exchange.getIn().getHeader("Accept", String.class));
+
+ String body = null;
+ if (exchange.getIn().getBody() != null) {
+
+ // 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
+ 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) {
+ 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;
+ }
+ }
+ }
+ }
+
+ // add missing default values which are mapped as headers
+ if (queryDefaultValues != null) {
+ for (Map.Entry<String, String> entry : queryDefaultValues.entrySet()) {
+ if (exchange.getIn().getHeader(entry.getKey()) == null) {
+ exchange.getIn().setHeader(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ // favor json over xml
+ if (isJson && jsonUnmarshal != null) {
+ // add reverse operation
+ state.put(STATE_KEY_DO_MARSHAL, STATE_JSON);
+ if (ObjectHelper.isNotEmpty(body)) {
+ jsonUnmarshal.process(exchange);
+ ExchangeHelper.prepareOutToIn(exchange);
+ exchange.setProperty(Exchange.INPUT_TYPE, new DataType(exchange.getIn().getBody().getClass()));
+ }
+ return;
+ } else if (isXml && xmlUnmarshal != null) {
+ // add reverse operation
+ state.put(STATE_KEY_DO_MARSHAL, STATE_XML);
+ if (ObjectHelper.isNotEmpty(body)) {
+ xmlUnmarshal.process(exchange);
+ ExchangeHelper.prepareOutToIn(exchange);
+ exchange.setProperty(Exchange.INPUT_TYPE, new DataType(exchange.getIn().getBody().getClass()));
+ }
+ return;
+ }
+
+ // we could not bind
+ if ("off".equals(bindingMode) || bindingMode.equals("auto")) {
+ // okay for auto we do not mind if we could not bind
+ state.put(STATE_KEY_DO_MARSHAL, STATE_JSON);
+ } else {
+ if (bindingMode.contains("xml")) {
+ exchange.setException(new BindingException("Cannot bind to xml as message body is not xml compatible", exchange));
+ } else {
+ exchange.setException(new BindingException("Cannot bind to json as message body is not json compatible", exchange));
+ }
+ }
+
+ }
+
+ private void marshal(Exchange exchange, Map<String, Object> state) {
+ // only marshal if there was no exception
+ if (exchange.getException() != null) {
+ return;
+ }
+
+ if (skipBindingOnErrorCode) {
+ Integer code = exchange.hasOut() ? exchange.getOut().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class) : exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
+ // if there is a custom http error code then skip binding
+ if (code != null && code >= 300) {
+ return;
+ }
+ }
+
+ boolean isXml = false;
+ boolean isJson = false;
+
+ // accept takes precedence
+ String accept = (String)state.get(STATE_KEY_ACCEPT);
+ if (accept != null) {
+ isXml = accept.toLowerCase(Locale.ENGLISH).contains("xml");
+ isJson = accept.toLowerCase(Locale.ENGLISH).contains("json");
+ }
+ // fallback to content type if still undecided
+ if (!isXml && !isJson) {
+ String contentType = ExchangeHelper.getContentType(exchange);
+ if (contentType != null) {
+ isXml = contentType.toLowerCase(Locale.ENGLISH).contains("xml");
+ isJson = contentType.toLowerCase(Locale.ENGLISH).contains("json");
+ }
+ }
+ // if content type could not tell us if it was json or xml, then fallback to if the binding was configured with
+ // that information in the consumes
+ if (!isXml && !isJson) {
+ isXml = produces != null && produces.toLowerCase(Locale.ENGLISH).contains("xml");
+ isJson = produces != null && produces.toLowerCase(Locale.ENGLISH).contains("json");
+ }
+
+ // only allow xml/json if the binding mode allows that (when off we still want to know if its xml or json)
+ if (bindingMode != null) {
+ isXml &= bindingMode.equals("off") || bindingMode.equals("auto") || bindingMode.contains("xml");
+ isJson &= bindingMode.equals("off") || 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 = state.get(STATE_KEY_DO_MARSHAL).equals(STATE_XML);
+ isJson = !isXml;
+ }
+
+ // need to prepare exchange first
+ ExchangeHelper.prepareOutToIn(exchange);
+
+ // ensure there is a content type header (even if binding is off)
+ ensureHeaderContentType(produces, isXml, isJson, exchange);
+
+ if (bindingMode == null || "off".equals(bindingMode)) {
+ // binding is off, so no message body binding
+ return;
+ }
+
+ // is there any marshaller at all
+ if (jsonMarshal == null && xmlMarshal == null) {
+ return;
+ }
+
+ // is the body empty
+ if ((exchange.hasOut() && exchange.getOut().getBody() == null) || (!exchange.hasOut() && exchange.getIn().getBody() == null)) {
+ return;
+ }
+
+ String contentType = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, String.class);
+ // need to lower-case so the contains check below can match if using upper case
+ contentType = contentType.toLowerCase(Locale.US);
+ try {
+ // favor json over xml
+ if (isJson && jsonMarshal != null) {
+ // only marshal if its json content type
+ if (contentType.contains("json")) {
+ jsonMarshal.process(exchange);
+ exchange.setProperty(Exchange.OUTPUT_TYPE, new DataType("json"));
+ }
+ } else if (isXml && xmlMarshal != null) {
+ // only marshal if its xml content type
+ if (contentType.contains("xml")) {
+ xmlMarshal.process(exchange);
+ exchange.setProperty(Exchange.OUTPUT_TYPE, new DataType("xml"));
+ }
+ } else {
+ // we could not bind
+ if (bindingMode.equals("auto")) {
+ // okay for auto we do not mind if we could not bind
+ } else {
+ if (bindingMode.contains("xml")) {
+ exchange.setException(new BindingException("Cannot bind to xml as message body is not xml compatible", exchange));
+ } else {
+ exchange.setException(new BindingException("Cannot bind to json as message body is not json compatible", exchange));
+ }
+ }
+ }
+ } catch (Throwable e) {
+ exchange.setException(e);
+ }
+ }
+
+ private void ensureHeaderContentType(String contentType, boolean isXml, boolean isJson, Exchange exchange) {
+ // favor given content type
+ if (contentType != null) {
+ String type = ExchangeHelper.getContentType(exchange);
+ if (type == null) {
+ exchange.getIn().setHeader(Exchange.CONTENT_TYPE, contentType);
+ }
+ }
+
+ // favor json over xml
+ if (isJson) {
+ // make sure there is a content-type with json
+ String type = ExchangeHelper.getContentType(exchange);
+ if (type == null) {
+ exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/json");
+ }
+ } else if (isXml) {
+ // make sure there is a content-type with xml
+ String type = ExchangeHelper.getContentType(exchange);
+ if (type == null) {
+ exchange.getIn().setHeader(Exchange.CONTENT_TYPE, "application/xml");
+ }
+ }
+ }
+
+ private void setCORSHeaders(Exchange exchange, Map<String, Object> state) {
+ // add the CORS headers after routing, but before the consumer writes the response
+ Message msg = exchange.hasOut() ? exchange.getOut() : exchange.getIn();
+
+ // use default value if none has been configured
+ String allowOrigin = corsHeaders != null ? corsHeaders.get("Access-Control-Allow-Origin") : null;
+ if (allowOrigin == null) {
+ allowOrigin = RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_ORIGIN;
+ }
+ String allowMethods = corsHeaders != null ? corsHeaders.get("Access-Control-Allow-Methods") : null;
+ if (allowMethods == null) {
+ allowMethods = RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_METHODS;
+ }
+ String allowHeaders = corsHeaders != null ? corsHeaders.get("Access-Control-Allow-Headers") : null;
+ if (allowHeaders == null) {
+ allowHeaders = RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_HEADERS;
+ }
+ String maxAge = corsHeaders != null ? corsHeaders.get("Access-Control-Max-Age") : null;
+ if (maxAge == null) {
+ maxAge = RestConfiguration.CORS_ACCESS_CONTROL_MAX_AGE;
+ }
+
+ msg.setHeader("Access-Control-Allow-Origin", allowOrigin);
+ msg.setHeader("Access-Control-Allow-Methods", allowMethods);
+ msg.setHeader("Access-Control-Allow-Headers", allowHeaders);
+ msg.setHeader("Access-Control-Max-Age", maxAge);
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/main/java/org/apache/camel/spi/DataType.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/DataType.java b/camel-core/src/main/java/org/apache/camel/spi/DataType.java
index 5d96839..973e5c4 100644
--- a/camel-core/src/main/java/org/apache/camel/spi/DataType.java
+++ b/camel-core/src/main/java/org/apache/camel/spi/DataType.java
@@ -62,7 +62,7 @@ public class DataType {
@Override
public String toString() {
if (this.typeString == null) {
- this.typeString = model + ":" + name;
+ this.typeString = name != null && !name.isEmpty() ? model + ":" + name : model;
}
return this.typeString;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java b/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java
index ce57112..54e6ad0 100644
--- a/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java
+++ b/camel-core/src/main/java/org/apache/camel/spi/RouteContext.java
@@ -192,9 +192,4 @@ public interface RouteContext extends RuntimeConfiguration, EndpointAware {
*/
int getAndIncrement(ProcessorDefinition<?> node);
- /**
- * Sets a {@link Contract} which declares input/output message type on the route.
- * @param contract {@link Contract} for this route
- */
- void setContract(Contract contract);
}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetEmbeddedRouteTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetEmbeddedRouteTest.java b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetEmbeddedRouteTest.java
index df9fe91..353dbcc 100644
--- a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetEmbeddedRouteTest.java
+++ b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetEmbeddedRouteTest.java
@@ -43,7 +43,7 @@ public class FromRestGetEmbeddedRouteTest extends ContextTestSupport {
assertNotNull(rest);
assertEquals("/say/hello", rest.getPath());
assertEquals(1, rest.getVerbs().size());
- ToDefinition to = assertIsInstanceOf(ToDefinition.class, rest.getVerbs().get(0).getRoute().getOutputs().get(1));
+ ToDefinition to = assertIsInstanceOf(ToDefinition.class, rest.getVerbs().get(0).getRoute().getOutputs().get(0));
assertEquals("mock:hello", to.getUri());
rest = context.getRestDefinitions().get(1);
@@ -51,7 +51,7 @@ public class FromRestGetEmbeddedRouteTest extends ContextTestSupport {
assertEquals("/say/bye", rest.getPath());
assertEquals(2, rest.getVerbs().size());
assertEquals("application/json", rest.getVerbs().get(0).getConsumes());
- to = assertIsInstanceOf(ToDefinition.class, rest.getVerbs().get(0).getRoute().getOutputs().get(1));
+ to = assertIsInstanceOf(ToDefinition.class, rest.getVerbs().get(0).getRoute().getOutputs().get(0));
assertEquals("mock:bye", to.getUri());
// the rest becomes routes and the input is a seda endpoint created by the DummyRestConsumerFactory
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetEndPathTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetEndPathTest.java b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetEndPathTest.java
index 14f8b8d..7b89964 100644
--- a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetEndPathTest.java
+++ b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetEndPathTest.java
@@ -38,7 +38,7 @@ public class FromRestGetEndPathTest extends FromRestGetTest {
assertEquals("/say/bye", rest.getPath());
assertEquals(2, rest.getVerbs().size());
assertEquals("application/json", rest.getVerbs().get(0).getConsumes());
- to = assertIsInstanceOf(ToDefinition.class, rest.getVerbs().get(0).getRoute().getOutputs().get(1));
+ to = assertIsInstanceOf(ToDefinition.class, rest.getVerbs().get(0).getRoute().getOutputs().get(0));
assertEquals("direct:bye", to.getUri());
// the rest becomes routes and the input is a seda endpoint created by the DummyRestConsumerFactory
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetInterceptTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetInterceptTest.java b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetInterceptTest.java
index 62ed09c..6df660d 100644
--- a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetInterceptTest.java
+++ b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetInterceptTest.java
@@ -32,7 +32,7 @@ public class FromRestGetInterceptTest extends ContextTestSupport {
public void testFromRestModel() throws Exception {
getMockEndpoint("mock:hello").expectedMessageCount(1);
getMockEndpoint("mock:bar").expectedMessageCount(1);
- getMockEndpoint("mock:intercept").expectedMessageCount(4);
+ getMockEndpoint("mock:intercept").expectedMessageCount(3);
String out = template.requestBody("seda:get-say-hello", "I was here", String.class);
assertEquals("Bye World", out);
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/camel-core/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java b/camel-core/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
index f79b492..96918a6 100644
--- a/camel-core/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
+++ b/camel-core/src/test/java/org/apache/camel/management/ManagedTransformerRegistryTest.java
@@ -107,8 +107,8 @@ public class ManagedTransformerRegistryTest extends ManagementTestSupport {
assertEquals("xml:test", to);
} else if (description.startsWith("MyTransformer")) {
assertEquals("custom", scheme);
- assertEquals("null:null", from);
- assertEquals("null:null", to);
+ assertEquals(null, from);
+ assertEquals(null, to);
} else {
fail("Unexpected transformer:" + description);
}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/RestJettyBindingModeJsonWithContractTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/RestJettyBindingModeJsonWithContractTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/RestJettyBindingModeJsonWithContractTest.java
new file mode 100644
index 0000000..d72dab1
--- /dev/null
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/RestJettyBindingModeJsonWithContractTest.java
@@ -0,0 +1,92 @@
+/**
+ * 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.jetty.rest;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.jetty.BaseJettyTest;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestDefinition;
+import org.junit.Test;
+
+public class RestJettyBindingModeJsonWithContractTest extends BaseJettyTest {
+
+ @Test
+ public void testBindingModeJsonWithContract() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:input");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(UserPojoEx.class);
+
+ String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+ Object answer = template.requestBody("http://localhost:" + getPort() + "/users/new", body);
+ assertNotNull(answer);
+ BufferedReader reader = new BufferedReader(new InputStreamReader((InputStream)answer));
+ String line;
+ String answerString = "";
+ while ((line = reader.readLine()) != null) {
+ answerString += line;
+ }
+ assertTrue("Unexpected response: " + answerString, answerString.contains("\"active\":true"));
+
+ assertMockEndpointsSatisfied();
+
+ Object obj = mock.getReceivedExchanges().get(0).getIn().getBody();
+ assertEquals(UserPojoEx.class, obj.getClass());
+ UserPojoEx user = (UserPojoEx)obj;
+ assertNotNull(user);
+ assertEquals(123, user.getId());
+ assertEquals("Donald Duck", user.getName());
+ assertEquals(true, user.isActive());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ context.getTypeConverterRegistry().addTypeConverters(new MyTypeConverters());
+ restConfiguration().component("jetty").host("localhost").port(getPort()).bindingMode(RestBindingMode.json);
+
+ rest("/users/")
+ // REST binding converts from JSON to UserPojo
+ .post("new").type(UserPojo.class)
+ .route()
+ // then contract advice converts from UserPojo to UserPojoEx
+ .inputType(UserPojoEx.class)
+ .to("mock:input");
+ }
+ };
+ }
+
+ public static class MyTypeConverters implements TypeConverters {
+ @Converter
+ public UserPojoEx toEx(UserPojo user) {
+ UserPojoEx ex = new UserPojoEx();
+ ex.setId(user.getId());
+ ex.setName(user.getName());
+ ex.setActive(true);
+ return ex;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/RestJettyBindingModeOffWithContractTest.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/RestJettyBindingModeOffWithContractTest.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/RestJettyBindingModeOffWithContractTest.java
new file mode 100644
index 0000000..fa17257
--- /dev/null
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/RestJettyBindingModeOffWithContractTest.java
@@ -0,0 +1,99 @@
+/**
+ * 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.jetty.rest;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.jetty.BaseJettyTest;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.model.dataformat.JsonDataFormat;
+import org.apache.camel.model.dataformat.JsonLibrary;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestDefinition;
+import org.junit.Test;
+
+public class RestJettyBindingModeOffWithContractTest extends BaseJettyTest {
+
+ @Test
+ public void testBindingModeOffWithContract() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:input");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(UserPojoEx.class);
+
+ String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+ Object answer = template.requestBodyAndHeader("http://localhost:" + getPort() + "/users/new", body, Exchange.CONTENT_TYPE, "application/json");
+ assertNotNull(answer);
+ BufferedReader reader = new BufferedReader(new InputStreamReader((InputStream)answer));
+ String line;
+ String answerString = "";
+ while ((line = reader.readLine()) != null) {
+ answerString += line;
+ }
+ assertTrue("Unexpected response: " + answerString, answerString.contains("\"active\":true"));
+
+ assertMockEndpointsSatisfied();
+
+ Object obj = mock.getReceivedExchanges().get(0).getIn().getBody();
+ assertEquals(UserPojoEx.class, obj.getClass());
+ UserPojoEx user = (UserPojoEx)obj;
+ assertNotNull(user);
+ assertEquals(123, user.getId());
+ assertEquals("Donald Duck", user.getName());
+ assertEquals(true, user.isActive());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ restConfiguration().component("jetty").host("localhost").port(getPort()).bindingMode(RestBindingMode.off);
+
+ JsonDataFormat jsondf = new JsonDataFormat();
+ jsondf.setLibrary(JsonLibrary.Jackson);
+ jsondf.setAllowUnmarshallType(true);
+ jsondf.setUnmarshalType(UserPojoEx.class);
+ transformer()
+ .fromType("json")
+ .toType(UserPojoEx.class)
+ .withDataFormat(jsondf);
+ transformer()
+ .fromType(UserPojoEx.class)
+ .toType("json")
+ .withDataFormat(jsondf);
+ rest("/users/")
+ // REST binding does nothing
+ .post("new")
+ .route()
+ // contract advice converts betweeen JSON and UserPojoEx directly
+ .inputType(UserPojoEx.class)
+ .outputType("json")
+ .process(ex -> {
+ ex.getIn().getBody(UserPojoEx.class).setActive(true);
+ })
+ .to("mock:input");
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/UserPojoEx.java
----------------------------------------------------------------------
diff --git a/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/UserPojoEx.java b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/UserPojoEx.java
new file mode 100644
index 0000000..5ae627a
--- /dev/null
+++ b/components/camel-jetty9/src/test/java/org/apache/camel/component/jetty/rest/UserPojoEx.java
@@ -0,0 +1,48 @@
+/**
+ * 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.jetty.rest;
+
+public class UserPojoEx {
+
+ private int id;
+ private String name;
+ private boolean active;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/RestNettyHttpBindingModeJsonWithContractTest.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/RestNettyHttpBindingModeJsonWithContractTest.java b/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/RestNettyHttpBindingModeJsonWithContractTest.java
new file mode 100644
index 0000000..d522064
--- /dev/null
+++ b/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/RestNettyHttpBindingModeJsonWithContractTest.java
@@ -0,0 +1,83 @@
+/**
+ * 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.netty4.http.rest;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.netty4.http.BaseNettyTest;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestDefinition;
+import org.junit.Test;
+
+public class RestNettyHttpBindingModeJsonWithContractTest extends BaseNettyTest {
+
+ @Test
+ public void testBindingModeJsonWithContract() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:input");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(UserPojoEx.class);
+
+ String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+ Object answer = template.requestBody("netty4-http:http://localhost:" + getPort() + "/users/new", body);
+ assertNotNull(answer);
+ String answerString = new String((byte[])answer);
+ assertTrue("Unexpected response: " + answerString, answerString.contains("\"active\":true"));
+
+ assertMockEndpointsSatisfied();
+
+ Object obj = mock.getReceivedExchanges().get(0).getIn().getBody();
+ assertEquals(UserPojoEx.class, obj.getClass());
+ UserPojoEx user = (UserPojoEx)obj;
+ assertNotNull(user);
+ assertEquals(123, user.getId());
+ assertEquals("Donald Duck", user.getName());
+ assertEquals(true, user.isActive());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ context.getTypeConverterRegistry().addTypeConverters(new MyTypeConverters());
+ restConfiguration().component("netty4-http").host("localhost").port(getPort()).bindingMode(RestBindingMode.json);
+
+ rest("/users/")
+ // REST binding converts from JSON to UserPojo
+ .post("new").type(UserPojo.class)
+ .route()
+ // then contract advice converts from UserPojo to UserPojoEx
+ .inputType(UserPojoEx.class)
+ .to("mock:input");
+ }
+ };
+ }
+
+ public static class MyTypeConverters implements TypeConverters {
+ @Converter
+ public UserPojoEx toEx(UserPojo user) {
+ UserPojoEx ex = new UserPojoEx();
+ ex.setId(user.getId());
+ ex.setName(user.getName());
+ ex.setActive(true);
+ return ex;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/RestNettyHttpBindingModeOffWithContractTest.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/RestNettyHttpBindingModeOffWithContractTest.java b/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/RestNettyHttpBindingModeOffWithContractTest.java
new file mode 100644
index 0000000..81ca1ad
--- /dev/null
+++ b/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/RestNettyHttpBindingModeOffWithContractTest.java
@@ -0,0 +1,90 @@
+/**
+ * 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.netty4.http.rest;
+
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConverters;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.component.netty4.http.BaseNettyTest;
+import org.apache.camel.model.dataformat.JsonDataFormat;
+import org.apache.camel.model.dataformat.JsonLibrary;
+import org.apache.camel.model.rest.RestBindingMode;
+import org.apache.camel.model.rest.RestDefinition;
+import org.junit.Test;
+
+public class RestNettyHttpBindingModeOffWithContractTest extends BaseNettyTest {
+
+ @Test
+ public void testBindingModeOffWithContract() throws Exception {
+ MockEndpoint mock = getMockEndpoint("mock:input");
+ mock.expectedMessageCount(1);
+ mock.message(0).body().isInstanceOf(UserPojoEx.class);
+
+ String body = "{\"id\": 123, \"name\": \"Donald Duck\"}";
+ Object answer = template.requestBodyAndHeader("netty4-http:http://localhost:" + getPort() + "/users/new", body, Exchange.CONTENT_TYPE, "application/json");
+ assertNotNull(answer);
+ String answerString = new String((byte[])answer);
+ assertTrue("Unexpected response: " + answerString, answerString.contains("\"active\":true"));
+
+ assertMockEndpointsSatisfied();
+
+ Object obj = mock.getReceivedExchanges().get(0).getIn().getBody();
+ assertEquals(UserPojoEx.class, obj.getClass());
+ UserPojoEx user = (UserPojoEx)obj;
+ assertNotNull(user);
+ assertEquals(123, user.getId());
+ assertEquals("Donald Duck", user.getName());
+ assertEquals(true, user.isActive());
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ restConfiguration().component("netty4-http").host("localhost").port(getPort()).bindingMode(RestBindingMode.off);
+
+ JsonDataFormat jsondf = new JsonDataFormat();
+ jsondf.setLibrary(JsonLibrary.Jackson);
+ jsondf.setAllowUnmarshallType(true);
+ jsondf.setUnmarshalType(UserPojoEx.class);
+ transformer()
+ .fromType("json")
+ .toType(UserPojoEx.class)
+ .withDataFormat(jsondf);
+ transformer()
+ .fromType(UserPojoEx.class)
+ .toType("json")
+ .withDataFormat(jsondf);
+ rest("/users/")
+ // REST binding does nothing
+ .post("new")
+ .route()
+ // contract advice converts betweeen JSON and UserPojoEx directly
+ .inputType(UserPojoEx.class)
+ .outputType("json")
+ .process(ex -> {
+ ex.getIn().getBody(UserPojoEx.class).setActive(true);
+ })
+ .to("mock:input");
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/8c9184b6/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/UserPojoEx.java
----------------------------------------------------------------------
diff --git a/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/UserPojoEx.java b/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/UserPojoEx.java
new file mode 100644
index 0000000..48d2466
--- /dev/null
+++ b/components/camel-netty4-http/src/test/java/org/apache/camel/component/netty4/http/rest/UserPojoEx.java
@@ -0,0 +1,48 @@
+/**
+ * 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.netty4.http.rest;
+
+public class UserPojoEx {
+
+ private int id;
+ private String name;
+ private boolean active;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+}
[3/3] camel git commit: CAMEL-10532 Extract ContractAdvice as an
individual file
Posted by da...@apache.org.
CAMEL-10532 Extract ContractAdvice as an individual file
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/25b2ba25
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/25b2ba25
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/25b2ba25
Branch: refs/heads/master
Commit: 25b2ba250776c0046d0bcec869f0aa98caa92e4c
Parents: 605710d
Author: Tomohisa Igarashi <tm...@gmail.com>
Authored: Fri Feb 3 15:17:23 2017 +0900
Committer: Tomohisa Igarashi <tm...@gmail.com>
Committed: Tue Feb 14 20:43:46 2017 +0900
----------------------------------------------------------------------
.../apache/camel/impl/DefaultRouteContext.java | 3 +-
.../camel/processor/CamelInternalProcessor.java | 140 -----------------
.../apache/camel/processor/ContractAdvice.java | 152 +++++++++++++++++++
3 files changed, 154 insertions(+), 141 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/25b2ba25/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
index 8a2e7c1..328dae9 100644
--- a/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
+++ b/camel-core/src/main/java/org/apache/camel/impl/DefaultRouteContext.java
@@ -35,6 +35,7 @@ import org.apache.camel.model.FromDefinition;
import org.apache.camel.model.ProcessorDefinition;
import org.apache.camel.model.RouteDefinition;
import org.apache.camel.processor.CamelInternalProcessor;
+import org.apache.camel.processor.ContractAdvice;
import org.apache.camel.processor.Pipeline;
import org.apache.camel.spi.Contract;
import org.apache.camel.spi.InterceptStrategy;
@@ -195,7 +196,7 @@ public class DefaultRouteContext implements RouteContext {
// wrap in contract
if (contract != null) {
- internal.addAdvice(new CamelInternalProcessor.ContractAdvice(contract));
+ internal.addAdvice(new ContractAdvice(contract));
}
// and create the route that wraps the UoW
http://git-wip-us.apache.org/repos/asf/camel/blob/25b2ba25/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java
index 3ce9220..c98b1b0 100644
--- a/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java
+++ b/camel-core/src/main/java/org/apache/camel/processor/CamelInternalProcessor.java
@@ -25,7 +25,6 @@ import java.util.concurrent.RejectedExecutionException;
import org.apache.camel.AsyncCallback;
import org.apache.camel.CamelContext;
import org.apache.camel.Exchange;
-import org.apache.camel.Message;
import org.apache.camel.MessageHistory;
import org.apache.camel.Ordered;
import org.apache.camel.Processor;
@@ -40,8 +39,6 @@ import org.apache.camel.model.ProcessorDefinitionHelper;
import org.apache.camel.processor.interceptor.BacklogDebugger;
import org.apache.camel.processor.interceptor.BacklogTracer;
import org.apache.camel.processor.interceptor.DefaultBacklogTracerEventMessage;
-import org.apache.camel.spi.Contract;
-import org.apache.camel.spi.DataType;
import org.apache.camel.spi.InflightRepository;
import org.apache.camel.spi.MessageHistoryFactory;
import org.apache.camel.spi.RouteContext;
@@ -857,141 +854,4 @@ public class CamelInternalProcessor extends DelegateAsyncProcessor {
// noop
}
}
-
- /**
- * Advice for data type contract
- * TODO add declarative validation
- */
- public static class ContractAdvice implements CamelInternalProcessorAdvice {
- private Contract contract;
-
- public ContractAdvice(Contract contract) {
- this.contract = contract;
- }
-
- @Override
- public Object before(Exchange exchange) throws Exception {
- DataType from = getCurrentType(exchange, Exchange.INPUT_TYPE);
- DataType to = contract.getInputType();
- if (to != null && !to.equals(from)) {
- LOG.debug("Looking for transformer for INPUT: from='{}', to='{}'", from, to);
- doTransform(exchange.getIn(), from, to);
- exchange.setProperty(Exchange.INPUT_TYPE, to);
- }
- return null;
- }
-
- @Override
- public void after(Exchange exchange, Object data) throws Exception {
- Message target = exchange.hasOut() ? exchange.getOut() : exchange.getIn();
- DataType from = getCurrentType(exchange, exchange.hasOut() ? Exchange.OUTPUT_TYPE : Exchange.INPUT_TYPE);
- DataType to = contract.getOutputType();
- if (to != null && !to.equals(from)) {
- LOG.debug("Looking for transformer for OUTPUT: from='{}', to='{}'", from, to);
- doTransform(target, from, to);
- exchange.setProperty(exchange.hasOut() ? Exchange.OUTPUT_TYPE : Exchange.INPUT_TYPE, to);
- }
- }
-
- private void doTransform(Message message, DataType from, DataType to) throws Exception {
- // transform into 'from' type before performing declared transformation
- convertIfRequired(message, from);
-
- if (applyExactlyMatchedTransformer(message, from, to)) {
- // Found exactly matched transformer. Java-Java transformer is also allowed.
- return;
- } else if (from == null || from.isJavaType()) {
- if (convertIfRequired(message, to)) {
- // Java->Java transformation just relies on TypeConverter if no explicit transformer
- return;
- } else if (from == null) {
- // {undefined}->Other transformation - assuming it's already in expected shape
- return;
- } else if (applyTransformerByToModel(message, from, to)) {
- // Java->Other transformation - found a transformer supports 'to' data model
- return;
- }
- } else if (from != null) {
- if (to.isJavaType()) {
- if (applyTransformerByFromModel(message, from, to)) {
- // Other->Java transformation - found a transformer supprts 'from' data model
- return;
- }
- } else if (applyTransformerChain(message, from, to)) {
- // Other->Other transformation - found a transformer chain
- return;
- }
- }
-
- throw new IllegalArgumentException("No Transformer found for [from='" + from + "', to='" + to + "']");
- }
-
- private boolean convertIfRequired(Message message, DataType type) throws Exception {
- // TODO for better performance it may be better to add TypeConveterTransformer
- // into transformer registry automatically to avoid unnecessary scan in transformer registry
- CamelContext context = message.getExchange().getContext();
- if (type != null && type.isJavaType() && type.getName() != null) {
- Class<?> typeJava = getClazz(type.getName(), context);
- if (!typeJava.isAssignableFrom(message.getBody().getClass())) {
- LOG.debug("Converting to '{}'", typeJava.getName());
- message.setBody(message.getMandatoryBody(typeJava));
- return true;
- }
- }
- return false;
- }
-
- private boolean applyTransformer(Transformer transformer, Message message, DataType from, DataType to) throws Exception {
- if (transformer != null) {
- LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
- transformer.transform(message, from, to);
- return true;
- }
- return false;
- }
- private boolean applyExactlyMatchedTransformer(Message message, DataType from, DataType to) throws Exception {
- Transformer transformer = message.getExchange().getContext().resolveTransformer(from, to);
- return applyTransformer(transformer, message, from, to);
- }
-
- private boolean applyTransformerByToModel(Message message, DataType from, DataType to) throws Exception {
- Transformer transformer = message.getExchange().getContext().resolveTransformer(to.getModel());
- return applyTransformer(transformer, message, from, to);
- }
-
- private boolean applyTransformerByFromModel(Message message, DataType from, DataType to) throws Exception {
- Transformer transformer = message.getExchange().getContext().resolveTransformer(from.getModel());
- return applyTransformer(transformer, message, from, to);
- }
-
- private boolean applyTransformerChain(Message message, DataType from, DataType to) throws Exception {
- CamelContext context = message.getExchange().getContext();
- Transformer fromTransformer = context.resolveTransformer(from.getModel());
- Transformer toTransformer = context.resolveTransformer(to.getModel());
- if (fromTransformer != null && toTransformer != null) {
- LOG.debug("Applying transformer 1/2: from='{}', to='{}', transformer='{}'", from, to, fromTransformer);
- fromTransformer.transform(message, from, new DataType(Object.class));
- LOG.debug("Applying transformer 2/2: from='{}', to='{}', transformer='{}'", from, to, toTransformer);
- toTransformer.transform(message, new DataType(Object.class), to);
- return true;
- }
- return false;
- }
-
- private Class<?> getClazz(String type, CamelContext context) throws Exception {
- return context.getClassResolver().resolveMandatoryClass(type);
- }
-
- private DataType getCurrentType(Exchange exchange, String name) {
- Object prop = exchange.getProperty(name);
- if (prop instanceof DataType) {
- return (DataType)prop;
- } else if (prop instanceof String) {
- DataType answer = new DataType((String)prop);
- exchange.setProperty(name, answer);
- return answer;
- }
- return null;
- }
- }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/25b2ba25/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java b/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
new file mode 100644
index 0000000..15a3d61
--- /dev/null
+++ b/camel-core/src/main/java/org/apache/camel/processor/ContractAdvice.java
@@ -0,0 +1,152 @@
+package org.apache.camel.processor;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.spi.Contract;
+import org.apache.camel.spi.DataType;
+import org.apache.camel.spi.Transformer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A {@code CamelInternalProcessorAdvice} which performs Transformation and Validation
+ * according to the data type Contract.
+ *
+ * TODO add declarative validation
+ * @see CamelInternalProcessor, CamelInternalProcessorAdvice
+ */
+public class ContractAdvice implements CamelInternalProcessorAdvice {
+ private static final Logger LOG = LoggerFactory.getLogger(CamelInternalProcessor.class);
+
+ private Contract contract;
+
+ public ContractAdvice(Contract contract) {
+ this.contract = contract;
+ }
+
+ @Override
+ public Object before(Exchange exchange) throws Exception {
+ DataType from = getCurrentType(exchange, Exchange.INPUT_TYPE);
+ DataType to = contract.getInputType();
+ if (to != null && !to.equals(from)) {
+ LOG.debug("Looking for transformer for INPUT: from='{}', to='{}'", from, to);
+ doTransform(exchange.getIn(), from, to);
+ exchange.setProperty(Exchange.INPUT_TYPE, to);
+ }
+ return null;
+ }
+
+ @Override
+ public void after(Exchange exchange, Object data) throws Exception {
+ Message target = exchange.hasOut() ? exchange.getOut() : exchange.getIn();
+ DataType from = getCurrentType(exchange, exchange.hasOut() ? Exchange.OUTPUT_TYPE : Exchange.INPUT_TYPE);
+ DataType to = contract.getOutputType();
+ if (to != null && !to.equals(from)) {
+ LOG.debug("Looking for transformer for OUTPUT: from='{}', to='{}'", from, to);
+ doTransform(target, from, to);
+ exchange.setProperty(exchange.hasOut() ? Exchange.OUTPUT_TYPE : Exchange.INPUT_TYPE, to);
+ }
+ }
+
+ private void doTransform(Message message, DataType from, DataType to) throws Exception {
+ // transform into 'from' type before performing declared transformation
+ convertIfRequired(message, from);
+
+ if (applyExactlyMatchedTransformer(message, from, to)) {
+ // Found exactly matched transformer. Java-Java transformer is also allowed.
+ return;
+ } else if (from == null || from.isJavaType()) {
+ if (convertIfRequired(message, to)) {
+ // Java->Java transformation just relies on TypeConverter if no explicit transformer
+ return;
+ } else if (from == null) {
+ // {undefined}->Other transformation - assuming it's already in expected shape
+ return;
+ } else if (applyTransformerByToModel(message, from, to)) {
+ // Java->Other transformation - found a transformer supports 'to' data model
+ return;
+ }
+ } else if (from != null) {
+ if (to.isJavaType()) {
+ if (applyTransformerByFromModel(message, from, to)) {
+ // Other->Java transformation - found a transformer supprts 'from' data model
+ return;
+ }
+ } else if (applyTransformerChain(message, from, to)) {
+ // Other->Other transformation - found a transformer chain
+ return;
+ }
+ }
+
+ throw new IllegalArgumentException("No Transformer found for [from='" + from + "', to='" + to + "']");
+ }
+
+ private boolean convertIfRequired(Message message, DataType type) throws Exception {
+ // TODO for better performance it may be better to add TypeConveterTransformer
+ // into transformer registry automatically to avoid unnecessary scan in transformer registry
+ CamelContext context = message.getExchange().getContext();
+ if (type != null && type.isJavaType() && type.getName() != null) {
+ Class<?> typeJava = getClazz(type.getName(), context);
+ if (!typeJava.isAssignableFrom(message.getBody().getClass())) {
+ LOG.debug("Converting to '{}'", typeJava.getName());
+ message.setBody(message.getMandatoryBody(typeJava));
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean applyTransformer(Transformer transformer, Message message, DataType from, DataType to) throws Exception {
+ if (transformer != null) {
+ LOG.debug("Applying transformer: from='{}', to='{}', transformer='{}'", from, to, transformer);
+ transformer.transform(message, from, to);
+ return true;
+ }
+ return false;
+ }
+ private boolean applyExactlyMatchedTransformer(Message message, DataType from, DataType to) throws Exception {
+ Transformer transformer = message.getExchange().getContext().resolveTransformer(from, to);
+ return applyTransformer(transformer, message, from, to);
+ }
+
+ private boolean applyTransformerByToModel(Message message, DataType from, DataType to) throws Exception {
+ Transformer transformer = message.getExchange().getContext().resolveTransformer(to.getModel());
+ return applyTransformer(transformer, message, from, to);
+ }
+
+ private boolean applyTransformerByFromModel(Message message, DataType from, DataType to) throws Exception {
+ Transformer transformer = message.getExchange().getContext().resolveTransformer(from.getModel());
+ return applyTransformer(transformer, message, from, to);
+ }
+
+ private boolean applyTransformerChain(Message message, DataType from, DataType to) throws Exception {
+ CamelContext context = message.getExchange().getContext();
+ Transformer fromTransformer = context.resolveTransformer(from.getModel());
+ Transformer toTransformer = context.resolveTransformer(to.getModel());
+ if (fromTransformer != null && toTransformer != null) {
+ LOG.debug("Applying transformer 1/2: from='{}', to='{}', transformer='{}'", from, to, fromTransformer);
+ fromTransformer.transform(message, from, new DataType(Object.class));
+ LOG.debug("Applying transformer 2/2: from='{}', to='{}', transformer='{}'", from, to, toTransformer);
+ toTransformer.transform(message, new DataType(Object.class), to);
+ return true;
+ }
+ return false;
+ }
+
+ private Class<?> getClazz(String type, CamelContext context) throws Exception {
+ return context.getClassResolver().resolveMandatoryClass(type);
+ }
+
+ private DataType getCurrentType(Exchange exchange, String name) {
+ Object prop = exchange.getProperty(name);
+ if (prop instanceof DataType) {
+ return (DataType)prop;
+ } else if (prop instanceof String) {
+ DataType answer = new DataType((String)prop);
+ exchange.setProperty(name, answer);
+ return answer;
+ }
+ return null;
+ }
+}
\ No newline at end of file