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/12 18:35:32 UTC

svn commit: r784184 - in /cxf/trunk/rt/frontend/jaxrs/src: main/java/org/apache/cxf/jaxrs/impl/ main/java/org/apache/cxf/jaxrs/model/wadl/ test/java/org/apache/cxf/jaxrs/model/wadl/ test/java/org/apache/cxf/jaxrs/resources/

Author: sergeyb
Date: Fri Jun 12 16:35:32 2009
New Revision: 784184

URL: http://svn.apache.org/viewvc?rev=784184&view=rev
Log:
CXF-1695 : prototyping initial WADL support, a lot more to be done

Added:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java   (with props)
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/wadl/
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/wadl/WadlGeneratorTest.java   (with props)
Modified:
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriInfoImpl.java
    cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/resources/Book.java

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriInfoImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriInfoImpl.java?rev=784184&r1=784183&r2=784184&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriInfoImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriInfoImpl.java Fri Jun 12 16:35:32 2009
@@ -47,6 +47,15 @@
     private Message message;
     private OperationResourceInfoStack stack;
 
+    @SuppressWarnings("unchecked")
+    public UriInfoImpl(Message m) {
+        this.message = m;
+        this.templateParams = (MultivaluedMap<String, String>)m.get(URITemplate.TEMPLATE_PARAMETERS);
+        if (m != null) {
+            this.stack = m.get(OperationResourceInfoStack.class);
+        }
+    }
+    
     public UriInfoImpl(Message m, MultivaluedMap<String, String> templateParams) {
         this.message = m;
         this.templateParams = templateParams;

Added: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java?rev=784184&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java Fri Jun 12 16:35:32 2009
@@ -0,0 +1,210 @@
+/**
+ * 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.model.wadl;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.apache.cxf.jaxrs.ext.RequestHandler;
+import org.apache.cxf.jaxrs.impl.UriInfoImpl;
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.model.OperationResourceInfo;
+import org.apache.cxf.jaxrs.model.Parameter;
+import org.apache.cxf.jaxrs.model.ParameterType;
+import org.apache.cxf.message.Message;
+
+// TODO :
+// 1. extract JavaDocs and put them into XML comments
+// 2. if _type = html -> convert the XML buil here using MH's stylesheet
+// 3. generate grammars 
+
+public class WadlGenerator implements RequestHandler {
+
+    public static final String WADL_QUERY = "_wadl"; 
+    public static final MediaType WADL_TYPE = MediaType.valueOf("application/vnd.sun.wadl+xml"); 
+    public static final String WADL_NS = "http://research.sun.com/wadl/2006/10";    
+    
+    public Response handleRequest(Message m, ClassResourceInfo resource) {
+        
+        UriInfo ui = new UriInfoImpl(m);
+        if (!ui.getQueryParameters().containsKey(WADL_QUERY)) {
+            return null;
+        }
+        
+        StringBuilder sb = new StringBuilder();
+        sb.append("<application xmlns=\"").append(WADL_NS).append("\">");
+        
+        sb.append("<resources base=\"").append(ui.getBaseUri().toString()).append("\">");
+        handleResource(sb, resource, resource.getURITemplate().getValue(),
+                       resource.getURITemplate().getVariables());
+        sb.append("</resources>");
+        sb.append("</application>");
+        
+        return Response.ok().type(WADL_TYPE).entity(sb.toString()).build();
+    }
+
+    private void handleResource(StringBuilder sb, ClassResourceInfo cri, String path,
+                                List<String> templateVars) {
+        sb.append("<resource path=\"").append(path).append("\">");
+        handleTemplateParams(sb, templateVars);
+        
+        List<OperationResourceInfo> sortedOps = sortOperationsByPath(
+            cri.getMethodDispatcher().getOperationResourceInfos());
+        List<OperationResourceInfo> opsWithSamePath = new LinkedList<OperationResourceInfo>();
+        for (int i = 0; i < sortedOps.size(); i++) {
+            
+            if (sortedOps.get(i).getHttpMethod() == null) {
+                Class<?> cls = sortedOps.get(i).getMethodToInvoke().getReturnType();
+                ClassResourceInfo subcri = cri.findResource(cls, cls);
+                if (subcri != null) {
+                    handleResource(sb, subcri, sortedOps.get(i).getURITemplate().getValue(), 
+                                   sortedOps.get(i).getURITemplate().getVariables());
+                    opsWithSamePath.clear();
+                    continue;
+                } else {
+                    handleDynamicSubresource(sb, sortedOps.get(i));
+                }
+            }
+            if (opsWithSamePath.size() == 0) {
+                opsWithSamePath.add(sortedOps.get(i));
+            } else if (i > 0 && sortedOps.get(i - 1).getURITemplate().getValue()
+                .equals(sortedOps.get(i).getURITemplate().getValue())) {
+                opsWithSamePath.add(sortedOps.get(i));
+            } else {
+                handleOperation(sb, opsWithSamePath);
+                opsWithSamePath.clear();
+                opsWithSamePath.add(sortedOps.get(i));
+            }
+        }
+        handleOperation(sb, opsWithSamePath);
+        sb.append("</resource>");
+    }
+    
+    private void handleOperation(StringBuilder sb, List<OperationResourceInfo> oris) {
+        if (oris.size() == 0) {
+            return;
+        }
+        String path = oris.get(0).getURITemplate().getValue();
+        boolean isSlash =  "/".equals(path);
+        if (!isSlash) {
+            sb.append("<resource path=\"").append(path).append("\">");
+        }
+        for (OperationResourceInfo ori : oris) {
+            handleTemplateParams(sb, ori.getURITemplate().getVariables());
+            handleMatrixParams(sb, ori);
+        }
+        for (OperationResourceInfo ori : oris) {
+            sb.append("<method name=\"").append(ori.getHttpMethod()).append("\">");
+            if (ori.getMethodToInvoke().getParameterTypes().length != 0) {
+                sb.append("<request>");
+                for (Parameter p : ori.getParameters()) {        
+                    handleParameter(sb, ori, p);             
+                }
+                sb.append("</request>");
+            }
+            if (Void.class != ori.getMethodToInvoke().getReturnType()) {
+                sb.append("<response>");
+                handleRepresentation(sb, ori);
+                sb.append("</response>");
+            }
+            sb.append("</method>");
+        }
+        if (!isSlash) {
+            sb.append("</resource>");
+        }
+    }
+    
+    private void handleDynamicSubresource(StringBuilder sb, OperationResourceInfo ori) {
+        
+        sb.append("<!-- Dynamic subresource -->");
+        sb.append("<resource path=\"").append(ori.getURITemplate().getValue()).append("\">");
+        if (ori.getMethodToInvoke().getParameterTypes().length != 0) {
+            sb.append("<request>");
+            for (Parameter p : ori.getParameters()) {        
+                handleParameter(sb, ori, p);             
+            }
+            sb.append("</request>");
+        }
+        sb.append("</resource>");
+    }
+    
+    
+    private void handleParameter(StringBuilder sb, OperationResourceInfo ori, Parameter pm) {
+        if (pm.getType() == ParameterType.REQUEST_BODY) {
+            handleRepresentation(sb, ori);
+            return;
+        }
+        if (pm.getType() == ParameterType.PATH || pm.getType() == ParameterType.MATRIX) {
+            return;
+        }
+        if (pm.getType() == ParameterType.HEADER || pm.getType() == ParameterType.QUERY) {
+            writeParam(sb, pm.getName(), pm.getType().toString().toLowerCase(), pm.getDefaultValue());
+        }
+        
+    }
+    
+    private void handleMatrixParams(StringBuilder sb, OperationResourceInfo ori) {
+        for (Parameter pm : ori.getParameters()) {
+            if (pm.getType() == ParameterType.MATRIX) {
+                writeParam(sb, pm.getName(), "matrix", pm.getDefaultValue());
+            }
+        }
+    }
+    
+    private void writeParam(StringBuilder sb, String name, String style, String dValue) {
+        sb.append("<param name=\"").append(name).append("\" ");
+        sb.append("style=\"").append(style).append("\"");
+        if (dValue != null) {
+            sb.append(" default=\"").append(dValue).append("\"");
+        }
+        sb.append("/>");
+    }
+    
+    private void handleTemplateParams(StringBuilder sb, List<String> vars) {
+        for (String var : vars) {
+            writeParam(sb, var, "template", null);
+        }
+    }
+    
+    private void handleRepresentation(StringBuilder sb, OperationResourceInfo ori) {
+        sb.append("<representation>");
+        sb.append("</representation>");
+    }
+    
+    private List<OperationResourceInfo> sortOperationsByPath(Set<OperationResourceInfo> ops) {
+        List<OperationResourceInfo> opsWithSamePath = new LinkedList<OperationResourceInfo>(ops);
+        Collections.sort(opsWithSamePath, new Comparator<OperationResourceInfo>() {
+
+            public int compare(OperationResourceInfo op1, OperationResourceInfo op2) {
+                String path1 = op1.getURITemplate().getValue();
+                String path2 = op2.getURITemplate().getValue();
+                return path1.compareTo(path2);
+            } 
+        
+        });
+        return opsWithSamePath;
+    }
+}

Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/wadl/WadlGenerator.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/wadl/WadlGeneratorTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/wadl/WadlGeneratorTest.java?rev=784184&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/wadl/WadlGeneratorTest.java (added)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/model/wadl/WadlGeneratorTest.java Fri Jun 12 16:35:32 2009
@@ -0,0 +1,94 @@
+/**
+ * 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.model.wadl;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.jaxrs.model.ClassResourceInfo;
+import org.apache.cxf.jaxrs.resources.BookStore;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+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 WadlGeneratorTest extends Assert {
+
+    private IMocksControl control;
+    
+    @Before
+    public void setUp() {
+        control = EasyMock.createNiceControl();
+        control.makeThreadSafe(true);
+    }
+    
+    @Test
+    public void testNoWadl() {
+        WadlGenerator wg = new WadlGenerator();
+        assertNull(wg.handleRequest(new MessageImpl(), null));
+    }
+    
+    @Test
+    public void testWadl() throws Exception {
+        WadlGenerator wg = new WadlGenerator();
+        Message m = mockMessage("http://localhost:8080/baz", "/bar", WadlGenerator.WADL_QUERY);
+        ClassResourceInfo cri = 
+            ResourceUtils.createClassResourceInfo(BookStore.class, BookStore.class, true, true);
+        Response r = wg.handleRequest(m, cri);
+        assertNotNull(r);
+        assertEquals(WadlGenerator.WADL_TYPE.toString(),
+                     r.getMetadata().getFirst(HttpHeaders.CONTENT_TYPE));
+//        System.out.println(r.getEntity().toString());
+//        File f = new File("test.xml");
+//        f.delete();
+//        f.createNewFile();
+//        System.out.println(f.getAbsolutePath());
+//        FileOutputStream fos = new FileOutputStream(f);
+//        fos.write(r.getEntity().toString().getBytes());
+//        fos.flush();
+//        fos.close();
+    }
+    
+    private Message mockMessage(String baseAddress, String pathInfo, String query) {
+        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);
+        control.replay();
+        return m;
+    }
+    
+}

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

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

Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/resources/Book.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/resources/Book.java?rev=784184&r1=784183&r2=784184&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/resources/Book.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/resources/Book.java Fri Jun 12 16:35:32 2009
@@ -59,7 +59,7 @@
     
     @Path("chapters/{chapterid}/")
     @GET
-    public Chapter getChapter(@PathParam("id")int chapterid) {
+    public Chapter getChapter(@PathParam("chapterid") int chapterid) {
         return chapters.get(new Long(chapterid));
     }