You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2009/06/23 23:54:09 UTC

svn commit: r787849 - in /cxf/trunk: rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ rt/frontend/jaxrs/src/test/java/org...

Author: sergeyb
Date: Tue Jun 23 21:54:08 2009
New Revision: 787849

URL: http://svn.apache.org/viewvc?rev=787849&view=rev
Log:
JAXRS : support for overriding HTTP methods

Added:
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/RequestPreprocessorTest.java   (with props)
    cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/RETRIEVE.java   (with props)
Removed:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/SystemQueryHandler.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/ext/SystemQueryHandlerTest.java
Modified:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RequestPreprocessor.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
    cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSpring.java
    cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerSpringBookTest.java

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RequestPreprocessor.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RequestPreprocessor.java?rev=787849&r1=787848&r2=787849&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RequestPreprocessor.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/RequestPreprocessor.java Tue Jun 23 21:54:08 2009
@@ -20,9 +20,12 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.UriInfo;
 
 import org.apache.cxf.jaxrs.utils.HttpUtils;
@@ -30,9 +33,27 @@
 
 public class RequestPreprocessor {
     
+    private static final String ACCEPT_QUERY = "_type";
+    private static final String METHOD_QUERY = "_method";
+    private static final String METHOD_HEADER = "X-HTTP-Method-Override";
+    
+    
+    private static final Map<String, String> SHORTCUTS;
+    static {
+        SHORTCUTS = new HashMap<String, String>();
+        SHORTCUTS.put("json", "application/json");
+        SHORTCUTS.put("text", "text/*");
+        SHORTCUTS.put("xml", "application/xml");
+        // more to come
+    }
+    
     private Map<Object, Object> languageMappings;
     private Map<Object, Object> extensionMappings;
     
+    public RequestPreprocessor() {
+        this(null, null);
+    }
+    
     public RequestPreprocessor(Map<Object, Object> languageMappings,
                            Map<Object, Object> extensionMappings) {
         this.languageMappings =
@@ -44,6 +65,10 @@
     public String preprocess(Message m, UriInfo u) {
         handleExtensionMappings(m, u);
         handleLanguageMappings(m, u);
+        
+        MultivaluedMap<String, String> queries = u.getQueryParameters();
+        handleTypeQuery(m, queries);
+        handleMethod(m, queries, new HttpHeadersImpl(m));
         return new UriInfoImpl(m, null).getPath();
     }
     
@@ -70,27 +95,54 @@
         
     }
     
-    private void updateAcceptTypeHeader(Message m, String anotherValue) {
-        m.put(Message.ACCEPT_CONTENT_TYPE, anotherValue);
-    }
-    
     @SuppressWarnings("unchecked")
     private void updateAcceptLanguageHeader(Message m, String anotherValue) {
         List<String> acceptLanguage =
-            ((Map<String, List<String>>)m.get(Message.PROTOCOL_HEADERS)).get("Accept-Language");
+            ((Map<String, List<String>>)m.get(Message.PROTOCOL_HEADERS)).get(HttpHeaders.ACCEPT_LANGUAGE);
         if (acceptLanguage == null) {
             acceptLanguage = new ArrayList<String>(); 
         }
         
         acceptLanguage.add(anotherValue);
         ((Map<String, List<String>>)m.get(Message.PROTOCOL_HEADERS))
-            .put("Accept-Language", acceptLanguage);
+            .put(HttpHeaders.ACCEPT_LANGUAGE, acceptLanguage);
     }
     
     private void updatePath(Message m, String path, String suffix) {
         String newPath = path.substring(0, path.length() - (suffix.length() + 1));
         HttpUtils.updatePath(m, newPath);
-        //m.put(Message.REQUEST_URI, newPath);
+    }
+    
+    private void handleMethod(Message m, 
+                              MultivaluedMap<String, String> queries,
+                              HttpHeaders headers) {
+        String method = queries.getFirst(METHOD_QUERY);
+        if (method == null) {
+            List<String> values = headers.getRequestHeader(METHOD_HEADER);
+            if (values.size() == 1) {
+                method = values.get(0);
+            }
+        }
+        if (method != null) {
+            m.put(Message.HTTP_REQUEST_METHOD, method);
+        }
+    }
+    
+    private void handleTypeQuery(Message m, MultivaluedMap<String, String> queries) {
+        String type = queries.getFirst(ACCEPT_QUERY);
+        if (type != null) {
+            if (SHORTCUTS.containsKey(type)) {
+                type = SHORTCUTS.get(type);
+            }
+            updateAcceptTypeHeader(m, type);
+        }
+    }
+    
+    @SuppressWarnings("unchecked")
+    private void updateAcceptTypeHeader(Message m, String acceptValue) {
+        m.put(Message.ACCEPT_CONTENT_TYPE, acceptValue);
+        ((Map<String, List<String>>)m.get(Message.PROTOCOL_HEADERS))
+        .put(HttpHeaders.ACCEPT, Collections.singletonList(acceptValue));
     }
     
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java?rev=787849&r1=787848&r2=787849&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ProviderFactory.java Tue Jun 23 21:54:08 2009
@@ -42,7 +42,6 @@
 import org.apache.cxf.jaxrs.ext.ParameterHandler;
 import org.apache.cxf.jaxrs.ext.RequestHandler;
 import org.apache.cxf.jaxrs.ext.ResponseHandler;
-import org.apache.cxf.jaxrs.ext.SystemQueryHandler;
 import org.apache.cxf.jaxrs.impl.RequestPreprocessor;
 import org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper;
 import org.apache.cxf.jaxrs.model.ProviderInfo;
@@ -78,7 +77,6 @@
                                     new PrimitiveTextProvider(),
                                     new MultipartProvider(),
                                     new WebApplicationExceptionMapper(),
-                                    new SystemQueryHandler(),
                                     new WadlGenerator());
     }
     

