View Javadoc

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