1 package net.sf.logdistiller.xml;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import java.io.*;
18 import java.util.*;
19 import javax.xml.parsers.DocumentBuilder;
20 import javax.xml.parsers.DocumentBuilderFactory;
21 import javax.xml.parsers.ParserConfigurationException;
22 import org.w3c.dom.Document;
23 import org.w3c.dom.Element;
24 import org.xml.sax.InputSource;
25 import org.xml.sax.SAXException;
26
27 import net.sf.logdistiller.*;
28 import net.sf.logdistiller.util.PropertiesReplacer;
29 import org.xml.sax.ErrorHandler;
30
31
32
33
34
35
36 public class DOMConfigurator
37 {
38 private final Map overriddenProperties;
39
40 private PropertiesReplacer replacer = null;
41
42 private boolean workInProgress = false;
43
44 private boolean old;
45
46 private List warnings = null;
47
48 private LogDistiller ld = null;
49
50 public DOMConfigurator()
51 {
52 overriddenProperties = null;
53 }
54
55 public DOMConfigurator( Map overriddenProperties )
56 {
57 this.overriddenProperties = overriddenProperties;
58 }
59
60 synchronized public LogDistiller read( File f )
61 throws ParserConfigurationException, IOException, SAXException
62 {
63 return read( f, null );
64 }
65
66 synchronized public LogDistiller read( File f, ErrorHandler errorHandler )
67 throws ParserConfigurationException, IOException, SAXException
68 {
69 return read( new FileInputStream( f ), errorHandler );
70 }
71
72 synchronized public LogDistiller read( InputStream in )
73 throws ParserConfigurationException, IOException, SAXException
74 {
75 return read( in, null );
76 }
77
78 synchronized public LogDistiller read( InputStream in, ErrorHandler errorHandler )
79 throws ParserConfigurationException, IOException, SAXException
80 {
81 return read( new InputSource( in ), errorHandler );
82 }
83
84 synchronized public LogDistiller read( InputSource inputSource )
85 throws ParserConfigurationException, IOException, SAXException
86 {
87 return read( inputSource, null );
88 }
89
90
91
92
93
94
95 protected boolean begin()
96 {
97 if ( workInProgress )
98 {
99
100 return false;
101 }
102 workInProgress = true;
103 warnings = new ArrayList();
104 old = false;
105 return true;
106 }
107
108 protected void end( boolean really )
109 {
110 if ( !really )
111 {
112 return;
113 }
114 workInProgress = false;
115 if ( ld != null )
116 {
117 Iterator iter = warnings.iterator();
118 while ( iter.hasNext() )
119 {
120 ld.addWarning( (String) iter.next() );
121 }
122 }
123 warnings = null;
124 ld = null;
125 }
126
127 protected void addWarning( String warning )
128 {
129 warnings.add( warning );
130 }
131
132 synchronized public LogDistiller read( InputSource inputSource, ErrorHandler errorHandler )
133 throws ParserConfigurationException, IOException, SAXException
134 {
135 boolean beginning = begin();
136 try
137 {
138 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
139 dbf.setValidating( true );
140 DocumentBuilder docBuilder = dbf.newDocumentBuilder();
141 docBuilder.setErrorHandler( ( errorHandler == null ) ? new SAXErrorHandler() : errorHandler );
142 LogDistillerEntityResolver resolver = new LogDistillerEntityResolver();
143 docBuilder.setEntityResolver( resolver );
144 Document doc = docBuilder.parse( inputSource );
145
146 if ( resolver.getCurrentDtd() == null )
147 {
148 addWarning( "no DTD used: you should use " + LogDistillerEntityResolver.LATEST_DTD_URL );
149 }
150 else if ( !LogDistillerEntityResolver.LATEST_DTD.equals( resolver.getCurrentDtd() ) )
151 {
152 addWarning( "using old DTD " + resolver.getCurrentDtd() + ": you should consider upgrading to "
153 + LogDistillerEntityResolver.LATEST_DTD + " (please read upgrade documentation)" );
154 }
155
156 ld = parse( doc.getDocumentElement() );
157 return ld;
158 }
159 finally
160 {
161 end( beginning );
162 }
163 }
164
165 synchronized public LogDistiller parse( Element element )
166 {
167 boolean beginning = begin();
168 try
169 {
170 if ( !"logdistiller".equals( element.getNodeName() ) )
171 {
172 throw new IllegalArgumentException( "document root element is '" + element.getNodeName()
173 + "' where it should be 'logdistiller': see " + LogDistillerEntityResolver.LATEST_DTD_URL );
174 }
175
176 String id = element.getAttribute( "id" );
177 Map properties = parseProperties( DOMUtils.getChildElementsByTagName( element, "property" ) );
178 replacer = new PropertiesReplacer( properties );
179 String description = replacer.replaceProperties( DOMUtils.getPCDATAByTagName( element, "description" ) );
180 LogDistiller.LogType logtype = null;
181 LogDistiller.Output output = null;
182
183 Iterator iter = DOMUtils.getChildElementsByTagName( element, "logtype" );
184 if ( iter.hasNext() )
185 {
186 logtype = parseLogType( (Element) iter.next() );
187 output = parseOutput( (Element) DOMUtils.getChildElementsByTagName( element, "output" ).next() );
188 }
189 else
190 {
191 old = true;
192 Map params = parseParams( DOMUtils.getChildElementsByTagName( element, "param" ) );
193 String logsUrl = (String) params.get( "logs.url" );
194 output =
195 new LogDistiller.Output( "logs", logsUrl, "default", "", params, buildCompatibilityReports( params ) );
196 }
197
198 LogDistiller.Category[] categories =
199 parseCategories( DOMUtils.getChildElementsByTagName( element, "category" ) );
200 LogDistiller.Group[] groups =
201 parseGroups( DOMUtils.getChildElementsByTagName( element, "group" ), categories );
202 return new LogDistiller( id, description, logtype, output, categories, groups, old );
203 }
204 finally
205 {
206 end( beginning );
207 }
208 }
209
210 protected Map parseProperties( Iterator iter )
211 {
212 Map map = new HashMap();
213 while ( iter.hasNext() )
214 {
215 Element param = (Element) iter.next();
216 String name = param.getAttribute( "name" );
217 String value = param.getAttribute( "value" );
218 if ( map.put( name, value ) != null )
219 {
220 addWarning( "multiple values were defined for '" + name
221 + "' property: the last one will override other values." );
222 }
223 }
224 if ( overriddenProperties != null )
225 {
226
227 Iterator iter2 = overriddenProperties.keySet().iterator();
228 while ( iter2.hasNext() )
229 {
230 String name = (String) iter2.next();
231 if ( map.put( name, overriddenProperties.get( name ) ) == null )
232 {
233 throw new IllegalArgumentException( "unable to override property '" + name + "': unknown property" );
234 }
235 }
236 }
237 return map;
238 }
239
240 protected LogDistiller.LogType parseLogType( Element element )
241 {
242 String id = element.getAttribute( "id" );
243 Map params = parseParams( DOMUtils.getChildElementsByTagName( element, "param" ) );
244 String paramAttributes = (String)params.get( "attributes" );
245
246 Attributes attributes = null;
247 Iterator iter = DOMUtils.getChildElementsByTagName( element, "attributes" );
248 if ( iter.hasNext() )
249 {
250 attributes = parseAttributes( paramAttributes, (Element) iter.next() );
251 }
252 else
253 {
254 attributes = new Attributes( paramAttributes, Attributes.NO_EXTENSIONS );
255 addWarning( "no logtype/attributes element defined: please consider adding this element (new in LogDistiller 1.1)." );
256 }
257 return new LogDistiller.LogType( id, params, attributes );
258 }
259
260 protected Attributes parseAttributes( String paramAttributes, Element element )
261 {
262 String provided = DOMUtils.getPCDATAByTagName( element, "provided" );
263 if ( provided == null )
264 {
265 addWarning( "logtype 'attributes' param has been replaced by <provided> element: please consider using this element (new in LogDistiller 1.1)" );
266 provided = paramAttributes;
267 }
268 Attributes.Extension[] extensions = parseExtensions( DOMUtils.getChildElementsByTagName( element, "extension" ) );
269 return new Attributes( provided, extensions );
270 }
271
272 protected Attributes.Extension[] parseExtensions( Iterator iter )
273 {
274 List extensions = new ArrayList();
275 while ( iter.hasNext() )
276 {
277 Element extension = (Element) iter.next();
278 extensions.add( parseExtension( extension ) );
279 }
280 return (Attributes.Extension[]) extensions.toArray( new Attributes.Extension[extensions.size()] );
281 }
282
283 protected Attributes.Extension parseExtension( Element element )
284 {
285 String source = element.getAttribute( "source" );
286 String provides = element.getAttribute( "provides" );
287 String regexp = DOMUtils.getPCDATA( element );
288 return new Attributes.Extension( source, provides, regexp );
289 }
290
291 protected LogDistiller.Output parseOutput( Element element )
292 {
293 String directory = replacer.replaceProperties( element.getAttribute( "directory" ) );
294 String url = replacer.replaceProperties( element.getAttribute( "url" ) );
295 String content = replacer.replaceProperties( element.getAttribute( "content" ) );
296 String skip = replacer.replaceProperties( element.getAttribute( "skip" ) );
297 Map params = parseParams( DOMUtils.getChildElementsByTagName( element, "param" ) );
298
299 String paramLogsUrl = (String) params.get( "logs.url" );
300 if ( paramLogsUrl != null )
301 {
302 if ( url == null )
303 {
304 url = paramLogsUrl;
305 addWarning( "in output element, param logs.url is now deprecated: please use url attribute (<output url=\"...\">)" );
306 }
307 else
308 {
309 addWarning( "in output element, attribute url and deprecated param logs.url have both been set: ignoring param" );
310 }
311 }
312
313 LogDistiller.Report[] reports = parseReports( DOMUtils.getChildElementsByTagName( element, "report" ) );
314
315 return new LogDistiller.Output( directory, url, content, skip, params, reports );
316 }
317
318 protected LogDistiller.Report[] parseReports( Iterator iter )
319 {
320 List reports = new ArrayList();
321 while ( iter.hasNext() )
322 {
323 Element report = (Element) iter.next();
324 reports.add( parseReport( report ) );
325 }
326 return (LogDistiller.Report[]) reports.toArray( new LogDistiller.Report[reports.size()] );
327 }
328
329 protected LogDistiller.Report parseReport( Element element )
330 {
331 String publisher = replacer.replaceProperties( element.getAttribute( "publisher" ) );
332 String format = replacer.replaceProperties( element.getAttribute( "format" ) );
333 Map params = parseParams( DOMUtils.getChildElementsByTagName( element, "param" ) );
334 return new LogDistiller.Report( publisher, format, params );
335 }
336
337 protected LogDistiller.Report[] buildCompatibilityReports( Map params )
338 {
339 LogDistiller.Report fileReport = new LogDistiller.Report( "file", "txt", new HashMap() );
340 String to = (String) params.get( "mail.to" );
341 if ( to == null )
342 {
343 return new LogDistiller.Report[] { fileReport };
344 }
345 Map newParams = new HashMap();
346 newParams.put( "to", replacer.replaceProperties( to ) );
347 String cc = (String) params.get( "mail.cc" );
348 if ( cc != null )
349 {
350 newParams.put( "cc", replacer.replaceProperties( cc ) );
351 }
352 LogDistiller.Report mailReport = new LogDistiller.Report( "mail", "txt", newParams );
353 return new LogDistiller.Report[] { fileReport, mailReport };
354 }
355
356 protected Map parseParams( Iterator iter )
357 {
358 Map params = new HashMap();
359 while ( iter.hasNext() )
360 {
361 Element param = (Element) iter.next();
362 String name = param.getAttribute( "name" );
363 String value = replacer.replaceProperties( DOMUtils.getPCDATA( param ) );
364 if ( params.put( name, value ) != null )
365 {
366 addWarning( "multiple values were defined for '" + name
367 + "' parameter: the last one will override other values." );
368 }
369 }
370 return params;
371 }
372
373 protected LogDistiller.Category[] parseCategories( Iterator iter )
374 {
375 List categories = new ArrayList();
376 while ( iter.hasNext() )
377 {
378 Element category = (Element) iter.next();
379 String id = category.getAttribute( "id" );
380 String description = DOMUtils.getPCDATA( category );
381 categories.add( new LogDistiller.Category( id, description ) );
382 }
383 return (LogDistiller.Category[]) categories.toArray( new LogDistiller.Category[categories.size()] );
384 }
385
386 protected LogDistiller.Group[] parseGroups( Iterator iter, LogDistiller.Category[] categories )
387 {
388 Map mapCategories = new HashMap();
389 for ( int i = 0; i < categories.length; i++ )
390 {
391 LogDistiller.Category category = categories[i];
392 mapCategories.put( category.getId(), category );
393 }
394 List groups = new ArrayList();
395 while ( iter.hasNext() )
396 {
397 Element group = (Element) iter.next();
398 groups.add( parseGroup( group, mapCategories ) );
399 }
400 return (LogDistiller.Group[]) groups.toArray( new LogDistiller.Group[groups.size()] );
401 }
402
403 protected LogDistiller.Group parseGroup( Element element, Map categories )
404 {
405 String id = element.getAttribute( "id" );
406 String description = replacer.replaceProperties( DOMUtils.getPCDATAByTagName( element, "description" ) );
407 String attr = replacer.replaceProperties( element.getAttribute( "continueProcessing" ) );
408 boolean continueProcessing = Boolean.valueOf( ( attr == null ) ? "false" : attr ).booleanValue();
409 attr = element.getAttribute( "save" );
410 if ( attr == null )
411 {
412 attr = "true";
413 }
414 boolean save = !"false".equals( attr );
415 Map params = parseParams( DOMUtils.getChildElementsByTagName( element, "param" ) );
416 Condition[] conditions = parseConditions( DOMUtils.getChildElementsByTagName( element, "condition" ) );
417 LogDistiller.Report[] reports = parseReports( DOMUtils.getChildElementsByTagName( element, "report" ) );
418 LogDistiller.Plugin[] plugins = parsePlugins( DOMUtils.getChildElementsByTagName( element, "plugin" ) );
419 if ( old )
420 {
421 reports = buildCompatibilityReports( params );
422 }
423 LogDistiller.Category category = (LogDistiller.Category) categories.get( element.getAttribute( "category" ) );
424 return new LogDistiller.Group( id, description, continueProcessing, save, params, conditions, reports, plugins,
425 category );
426 }
427
428 protected Condition[] parseConditions( Iterator iter )
429 {
430 List conditions = new ArrayList();
431 while ( iter.hasNext() )
432 {
433 Element condition = (Element) iter.next();
434 conditions.add( parseCondition( condition ) );
435 }
436 return (Condition[]) conditions.toArray( new Condition[conditions.size()] );
437 }
438
439 protected Condition parseCondition( Element element )
440 {
441 String tags = element.getAttribute( "tags" );
442 Match[] matches = parseMatchs( DOMUtils.getChildElementsByTagName( element, "match" ) );
443 return new Condition( tags, matches );
444 }
445
446 protected Match[] parseMatchs( Iterator iter )
447 {
448 List matchs = new ArrayList();
449 while ( iter.hasNext() )
450 {
451 Element match = (Element) iter.next();
452 matchs.add( parseMatch( match ) );
453 }
454 return (Match[]) matchs.toArray( new Match[matchs.size()] );
455 }
456
457 protected Match parseMatch( Element element )
458 {
459 String attribute = element.getAttribute( "attribute" );
460 String type = element.getAttribute( "type" );
461 String reference = replacer.replaceProperties( DOMUtils.getPCDATA( element ) );
462 return new Match( attribute, type, reference );
463 }
464
465 protected LogDistiller.Plugin[] parsePlugins( Iterator iter )
466 {
467 List plugins = new ArrayList();
468 while ( iter.hasNext() )
469 {
470 Element plugin = (Element) iter.next();
471 plugins.add( parsePlugin( plugin ) );
472 }
473 return (LogDistiller.Plugin[]) plugins.toArray( new LogDistiller.Plugin[plugins.size()] );
474 }
475
476 protected LogDistiller.Plugin parsePlugin( Element element )
477 {
478 String type = element.getAttribute( "type" );
479 if ( Plugins.getPlugin( type ) == null )
480 {
481 throw new PluginConfigException( "plugin type '" + type + "' unknown, valid values: "
482 + Plugins.listAllPluginIds() );
483 }
484 String attr = element.getAttribute( "globalReport" );
485 boolean globalReport = Boolean.valueOf( ( attr == null ) ? "true" : attr ).booleanValue();
486 attr = element.getAttribute( "groupReport" );
487 boolean groupReport = Boolean.valueOf( ( attr == null ) ? "true" : attr ).booleanValue();
488 Map params = parseParams( DOMUtils.getChildElementsByTagName( element, "param" ) );
489 return new LogDistiller.Plugin( type, globalReport, groupReport, params );
490 }
491 }