/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2010-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.jersey.impl.wadl;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import com.sun.jersey.api.JResponse;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.LoggingFilter;
import com.sun.jersey.api.core.DefaultResourceConfig;
import com.sun.jersey.api.core.ResourceConfig;
import com.sun.jersey.api.representation.Form;
import com.sun.jersey.api.wadl.config.WadlGeneratorConfig;
import com.sun.jersey.api.wadl.config.WadlGeneratorDescription;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.core.header.MediaTypes;
import com.sun.jersey.core.util.SaxHelper;
import com.sun.jersey.impl.AbstractResourceTester;
import com.sun.jersey.impl.entity.JAXBBean;
import com.sun.jersey.server.wadl.WadlApplicationContext;
import com.sun.jersey.server.wadl.WadlGenerator;
import com.sun.jersey.server.wadl.WadlGeneratorImpl;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.sun.research.ws.wadl.Resources;
/**
* Wadl test cases.
*
* @author mh124079
* @author Michal Gajdos (michal.gajdos at oracle.com)
*/
public class WadlResourceTest extends AbstractResourceTester {
public WadlResourceTest(String testName) {
super(testName);
}
@Path("foo")
public static class ExtraResource {
@GET
@Produces("application/xml")
public String getRep() {
return null;
}
}
@Path("widgets")
public static class WidgetsResource {
@GET
@Produces({"application/xml", "application/json"})
public String getWidgets() {
return null;
}
@POST
@Consumes({"application/xml"})
@Produces({"application/xml", "application/json"})
public String createWidget(String bar, @MatrixParam("test") String test) {
return bar;
}
@PUT
@Path("{id}")
@Consumes("application/xml")
public void updateWidget(String bar, @PathParam("id")int id) {
}
@GET
@Path("{id}")
@Produces({"application/xml", "application/json"})
public String getWidget(@PathParam("id")int id) {
return null;
}
@DELETE
@Path("{id}")
public void deleteWidget(@PathParam("id")int id) {
}
@Path("{id}/verbose")
public ExtraResource getVerbose(@PathParam("id")int id) {
return new ExtraResource();
}
}
public void testDisableWadl() {
ResourceConfig rc = new DefaultResourceConfig(WidgetsResource.class, ExtraResource.class);
rc.getFeatures().put(ResourceConfig.FEATURE_DISABLE_WADL, true);
initiateWebApplication(rc);
WebResource r = resource("/application.wadl", false);
ClientResponse cr = r.get(ClientResponse.class);
assertEquals(404, cr.getStatus());
}
public void testEnableWadl() {
ResourceConfig rc = new DefaultResourceConfig(WidgetsResource.class, ExtraResource.class);
rc.getFeatures().put(ResourceConfig.FEATURE_DISABLE_WADL, false);
initiateWebApplication(rc);
WebResource r = resource("/application.wadl", false);
ClientResponse cr = r.get(ClientResponse.class);
assertEquals(200, cr.getStatus());
}
/**
* Test WADL generation.
*
* @throws Exception in case of unexpected test failure.
*/
public void testGetWadl() throws Exception {
initiateWebApplication(WidgetsResource.class, ExtraResource.class);
WebResource r = resource("/application.wadl");
File tmpFile = r.get(File.class);
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
DocumentBuilder b = bf.newDocumentBuilder();
Document d = b.parse(tmpFile);
printSource(new DOMSource(d));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
// check base URI
String val = (String)xp.evaluate("/wadl:application/wadl:resources/@base", d, XPathConstants.STRING);
assertEquals(val,BASE_URI.toString());
// check total number of resources is 4
val = (String)xp.evaluate("count(//wadl:resource)", d, XPathConstants.STRING);
assertEquals(val,"4");
// check only once resource with for {id}
val = (String)xp.evaluate("count(//wadl:resource[@path='{id}'])", d, XPathConstants.STRING);
assertEquals(val,"1");
// check only once resource with for {id}/verbose
val = (String)xp.evaluate("count(//wadl:resource[@path='{id}/verbose'])", d, XPathConstants.STRING);
assertEquals(val,"1");
// check only once resource with for widgets
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets'])", d, XPathConstants.STRING);
assertEquals(val,"1");
// check 3 methods for {id}
val = (String)xp.evaluate("count(//wadl:resource[@path='{id}']/wadl:method)", d, XPathConstants.STRING);
assertEquals(val,"3");
// check 2 methods for widgets
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets']/wadl:method)", d, XPathConstants.STRING);
assertEquals(val,"2");
// check 1 matrix param on resource
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets']/wadl:param[@name='test'])", d, XPathConstants.STRING);
assertEquals(val,"1");
// check type of {id} is int
String prefix = getXmlSchemaNamespacePrefix(
(Node) xp.evaluate("//wadl:resource[@path='{id}']/wadl:param[@name='id']", d, XPathConstants.NODE));
val = (String)xp.evaluate("//wadl:resource[@path='{id}']/wadl:param[@name='id']/@type", d, XPathConstants.STRING);
assertEquals(val, (prefix == null ? "" : prefix + ":") + "int");
// check number of output representations is two
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets']/wadl:method[@name='GET']/wadl:response/wadl:representation)", d, XPathConstants.STRING);
assertEquals(val,"2");
// check number of output representations is one
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets']/wadl:method[@name='POST']/wadl:request/wadl:representation)", d, XPathConstants.STRING);
assertEquals(val,"1");
// check type of {id}/verbose is int
prefix = getXmlSchemaNamespacePrefix(
(Node) xp.evaluate("//wadl:resource[@path='{id}/verbose']/wadl:param[@name='id']", d, XPathConstants.NODE));
val = (String)xp.evaluate("//wadl:resource[@path='{id}/verbose']/wadl:param[@name='id']/@type", d, XPathConstants.STRING);
assertEquals(val, (prefix == null ? "" : prefix + ":") + "int");
}
public void testLastModifiedGET() {
initiateWebApplication(WidgetsResource.class, ExtraResource.class);
WebResource r = resource("/application.wadl");
ClientResponse cr = r.get(ClientResponse.class);
assertTrue(cr.getHeaders().containsKey("Last-modified"));
}
public void testLastModifiedOPTIONS() {
initiateWebApplication(WidgetsResource.class, ExtraResource.class);
WebResource r = resource("/widgets/3/verbose");
ClientResponse cr = r.options(ClientResponse.class);
assertTrue(cr.getHeaders().containsKey("Last-modified"));
}
public void testOptionsResourceWadl() throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
initiateWebApplication(WidgetsResource.class, ExtraResource.class);
WebResource r = resource("/widgets");
// test WidgetsResource
File tmpFile = r.options(File.class);
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
DocumentBuilder b = bf.newDocumentBuilder();
Document d = b.parse(tmpFile);
printSource(new DOMSource(d));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
// check base URI
String val = (String)xp.evaluate("/wadl:application/wadl:resources/@base", d, XPathConstants.STRING);
assertEquals(val,BASE_URI.toString());
// check total number of resources is 3 (no ExtraResource details included)
val = (String)xp.evaluate("count(//wadl:resource)", d, XPathConstants.STRING);
assertEquals(val,"3");
// check only once resource with for {id}
val = (String)xp.evaluate("count(//wadl:resource[@path='{id}'])", d, XPathConstants.STRING);
assertEquals(val,"1");
// check only once resource with for {id}/verbose
val = (String)xp.evaluate("count(//wadl:resource[@path='{id}/verbose'])", d, XPathConstants.STRING);
assertEquals(val,"1");
// check only once resource with for widgets
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets'])", d, XPathConstants.STRING);
assertEquals(val,"1");
// check 3 methods for {id}
val = (String)xp.evaluate("count(//wadl:resource[@path='{id}']/wadl:method)", d, XPathConstants.STRING);
assertEquals(val,"3");
// check 2 methods for widgets
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets']/wadl:method)", d, XPathConstants.STRING);
assertEquals(val,"2");
// check type of {id} is int
String prefix = getXmlSchemaNamespacePrefix(
(Node) xp.evaluate("//wadl:resource[@path='{id}']/wadl:param[@name='id']", d, XPathConstants.NODE));
val = (String)xp.evaluate("//wadl:resource[@path='{id}']/wadl:param[@name='id']/@type", d, XPathConstants.STRING);
assertEquals(val, (prefix == null ? "" : prefix + ":") + "int");
// check number of output representations is two
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets']/wadl:method[@name='GET']/wadl:response/wadl:representation)", d, XPathConstants.STRING);
assertEquals(val,"2");
// check number of output representations is one
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets']/wadl:method[@name='POST']/wadl:request/wadl:representation)", d, XPathConstants.STRING);
assertEquals(val,"1");
// test ExtraResource
r = resource("/foo");
tmpFile = r.options(File.class);
b = bf.newDocumentBuilder();
d = b.parse(tmpFile);
printSource(new DOMSource(d));
// check base URI
val = (String)xp.evaluate("/wadl:application/wadl:resources/@base", d, XPathConstants.STRING);
assertEquals(val,BASE_URI.toString());
// check total number of resources is 1 (no ExtraResource details included)
val = (String)xp.evaluate("count(//wadl:resource)", d, XPathConstants.STRING);
assertEquals(val,"1");
// check only once resource with path foo
val = (String)xp.evaluate("count(//wadl:resource[@path='foo'])", d, XPathConstants.STRING);
assertEquals(val,"1");
// check 1 methods for foo
val = (String)xp.evaluate("count(//wadl:resource[@path='foo']/wadl:method)", d, XPathConstants.STRING);
assertEquals(val,"1");
}
private String getXmlSchemaNamespacePrefix(final Node elementNode) {
final NamedNodeMap attributes = elementNode.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
final Node item = attributes.item(i);
if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(item.getNodeValue())) {
return item.getLocalName();
}
}
return "xs";
}
public void testOptionsLocatorWadl() throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
initiateWebApplication(WidgetsResource.class, ExtraResource.class);
WebResource r = resource("/widgets/3/verbose");
// test WidgetsResource
File tmpFile = r.accept(MediaTypes.WADL).options(File.class);
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
DocumentBuilder b = bf.newDocumentBuilder();
Document d = b.parse(tmpFile);
printSource(new DOMSource(d));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
// check base URI
String val = (String)xp.evaluate("/wadl:application/wadl:resources/@base", d, XPathConstants.STRING);
assertEquals(val,BASE_URI.toString());
// check total number of resources is 1 (no ExtraResource details included)
val = (String)xp.evaluate("count(//wadl:resource)", d, XPathConstants.STRING);
assertEquals(val,"1");
// check only once resource with path
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets/3/verbose'])", d, XPathConstants.STRING);
assertEquals(val,"1");
// check 1 methods
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets/3/verbose']/wadl:method)", d, XPathConstants.STRING);
assertEquals(val,"1");
}
public void testOptionsSubResourceWadl() throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
initiateWebApplication(WidgetsResource.class, ExtraResource.class);
WebResource r = resource("/widgets/3");
// test WidgetsResource
File tmpFile = r.accept(MediaTypes.WADL).options(File.class);
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
DocumentBuilder b = bf.newDocumentBuilder();
Document d = b.parse(tmpFile);
printSource(new DOMSource(d));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
String val = (String)xp.evaluate("/wadl:application/wadl:resources/@base", d, XPathConstants.STRING);
assertEquals(val,BASE_URI.toString());
// check total number of resources is 1
val = (String)xp.evaluate("count(//wadl:resource)", d, XPathConstants.STRING);
assertEquals(val,"1");
// check only one resource with for {id}
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets/3'])", d, XPathConstants.STRING);
assertEquals(val,"1");
// check 3 methods
val = (String)xp.evaluate("count(//wadl:resource[@path='widgets/3']/wadl:method)", d, XPathConstants.STRING);
assertEquals(val,"3");
}
@Path("root")
public static class RootResource {
@Path("loc")
public Object getSub() {
return new SubResource();
}
@Path("switch")
@POST
public void switchMethod(@Context WadlApplicationContext wadlApplicationContext) {
wadlApplicationContext.setWadlGenerationEnabled(!wadlApplicationContext.isWadlGenerationEnabled());
}
}
public static class SubResource {
@Path("loc")
public Object getSub() {
return new SubResource();
}
@GET
@Produces("text/plain")
public String hello() {
return "Hello World !";
}
@GET
@Path("sub")
@Produces("text/plain")
public String helloSub() {
return "Hello World !";
}
}
public void testRecursive() throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
initiateWebApplication(RootResource.class);
WebResource r = resource("/root/loc");
// test WidgetsResource
File tmpFile = r.accept(MediaTypes.WADL).options(File.class);
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
DocumentBuilder b = bf.newDocumentBuilder();
Document d = b.parse(tmpFile);
printSource(new DOMSource(d));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
String val = (String)xp.evaluate("/wadl:application/wadl:resources/@base", d, XPathConstants.STRING);
assertEquals(val,BASE_URI.toString());
// check only one resource with for 'root/loc'
val = (String)xp.evaluate("count(//wadl:resource[@path='root/loc'])", d, XPathConstants.STRING);
assertEquals(val,"1");
r = resource("/root/loc/loc");
// test WidgetsResource
tmpFile = r.accept(MediaTypes.WADL).options(File.class);
bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
b = bf.newDocumentBuilder();
d = b.parse(tmpFile);
printSource(new DOMSource(d));
xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
val = (String)xp.evaluate("/wadl:application/wadl:resources/@base", d, XPathConstants.STRING);
assertEquals(val,BASE_URI.toString());
// check only one resource with for 'root/loc'
val = (String)xp.evaluate("count(//wadl:resource[@path='root/loc/loc'])", d, XPathConstants.STRING);
assertEquals(val,"1");
}
@Path("root1")
public static class RootResource1 {
@Path("loc")
public SubResource getSub() {
return new SubResource();
}
}
@Path("root2")
public static class RootResource2 {
@Path("loc")
public SubResource getSub() {
return new SubResource();
}
}
public void testRecursive2() throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
initiateWebApplication(RootResource1.class, RootResource2.class);
WebResource r = resource("/application.wadl");
File tmpFile = r.get(File.class);
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
DocumentBuilder b = bf.newDocumentBuilder();
Document d = b.parse(tmpFile);
printSource(new DOMSource(d));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
String val = (String)xp.evaluate("/wadl:application/wadl:resources/@base", d, XPathConstants.STRING);
assertEquals(val,BASE_URI.toString());
// check only one resource with for 'root/loc'
val = (String)xp.evaluate("count(//wadl:resource[@path='loc'])", d, XPathConstants.STRING);
assertEquals("4", val);
// check for method with id of hello
val = (String)xp.evaluate("count(//wadl:resource[@path='loc']/wadl:method[@id='hello'])", d, XPathConstants.STRING);
assertEquals("2", val);
}
@Path("form")
public static class FormResource {
@POST
@Consumes( "application/x-www-form-urlencoded" )
public void post(
@FormParam( "a" ) String a,
@FormParam( "b" ) String b,
@FormParam( "c" ) JAXBBean c,
@FormParam( "c" ) FormDataContentDisposition cdc,
Form form ) {
}
}
public void testFormParam() throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
initiateWebApplication(FormResource.class);
WebResource r = resource("/application.wadl");
File tmpFile = r.get(File.class);
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
DocumentBuilder b = bf.newDocumentBuilder();
Document d = b.parse(tmpFile);
printSource(new DOMSource(d));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
final String requestPath = "//wadl:resource[@path='form']/wadl:method[@name='POST']/wadl:request";
final String representationPath = requestPath + "/wadl:representation";
// check number of request params is zero
int count = ( (Double)xp.evaluate("count(" + requestPath + "/wadl:param)", d, XPathConstants.NUMBER) ).intValue();
assertEquals( 0, count );
// check number of request representations is one
count = ( (Double)xp.evaluate("count(" + representationPath + ")", d, XPathConstants.NUMBER) ).intValue();
assertEquals( 1, count );
// check number of request representation params is three
count = ( (Double)xp.evaluate("count(" + representationPath + "/wadl:param)", d, XPathConstants.NUMBER) ).intValue();
assertEquals( 3, count );
// check the style of the request representation param is 'query'
String val = (String)xp.evaluate( representationPath + "/wadl:param[@name='a']/@style", d, XPathConstants.STRING);
assertEquals( "query", val );
val = (String)xp.evaluate( representationPath + "/wadl:param[@name='b']/@style", d, XPathConstants.STRING);
assertEquals( "query", val );
}
@Path("fieldParam/{pp}")
public static class FieldParamResource {
@HeaderParam("hp") String hp;
@MatrixParam("mp") String mp;
@PathParam("pp") String pp;
@QueryParam("q") String q;
@GET
@Produces("text/plain" )
public String get() {
return pp;
}
}
public void testFieldParam() throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
_testFieldAndSetterParam(FieldParamResource.class, "fieldParam");
}
@Path("setterParam/{pp}")
public static class SetterParamResource {
@HeaderParam("hp")
public void setHp(String hp) {};
@MatrixParam("mp")
public void setMp(String mp) {};
@PathParam("pp")
public void setPP(String pp) {};
@QueryParam("q")
public void setQ(String q) {};
@GET
@Produces("text/plain" )
public String get() {
return "nonsense";
}
}
public void testSetterParam() throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
_testFieldAndSetterParam(SetterParamResource.class, "setterParam");
}
public void testEnableDisableRuntime() {
initiateWebApplication(RootResource.class);
WebResource r = resource("/", false);
r.addFilter(new LoggingFilter());
ClientResponse response = r.path("application.wadl").get(ClientResponse.class);
assertTrue(response.getStatus() == 200);
response = r.path("root").options(ClientResponse.class);
assertTrue(response.getStatus() == 200);
r.path("root/switch").post();
response = r.path("application.wadl").get(ClientResponse.class);
assertTrue(response.getStatus() == 404);
response = r.path("root").options(ClientResponse.class);
assertTrue(response.getStatus() == 204);
r.path("root/switch").post();
response = r.path("application.wadl").get(ClientResponse.class);
assertTrue(response.getStatus() == 200);
response = r.path("root").options(ClientResponse.class);
assertTrue(response.getStatus() == 200);
}
private void _testFieldAndSetterParam(Class resourceClass, String path) throws ParserConfigurationException, SAXException, IOException, XPathExpressionException {
initiateWebApplication(resourceClass);
WebResource r = resource("/application.wadl");
File tmpFile = r.get(File.class);
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
DocumentBuilder b = bf.newDocumentBuilder();
Document d = b.parse(tmpFile);
printSource(new DOMSource(d));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
final String resourcePath = String.format("//wadl:resource[@path='%s/{pp}']", path);
final String methodPath = resourcePath + "/wadl:method[@name='GET']";
// check number of resource methods is one
int methodCount = ( (Double)xp.evaluate("count(" + methodPath + ")", d, XPathConstants.NUMBER) ).intValue();
assertEquals(1, methodCount );
Map<String, String> paramStyles = new HashMap<String, String>();
paramStyles.put("hp", "header");
paramStyles.put("mp", "matrix");
paramStyles.put("pp", "template");
paramStyles.put("q", "query");
for(Entry<String, String> param : paramStyles.entrySet()) {
String pName = param.getKey();
String pStyle = param.getValue();
String paramXPath = String.format("%s/wadl:param[@name='%s']", resourcePath, pName);
// check number of params is one
int pc = ( (Double)xp.evaluate("count(" + paramXPath + ")", d, XPathConstants.NUMBER) ).intValue();
assertEquals(1, pc );
// check the style of the param
String style = (String)xp.evaluate(paramXPath + "/@style", d, XPathConstants.STRING);
assertEquals(pStyle, style );
}
}
private static void printSource(Source source) {
try {
System.out.println("---------------------");
Transformer trans = TransformerFactory.newInstance().newTransformer();
Properties oprops = new Properties();
oprops.put(OutputKeys.OMIT_XML_DECLARATION, "yes");
oprops.put(OutputKeys.INDENT, "yes");
oprops.put(OutputKeys.METHOD, "xml");
trans.setOutputProperties(oprops);
trans.transform(source, new StreamResult(System.out));
} catch (Exception e) {
e.printStackTrace();
}
}
public static class MyWadlGeneratorConfig extends WadlGeneratorConfig {
@Override
public List<WadlGeneratorDescription> configure() {
return generator(MyWadlGenerator.class).descriptions();
}
public static class MyWadlGenerator extends WadlGeneratorImpl {
public static final String CUSTOM_RESOURCES_BASE_URI = "http://myBaseUri";
@Override
public Resources createResources() {
Resources resources = super.createResources();
resources.setBase(CUSTOM_RESOURCES_BASE_URI);
return resources;
}
@Override
public void setWadlGeneratorDelegate(WadlGenerator delegate) {
// nothing
}
}
}
/**
* Test overriding WADL's /application/resources/@base attribute.
*
* @throws Exception in case of unexpected test failure.
*/
public void testCustomWadlResourcesBaseUri() throws Exception {
ResourceConfig rc = new DefaultResourceConfig(WidgetsResource.class, ExtraResource.class);
rc.getProperties().put(ResourceConfig.PROPERTY_WADL_GENERATOR_CONFIG, "com.sun.jersey.impl.wadl.WadlResourceTest$MyWadlGeneratorConfig");
initiateWebApplication(rc);
WebResource r = resource("/application.wadl");
File tmpFile = r.get(File.class);
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
DocumentBuilder b = bf.newDocumentBuilder();
Document d = b.parse(tmpFile);
printSource(new DOMSource(d));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
// check base URI
String val = (String) xp.evaluate("/wadl:application/wadl:resources/@base", d, XPathConstants.STRING);
assertEquals(val, MyWadlGeneratorConfig.MyWadlGenerator.CUSTOM_RESOURCES_BASE_URI);
}
@Path("jresponse")
public static class JResponseTestResource {
@GET
@Produces("text/plain")
public JResponse<List<String>> getClichedMessage() {
// Return some cliched textual content
return JResponse.<List<String>>status(200).entity(new ArrayList() {
{
add("Hello world!");
}
}).build();
}
}
public void testJresponse() throws Exception {
ResourceConfig rc = new DefaultResourceConfig(JResponseTestResource.class);
initiateWebApplication(rc);
WebResource r = resource("/application.wadl");
assertTrue(r.get(String.class).length() > 0);
}
@Path("emptyproduces")
public static class EmptyProducesTestResource {
@PUT
@Produces({})
public Response put(final String str) {
return Response.ok().build();
}
@POST
@Path("/sub")
@Produces({})
public Response post(final String str) {
return Response.ok().build();
}
}
public void testEmptyProduces() throws Exception {
ResourceConfig rc = new DefaultResourceConfig(EmptyProducesTestResource.class);
initiateWebApplication(rc);
WebResource r = resource("/application.wadl");
File tmpFile = r.get(File.class);
DocumentBuilderFactory bf = DocumentBuilderFactory.newInstance();
bf.setNamespaceAware(true);
bf.setValidating(false);
if (!SaxHelper.isXdkDocumentBuilderFactory(bf)) {
bf.setXIncludeAware(false);
}
DocumentBuilder b = bf.newDocumentBuilder();
Document d = b.parse(tmpFile);
printSource(new DOMSource(d));
XPath xp = XPathFactory.newInstance().newXPath();
xp.setNamespaceContext(new NSResolver("wadl", "http://wadl.dev.java.net/2009/02"));
final NodeList responseElements = (NodeList) xp.evaluate(
"/wadl:application/wadl:resources//wadl:method/wadl:response", d, XPathConstants.NODESET);
for (int i = 0; i < responseElements.getLength(); i++) {
final Node item = responseElements.item(i);
assertEquals(0, item.getChildNodes().getLength());
assertEquals(0, item.getAttributes().getLength());
}
}
@Path("wadl6test")
public static class OptionsResource {
@GET
@Path("foo1")
public String foo1() {
return "foo1";
}
@GET
@Path("/foo2")
public String foo2() {
return "foo2";
}
@GET
@Path("foo3/")
public String foo3() {
return "foo3";
}
@GET
@Path("/foo4/")
public String foo4() {
return "foo4";
}
}
/**
* Tests OPTIONS method on a resource method annotated with @Path and containing a leading '/'.
*/
public void testGetWithPathAndLeadingSlash() throws Exception {
ResourceConfig rc = new DefaultResourceConfig(OptionsResource.class);
initiateWebApplication(rc);
for (int i = 1; i < 5; i++) {
final String[] paths = {
"foo" + i,
"/foo" + i,
"foo" + i + '/',
"/foo" + i + '/'
};
for (final String path : paths) {
final String document = resource("wadl6test").
path(path).
accept("application/vnd.sun.wadl+xml").
options(String.class);
// check that the resulting document contains a method element with id="fooX"
assertTrue(Pattern.
compile(".*<([\\w]+:)*method[^>]+id=\"foo" + i + "\"[^>]*>.*", Pattern.MULTILINE | Pattern.DOTALL).
matcher(document).
matches());
}
}
}
@Path(value = "/wadl7test")
public static class OptionSubResource {
@GET
@Path(value = "/sub")
@Produces(value = "text/html")
public Response headSub() {
return Response.ok().build();
}
}
/**
* On receipt of an OPTIONS request an implementation MUST: Generate an automatic response using the metadata provided by the
* JAX-RS annotations on the matching class and its methods.
*/
public void testOptionSub() throws Exception {
final ResourceConfig resourceConfig = new DefaultResourceConfig(OptionSubResource.class);
initiateWebApplication(resourceConfig);
final ClientResponse response = resource("wadl7test").path("sub").accept("text/html").options(ClientResponse.class);
final Set<String> allow = response.getAllow();
assertEquals(204, response.getStatus());
assertEquals(new HashSet<String>(){{ add("GET"); add("OPTIONS"); add("HEAD"); }}, allow);
}
}