CAMEL-7354: Rest DSL. Integrate with camel-servlet.

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

Branch: refs/heads/master
Commit: 036f6cbb1e49e92c44d3114807e5b3b44b3e14cc
Parents: 61a1a2a
Author: Claus Ibsen <davscl...@apache.org>
Authored: Mon Jul 28 15:44:24 2014 +0200
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Mon Jul 28 15:44:24 2014 +0200

----------------------------------------------------------------------
 .../component/jetty/JettyHttpComponent.java     |  32 ++----
 .../camel/component/jetty/JettyRestFilter.java  |  47 ---------
 .../servlet/CamelHttpTransportServlet.java      |   3 +
 .../component/servlet/ServletComponent.java     |  54 +++++++++-
 .../servlet/ServletRestHttpBinding.java         |  67 ++++++++++++
 ...rvletRestServletResolveConsumerStrategy.java | 102 +++++++++++++++++++
 .../servlet/rest/RestServletGetTest.java        |  66 ++++++++++++
 7 files changed, 300 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/036f6cbb/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
----------------------------------------------------------------------
diff --git 
a/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
 
b/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
index 1aee4be..757264d 100644
--- 
a/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
+++ 
b/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyHttpComponent.java
@@ -377,23 +377,16 @@ public class JettyHttpComponent extends HttpComponent 
implements RestConsumerFac
         ServletContextHandler context = 
server.getChildHandlerByClass(ServletContextHandler.class);
         List<Filter> filters = endpoint.getFilters();
         for (Filter filter : filters) {
-            if (filter instanceof JettyRestFilter) {
-                // special for rest filter
-                FilterHolder filterHolder = new FilterHolder();
-                filterHolder.setFilter(new CamelFilterWrapper(filter));
-                addFilter(context, filterHolder, "*");
-            } else {
-                FilterHolder filterHolder = new FilterHolder();
-                filterHolder.setFilter(new CamelFilterWrapper(filter));
-                String pathSpec = endpoint.getPath();
-                if (pathSpec == null || "".equals(pathSpec)) {
-                    pathSpec = "/";
-                }
-                if (endpoint.isMatchOnUriPrefix()) {
-                    pathSpec = pathSpec.endsWith("/") ? pathSpec + "*" : 
pathSpec + "/*";
-                }
-                addFilter(context, filterHolder, pathSpec);
+            FilterHolder filterHolder = new FilterHolder();
+            filterHolder.setFilter(new CamelFilterWrapper(filter));
+            String pathSpec = endpoint.getPath();
+            if (pathSpec == null || "".equals(pathSpec)) {
+                pathSpec = "/";
+            }
+            if (endpoint.isMatchOnUriPrefix()) {
+                pathSpec = pathSpec.endsWith("/") ? pathSpec + "*" : pathSpec 
+ "/*";
             }
+            addFilter(context, filterHolder, pathSpec);
         }
     }
     
@@ -995,13 +988,6 @@ public class JettyHttpComponent extends HttpComponent 
implements RestConsumerFac
         JettyHttpEndpoint endpoint = camelContext.getEndpoint(url, 
JettyHttpEndpoint.class);
         setProperties(endpoint, parameters);
 
-        // add our filter
-        //List<Filter> list = endpoint.getFilters();
-        //if (list == null) {
-        //    list = new ArrayList<Filter>();
-        //}
-        //list.add(0, new JettyRestFilter());
-        //endpoint.setFilters(list);
         // disable this filter as we want to use ours
         endpoint.setEnableMultipartFilter(false);
         // use the rest binding

http://git-wip-us.apache.org/repos/asf/camel/blob/036f6cbb/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyRestFilter.java
----------------------------------------------------------------------
diff --git 
a/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyRestFilter.java
 
