View Javadoc

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