PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/atlassian-plugins-schema/src/main/java/com/atlassian/plugin/schema/spi/DocumentBasedSchema.java

https://bitbucket.org/rmanalan/atlassian-plugins
Java | 302 lines | 259 code | 39 blank | 4 comment | 2 complexity | c1ffb5ec5027667514ffd4606d83ccfb MD5 | raw file
Possible License(s): BSD-3-Clause
  1. package com.atlassian.plugin.schema.spi;
  2. import com.atlassian.plugin.Permissions;
  3. import com.atlassian.plugin.Plugin;
  4. import com.google.common.collect.ImmutableSet;
  5. import org.dom4j.Document;
  6. import org.dom4j.DocumentException;
  7. import org.dom4j.io.SAXReader;
  8. import org.xml.sax.EntityResolver;
  9. import org.xml.sax.InputSource;
  10. import org.xml.sax.SAXException;
  11. import org.xml.sax.XMLReader;
  12. import javax.xml.XMLConstants;
  13. import javax.xml.parsers.ParserConfigurationException;
  14. import javax.xml.parsers.SAXParserFactory;
  15. import java.io.ByteArrayInputStream;
  16. import java.io.IOException;
  17. import java.net.URL;
  18. import static com.google.common.base.Preconditions.checkNotNull;
  19. import static java.util.Collections.emptySet;
  20. /**
  21. * Schema based on a XML document resource in the plugin
  22. */
  23. public final class DocumentBasedSchema implements Schema
  24. {
  25. private final String name;
  26. private final String description;
  27. private final String path;
  28. private final String elementName;
  29. private final String fileName;
  30. private final String complexType;
  31. private final String maxOccurs;
  32. private final Iterable<String> requiredPermissions;
  33. private final Iterable<String> optionalPermissions;
  34. private final Plugin plugin;
  35. private final SchemaTransformer schemaTransformer;
  36. private DocumentBasedSchema(String elementName,
  37. String name,
  38. String description,
  39. String path,
  40. String fileName,
  41. String complexType,
  42. String maxOccurs,
  43. Iterable<String> requiredPermissions,
  44. Iterable<String> optionalPermissions,
  45. Plugin plugin,
  46. SchemaTransformer schemaTransformer
  47. )
  48. {
  49. this.name = name;
  50. this.elementName = elementName;
  51. this.description = description;
  52. this.path = path;
  53. this.fileName = fileName;
  54. this.complexType = complexType;
  55. this.maxOccurs = maxOccurs;
  56. this.requiredPermissions = requiredPermissions;
  57. this.optionalPermissions = optionalPermissions;
  58. this.plugin = plugin;
  59. this.schemaTransformer = schemaTransformer;
  60. }
  61. @Override
  62. public String getName()
  63. {
  64. return name;
  65. }
  66. @Override
  67. public String getDescription()
  68. {
  69. return description;
  70. }
  71. @Override
  72. public String getFileName()
  73. {
  74. return fileName;
  75. }
  76. @Override
  77. public String getElementName()
  78. {
  79. return elementName;
  80. }
  81. @Override
  82. public String getComplexType()
  83. {
  84. return complexType;
  85. }
  86. @Override
  87. public String getMaxOccurs()
  88. {
  89. return maxOccurs;
  90. }
  91. @Override
  92. public Iterable<String> getRequiredPermissions()
  93. {
  94. return requiredPermissions;
  95. }
  96. @Override
  97. public Iterable<String> getOptionalPermissions()
  98. {
  99. return optionalPermissions;
  100. }
  101. @Override
  102. public Document getDocument()
  103. {
  104. final URL sourceUrl = plugin.getResource(path);
  105. if (sourceUrl == null)
  106. {
  107. throw new IllegalStateException("Cannot find schema document " + path);
  108. }
  109. Document source = parseDocument(sourceUrl);
  110. return schemaTransformer.transform(source);
  111. }
  112. public static DynamicSchemaBuilder builder()
  113. {
  114. return new DynamicSchemaBuilder();
  115. }
  116. public static DynamicSchemaBuilder builder(String id)
  117. {
  118. return new DynamicSchemaBuilder(id);
  119. }
  120. public static class DynamicSchemaBuilder
  121. {
  122. private String name;
  123. private String description;
  124. private String path;
  125. private String fileName;
  126. private String elementName;
  127. private String complexType;
  128. private String maxOccurs = "unbounded";
  129. // default set of permissions for modules is pretty much unrestricted access to backend and front-end code
  130. private Iterable<String> requiredPermissions = ImmutableSet.of(Permissions.EXECUTE_JAVA, Permissions.GENERATE_ANY_HTML);
  131. private Iterable<String> optionalPermissions = emptySet();
  132. private Plugin plugin;
  133. private SchemaTransformer schemaTransformer = SchemaTransformer.IDENTITY;
  134. public DynamicSchemaBuilder()
  135. {
  136. }
  137. public DynamicSchemaBuilder(String elementName)
  138. {
  139. this.elementName = elementName;
  140. this.fileName = elementName + ".xsd";
  141. this.path = "/xsd/" + this.fileName;
  142. this.complexType = IdUtils.dashesToCamelCase(elementName) + "Type";
  143. this.name = IdUtils.dashesToTitle(elementName);
  144. this.description = "A " + name + " module";
  145. }
  146. public DynamicSchemaBuilder setName(String name)
  147. {
  148. this.name = name;
  149. return this;
  150. }
  151. public DynamicSchemaBuilder setDescription(String description)
  152. {
  153. this.description = description;
  154. return this;
  155. }
  156. public DynamicSchemaBuilder setPath(String path)
  157. {
  158. this.path = path;
  159. return this;
  160. }
  161. public DynamicSchemaBuilder setFileName(String fileName)
  162. {
  163. this.fileName = fileName;
  164. return this;
  165. }
  166. public DynamicSchemaBuilder setElementName(String elementName)
  167. {
  168. this.elementName = elementName;
  169. return this;
  170. }
  171. public DynamicSchemaBuilder setRequiredPermissions(Iterable<String> permissions)
  172. {
  173. this.requiredPermissions = permissions;
  174. return this;
  175. }
  176. public DynamicSchemaBuilder setOptionalPermissions(Iterable<String> permissions)
  177. {
  178. this.optionalPermissions = permissions;
  179. return this;
  180. }
  181. public DynamicSchemaBuilder setComplexType(String complexType)
  182. {
  183. this.complexType = complexType;
  184. return this;
  185. }
  186. public DynamicSchemaBuilder setMaxOccurs(String maxOccurs)
  187. {
  188. this.maxOccurs = maxOccurs;
  189. return this;
  190. }
  191. public DynamicSchemaBuilder setPlugin(Plugin plugin)
  192. {
  193. this.plugin = plugin;
  194. return this;
  195. }
  196. public DynamicSchemaBuilder setTransformer(SchemaTransformer schemaTransformer)
  197. {
  198. this.schemaTransformer = schemaTransformer;
  199. return this;
  200. }
  201. public DocumentBasedSchema build()
  202. {
  203. checkNotNull(elementName);
  204. checkNotNull(fileName);
  205. checkNotNull(name);
  206. checkNotNull(description);
  207. checkNotNull(complexType);
  208. checkNotNull(plugin);
  209. checkNotNull(requiredPermissions);
  210. checkNotNull(optionalPermissions);
  211. return new DocumentBasedSchema(elementName, name, description, path, fileName, complexType, maxOccurs,
  212. requiredPermissions, optionalPermissions, plugin,
  213. schemaTransformer);
  214. }
  215. }
  216. private static Document parseDocument(URL xmlUrl)
  217. {
  218. Document source;
  219. try
  220. {
  221. source = createSecureSaxReader().read(xmlUrl);
  222. }
  223. catch (DocumentException e)
  224. {
  225. throw new IllegalArgumentException("Unable to parse XML", e);
  226. }
  227. return source;
  228. }
  229. public static SAXReader createSecureSaxReader()
  230. {
  231. return createReader(false);
  232. }
  233. private static SAXReader createReader(boolean validating)
  234. {
  235. XMLReader xmlReader;
  236. try
  237. {
  238. SAXParserFactory spf = SAXParserFactory.newInstance();
  239. spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
  240. false);
  241. spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
  242. xmlReader = spf.newSAXParser().getXMLReader();
  243. xmlReader.setEntityResolver(EMPTY_ENTITY_RESOLVER);
  244. }
  245. catch (ParserConfigurationException e)
  246. {
  247. throw new RuntimeException("XML Parser configured incorrectly", e);
  248. }
  249. catch (SAXException e)
  250. {
  251. throw new RuntimeException("Unable to configure XML parser", e);
  252. }
  253. return new SAXReader(xmlReader, validating);
  254. }
  255. private static InputSource EMPTY_INPUT_SOURCE = new InputSource(new ByteArrayInputStream(new byte[0]));
  256. private static final EntityResolver EMPTY_ENTITY_RESOLVER = new EntityResolver()
  257. {
  258. public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException
  259. {
  260. return EMPTY_INPUT_SOURCE;
  261. }
  262. };
  263. }