Added: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/RequestPreprocessorTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/RequestPreprocessorTest.java?rev=787849&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/RequestPreprocessorTest.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/RequestPreprocessorTest.java Tue Jun 23 21:54:08 2009
@@ -0,0 +1,110 @@
+/**
+ * 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.cxf.jaxrs.impl;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cxf.message.Exchange;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
+import org.apache.cxf.service.model.EndpointInfo;
+import org.apache.cxf.transport.servlet.ServletDestination;
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+
+
+public class RequestPreprocessorTest extends Assert {
+
+    private IMocksControl control;
+    
+    @Before
+    public void setUp() {
+        control = EasyMock.createNiceControl();
+        control.makeThreadSafe(true);
+    }
+    
+    @Test
+    public void testMethodQuery() {
+        Message m = mockMessage("http://localhost:8080", "/bar", "_method=GET", "POST");
+        RequestPreprocessor sqh = new RequestPreprocessor();
+        sqh.preprocess(m, new UriInfoImpl(m, null));
+        assertEquals("GET", m.get(Message.HTTP_REQUEST_METHOD));
+    }
+    
+    @Test
+    public void testMethodOverride() {
+        Message m = mockMessage("http://localhost:8080", "/bar", "bar", "POST", "GET");
+        RequestPreprocessor sqh = new RequestPreprocessor();
+        sqh.preprocess(m, new UriInfoImpl(m, null));
+        assertEquals("GET", m.get(Message.HTTP_REQUEST_METHOD));
+    }
+    
+    @Test
+    public void testTypeQuery() {
+        Message m = mockMessage("http://localhost:8080", "/bar", "_type=xml", "POST");
+        RequestPreprocessor sqh = new RequestPreprocessor();
+        sqh.preprocess(m, new UriInfoImpl(m, null));
+        assertEquals("POST", m.get(Message.HTTP_REQUEST_METHOD));
+        assertEquals("application/xml", m.get(Message.ACCEPT_CONTENT_TYPE));
+    }
+    
+    private Message mockMessage(String baseAddress, 
+                                String pathInfo, 
+                                String query,
+                                String method) {
+        return mockMessage(baseAddress, pathInfo, query, method, null);
+    }
+    
+    private Message mockMessage(String baseAddress, 
+                                String pathInfo, 
+                                String query,
+                                String method,
+                                String methodHeader) {
+        Message m = new MessageImpl();
+        control.reset();
+        Exchange e = control.createMock(Exchange.class);
+        m.setExchange(e);
+        ServletDestination d = control.createMock(ServletDestination.class);
+        e.getDestination();
+        EasyMock.expectLastCall().andReturn(d).anyTimes();
+        EndpointInfo epr = new EndpointInfo(); 
+        epr.setAddress(baseAddress);
+        d.getEndpointInfo();
+        EasyMock.expectLastCall().andReturn(epr).anyTimes();
+        m.put(Message.REQUEST_URI, pathInfo);
+        m.put(Message.QUERY_STRING, query);
+        m.put(Message.HTTP_REQUEST_METHOD, method);
+        Map<String, List<String>> headers = new HashMap<String, List<String>>();
+        if (methodHeader != null) {
+            headers.put("X-HTTP-Method-Override", Collections.singletonList(methodHeader));   
+        }
+        m.put(Message.PROTOCOL_HEADERS, headers);
+        control.replay();
+        return m;
+    }
+}

Propchange: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/RequestPreprocessorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/RequestPreprocessorTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSpring.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSpring.java?rev=787849&r1=787848&r2=787849&view=diff
==============================================================================
--- cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSpring.java (original)
+++ cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/BookStoreSpring.java Tue Jun 23 21:54:08 2009
@@ -127,6 +127,13 @@
         return b;
     }
     
+    @RETRIEVE
+    @Path("books/aegis/retrieve")
+    @Produces({"application/html;q=1.0", "application/xml;q=0.5", "application/json;q=0.5" })
+    public Book getBookAegisRetrieve() {
+        return getBookAegis();
+    }
+    
     @GET
     @Path("books/xslt/{id}")
     @Produces({"text/html", "application/xhtml+xml", "application/xml" })

Modified: cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerSpringBookTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerSpringBookTest.java?rev=787849&r1=787848&r2=787849&view=diff
==============================================================================
--- cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerSpringBookTest.java (original)
+++ cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSClientServerSpringBookTest.java Tue Jun 23 21:54:08 2009
@@ -31,6 +31,7 @@
 
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.methods.FileRequestEntity;
+import org.apache.commons.httpclient.methods.GetMethod;
 import org.apache.commons.httpclient.methods.PostMethod;
 import org.apache.commons.httpclient.methods.RequestEntity;
 import org.apache.cxf.helpers.IOUtils;
@@ -61,6 +62,21 @@
     }
     
     @Test
+    public void testGetBookXSLTHtml() throws Exception {
+        
+        String endpointAddress =
+            "http://localhost:9080/the/thebooks5/bookstore/books/xslt";
+        WebClient wc = WebClient.create(endpointAddress);
+        wc.accept("application/xhtml+xml").path(666).matrix("name2", 2).query("name", "Action - ");
+        XMLSource source = wc.get(XMLSource.class);
+        Map<String, String> namespaces = new HashMap<String, String>();
+        namespaces.put("xhtml", "http://www.w3.org/1999/xhtml");
+        Book2 b = source.getNode("xhtml:html/xhtml:body/xhtml:ul/xhtml:Book", namespaces, Book2.class);
+        assertEquals(666, b.getId());
+        assertEquals("CXF in Action - 2", b.getName());
+    }
+
+    @Test
     public void testGetBookByUriInfo2() throws Exception {
         String endpointAddress =
             "http://localhost:9080/the/thebooks3/bookstore/bookinfo?"
@@ -122,10 +138,18 @@
     }
     
     private void getBook(String endpointAddress, String resource, String type) throws Exception {
+        getBook(endpointAddress, resource, type, null);
+    }
+    
+    private void getBook(String endpointAddress, String resource, String type, String mHeader) 
+        throws Exception {
         URL url = new URL(endpointAddress);
         URLConnection connect = url.openConnection();
         connect.addRequestProperty("Content-Type", "*/*");
         connect.addRequestProperty("Accept", type);
