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 2014/12/08 18:31:56 UTC
[1/2] camel git commit: CAMEL-8133: rest-dsl make it easy to enable
and configure CORS. Also fixed an issue with the skip option.
Repository: camel
Updated Branches:
refs/heads/camel-2.14.x a0100ba07 -> 4cbee5f11
refs/heads/master 8cfabc840 -> 7cbd69884
CAMEL-8133: rest-dsl make it easy to enable and configure CORS. Also fixed an issue with the skip option.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/7cbd6988
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/7cbd6988
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/7cbd6988
Branch: refs/heads/master
Commit: 7cbd69884385eb340e74dc215c4247deff7c2ef2
Parents: 8cfabc8
Author: Claus Ibsen <da...@apache.org>
Authored: Mon Dec 8 18:31:27 2014 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Mon Dec 8 18:31:27 2014 +0100
----------------------------------------------------------------------
.../camel/model/rest/RestBindingDefinition.java | 29 ++++++--
.../model/rest/RestConfigurationDefinition.java | 53 +++++++++++++
.../apache/camel/model/rest/RestDefinition.java | 35 ++++++++-
.../apache/camel/model/rest/VerbDefinition.java | 11 +++
.../processor/binding/RestBindingProcessor.java | 63 +++++++++++++++-
.../org/apache/camel/spi/RestConfiguration.java | 51 +++++++++++++
.../rest/FromRestGetCorsCustomTest.java | 78 ++++++++++++++++++++
.../component/rest/FromRestGetCorsTest.java | 77 +++++++++++++++++++
8 files changed, 390 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/7cbd6988/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 3f07d26..abe2a06 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
@@ -54,6 +54,9 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
@XmlAttribute
private Boolean skipBindingOnErrorCode;
+ @XmlAttribute
+ private Boolean enableCORS;
+
@Override
public String toString() {
return "RestBinding";
@@ -69,18 +72,26 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
CamelContext context = routeContext.getCamelContext();
- // the default binding mode can be overridden per rest verb
+ // these options can be overriden per rest verb
String mode = context.getRestConfiguration().getBindingMode().name();
if (bindingMode != null) {
mode = bindingMode.name();
}
+ boolean cors = context.getRestConfiguration().isEnableCORS();
+ if (enableCORS != null) {
+ cors = enableCORS;
+ }
+ boolean skip = context.getRestConfiguration().isSkipBindingOnErrorCode();
+ if (skipBindingOnErrorCode != null) {
+ skip = skipBindingOnErrorCode;
+ }
- // skip by default
- boolean skip = skipBindingOnErrorCode == null || skipBindingOnErrorCode;
+ // cors headers
+ Map<String, String> corsHeaders = context.getRestConfiguration().getCorsHeaders();
if (mode == null || "off".equals(mode)) {
// binding mode is off, so create a off mode binding processor
- return new RestBindingProcessor(null, null, null, null, consumes, produces, mode, skip);
+ return new RestBindingProcessor(null, null, null, null, consumes, produces, mode, skip, cors, corsHeaders);
}
// setup json data format
@@ -182,7 +193,7 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
context.addService(outJaxb);
}
- return new RestBindingProcessor(json, jaxb, outJson, outJaxb, consumes, produces, mode, skip);
+ return new RestBindingProcessor(json, jaxb, outJson, outJaxb, consumes, produces, mode, skip, cors, corsHeaders);
}
private void setAdditionalConfiguration(CamelContext context, DataFormat dataFormat) throws Exception {
@@ -242,4 +253,12 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
public void setSkipBindingOnErrorCode(Boolean skipBindingOnErrorCode) {
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
}
+
+ public Boolean getEnableCORS() {
+ return enableCORS;
+ }
+
+ public void setEnableCORS(Boolean enableCORS) {
+ this.enableCORS = enableCORS;
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7cbd6988/camel-core/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java b/camel-core/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java
index 50d3879..b033dc6 100644
--- a/camel-core/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java
@@ -62,6 +62,9 @@ public class RestConfigurationDefinition {
private Boolean skipBindingOnErrorCode;
@XmlAttribute
+ private Boolean enableCORS;
+
+ @XmlAttribute
private String jsonDataFormat;
@XmlAttribute
@@ -79,6 +82,9 @@ public class RestConfigurationDefinition {
@XmlElement(name = "dataFormatProperty")
private List<RestPropertyDefinition> dataFormatProperties = new ArrayList<RestPropertyDefinition>();
+ @XmlElement(name = "corsHeaders")
+ private List<RestPropertyDefinition> corsHeaders = new ArrayList<RestPropertyDefinition>();
+
public String getComponent() {
return component;
}
@@ -143,6 +149,14 @@ public class RestConfigurationDefinition {
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
}
+ public Boolean getEnableCORS() {
+ return enableCORS;
+ }
+
+ public void setEnableCORS(Boolean enableCORS) {
+ this.enableCORS = enableCORS;
+ }
+
public String getJsonDataFormat() {
return jsonDataFormat;
}
@@ -191,6 +205,14 @@ public class RestConfigurationDefinition {
this.dataFormatProperties = dataFormatProperties;
}
+ public List<RestPropertyDefinition> getCorsHeaders() {
+ return corsHeaders;
+ }
+
+ public void setCorsHeaders(List<RestPropertyDefinition> corsHeaders) {
+ this.corsHeaders = corsHeaders;
+ }
+
// Fluent API
//-------------------------------------------------------------------------
@@ -270,6 +292,14 @@ public class RestConfigurationDefinition {
}
/**
+ * To specify whether to enable CORS which means Camel will automatic include CORS in the HTTP headers in the response.
+ */
+ public RestConfigurationDefinition enableCORS(boolean enableCORS) {
+ setEnableCORS(enableCORS);
+ return this;
+ }
+
+ /**
* To use a specific json data format
* <p/>
* <b>Important:</b> This option is only for setting a custom name of the data format, not to refer to an existing data format instance.
@@ -337,6 +367,17 @@ public class RestConfigurationDefinition {
return this;
}
+ /**
+ * For configuring CORS headers
+ */
+ public RestConfigurationDefinition corsHeaderProperty(String key, String value) {
+ RestPropertyDefinition prop = new RestPropertyDefinition();
+ prop.setKey(key);
+ prop.setValue(value);
+ getCorsHeaders().add(prop);
+ return this;
+ }
+
// Implementation
//-------------------------------------------------------------------------
@@ -373,6 +414,9 @@ public class RestConfigurationDefinition {
if (skipBindingOnErrorCode != null) {
answer.setSkipBindingOnErrorCode(skipBindingOnErrorCode);
}
+ if (enableCORS != null) {
+ answer.setEnableCORS(enableCORS);
+ }
if (jsonDataFormat != null) {
answer.setJsonDataFormat(jsonDataFormat);
}
@@ -415,6 +459,15 @@ public class RestConfigurationDefinition {
}
answer.setDataFormatProperties(props);
}
+ if (!corsHeaders.isEmpty()) {
+ Map<String, String> props = new HashMap<String, String>();
+ for (RestPropertyDefinition prop : corsHeaders) {
+ String key = prop.getKey();
+ String value = CamelContextHelper.parseText(context, prop.getValue());
+ props.put(key, value);
+ }
+ answer.setCorsHeaders(props);
+ }
return answer;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7cbd6988/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 479f830..64128cd 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
@@ -56,6 +56,9 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
@XmlAttribute
private Boolean skipBindingOnErrorCode;
+ @XmlAttribute
+ private Boolean enableCORS;
+
@XmlElementRef
private List<VerbDefinition> verbs = new ArrayList<VerbDefinition>();
@@ -111,7 +114,15 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
public void setSkipBindingOnErrorCode(Boolean skipBindingOnErrorCode) {
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
}
-
+
+ public Boolean getEnableCORS() {
+ return enableCORS;
+ }
+
+ public void setEnableCORS(Boolean enableCORS) {
+ this.enableCORS = enableCORS;
+ }
+
// Fluent API
//-------------------------------------------------------------------------
@@ -305,6 +316,18 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
return this;
}
+ public RestDefinition enableCORS(boolean enableCORS) {
+ if (getVerbs().isEmpty()) {
+ this.enableCORS = enableCORS;
+ } else {
+ // add on last verb as that is how the Java DSL works
+ VerbDefinition verb = getVerbs().get(getVerbs().size() - 1);
+ verb.setEnableCORS(enableCORS);
+ }
+
+ return this;
+ }
+
/**
* Routes directly to the given endpoint.
* <p/>
@@ -405,6 +428,16 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
} else {
binding.setBindingMode(getBindingMode());
}
+ if (verb.getSkipBindingOnErrorCode() != null) {
+ binding.setSkipBindingOnErrorCode(verb.getSkipBindingOnErrorCode());
+ } else {
+ binding.setSkipBindingOnErrorCode(getSkipBindingOnErrorCode());
+ }
+ if (verb.getEnableCORS() != null) {
+ binding.setEnableCORS(verb.getEnableCORS());
+ } else {
+ binding.setEnableCORS(getEnableCORS());
+ }
route.getOutputs().add(0, binding);
// create the from endpoint uri which is using the rest component
http://git-wip-us.apache.org/repos/asf/camel/blob/7cbd6988/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java b/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
index 4ba401c..af56af1 100644
--- a/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
@@ -51,6 +51,9 @@ public class VerbDefinition extends OptionalIdentifiedDefinition<VerbDefinition>
private Boolean skipBindingOnErrorCode;
@XmlAttribute
+ private Boolean enableCORS;
+
+ @XmlAttribute
private String type;
@XmlAttribute
@@ -129,6 +132,14 @@ public class VerbDefinition extends OptionalIdentifiedDefinition<VerbDefinition>
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
}
+ public Boolean getEnableCORS() {
+ return enableCORS;
+ }
+
+ public void setEnableCORS(Boolean enableCORS) {
+ this.enableCORS = enableCORS;
+ }
+
public String getType() {
return type;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7cbd6988/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
index 9be0118..8a0de0d 100644
--- a/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
+++ b/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
@@ -17,14 +17,17 @@
package org.apache.camel.processor.binding;
import java.util.Locale;
+import java.util.Map;
import org.apache.camel.AsyncCallback;
import org.apache.camel.AsyncProcessor;
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.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;
@@ -49,10 +52,14 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess
private final String produces;
private final String bindingMode;
private final boolean skipBindingOnErrorCode;
+ private final boolean enableCORS;
+ private final Map<String, String> corsHeaders;
public RestBindingProcessor(DataFormat jsonDataFormat, DataFormat xmlDataFormat,
DataFormat outJsonDataFormat, DataFormat outXmlDataFormat,
- String consumes, String produces, String bindingMode, boolean skipBindingOnErrorCode) {
+ String consumes, String produces, String bindingMode,
+ boolean skipBindingOnErrorCode, boolean enableCORS,
+ Map<String, String> corsHeaders) {
if (jsonDataFormat != null) {
this.jsonUnmarshal = new UnmarshalProcessor(jsonDataFormat);
@@ -84,6 +91,8 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess
this.produces = produces;
this.bindingMode = bindingMode;
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
+ this.enableCORS = enableCORS;
+ this.corsHeaders = corsHeaders;
}
@Override
@@ -93,6 +102,10 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess
@Override
public boolean process(Exchange exchange, final AsyncCallback callback) {
+ if (enableCORS) {
+ exchange.addOnCompletion(new RestBindingCORSOnCompletion(corsHeaders));
+ }
+
if (bindingMode == null || "off".equals(bindingMode)) {
// binding is off
callback.done(true);
@@ -339,6 +352,54 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess
exchange.setException(e);
}
}
+
+ @Override
+ public String toString() {
+ return "RestBindingMarshalOnCompletion";
+ }
+ }
+
+ private final class RestBindingCORSOnCompletion extends SynchronizationAdapter {
+
+ private final Map<String, String> corsHeaders;
+
+ private RestBindingCORSOnCompletion(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 "RestBindingCORSOnCompletion";
+ }
}
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7cbd6988/camel-core/src/main/java/org/apache/camel/spi/RestConfiguration.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/RestConfiguration.java b/camel-core/src/main/java/org/apache/camel/spi/RestConfiguration.java
index 50d64f7..5daecd9 100644
--- a/camel-core/src/main/java/org/apache/camel/spi/RestConfiguration.java
+++ b/camel-core/src/main/java/org/apache/camel/spi/RestConfiguration.java
@@ -24,6 +24,11 @@ import java.util.Map;
*/
public class RestConfiguration {
+ public static final String CORS_ACCESS_CONTROL_ALLOW_ORIGIN = "*";
+ public static final String CORS_ACCESS_CONTROL_ALLOW_METHODS = "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH";
+ public static final String CORS_ACCESS_CONTROL_MAX_AGE = "3600";
+ public static final String CORS_ACCESS_CONTROL_ALLOW_HEADERS = "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers";
+
public enum RestBindingMode {
auto, off, json, xml, json_xml
}
@@ -40,12 +45,14 @@ public class RestConfiguration {
private RestHostNameResolver restHostNameResolver = RestHostNameResolver.localHostName;
private RestBindingMode bindingMode = RestBindingMode.off;
private boolean skipBindingOnErrorCode = true;
+ private boolean enableCORS;
private String jsonDataFormat;
private String xmlDataFormat;
private Map<String, Object> componentProperties;
private Map<String, Object> endpointProperties;
private Map<String, Object> consumerProperties;
private Map<String, Object> dataFormatProperties;
+ private Map<String, String> corsHeaders;
/**
* Gets the name of the Camel component to use as the REST consumer
@@ -198,6 +205,8 @@ public class RestConfiguration {
* Whether to skip binding output if there is a custom HTTP error code, and instead use the response body as-is.
* <p/>
* This option is default <tt>true</tt>.
+ *
+ * @return whether to skip binding on error code
*/
public boolean isSkipBindingOnErrorCode() {
return skipBindingOnErrorCode;
@@ -207,12 +216,36 @@ public class RestConfiguration {
* Whether to skip binding output if there is a custom HTTP error code, and instead use the response body as-is.
* <p/>
* This option is default <tt>true</tt>.
+ *
+ * @param skipBindingOnErrorCode whether to skip binding on error code
*/
public void setSkipBindingOnErrorCode(boolean skipBindingOnErrorCode) {
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
}
/**
+ * To specify whether to enable CORS which means Camel will automatic include CORS in the HTTP headers in the response.
+ * <p/>
+ * This option is default <tt>false</tt>
+ *
+ * @return whether CORS is enabled or not
+ */
+ public boolean isEnableCORS() {
+ return enableCORS;
+ }
+
+ /**
+ * To specify whether to enable CORS which means Camel will automatic include CORS in the HTTP headers in the response.
+ * <p/>
+ * This option is default <tt>false</tt>
+ *
+ * @param enableCORS <tt>true</tt> to enable CORS
+ */
+ public void setEnableCORS(boolean enableCORS) {
+ this.enableCORS = enableCORS;
+ }
+
+ /**
* Gets the name of the json data format.
* <p/>
* <b>Important:</b> This option is only for setting a custom name of the data format, not to refer to an existing data format instance.
@@ -327,4 +360,22 @@ public class RestConfiguration {
public void setDataFormatProperties(Map<String, Object> dataFormatProperties) {
this.dataFormatProperties = dataFormatProperties;
}
+
+ /**
+ * Gets the CORS headers to use if CORS has been enabled.
+ *
+ * @return the CORS headers
+ */
+ public Map<String, String> getCorsHeaders() {
+ return corsHeaders;
+ }
+
+ /**
+ * Sets the CORS headers to use if CORS has been enabled.
+ *
+ * @param corsHeaders the CORS headers
+ */
+ public void setCorsHeaders(Map<String, String> corsHeaders) {
+ this.corsHeaders = corsHeaders;
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/7cbd6988/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsCustomTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsCustomTest.java b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsCustomTest.java
new file mode 100644
index 0000000..997fbbf
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsCustomTest.java
@@ -0,0 +1,78 @@
+/**
+ * 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 org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.spi.RestConfiguration;
+
+public class FromRestGetCorsCustomTest extends ContextTestSupport {
+
+ @Override
+ protected JndiRegistry createRegistry() throws Exception {
+ JndiRegistry jndi = super.createRegistry();
+ jndi.bind("dummy-rest", new DummyRestConsumerFactory());
+ return jndi;
+ }
+
+ public void testCors() throws Exception {
+ // the rest becomes routes and the input is a seda endpoint created by the DummyRestConsumerFactory
+ getMockEndpoint("mock:update").expectedMessageCount(1);
+
+ Exchange out = template.request("seda:post-say-bye", new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ exchange.getIn().setBody("I was here");
+ }
+ });
+ assertNotNull(out);
+
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Origin"), "myserver");
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Methods"), RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_METHODS);
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Headers"), RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_HEADERS);
+ assertEquals(out.getOut().getHeader("Access-Control-Max-Age"), "180");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ restConfiguration().enableCORS(true).corsHeaderProperty("Access-Control-Allow-Origin", "myserver");
+ restConfiguration().enableCORS(true).corsHeaderProperty("Access-Control-Max-Age", "180");
+
+ rest("/say/hello")
+ .get().to("direct:hello");
+
+ rest("/say/bye")
+ .get().consumes("application/json").to("direct:bye")
+ .post().to("mock:update");
+
+ from("direct:hello")
+ .transform().constant("Hello World");
+
+ from("direct:bye")
+ .transform().constant("Bye World");
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/7cbd6988/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsTest.java b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsTest.java
new file mode 100644
index 0000000..b0b213c
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsTest.java
@@ -0,0 +1,77 @@
+/**
+ * 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 org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.spi.RestConfiguration;
+
+public class FromRestGetCorsTest extends ContextTestSupport {
+
+ @Override
+ protected JndiRegistry createRegistry() throws Exception {
+ JndiRegistry jndi = super.createRegistry();
+ jndi.bind("dummy-rest", new DummyRestConsumerFactory());
+ return jndi;
+ }
+
+ public void testCors() throws Exception {
+ // the rest becomes routes and the input is a seda endpoint created by the DummyRestConsumerFactory
+ getMockEndpoint("mock:update").expectedMessageCount(1);
+
+ Exchange out = template.request("seda:post-say-bye", new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ exchange.getIn().setBody("I was here");
+ }
+ });
+ assertNotNull(out);
+
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Origin"), RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_ORIGIN);
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Methods"), RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_METHODS);
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Headers"), RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_HEADERS);
+ assertEquals(out.getOut().getHeader("Access-Control-Max-Age"), RestConfiguration.CORS_ACCESS_CONTROL_MAX_AGE);
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ restConfiguration().enableCORS(true);
+
+ rest("/say/hello")
+ .get().to("direct:hello");
+
+ rest("/say/bye")
+ .get().consumes("application/json").to("direct:bye")
+ .post().to("mock:update");
+
+ from("direct:hello")
+ .transform().constant("Hello World");
+
+ from("direct:bye")
+ .transform().constant("Bye World");
+ }
+ };
+ }
+}
[2/2] camel git commit: CAMEL-8133: rest-dsl make it easy to enable
and configure CORS. Also fixed an issue with the skip option.
Posted by da...@apache.org.
CAMEL-8133: rest-dsl make it easy to enable and configure CORS. Also fixed an issue with the skip option.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/4cbee5f1
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/4cbee5f1
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/4cbee5f1
Branch: refs/heads/camel-2.14.x
Commit: 4cbee5f1171c38a0f5f8678823a9ab520b8d6090
Parents: a0100ba
Author: Claus Ibsen <da...@apache.org>
Authored: Mon Dec 8 18:31:27 2014 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Mon Dec 8 18:31:43 2014 +0100
----------------------------------------------------------------------
.../camel/model/rest/RestBindingDefinition.java | 29 ++++++--
.../model/rest/RestConfigurationDefinition.java | 53 +++++++++++++
.../apache/camel/model/rest/RestDefinition.java | 35 ++++++++-
.../apache/camel/model/rest/VerbDefinition.java | 11 +++
.../processor/binding/RestBindingProcessor.java | 63 +++++++++++++++-
.../org/apache/camel/spi/RestConfiguration.java | 51 +++++++++++++
.../rest/FromRestGetCorsCustomTest.java | 78 ++++++++++++++++++++
.../component/rest/FromRestGetCorsTest.java | 77 +++++++++++++++++++
8 files changed, 390 insertions(+), 7 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/4cbee5f1/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 3f07d26..abe2a06 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
@@ -54,6 +54,9 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
@XmlAttribute
private Boolean skipBindingOnErrorCode;
+ @XmlAttribute
+ private Boolean enableCORS;
+
@Override
public String toString() {
return "RestBinding";
@@ -69,18 +72,26 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
CamelContext context = routeContext.getCamelContext();
- // the default binding mode can be overridden per rest verb
+ // these options can be overriden per rest verb
String mode = context.getRestConfiguration().getBindingMode().name();
if (bindingMode != null) {
mode = bindingMode.name();
}
+ boolean cors = context.getRestConfiguration().isEnableCORS();
+ if (enableCORS != null) {
+ cors = enableCORS;
+ }
+ boolean skip = context.getRestConfiguration().isSkipBindingOnErrorCode();
+ if (skipBindingOnErrorCode != null) {
+ skip = skipBindingOnErrorCode;
+ }
- // skip by default
- boolean skip = skipBindingOnErrorCode == null || skipBindingOnErrorCode;
+ // cors headers
+ Map<String, String> corsHeaders = context.getRestConfiguration().getCorsHeaders();
if (mode == null || "off".equals(mode)) {
// binding mode is off, so create a off mode binding processor
- return new RestBindingProcessor(null, null, null, null, consumes, produces, mode, skip);
+ return new RestBindingProcessor(null, null, null, null, consumes, produces, mode, skip, cors, corsHeaders);
}
// setup json data format
@@ -182,7 +193,7 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
context.addService(outJaxb);
}
- return new RestBindingProcessor(json, jaxb, outJson, outJaxb, consumes, produces, mode, skip);
+ return new RestBindingProcessor(json, jaxb, outJson, outJaxb, consumes, produces, mode, skip, cors, corsHeaders);
}
private void setAdditionalConfiguration(CamelContext context, DataFormat dataFormat) throws Exception {
@@ -242,4 +253,12 @@ public class RestBindingDefinition extends NoOutputDefinition<RestBindingDefinit
public void setSkipBindingOnErrorCode(Boolean skipBindingOnErrorCode) {
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
}
+
+ public Boolean getEnableCORS() {
+ return enableCORS;
+ }
+
+ public void setEnableCORS(Boolean enableCORS) {
+ this.enableCORS = enableCORS;
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4cbee5f1/camel-core/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java b/camel-core/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java
index 50d3879..b033dc6 100644
--- a/camel-core/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/rest/RestConfigurationDefinition.java
@@ -62,6 +62,9 @@ public class RestConfigurationDefinition {
private Boolean skipBindingOnErrorCode;
@XmlAttribute
+ private Boolean enableCORS;
+
+ @XmlAttribute
private String jsonDataFormat;
@XmlAttribute
@@ -79,6 +82,9 @@ public class RestConfigurationDefinition {
@XmlElement(name = "dataFormatProperty")
private List<RestPropertyDefinition> dataFormatProperties = new ArrayList<RestPropertyDefinition>();
+ @XmlElement(name = "corsHeaders")
+ private List<RestPropertyDefinition> corsHeaders = new ArrayList<RestPropertyDefinition>();
+
public String getComponent() {
return component;
}
@@ -143,6 +149,14 @@ public class RestConfigurationDefinition {
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
}
+ public Boolean getEnableCORS() {
+ return enableCORS;
+ }
+
+ public void setEnableCORS(Boolean enableCORS) {
+ this.enableCORS = enableCORS;
+ }
+
public String getJsonDataFormat() {
return jsonDataFormat;
}
@@ -191,6 +205,14 @@ public class RestConfigurationDefinition {
this.dataFormatProperties = dataFormatProperties;
}
+ public List<RestPropertyDefinition> getCorsHeaders() {
+ return corsHeaders;
+ }
+
+ public void setCorsHeaders(List<RestPropertyDefinition> corsHeaders) {
+ this.corsHeaders = corsHeaders;
+ }
+
// Fluent API
//-------------------------------------------------------------------------
@@ -270,6 +292,14 @@ public class RestConfigurationDefinition {
}
/**
+ * To specify whether to enable CORS which means Camel will automatic include CORS in the HTTP headers in the response.
+ */
+ public RestConfigurationDefinition enableCORS(boolean enableCORS) {
+ setEnableCORS(enableCORS);
+ return this;
+ }
+
+ /**
* To use a specific json data format
* <p/>
* <b>Important:</b> This option is only for setting a custom name of the data format, not to refer to an existing data format instance.
@@ -337,6 +367,17 @@ public class RestConfigurationDefinition {
return this;
}
+ /**
+ * For configuring CORS headers
+ */
+ public RestConfigurationDefinition corsHeaderProperty(String key, String value) {
+ RestPropertyDefinition prop = new RestPropertyDefinition();
+ prop.setKey(key);
+ prop.setValue(value);
+ getCorsHeaders().add(prop);
+ return this;
+ }
+
// Implementation
//-------------------------------------------------------------------------
@@ -373,6 +414,9 @@ public class RestConfigurationDefinition {
if (skipBindingOnErrorCode != null) {
answer.setSkipBindingOnErrorCode(skipBindingOnErrorCode);
}
+ if (enableCORS != null) {
+ answer.setEnableCORS(enableCORS);
+ }
if (jsonDataFormat != null) {
answer.setJsonDataFormat(jsonDataFormat);
}
@@ -415,6 +459,15 @@ public class RestConfigurationDefinition {
}
answer.setDataFormatProperties(props);
}
+ if (!corsHeaders.isEmpty()) {
+ Map<String, String> props = new HashMap<String, String>();
+ for (RestPropertyDefinition prop : corsHeaders) {
+ String key = prop.getKey();
+ String value = CamelContextHelper.parseText(context, prop.getValue());
+ props.put(key, value);
+ }
+ answer.setCorsHeaders(props);
+ }
return answer;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4cbee5f1/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 479f830..64128cd 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
@@ -56,6 +56,9 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
@XmlAttribute
private Boolean skipBindingOnErrorCode;
+ @XmlAttribute
+ private Boolean enableCORS;
+
@XmlElementRef
private List<VerbDefinition> verbs = new ArrayList<VerbDefinition>();
@@ -111,7 +114,15 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
public void setSkipBindingOnErrorCode(Boolean skipBindingOnErrorCode) {
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
}
-
+
+ public Boolean getEnableCORS() {
+ return enableCORS;
+ }
+
+ public void setEnableCORS(Boolean enableCORS) {
+ this.enableCORS = enableCORS;
+ }
+
// Fluent API
//-------------------------------------------------------------------------
@@ -305,6 +316,18 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
return this;
}
+ public RestDefinition enableCORS(boolean enableCORS) {
+ if (getVerbs().isEmpty()) {
+ this.enableCORS = enableCORS;
+ } else {
+ // add on last verb as that is how the Java DSL works
+ VerbDefinition verb = getVerbs().get(getVerbs().size() - 1);
+ verb.setEnableCORS(enableCORS);
+ }
+
+ return this;
+ }
+
/**
* Routes directly to the given endpoint.
* <p/>
@@ -405,6 +428,16 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition>
} else {
binding.setBindingMode(getBindingMode());
}
+ if (verb.getSkipBindingOnErrorCode() != null) {
+ binding.setSkipBindingOnErrorCode(verb.getSkipBindingOnErrorCode());
+ } else {
+ binding.setSkipBindingOnErrorCode(getSkipBindingOnErrorCode());
+ }
+ if (verb.getEnableCORS() != null) {
+ binding.setEnableCORS(verb.getEnableCORS());
+ } else {
+ binding.setEnableCORS(getEnableCORS());
+ }
route.getOutputs().add(0, binding);
// create the from endpoint uri which is using the rest component
http://git-wip-us.apache.org/repos/asf/camel/blob/4cbee5f1/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java b/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
index 4ba401c..af56af1 100644
--- a/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
+++ b/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java
@@ -51,6 +51,9 @@ public class VerbDefinition extends OptionalIdentifiedDefinition<VerbDefinition>
private Boolean skipBindingOnErrorCode;
@XmlAttribute
+ private Boolean enableCORS;
+
+ @XmlAttribute
private String type;
@XmlAttribute
@@ -129,6 +132,14 @@ public class VerbDefinition extends OptionalIdentifiedDefinition<VerbDefinition>
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
}
+ public Boolean getEnableCORS() {
+ return enableCORS;
+ }
+
+ public void setEnableCORS(Boolean enableCORS) {
+ this.enableCORS = enableCORS;
+ }
+
public String getType() {
return type;
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4cbee5f1/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java b/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
index 9be0118..8a0de0d 100644
--- a/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
+++ b/camel-core/src/main/java/org/apache/camel/processor/binding/RestBindingProcessor.java
@@ -17,14 +17,17 @@
package org.apache.camel.processor.binding;
import java.util.Locale;
+import java.util.Map;
import org.apache.camel.AsyncCallback;
import org.apache.camel.AsyncProcessor;
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.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;
@@ -49,10 +52,14 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess
private final String produces;
private final String bindingMode;
private final boolean skipBindingOnErrorCode;
+ private final boolean enableCORS;
+ private final Map<String, String> corsHeaders;
public RestBindingProcessor(DataFormat jsonDataFormat, DataFormat xmlDataFormat,
DataFormat outJsonDataFormat, DataFormat outXmlDataFormat,
- String consumes, String produces, String bindingMode, boolean skipBindingOnErrorCode) {
+ String consumes, String produces, String bindingMode,
+ boolean skipBindingOnErrorCode, boolean enableCORS,
+ Map<String, String> corsHeaders) {
if (jsonDataFormat != null) {
this.jsonUnmarshal = new UnmarshalProcessor(jsonDataFormat);
@@ -84,6 +91,8 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess
this.produces = produces;
this.bindingMode = bindingMode;
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
+ this.enableCORS = enableCORS;
+ this.corsHeaders = corsHeaders;
}
@Override
@@ -93,6 +102,10 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess
@Override
public boolean process(Exchange exchange, final AsyncCallback callback) {
+ if (enableCORS) {
+ exchange.addOnCompletion(new RestBindingCORSOnCompletion(corsHeaders));
+ }
+
if (bindingMode == null || "off".equals(bindingMode)) {
// binding is off
callback.done(true);
@@ -339,6 +352,54 @@ public class RestBindingProcessor extends ServiceSupport implements AsyncProcess
exchange.setException(e);
}
}
+
+ @Override
+ public String toString() {
+ return "RestBindingMarshalOnCompletion";
+ }
+ }
+
+ private final class RestBindingCORSOnCompletion extends SynchronizationAdapter {
+
+ private final Map<String, String> corsHeaders;
+
+ private RestBindingCORSOnCompletion(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 "RestBindingCORSOnCompletion";
+ }
}
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4cbee5f1/camel-core/src/main/java/org/apache/camel/spi/RestConfiguration.java
----------------------------------------------------------------------
diff --git a/camel-core/src/main/java/org/apache/camel/spi/RestConfiguration.java b/camel-core/src/main/java/org/apache/camel/spi/RestConfiguration.java
index 50d64f7..5daecd9 100644
--- a/camel-core/src/main/java/org/apache/camel/spi/RestConfiguration.java
+++ b/camel-core/src/main/java/org/apache/camel/spi/RestConfiguration.java
@@ -24,6 +24,11 @@ import java.util.Map;
*/
public class RestConfiguration {
+ public static final String CORS_ACCESS_CONTROL_ALLOW_ORIGIN = "*";
+ public static final String CORS_ACCESS_CONTROL_ALLOW_METHODS = "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH";
+ public static final String CORS_ACCESS_CONTROL_MAX_AGE = "3600";
+ public static final String CORS_ACCESS_CONTROL_ALLOW_HEADERS = "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers";
+
public enum RestBindingMode {
auto, off, json, xml, json_xml
}
@@ -40,12 +45,14 @@ public class RestConfiguration {
private RestHostNameResolver restHostNameResolver = RestHostNameResolver.localHostName;
private RestBindingMode bindingMode = RestBindingMode.off;
private boolean skipBindingOnErrorCode = true;
+ private boolean enableCORS;
private String jsonDataFormat;
private String xmlDataFormat;
private Map<String, Object> componentProperties;
private Map<String, Object> endpointProperties;
private Map<String, Object> consumerProperties;
private Map<String, Object> dataFormatProperties;
+ private Map<String, String> corsHeaders;
/**
* Gets the name of the Camel component to use as the REST consumer
@@ -198,6 +205,8 @@ public class RestConfiguration {
* Whether to skip binding output if there is a custom HTTP error code, and instead use the response body as-is.
* <p/>
* This option is default <tt>true</tt>.
+ *
+ * @return whether to skip binding on error code
*/
public boolean isSkipBindingOnErrorCode() {
return skipBindingOnErrorCode;
@@ -207,12 +216,36 @@ public class RestConfiguration {
* Whether to skip binding output if there is a custom HTTP error code, and instead use the response body as-is.
* <p/>
* This option is default <tt>true</tt>.
+ *
+ * @param skipBindingOnErrorCode whether to skip binding on error code
*/
public void setSkipBindingOnErrorCode(boolean skipBindingOnErrorCode) {
this.skipBindingOnErrorCode = skipBindingOnErrorCode;
}
/**
+ * To specify whether to enable CORS which means Camel will automatic include CORS in the HTTP headers in the response.
+ * <p/>
+ * This option is default <tt>false</tt>
+ *
+ * @return whether CORS is enabled or not
+ */
+ public boolean isEnableCORS() {
+ return enableCORS;
+ }
+
+ /**
+ * To specify whether to enable CORS which means Camel will automatic include CORS in the HTTP headers in the response.
+ * <p/>
+ * This option is default <tt>false</tt>
+ *
+ * @param enableCORS <tt>true</tt> to enable CORS
+ */
+ public void setEnableCORS(boolean enableCORS) {
+ this.enableCORS = enableCORS;
+ }
+
+ /**
* Gets the name of the json data format.
* <p/>
* <b>Important:</b> This option is only for setting a custom name of the data format, not to refer to an existing data format instance.
@@ -327,4 +360,22 @@ public class RestConfiguration {
public void setDataFormatProperties(Map<String, Object> dataFormatProperties) {
this.dataFormatProperties = dataFormatProperties;
}
+
+ /**
+ * Gets the CORS headers to use if CORS has been enabled.
+ *
+ * @return the CORS headers
+ */
+ public Map<String, String> getCorsHeaders() {
+ return corsHeaders;
+ }
+
+ /**
+ * Sets the CORS headers to use if CORS has been enabled.
+ *
+ * @param corsHeaders the CORS headers
+ */
+ public void setCorsHeaders(Map<String, String> corsHeaders) {
+ this.corsHeaders = corsHeaders;
+ }
}
http://git-wip-us.apache.org/repos/asf/camel/blob/4cbee5f1/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsCustomTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsCustomTest.java b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsCustomTest.java
new file mode 100644
index 0000000..997fbbf
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsCustomTest.java
@@ -0,0 +1,78 @@
+/**
+ * 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 org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.spi.RestConfiguration;
+
+public class FromRestGetCorsCustomTest extends ContextTestSupport {
+
+ @Override
+ protected JndiRegistry createRegistry() throws Exception {
+ JndiRegistry jndi = super.createRegistry();
+ jndi.bind("dummy-rest", new DummyRestConsumerFactory());
+ return jndi;
+ }
+
+ public void testCors() throws Exception {
+ // the rest becomes routes and the input is a seda endpoint created by the DummyRestConsumerFactory
+ getMockEndpoint("mock:update").expectedMessageCount(1);
+
+ Exchange out = template.request("seda:post-say-bye", new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ exchange.getIn().setBody("I was here");
+ }
+ });
+ assertNotNull(out);
+
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Origin"), "myserver");
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Methods"), RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_METHODS);
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Headers"), RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_HEADERS);
+ assertEquals(out.getOut().getHeader("Access-Control-Max-Age"), "180");
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ restConfiguration().enableCORS(true).corsHeaderProperty("Access-Control-Allow-Origin", "myserver");
+ restConfiguration().enableCORS(true).corsHeaderProperty("Access-Control-Max-Age", "180");
+
+ rest("/say/hello")
+ .get().to("direct:hello");
+
+ rest("/say/bye")
+ .get().consumes("application/json").to("direct:bye")
+ .post().to("mock:update");
+
+ from("direct:hello")
+ .transform().constant("Hello World");
+
+ from("direct:bye")
+ .transform().constant("Bye World");
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/camel/blob/4cbee5f1/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsTest.java
----------------------------------------------------------------------
diff --git a/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsTest.java b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsTest.java
new file mode 100644
index 0000000..b0b213c
--- /dev/null
+++ b/camel-core/src/test/java/org/apache/camel/component/rest/FromRestGetCorsTest.java
@@ -0,0 +1,77 @@
+/**
+ * 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 org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.JndiRegistry;
+import org.apache.camel.spi.RestConfiguration;
+
+public class FromRestGetCorsTest extends ContextTestSupport {
+
+ @Override
+ protected JndiRegistry createRegistry() throws Exception {
+ JndiRegistry jndi = super.createRegistry();
+ jndi.bind("dummy-rest", new DummyRestConsumerFactory());
+ return jndi;
+ }
+
+ public void testCors() throws Exception {
+ // the rest becomes routes and the input is a seda endpoint created by the DummyRestConsumerFactory
+ getMockEndpoint("mock:update").expectedMessageCount(1);
+
+ Exchange out = template.request("seda:post-say-bye", new Processor() {
+ @Override
+ public void process(Exchange exchange) throws Exception {
+ exchange.getIn().setBody("I was here");
+ }
+ });
+ assertNotNull(out);
+
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Origin"), RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_ORIGIN);
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Methods"), RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_METHODS);
+ assertEquals(out.getOut().getHeader("Access-Control-Allow-Headers"), RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_HEADERS);
+ assertEquals(out.getOut().getHeader("Access-Control-Max-Age"), RestConfiguration.CORS_ACCESS_CONTROL_MAX_AGE);
+
+ assertMockEndpointsSatisfied();
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() throws Exception {
+ return new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ restConfiguration().enableCORS(true);
+
+ rest("/say/hello")
+ .get().to("direct:hello");
+
+ rest("/say/bye")
+ .get().consumes("application/json").to("direct:bye")
+ .post().to("mock:update");
+
+ from("direct:hello")
+ .transform().constant("Hello World");
+
+ from("direct:bye")
+ .transform().constant("Bye World");
+ }
+ };
+ }
+}