b/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyRestFilter.java
deleted file mode 100644
index 9dd612e..0000000
--- 
a/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/JettyRestFilter.java
+++ /dev/null
@@ -1,47 +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.jetty;
-
-import java.io.IOException;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-public class JettyRestFilter implements Filter {
-
-    // TODO: we may want to use a filter so we can reuse this for camel-servlet
-    // to have it match the request with list of accepted paths
-
-
-    @Override
-    public void init(FilterConfig filterConfig) throws ServletException {
-        // noop
-    }
-
-    @Override
-    public void doFilter(ServletRequest servletRequest, ServletResponse 
servletResponse, FilterChain filterChain) throws IOException, ServletException {
-        filterChain.doFilter(servletRequest, servletResponse);
-    }
-
-    @Override
-    public void destroy() {
-        // noop
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/036f6cbb/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/CamelHttpTransportServlet.java
----------------------------------------------------------------------
diff --git 
a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/CamelHttpTransportServlet.java
 
b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/CamelHttpTransportServlet.java
index f064136..733ea72 100644
--- 
a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/CamelHttpTransportServlet.java
+++ 
b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/CamelHttpTransportServlet.java
@@ -39,6 +39,9 @@ public class CamelHttpTransportServlet extends CamelServlet {
     public void init(ServletConfig config) throws ServletException {
         super.init(config);
 
+        // use rest enabled resolver in case we use rest
+        this.setServletResolveConsumerStrategy(new 
ServletRestServletResolveConsumerStrategy());
+
         String ignore = config.getInitParameter("ignoreDuplicateServletName");
         Boolean bool = ObjectConverter.toBoolean(ignore);
         if (bool != null) {

http://git-wip-us.apache.org/repos/asf/camel/blob/036f6cbb/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
----------------------------------------------------------------------
diff --git 
a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
 
b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
index 789538c..0fbe4d6 100644
--- 
a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
+++ 
b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletComponent.java
@@ -17,11 +17,16 @@
 package org.apache.camel.component.servlet;
 
 import java.net.URI;
+import java.util.HashMap;
 import java.util.LinkedHashSet;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.camel.CamelContext;
+import org.apache.camel.Consumer;
 import org.apache.camel.Endpoint;
+import org.apache.camel.Processor;
 import org.apache.camel.component.http.AuthMethod;
 import org.apache.camel.component.http.HttpBinding;
 import org.apache.camel.component.http.HttpClientConfigurer;
@@ -29,13 +34,16 @@ import org.apache.camel.component.http.HttpComponent;
 import org.apache.camel.component.http.HttpConsumer;
 import org.apache.camel.component.http.HttpEndpoint;
 import org.apache.camel.spi.HeaderFilterStrategy;
+import org.apache.camel.spi.RestConfiguration;
+import org.apache.camel.spi.RestConsumerFactory;
+import org.apache.camel.util.FileUtil;
 import org.apache.camel.util.IntrospectionSupport;
 import org.apache.camel.util.URISupport;
 import org.apache.camel.util.UnsafeUriCharactersEncoder;
 import org.apache.commons.httpclient.HttpConnectionManager;
 import org.apache.commons.httpclient.params.HttpClientParams;
 
-public class ServletComponent extends HttpComponent {
+public class ServletComponent extends HttpComponent implements 
RestConsumerFactory {
 
     private String servletName = "CamelServlet";
     private HttpRegistry httpRegistry;
@@ -156,4 +164,48 @@ public class ServletComponent extends HttpComponent {
     }
 
 
+    @Override
+    public Consumer createConsumer(CamelContext camelContext, Processor 
processor, String verb, String path,
+                                   String consumes, String produces, 
Map<String, Object> parameters) throws Exception {
+        path = FileUtil.stripLeadingSeparator(path);
+
+        // if no explicit port/host configured, then use port from rest 
configuration
+        RestConfiguration config = getCamelContext().getRestConfiguration();
+
+        Map<String, Object> map = new HashMap<String, Object>();
+        // build query string, and append any endpoint configuration properties
+        if (config != null && (config.getComponent() == null || 
config.getComponent().equals("servlet"))) {
+            // setup endpoint options
+            if (config.getEndpointProperties() != null && 
!config.getEndpointProperties().isEmpty()) {
+                map.putAll(config.getEndpointProperties());
+            }
+        }
+
+        String query = URISupport.createQueryString(map);
+
+        // servlet:///hello
+        String url = "servlet:///%s?httpMethodRestrict=%s";
+        if (!query.isEmpty()) {
+            url = url + "?" + query;
+        }
+
+        // must use upper case for restrict
+        String restrict = verb.toUpperCase(Locale.US);
+
+        // get the endpoint
+        url = String.format(url, path, restrict);
+        ServletEndpoint endpoint = camelContext.getEndpoint(url, 
ServletEndpoint.class);
+        setProperties(endpoint, parameters);
+
+        // use the rest binding
+        endpoint.setBinding(new ServletRestHttpBinding());
+
+        // configure consumer properties
+        Consumer consumer = endpoint.createConsumer(processor);
+        if (config != null && config.getConsumerProperties() != null && 
!config.getConsumerProperties().isEmpty()) {
+            setProperties(consumer, config.getConsumerProperties());
+        }
+
+        return consumer;
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/camel/blob/036f6cbb/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletRestHttpBinding.java
----------------------------------------------------------------------
diff --git 
a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletRestHttpBinding.java
 
b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletRestHttpBinding.java
new file mode 100644
index 0000000..add507a
--- /dev/null
+++ 
b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletRestHttpBinding.java
@@ -0,0 +1,67 @@
+/**
+ * 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;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.camel.component.http.DefaultHttpBinding;
+import org.apache.camel.component.http.HttpMessage;
+
+public class ServletRestHttpBinding extends DefaultHttpBinding {
+
+    @Override
+    protected void populateRequestParameters(HttpServletRequest request, 
HttpMessage message) throws Exception {
+        super.populateRequestParameters(request, message);
+
+        String path = request.getPathInfo();
+        if (path == null) {
+            return;
+        }
+
+        // in the endpoint the user may have defined rest {} placeholders
+        // so we need to map those placeholders with data from the incoming 
request context path
+
+        ServletEndpoint endpoint = (ServletEndpoint) 
message.getExchange().getFromEndpoint();
+        String consumerPath = endpoint.getPath();
+
+        if (useRestMatching(consumerPath)) {
+
+            // split using single char / is optimized in the jdk
+            String[] paths = path.split("/");
+            String[] consumerPaths = consumerPath.split("/");
+
+            for (int i = 0; i < consumerPaths.length; i++) {
+                if (paths.length < i) {
+                    break;
+                }
+                String p1 = consumerPaths[i];
+                if (p1.startsWith("{") && p1.endsWith("}")) {
+                    String key = p1.substring(1, p1.length() - 1);
+                    String value = paths[i];
+                    if (value != null) {
+                        message.setHeader(key, value);
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean useRestMatching(String path) {
+        // only need to do rest matching if using { } placeholders
+        return path.indexOf('{') > -1;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/036f6cbb/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletRestServletResolveConsumerStrategy.java
----------------------------------------------------------------------
diff --git 
a/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletRestServletResolveConsumerStrategy.java
 
b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletRestServletResolveConsumerStrategy.java
new file mode 100644
index 0000000..7a5a57b
--- /dev/null
+++ 
b/components/camel-servlet/src/main/java/org/apache/camel/component/servlet/ServletRestServletResolveConsumerStrategy.java
@@ -0,0 +1,102 @@
+/**
+ * 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;
+
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.camel.component.http.HttpConsumer;
+import org.apache.camel.component.http.HttpServletResolveConsumerStrategy;
+
+/**
+ * A {@link 
org.apache.camel.component.http.HttpServletResolveConsumerStrategy} that 
supports the Rest DSL.
+ */
+public class ServletRestServletResolveConsumerStrategy extends 
HttpServletResolveConsumerStrategy {
+
+    @Override
+    public HttpConsumer resolve(HttpServletRequest request, Map<String, 
HttpConsumer> consumers) {
+        String path = request.getPathInfo();
+        if (path == null) {
+            return null;
+        }
+
+        for (String key : consumers.keySet()) {
+            if (useRestMatching(key) && matchRestPath(path, key)) {
+                return consumers.get(key);
+            }
+        }
+
+        // fallback to default
+        return super.resolve(request, consumers);
+    }
+
+    private boolean useRestMatching(String path) {
+        // only need to do rest matching if using { } placeholders
+        return path.indexOf('{') > -1;
+    }
+
+    /**
+     * Matches the given request path with the configured consumer path
+     *
+     * @param requestPath   the request path
+     * @param consumerPath  the consumer path which may use { } tokens
+     * @return <tt>true</tt> if matched, <tt>false</tt> otherwise
+     */
+    public boolean matchRestPath(String requestPath, String consumerPath) {
+        // remove starting/ending slashes
+        if (requestPath.startsWith("/")) {
+            requestPath = requestPath.substring(1);
+        }
+        if (requestPath.endsWith("/")) {
+            requestPath = requestPath.substring(0, requestPath.length() - 1);
+        }
+        // remove starting/ending slashes
+        if (consumerPath.startsWith("/")) {
+            consumerPath = consumerPath.substring(1);
+        }
+        if (consumerPath.endsWith("/")) {
+            consumerPath = consumerPath.substring(0, consumerPath.length() - 
1);
+        }
+
+        // split using single char / is optimized in the jdk
+        String[] requestPaths = requestPath.split("/");
+        String[] consumerPaths = consumerPath.split("/");
+
+        // must be same number of path's
+        if (requestPaths.length != consumerPaths.length) {
+            return false;
+        }
+
+        for (int i = 0; i < requestPaths.length; i++) {
+            String p1 = requestPaths[i];
+            String p2 = consumerPaths[i];
+
+            if (p2.startsWith("{") && p2.endsWith("}")) {
+                // always matches
+                continue;
+            }
+
+            if (!p1.equals(p2)) {
+                return false;
+            }
+        }
+
+        // assume matching
+        return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/036f6cbb/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletGetTest.java
----------------------------------------------------------------------
diff --git 
a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletGetTest.java
 
b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletGetTest.java
new file mode 100644
index 0000000..fc9611d
--- /dev/null
+++ 
b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletGetTest.java
@@ -0,0 +1,66 @@
+/**
+ * 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 com.meterware.httpunit.GetMethodWebRequest;
+import com.meterware.httpunit.WebRequest;
+import com.meterware.httpunit.WebResponse;
+import com.meterware.servletunit.ServletUnitClient;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.servlet.ServletCamelRouterTestSupport;
+import org.junit.Test;
+
+public class RestServletGetTest extends ServletCamelRouterTestSupport {
+
+    @Test
+    public void testServletProducerGet() throws Exception {
+        WebRequest req = new GetMethodWebRequest(CONTEXT_URL + 
"/services/users/123/basic");
+        ServletUnitClient client = newClient();
+        client.setExceptionsThrownOnErrorStatus(false);
+        WebResponse response = client.getResponse(req);
+
+        assertEquals(200, response.getResponseCode());
+
+        assertEquals("123;Donald Duck", response.getText());
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                // configure to use servlet on localhost
+                restConfiguration().component("servlet").host("localhost");
+
+                // use the rest DSL to define the rest services
+                rest("/users/")
+                    .get("{id}/basic")
+                        .route()
+                        .to("mock:input")
+                        .process(new Processor() {
+                            public void process(Exchange exchange) throws 
Exception {
+                                String id = exchange.getIn().getHeader("id", 
String.class);
+                                exchange.getOut().setBody(id + ";Donald Duck");
+                            }
+                        });
+            }
+        };
+    }
+
+}

Reply via email to