View Javadoc

1   package com.atlassian.plugin.parsers;
2   
3   import com.atlassian.plugin.*;
4   import com.atlassian.plugin.impl.UnloadablePluginFactory;
5   import com.atlassian.plugin.descriptors.UnloadableModuleDescriptor;
6   import com.atlassian.plugin.descriptors.UnrecognisedModuleDescriptor;
7   import com.atlassian.plugin.descriptors.UnrecognisedModuleDescriptorFactory;
8   import com.atlassian.plugin.descriptors.UnloadableModuleDescriptorFactory;
9   import org.dom4j.Element;
10  import org.dom4j.Document;
11  import org.dom4j.DocumentException;
12  import org.dom4j.io.SAXReader;
13  import org.apache.commons.logging.Log;
14  import org.apache.commons.logging.LogFactory;
15  
16  import java.util.Iterator;
17  import java.io.InputStream;
18  
19  /**
20   * Provides access to the descriptor information retrieved from an XML InputStream.
21   * <p/>
22   * Uses the dom4j {@link SAXReader} to parse the XML stream into a document
23   * when the parser is constructed.
24   *
25   * @see XmlDescriptorParserFactory
26   */
27  public class XmlDescriptorParser implements DescriptorParser
28  {
29      private static Log log = LogFactory.getLog(XmlDescriptorParser.class);
30  
31      boolean recogniseSystemPlugins = false;
32      private Document document;
33  
34      /**
35       * @throws PluginParseException if there is a problem reading the descriptor from the XML {@link InputStream}.
36       */
37      public XmlDescriptorParser(InputStream source) throws PluginParseException
38      {
39          if (source == null)
40              throw new IllegalArgumentException("source cannot be null");
41          document = createDocument(source);
42      }
43  
44      protected Document createDocument(InputStream source) throws PluginParseException
45      {
46          SAXReader reader = new SAXReader();
47          try
48          {
49              return reader.read(source);
50          }
51          catch (DocumentException e)
52          {
53              throw new PluginParseException("Cannot parse XML plugin descriptor", e);
54          }
55      }
56  
57      protected Document getDocument()
58      {
59          return document;
60      }
61  
62      public Plugin configurePlugin(ModuleDescriptorFactory moduleDescriptorFactory, Plugin plugin) throws PluginParseException
63      {
64  
65          Element pluginElement = getPluginElement();
66          plugin.setName(pluginElement.attributeValue("name"));
67          plugin.setKey(getKey());
68  
69          if (pluginElement.attributeValue("i18n-name-key") != null)
70          {
71              plugin.setI18nNameKey(pluginElement.attributeValue("i18n-name-key"));
72          }
73  
74          if (plugin.getKey().indexOf(":") > 0)
75              throw new PluginParseException("Plugin keys cannot contain ':'. Key is '" + plugin.getKey() + "'");
76  
77          if ("disabled".equalsIgnoreCase(pluginElement.attributeValue("state")))
78              plugin.setEnabledByDefault(false);
79  
80          for (Iterator i = pluginElement.elementIterator(); i.hasNext();)
81          {
82              Element element = (Element) i.next();
83  
84              if ("plugin-info".equalsIgnoreCase(element.getName()))
85              {
86                  plugin.setPluginInformation(createPluginInformation(element));
87              }
88              else if (!"resource".equalsIgnoreCase(element.getName()))
89              {
90                  ModuleDescriptor moduleDescriptor = createModuleDescriptor(plugin, element, moduleDescriptorFactory);
91  
92                  // If we're not loading the module descriptor, null is returned, so we skip it
93                  if (moduleDescriptor == null)
94                      continue;
95  
96                  if (plugin.getModuleDescriptor(moduleDescriptor.getKey()) != null)
97                      throw new PluginParseException("Found duplicate key '" + moduleDescriptor.getKey() + "' within plugin '" + plugin.getKey() + "'");
98  
99                  plugin.addModuleDescriptor(moduleDescriptor);
100 
101                 // If we have any unloadable modules, also create an unloadable plugin, which will make it clear that there was a problem
102                 if (moduleDescriptor instanceof UnloadableModuleDescriptor)
103                 {
104                     log.error("There were errors loading the plugin '" + plugin.getName() + "'. The plugin has been disabled.");
105                     return UnloadablePluginFactory.createUnloadablePlugin(plugin);
106                 }
107             }
108         }
109 
110         plugin.setResources(Resources.fromXml(pluginElement));
111 
112         return plugin;
113     }
114 
115     private Element getPluginElement()
116     {
117         return document.getRootElement();
118     }
119 
120     protected ModuleDescriptor createModuleDescriptor(Plugin plugin, Element element, ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException
121     {
122         String name = element.getName();
123 
124         ModuleDescriptor moduleDescriptorDescriptor;
125 
126         // Try to retrieve the module descriptor
127         try
128         {
129             moduleDescriptorDescriptor = moduleDescriptorFactory.getModuleDescriptor(name);
130         }
131         // When there's a problem loading a module, return an UnrecognisedModuleDescriptor with error
132         catch (Throwable e)
133         {
134             UnrecognisedModuleDescriptor descriptor = UnrecognisedModuleDescriptorFactory.createUnrecognisedModuleDescriptor(plugin, element, e, moduleDescriptorFactory);
135 
136             log.error("There were problems loading the module '" + name + "' in plugin '" + plugin.getName() + "'. The module has been disabled.");
137             log.error(descriptor.getErrorText(), e);
138 
139             return descriptor;
140         }
141 
142         // When the module descriptor has been excluded, null is returned (PLUG-5)
143         if (moduleDescriptorDescriptor == null)
144         {
145             log.info("The module '" + name + "' in plugin '" + plugin.getName() + "' is in the list of excluded module descriptors, so not enabling.");
146             return null;
147         }
148 
149         // Once we have the module descriptor, create it using the given information
150         try
151         {
152             moduleDescriptorDescriptor.init(plugin, element);
153         }
154         // If it fails, return a dummy module that contains the error
155         catch (PluginParseException e)
156         {
157             UnloadableModuleDescriptor descriptor = UnloadableModuleDescriptorFactory.createUnloadableModuleDescriptor(plugin, element, e, moduleDescriptorFactory);
158 
159             log.error("There were problems loading the module '" + name + "'. The module and its plugin have been disabled.");
160             log.error(descriptor.getErrorText(), e);
161 
162             return descriptor;
163         }
164 
165         return moduleDescriptorDescriptor;
166     }
167 
168 
169     protected PluginInformation createPluginInformation(Element element)
170     {
171         PluginInformation pluginInfo = new PluginInformation();
172 
173         if (element.element("description") != null)
174         {
175             pluginInfo.setDescription(element.element("description").getTextTrim());
176             if (element.element("description").attributeValue("key") != null)
177             {
178                 pluginInfo.setDescriptionKey(element.element("description").attributeValue("key"));
179             }
180         }
181 
182         if (element.element("version") != null)
183             pluginInfo.setVersion(element.element("version").getTextTrim());
184 
185         if (element.element("vendor") != null)
186         {
187             final Element vendor = element.element("vendor");
188             pluginInfo.setVendorName(vendor.attributeValue("name"));
189             pluginInfo.setVendorUrl(vendor.attributeValue("url"));
190         }
191 
192         // initialize any parameters on the plugin xml definition
193         for (Iterator iterator = element.elements("param").iterator(); iterator.hasNext();)
194         {
195             Element param = (Element) iterator.next();
196 
197             // Retrieve the parameter info => name & text
198             if (param.attribute("name") != null)
199                 pluginInfo.addParameter(param.attribute("name").getData().toString(), param.getText());
200         }
201 
202         if (element.element("application-version") != null)
203         {
204             pluginInfo.setMaxVersion(Float.parseFloat(element.element("application-version").attributeValue("max")));
205             pluginInfo.setMinVersion(Float.parseFloat(element.element("application-version").attributeValue("min")));
206         }
207 
208         if (element.element("java-version") != null)
209         {
210             pluginInfo.setMinJavaVersion(Float.valueOf(element.element("java-version").attributeValue("min")));
211         }
212 
213         return pluginInfo;
214     }
215 
216     public String getKey()
217     {
218         return getPluginElement().attributeValue("key");
219     }
220 
221     public int getPluginsVersion()
222     {
223         String val = getPluginElement().attributeValue("pluginsVersion");
224         if (val != null) {
225             return Integer.parseInt(val);
226         } else {
227             return 1;
228         }
229     }
230 
231     public boolean isSystemPlugin()
232     {
233         return "true".equalsIgnoreCase(getPluginElement().attributeValue("system"));
234     }
235 }