+        if (mHeader != null) {
+            connect.addRequestProperty("X-HTTP-Method-Override", mHeader);
+        }
         InputStream in = connect.getInputStream();           
 
         InputStream expected = getClass().getResourceAsStream(resource);
@@ -192,6 +216,39 @@
     }
     
     @Test
+    public void testRetrieveBookAegis1() throws Exception {
+        
+        String endpointAddress =
+            "http://localhost:9080/the/thebooks4/bookstore/books/aegis/retrieve?_method=RETRIEVE"; 
+        getBook(endpointAddress, "resources/expected_add_book_aegis.txt", "application/xml"); 
+    }
+    
+    @Test
+    public void testRetrieveBookAegis2() throws Exception {
+        
+        String endpointAddress =
+            "http://localhost:9080/the/thebooks4/bookstore/books/aegis/retrieve"; 
+        getBook(endpointAddress, "resources/expected_add_book_aegis.txt", "application/xml", "RETRIEVE"); 
+    }
+    
+    @Test
+    @Ignore
+    public void testRetrieveBookAegis3() throws Exception {
+        GetMethod get = new GetMethod("http://localhost:9080/the/thebooks4/bookstore/books/aegis/retrieve");
+        get.setRequestHeader("Content-Type", "*/*");
+        get.setRequestHeader("Accept", "application/xml");
+        HttpClient httpClient = new HttpClient();
+        try {
+            httpClient.executeMethod(get);           
+            String aegisData = getStringFromInputStream(get.getResponseBodyAsStream());
+            InputStream expected = getClass().getResourceAsStream("resources/expected_add_book_aegis.txt");
+            assertEquals(getStringFromInputStream(expected), aegisData);
+        } finally {
+            get.releaseConnection();
+        }
+    }
+    
+    @Test
     public void testGetBookUserResource() throws Exception {
         
         String endpointAddress =
@@ -270,21 +327,6 @@
     }
     
     @Test
