package no.met.metadataeditor.service; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import org.apache.commons.lang.StringUtils; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; import javax.ws.rs.FormParam; import javax.ws.rs.GET; 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.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; /** * Automatically generate web service documentation by reading the annotations * for a class. */ public class ServiceDescriptionGenerator { private static final Logger logger = Logger.getLogger(ServiceDescriptionGenerator.class.getName()); /** * Create a description of the web service offered by a class in XML. The * documentation is created by looking at the web service annotations. * * @param c * The class to generate documentation for. * @return A XML document object. * @throws ParserConfigurationException */ public static Document getXMLServiceDescription(Class<? extends Object> c) throws ParserConfigurationException { List<Method> serviceMethods = getServiceMethods(c); DocumentBuilderFactory df = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = df.newDocumentBuilder(); Document doc = builder.newDocument(); Element rootElement = doc.createElement("services"); doc.appendChild(rootElement); for (Method m : serviceMethods) { Element service = doc.createElement("service"); MethodInfo mi = getMethodInfo(m); Attr pathAttr = doc.createAttribute("path"); pathAttr.setValue(mi.path); service.setAttributeNode(pathAttr); Attr methodsAttr = doc.createAttribute("methods"); methodsAttr.setValue(mi.methods); service.setAttributeNode(methodsAttr); if (mi.produces != null) { Attr producesAttr = doc.createAttribute("returmMimeType"); producesAttr.setValue(StringUtils.join(mi.produces, ',')); service.setAttributeNode(producesAttr); } if (mi.description != null) { Attr descriptionAttr = doc.createAttribute("description"); descriptionAttr.setValue(mi.description); service.setAttributeNode(descriptionAttr); } List<ParameterInfo> params = getParameters(m); for (ParameterInfo pi : params) { Element param = doc.createElement("parameter"); Attr nameAttr = doc.createAttribute("name"); nameAttr.setValue(pi.name); param.setAttributeNode(nameAttr); Attr typeAttr = doc.createAttribute("type"); typeAttr.setValue(pi.type); param.setAttributeNode(typeAttr); if (pi.defaultValue != null) { Attr defaultValueAttr = doc.createAttribute("defaultValue"); defaultValueAttr.setValue(pi.defaultValue); param.setAttributeNode(defaultValueAttr); } service.appendChild(param); } rootElement.appendChild(service); } return doc; } private static MethodInfo getMethodInfo(Method m) { MethodInfo mi = new MethodInfo(); Path path = m.getAnnotation(Path.class); mi.path = path.value(); Produces produces = m.getAnnotation(Produces.class); if (produces != null) { mi.produces = produces.value(); } ServiceDescription description = m.getAnnotation(ServiceDescription.class); if (description != null) { mi.description = description.value(); } mi.methods = getSupportedMethods(m); return mi; } /** * @param c The class to search for methods in. * @return A list of method that is used to offer web services in the class. */ private static List<Method> getServiceMethods(Class<? extends Object> c) { List<Method> serviceMethods = new ArrayList<>(); for (Method m : c.getMethods()) { logger.info(m.getName()); if (m.isAnnotationPresent(Path.class)) { serviceMethods.add(m); } } return serviceMethods; } /** * @param method The method to get information about. * @return Information about all the parameters to web service call to the method. */ private static List<ParameterInfo> getParameters(Method method) { List<ParameterInfo> parameters = new ArrayList<>(); Annotation[][] paramAnnotations = method.getParameterAnnotations(); for (Annotation[] annotationForParam : paramAnnotations) { ParameterInfo pi = new ParameterInfo(); for (Annotation a : annotationForParam) { if (a instanceof QueryParam) { pi.name = ((QueryParam) a).value(); pi.name = "query"; } else if( a instanceof FormParam ) { pi.name = ((FormParam) a).value(); pi.type = "form"; } else if( a instanceof PathParam ) { pi.name = ((PathParam) a).value(); pi.type = "path"; } else if (a instanceof DefaultValue) { pi.defaultValue = ((DefaultValue) a).value(); } } if (pi.name != null) { parameters.add(pi); } } return parameters; } private static String getSupportedMethods(Method m){ List<String> methods = new ArrayList<>(); GET get = m.getAnnotation(GET.class); if( get != null ){ methods.add("GET"); } POST post = m.getAnnotation(POST.class); if( post != null ){ methods.add("POST"); } PUT put = m.getAnnotation(PUT.class); if( put != null ){ methods.add("PUT"); } DELETE delete = m.getAnnotation(DELETE.class); if( delete != null ){ methods.add("DELETE"); } return StringUtils.join(methods, ","); } private static class ParameterInfo { String name; String defaultValue; String type; } private static class MethodInfo { String path; String produces[]; String description; String methods; } }