112515717cb7521acdc87e022a58f62952791e15
[SpringWebServicesForFun/.git] /
1 package de.spring.webservices.rest.wadl;
2
3 import java.lang.annotation.Annotation;
4 import java.lang.reflect.Method;
5 import java.util.List;
6 import java.util.Set;
7
8 import javax.servlet.http.HttpServletRequest;
9 import javax.xml.namespace.QName;
10
11 import org.apache.commons.lang.StringUtils;
12 import org.jvnet.ws.wadl.Application;
13 import org.jvnet.ws.wadl.Doc;
14 import org.jvnet.ws.wadl.Param;
15 import org.jvnet.ws.wadl.ParamStyle;
16 import org.jvnet.ws.wadl.Representation;
17 import org.jvnet.ws.wadl.Request;
18 import org.jvnet.ws.wadl.Resource;
19 import org.jvnet.ws.wadl.Resources;
20 import org.jvnet.ws.wadl.Response;
21 import org.springframework.beans.factory.annotation.Autowired;
22 import org.springframework.context.ApplicationContext;
23 import org.springframework.http.HttpStatus;
24 import org.springframework.http.MediaType;
25 import org.springframework.stereotype.Controller;
26 import org.springframework.web.bind.annotation.PathVariable;
27 import org.springframework.web.bind.annotation.RequestMapping;
28 import org.springframework.web.bind.annotation.RequestMethod;
29 import org.springframework.web.bind.annotation.RequestParam;
30 import org.springframework.web.bind.annotation.ResponseBody;
31 import org.springframework.web.bind.annotation.ResponseStatus;
32 import org.springframework.web.bind.annotation.RestController;
33 import org.springframework.web.bind.annotation.ValueConstants;
34 import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
35 import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
36
37 /**
38  * Taken from: http://javattitude.com/2014/05/26/wadl-generator-for-spring-rest/
39  * 
40  * With some modifications.
41  *
42  */
43 @Controller
44 @RequestMapping("/rest.wadl")
45 public class WADLController {
46         private static final String NAMESPACE_URI = "http://www.w3.org/2001/XMLSchema" ;
47         private static final String WADL_TITLE = "Spring REST Service WADL";
48         
49     private final AbstractHandlerMethodMapping<RequestMappingInfo> handlerMapping;
50     private final ApplicationContext context;
51     
52     @Autowired
53         public WADLController(AbstractHandlerMethodMapping<RequestMappingInfo> handlerMapping, ApplicationContext context) {
54                 this.handlerMapping = handlerMapping;
55                 this.context = context;
56         }
57         
58     @RequestMapping(produces = { MediaType.APPLICATION_XML_VALUE }, method=RequestMethod.GET ) 
59     public @ResponseBody Application generateWadl(HttpServletRequest request) {
60         Application result = new Application();
61         
62         Doc doc = new Doc();
63         doc.setTitle(WADL_TITLE);
64         result.getDoc().add(doc);
65         
66         Resources wadlResources = new Resources();
67         wadlResources.setBase(getBaseUrl(request));
68                  
69         handlerMapping.getHandlerMethods().forEach( (mappingInfo, handlerMethod) -> {
70             Object object = handlerMethod.getBean();
71             Object bean = context.getBean(object.toString());
72             if(!bean.getClass().isAnnotationPresent(RestController.class)) {
73                 return;
74             }
75             
76             mappingInfo.getMethodsCondition().getMethods().forEach(httpMethod -> {
77                 Resource wadlResource = null; 
78                 org.jvnet.ws.wadl.Method wadlMethod = new org.jvnet.ws.wadl.Method();
79      
80                 Set<String> pattern =  mappingInfo.getPatternsCondition().getPatterns();
81                 for (String uri : pattern) {
82                         wadlResource = createOrFind(uri, wadlResources); 
83                     wadlResource.setPath(uri);      
84                 }
85                  
86                 wadlMethod.setName(httpMethod.name());
87                 Method javaMethod = handlerMethod.getMethod();
88                 wadlMethod.setId(javaMethod.getName());
89                 Doc wadlDocMethod = new Doc();
90                 wadlDocMethod.setTitle(javaMethod.getDeclaringClass().getSimpleName() + "." + javaMethod.getName());
91                 wadlMethod.getDoc().add(wadlDocMethod);
92                  
93                 // Request
94                 Request wadlRequest = new Request();
95                 Annotation[][] annotations = javaMethod.getParameterAnnotations();
96                 Class<?>[] paramTypes = javaMethod.getParameterTypes();
97                 int i = 0;
98                 for (Annotation[] annotation : annotations) {
99                         Class<?> paramType =paramTypes[i];
100                         i++;
101                     for (Annotation annotation2 : annotation) {
102                     
103                         Param wadlParam = doParam(annotation2, paramType);
104                         if (wadlParam != null) {
105                                 wadlRequest.getParam().add(wadlParam);
106                         }
107                     }
108                 }
109                 if (!wadlRequest.getParam().isEmpty() ) {
110                     wadlMethod.setRequest(wadlRequest);
111                 }
112                  
113                 // Response
114                 Set<MediaType> mediaTypes = mappingInfo.getProducesCondition().getProducibleMediaTypes();
115                 if (!mediaTypes.isEmpty()) {
116                         ResponseStatus status = handlerMethod.getMethodAnnotation(ResponseStatus.class);
117                     Response wadlResponse = doResponse(mediaTypes, status);
118                     wadlMethod.getResponse().add(wadlResponse);
119                 }
120                 
121                 
122                 wadlResource.getMethodOrResource().add(wadlMethod);          
123             });
124              
125         });
126         result.getResources().add(wadlResources);
127          
128         return result;
129     }
130     
131     private Param doParam(Annotation annotation2, Class<?> paramType) {
132         Param wadlParam = null;
133         
134         if (annotation2 instanceof RequestParam ) {
135             RequestParam param = (RequestParam)annotation2;
136             
137             wadlParam = new Param();
138             QName nm = convertJavaToXMLType(paramType);
139             if (StringUtils.isNotEmpty(nm.getLocalPart())) {
140                 wadlParam.setType(nm);
141             }
142             wadlParam.setName(param.value());
143             
144             
145             if (!ValueConstants.DEFAULT_NONE.equals(param.defaultValue())) {
146                 String defaultValue = cleanDefault(param.defaultValue());
147                 if (StringUtils.isNotEmpty(defaultValue) ) {
148                     wadlParam.setDefault(defaultValue);
149                 }
150             }
151
152             wadlParam.setStyle(ParamStyle.QUERY);
153             wadlParam.setRequired(param.required());       
154         } else if (annotation2 instanceof PathVariable ) {
155             PathVariable param = (PathVariable)annotation2;
156             
157             wadlParam = new Param();                            
158             QName nm = convertJavaToXMLType(paramType);
159             if (StringUtils.isNotEmpty(nm.getLocalPart())) {
160                 wadlParam.setType(nm);
161             }
162             wadlParam.setName(param.value());
163             
164             
165             wadlParam.setStyle(ParamStyle.TEMPLATE);
166             wadlParam.setRequired(true);
167         }
168         
169         return wadlParam;
170     }
171      
172     private Response doResponse(Set<MediaType> mediaTypes, ResponseStatus status) {
173         Response wadlResponse = new Response();
174         
175         mediaTypes.forEach(mediaType -> {
176             Representation wadlRepresentation = new Representation();
177             wadlRepresentation.setMediaType(mediaType.toString());
178             wadlResponse.getRepresentation().add(wadlRepresentation);
179         });
180         
181         wadlResponse.getStatus().add(getResposeValue(status));
182
183         return wadlResponse;
184     }
185     
186     private long getResposeValue(ResponseStatus status) {
187         if(status == null) {
188                 return HttpStatus.OK.value();
189         } else {
190             HttpStatus httpcode = status.value();
191             return httpcode.value();
192         }
193     }
194     
195     private QName convertJavaToXMLType(Class<?> type) {
196         QName nm = new QName("");
197         String classname = type.toString();
198         classname = classname.toLowerCase();
199         
200                 if (classname.indexOf("string") >= 0) {
201                         nm = new QName(NAMESPACE_URI, "string", "xs");
202                 } else if (classname.indexOf("integer") >= 0) {
203                         nm = new QName(NAMESPACE_URI, "int", "xs");
204                 } else if (classname.indexOf("long") >= 0) {
205                         nm = new QName(NAMESPACE_URI, "long", "xs");
206                 }
207         
208         return nm;
209     }
210     
211     private Resource createOrFind(String uri, Resources wadResources) {
212           List<Resource> current = wadResources.getResource();
213           for(Resource resource:current) {
214                   if(resource.getPath().equalsIgnoreCase(uri)){
215                           return resource;
216                   }
217           }
218           Resource wadlResource = new Resource();
219           current.add(wadlResource);
220           return wadlResource;
221     }
222     
223     private String getBaseUrl(HttpServletRequest request) {
224         String requestUri = request.getRequestURI();
225         int index = requestUri.lastIndexOf('/');
226         requestUri = requestUri.substring(0, index);
227         
228         return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + requestUri;
229     }
230      
231     private String cleanDefault(String value) {
232         value = value.replaceAll("\t", "");
233         value = value.replaceAll("\n", "");
234         return value;
235     }
236 }