-    public void testGetBookXSLTHtml() throws Exception {
-        
-        String endpointAddress =
-            "http://localhost:9080/the/thebooks5/bookstore/books/xslt";
-        WebClient wc = WebClient.create(endpointAddress);
-        wc.accept("application/xhtml+xml").path(666).matrix("name2", 2).query("name", "Action - ");
-        XMLSource source = wc.get(XMLSource.class);
-        Map<String, String> namespaces = new HashMap<String, String>();
-        namespaces.put("xhtml", "http://www.w3.org/1999/xhtml");
-        Book2 b = source.getNode("xhtml:html/xhtml:body/xhtml:ul/xhtml:Book", namespaces, Book2.class);
-        assertEquals(666, b.getId());
-        assertEquals("CXF in Action - 2", b.getName());
-    }
-    
-    @Test
     public void testAddValidBookJson() throws Exception {
         doPost("http://localhost:9080/the/bookstore/books/convert",
                200,
@@ -340,6 +382,7 @@
         return bos.getOut().toString();        
     }
 
+        
     @Ignore
     @XmlRootElement(name = "Book", namespace = "http://www.w3.org/1999/xhtml")
     public static class Book2 {

Added: cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/RETRIEVE.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/RETRIEVE.java?rev=787849&view=auto
==============================================================================
--- cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/RETRIEVE.java (added)
+++ cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/RETRIEVE.java Tue Jun 23 21:54:08 2009
@@ -0,0 +1,33 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.systest.jaxrs;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.ws.rs.HttpMethod;
+
+@Target({ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@HttpMethod("RETRIEVE")
+public @interface RETRIEVE {
+
+}

Propchange: cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/RETRIEVE.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/RETRIEVE.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date