1 package com.atlassian.plugins.rest.doclet.generators.resourcedoc;
2
3 import com.atlassian.annotations.ExperimentalApi;
4 import com.sun.jersey.api.model.AbstractResource;
5 import com.sun.jersey.api.model.AbstractResourceMethod;
6 import com.sun.jersey.server.wadl.WadlGenerator;
7 import com.sun.jersey.server.wadl.generators.resourcedoc.WadlGeneratorResourceDocSupport;
8 import com.sun.jersey.server.wadl.generators.resourcedoc.model.ResourceDocType;
9 import com.sun.research.ws.wadl.Method;
10 import com.sun.research.ws.wadl.Resource;
11 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory;
13 import org.w3c.dom.Document;
14 import org.w3c.dom.NamedNodeMap;
15 import org.w3c.dom.Node;
16 import org.w3c.dom.NodeList;
17
18 import java.net.URL;
19 import java.util.HashMap;
20 import javax.xml.namespace.QName;
21 import javax.xml.parsers.DocumentBuilder;
22 import javax.xml.parsers.DocumentBuilderFactory;
23
24
25
26
27
28
29
30
31
32
33
34
35
36 public class AtlassianWadlGeneratorResourceDocSupport extends WadlGeneratorResourceDocSupport
37 {
38 private HashMap<String, ResourcePathInformation> resourcePathInformation;
39
40 private static final Logger LOG = LoggerFactory.getLogger(AtlassianWadlGeneratorResourceDocSupport.class);
41 private static final String ATLASSIAN_PLUGIN_XML = "atlassian-plugin.xml";
42
43 public AtlassianWadlGeneratorResourceDocSupport()
44 {
45 super();
46 }
47
48 public AtlassianWadlGeneratorResourceDocSupport(WadlGenerator wadlGenerator, ResourceDocType resourceDoc)
49 {
50 super(wadlGenerator, resourceDoc);
51 }
52
53 @Override
54 public void init() throws Exception
55 {
56 super.init();
57 parseAtlassianPluginXML();
58 }
59
60 private void parseAtlassianPluginXML()
61 {
62
63 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
64
65 try
66 {
67 final URL resource = getClass().getClassLoader().getResource(ATLASSIAN_PLUGIN_XML);
68 if (resource == null) return;
69 LOG.info("Found " + ATLASSIAN_PLUGIN_XML + " file! Looking for rest plugin module descriptors...");
70
71 DocumentBuilder db = dbf.newDocumentBuilder();
72
73 resourcePathInformation = new HashMap<String, ResourcePathInformation>();
74
75 final Document document = db.parse(resource.toExternalForm());
76 final NodeList restPluginModuleDescriptors = document.getElementsByTagName("rest");
77 final int numPluginModuleDescriptors = restPluginModuleDescriptors.getLength();
78 LOG.info("Found " + numPluginModuleDescriptors + " rest plugin module descriptors.");
79
80 for (int i = 0; i < numPluginModuleDescriptors; i++)
81 {
82 final Node node = restPluginModuleDescriptors.item(i);
83
84 final NamedNodeMap attributes = node.getAttributes();
85 final Node pathItem = attributes.getNamedItem("path");
86 final Node versionItem = attributes.getNamedItem("version");
87 if (pathItem == null || versionItem == null)
88 continue;
89
90 String resourcePath = pathItem.getNodeValue();
91 String version = versionItem.getNodeValue();
92
93 LOG.info("Found rest end point with path '" + resourcePath + "' and version '" + version + "'");
94
95
96 if (resourcePath.indexOf("/") != -1)
97 {
98 resourcePath = resourcePath.substring(resourcePath.indexOf("/") + 1);
99 }
100
101 final NodeList list = node.getChildNodes();
102 for (int j = 0; j < list.getLength(); j++)
103 {
104 final Node child = list.item(j);
105 if (child.getNodeName().equals("package"))
106 {
107 final String packageName = child.getFirstChild().getNodeValue();
108 LOG.info("Map package '" + packageName + "' to resource path '" + resourcePath + "' and version '" + version + "'");
109 resourcePathInformation.put(packageName, new ResourcePathInformation(resourcePath, version));
110 }
111 }
112 }
113 }
114 catch (Exception ex)
115 {
116 LOG.error("Failed to read " + ATLASSIAN_PLUGIN_XML + " and parse rest plugin module descriptor information. Reason", ex);
117 }
118 }
119
120 @Override
121 public Resource createResource(AbstractResource r, String path)
122 {
123 final Resource result = super.createResource(r, path);
124 boolean resourcePathChanged = false;
125 for (String packageName : resourcePathInformation.keySet())
126 {
127 if (r.getResourceClass().getPackage().getName().startsWith(packageName))
128 {
129 final ResourcePathInformation pathInformation = resourcePathInformation.get(packageName);
130 final String newPath = pathInformation.getPath() + "/" + pathInformation.getVersion() + "/" + result.getPath();
131 result.setPath(newPath);
132 resourcePathChanged = true;
133 LOG.info("Setting resource path of rest end point '" + r.getResourceClass().getCanonicalName() + "' to '" + newPath + "'");
134 break;
135 }
136 }
137 if (!resourcePathChanged)
138 {
139 LOG.info("Resource path of rest end point '" + r.getResourceClass().getCanonicalName() + "' unchanged no mapping to rest plugin module descriptor found.");
140 }
141
142 return result;
143 }
144
145 @Override
146 public Method createMethod(final AbstractResource r, final AbstractResourceMethod m)
147 {
148 final Method method = super.createMethod(r, m);
149 if (m.getMethod().getAnnotation(ExperimentalApi.class) != null)
150 {
151 method.getOtherAttributes().put(new QName("experimental"), Boolean.TRUE.toString());
152 }
153 return method;
154 }
155
156 public class ResourcePathInformation
157 {
158 private final String path;
159 private final String version;
160
161 public ResourcePathInformation(String path, String version)
162 {
163 this.path = path;
164 this.version = version;
165 }
166
167 public String getVersion()
168 {
169 return version;
170 }
171
172 public String getPath()
173 {
174 return path;
175 }
176 }
177
178 }