1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package de.smartics.properties.spi.core.metadata.projectdoc;
17
18 import static de.smartics.util.lang.StaticAnalysis.UNCHECKED;
19
20 import java.io.BufferedInputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.util.List;
24 import java.util.Locale;
25
26 import javax.annotation.CheckForNull;
27
28 import org.apache.commons.io.IOUtils;
29 import org.jdom.Document;
30 import org.jdom.Element;
31 import org.jdom.JDOMException;
32 import org.jdom.Namespace;
33 import org.jdom.input.SAXBuilder;
34 import org.jdom.output.XMLOutputter;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import de.smartics.properties.api.core.domain.DocumentMetaData;
39 import de.smartics.properties.api.core.domain.ProjectdocMetaData;
40 import de.smartics.properties.api.core.domain.PropertiesContext;
41 import de.smartics.properties.api.core.domain.PropertyDescriptor;
42 import de.smartics.properties.spi.core.metadata.projectdoc.ProjectdocAnnotationCollector.Defaults;
43 import de.smartics.util.lang.Arg;
44
45
46
47
48 public abstract class ProjectdocMetaDataParser
49 {
50
51
52
53
54
55
56
57 private static final Logger LOG = LoggerFactory
58 .getLogger(ProjectdocMetaDataParser.class);
59
60
61
62
63
64
65 protected final PropertiesContext context;
66
67
68
69
70 protected final Defaults defaults;
71
72
73
74
75
76
77
78
79
80
81
82
83 protected ProjectdocMetaDataParser(final PropertiesContext context)
84 throws NullPointerException
85 {
86 this(context, null);
87 }
88
89
90
91
92
93
94
95
96
97 protected ProjectdocMetaDataParser(final PropertiesContext context,
98 final Defaults defaults) throws NullPointerException
99 {
100 this.context = Arg.checkNotNull("context", context);
101 this.defaults = defaults;
102 }
103
104
105
106
107
108
109
110 public final class ParserContext
111 {
112
113
114
115
116
117
118
119
120
121
122 private final PropertyDescriptor descriptor;
123
124
125
126
127 private final Locale locale;
128
129
130
131
132 private final String systemId;
133
134
135
136
137 private final Document document;
138
139
140
141
142
143
144 private final ProjectdocMetaData metaData;
145
146
147
148
149
150 private ParserContext(final PropertyDescriptor descriptor,
151 final Locale locale, final String systemId, final Document document,
152 final ProjectdocMetaData metaData)
153 {
154 this.descriptor = descriptor;
155 this.locale = locale;
156 this.systemId = systemId;
157 this.document = document;
158 this.metaData = metaData;
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 public PropertyDescriptor getDescriptor()
175 {
176 return descriptor;
177 }
178
179
180
181
182
183
184 public Locale getLocale()
185 {
186 return locale;
187 }
188
189
190
191
192
193
194 public String getSystemId()
195 {
196 return systemId;
197 }
198
199
200
201
202
203
204 public Document getDocument()
205 {
206 return document;
207 }
208
209
210
211
212
213
214
215
216 public ProjectdocMetaData getMetaData()
217 {
218 return metaData;
219 }
220
221
222
223
224 }
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247 @CheckForNull
248 public ProjectdocMetaData parse(final PropertyDescriptor descriptor,
249 final Locale locale)
250 {
251 try
252 {
253 final ProjectdocMetaData metaData = new ProjectdocMetaData();
254 parseBase(descriptor, locale, metaData);
255 return metaData;
256 }
257 catch (final MetaDataException e)
258 {
259 LOG.warn("Cannot parse meta data for property descriptor '{}': {}",
260 descriptor, e);
261 return null;
262 }
263 }
264
265
266
267
268
269
270
271
272
273 protected final void parseBase(final PropertyDescriptor descriptor,
274 final Locale locale, final ProjectdocMetaData metaData)
275 throws MetaDataException
276 {
277 final String path = calcPath(descriptor, locale);
278
279 final ClassLoader loader = descriptor.getDeclaringType().getClassLoader();
280
281 InputStream input = null;
282 try
283 {
284 final InputStream resource = load(path, loader);
285 if (resource != null)
286 {
287 input = new BufferedInputStream(resource);
288 parse(descriptor, path, locale, input, metaData);
289 }
290 else
291 {
292 throw new MetaDataException(path);
293 }
294 }
295 finally
296 {
297 IOUtils.closeQuietly(input);
298 }
299 }
300
301
302
303
304
305
306
307
308 protected abstract String calcPath(final PropertyDescriptor descriptor,
309 final Locale locale);
310
311 private InputStream load(final String path, final ClassLoader loader)
312 {
313 InputStream input = loader.getResourceAsStream(path);
314 if (input == null)
315 {
316 input = loader.getResourceAsStream('/' + path);
317 }
318 return input;
319 }
320
321 private DocumentMetaData parse(final PropertyDescriptor descriptor,
322 final String systemId, final Locale locale, final InputStream input,
323 final ProjectdocMetaData metaData) throws MetaDataException
324 {
325 try
326 {
327 final SAXBuilder parser = new SAXBuilder();
328 final Document document = parser.build(input, systemId);
329
330 final Element rootNode = document.getRootElement();
331 addIdInfo(metaData, rootNode);
332 addFiling(metaData, rootNode);
333 addDescription(metaData, rootNode);
334
335 final ParserContext context =
336 new ParserContext(descriptor, locale, systemId, document, metaData);
337 parseAdditional(context);
338
339 return metaData;
340 }
341 catch (final JDOMException e)
342 {
343 throw new MetaDataException(systemId, e);
344 }
345 catch (final IOException e)
346 {
347 throw new MetaDataException(systemId, e);
348 }
349 }
350
351
352
353
354
355
356
357
358 protected void parseAdditional(final ParserContext context)
359 throws MetaDataException
360 {
361 }
362
363 private void addIdInfo(final ProjectdocMetaData metaData,
364 final Element rootNode)
365 {
366 if (defaults != null)
367 {
368 metaData.setName(defaults.getName());
369 metaData.setSpace(defaults.getSpace());
370 metaData.setTitle(defaults.getTitle());
371 }
372
373 final Element identification = rootNode.getChild("identification", getNs());
374 if (identification != null)
375 {
376 final String space =
377 identification.getChildTextNormalize("space", getNs());
378 metaData.setSpace(space);
379 final String title =
380 identification.getChildTextNormalize("title", getNs());
381 metaData.setTitle(title);
382 }
383
384 final String name = rootNode.getChildTextNormalize("name", getNs());
385 metaData.setName(name);
386 }
387
388 private void addFiling(final ProjectdocMetaData metaData,
389 final Element rootNode)
390 {
391 final Element filing = rootNode.getChild("filing", getNs());
392 if (filing != null)
393 {
394 addParents(metaData, filing);
395 addCategories(metaData, filing);
396 addTags(metaData, filing);
397 setSortKey(metaData, filing);
398 }
399 }
400
401 @SuppressWarnings(UNCHECKED)
402 private void addParents(final ProjectdocMetaData metaData,
403 final Element filing)
404 {
405 final Element parentsElement = filing.getChild("parents", getNs());
406 if (parentsElement != null)
407 {
408 final List<Element> parents =
409 parentsElement.getChildren("parent", getNs());
410 for (final Element parent : parents)
411 {
412 final String parentName = parent.getTextNormalize();
413 metaData.addParent(parentName);
414 }
415 }
416 }
417
418 @SuppressWarnings(UNCHECKED)
419 private void addCategories(final ProjectdocMetaData metaData,
420 final Element filing)
421 {
422 final Element categoriesElement = filing.getChild("categories", getNs());
423 if (categoriesElement != null)
424 {
425 final List<Element> categories =
426 categoriesElement.getChildren("category", getNs());
427 for (final Element category : categories)
428 {
429 final String categoryName = category.getTextNormalize();
430 metaData.addCategory(categoryName);
431 }
432 }
433 }
434
435 @SuppressWarnings(UNCHECKED)
436 private void addTags(final ProjectdocMetaData metaData, final Element filing)
437 {
438 final Element tagsElement = filing.getChild("tags", getNs());
439 if (tagsElement != null)
440 {
441 final List<Element> tags = tagsElement.getChildren("tag", getNs());
442 for (final Element tag : tags)
443 {
444 final String tagName = tag.getTextNormalize();
445 metaData.addTag(tagName);
446 }
447 }
448 }
449
450 private void setSortKey(final ProjectdocMetaData metaData,
451 final Element filing)
452 {
453 final String sortKey = filing.getChildTextNormalize("sortKey", getNs());
454 metaData.setSortKey(sortKey);
455 }
456
457 @SuppressWarnings(UNCHECKED)
458 private void addDescription(final ProjectdocMetaData metaData,
459 final Element rootNode)
460 {
461 final Element description = rootNode.getChild("description", getNs());
462 if (description != null)
463 {
464 final Element audienceElement = description.getChild("audience", getNs());
465 if (audienceElement != null)
466 {
467 final List<Element> members =
468 audienceElement.getChildren("member", getNs());
469 for (final Element member : members)
470 {
471 final String memberName = member.getTextNormalize();
472 metaData.addAudience(memberName);
473 }
474 }
475
476 final Element shortDescriptionElement =
477 description.getChild("shortDescription", getNs());
478 final String shortDescription = toString(shortDescriptionElement);
479 metaData.setShortDescription(shortDescription);
480
481 final Element summaryElement = description.getChild("summary", getNs());
482 final String summary = toString(summaryElement);
483 metaData.setSummary(summary);
484
485 final Element notesElement = description.getChild("notes", getNs());
486 final String notes = toString(notesElement);
487 metaData.addNote(notes);
488 }
489 }
490
491
492
493
494
495
496 protected abstract Namespace getNs();
497
498 private static String toString(final Element element)
499 {
500 final XMLOutputter outp = new XMLOutputter();
501 final StringBuilder buffer = new StringBuilder(1024);
502
503 final List<?> children = element.getContent();
504 final String string = outp.outputString(children);
505 buffer.append(string);
506
507 return buffer.toString().trim();
508 }
509
510
511
512 }