producer XML configuration support: Producers can be set up using an XML input
[mir.git] / source / mir / producer / reader / ProducerConfigReader.java
1 package  mir.producer.reader;
2
3 import java.io.*;
4 import java.util.*;
5 import java.lang.System;
6 import org.xml.sax.helpers.DefaultHandler;
7 import org.xml.sax.*;
8 import javax.xml.parsers.ParserConfigurationException;
9 import javax.xml.parsers.SAXParser;
10 import javax.xml.parsers.SAXParserFactory;
11
12 import mir.util.*;
13 import mir.config.exceptions.*;
14 import mir.producer.*;
15
16 //import mir.producer.exceptions.*;
17 import mir.misc.Location;
18
19 public class ProducerConfigReader {
20   private ProducerNodeBuilderLibrary builderLibrary;
21   private ProducerNodeBuilderLibrary scriptedNodeBuilderLibrary;
22
23   public ProducerConfigReader() {
24     super();
25   };
26
27   public void parseFile(String aFileName, ProducerNodeBuilderLibrary aBuilderLibrary, Map aProducerFactories) throws ConfigFailure {
28     parseFile(aFileName, aBuilderLibrary, aProducerFactories, new Vector());
29
30   }
31
32   public void parseFile(String aFileName, ProducerNodeBuilderLibrary aBuilderLibrary, Map aProducerFactories, List aUsedFiles) throws ConfigFailure {
33     try {
34       builderLibrary = aBuilderLibrary;
35       scriptedNodeBuilderLibrary = new ProducerNodeBuilderLibrary();
36
37       SAXParserFactory parserFactory = SAXParserFactory.newInstance();
38
39       parserFactory.setNamespaceAware(false);
40       parserFactory.setValidating(true);
41
42       ProducerConfigHandler handler = new ProducerConfigHandler(parserFactory, aProducerFactories, aUsedFiles);
43
44       handler.includeFile(aFileName);
45     }
46     catch (Throwable e) {
47       if (e instanceof SAXParseException && ((SAXParseException) e).getException() instanceof ConfigFailure) {
48         throw (ConfigFailure) ((SAXParseException) e).getException();
49       }
50       else {
51         e.printStackTrace();
52         throw new ConfigFailure( e.getMessage() );
53       }
54     }
55   }
56
57   private class ProducerConfigHandler extends DefaultHandler {
58     private Locator locator;
59     private Stack includeFileStack;
60     private SAXParserFactory parserFactory;
61     private SectionsManager manager;
62     private List usedFiles;
63     private InputSource inputSource;
64
65     public ProducerConfigHandler(SAXParserFactory aParserFactory, Map aProducers, List aUsedFiles) {
66       super();
67
68       includeFileStack=new Stack();
69       parserFactory=aParserFactory;
70       includeFileStack = new Stack();
71       manager = new SectionsManager();
72       usedFiles = aUsedFiles;
73
74       manager.pushHandler(new RootSectionHandler(aProducers));
75    }
76
77     public String getLocatorDescription(Locator aLocator) {
78       return aLocator.getPublicId()+" ("+aLocator.getLineNumber()+")";
79     }
80
81     public void setDocumentLocator(Locator aLocator) {
82       locator=aLocator;
83     }
84
85     private void includeFile(String aFileName) throws ConfigFailure, SAXParseException, SAXException {
86       File file;
87       SAXParser parser;
88
89       try {
90         if (!includeFileStack.empty())
91           file = new File(new File((String) includeFileStack.peek()).getParent(), aFileName);
92         else
93           file = new File(aFileName);
94
95         System.err.println("about to include "+file.getCanonicalPath());
96
97         if (includeFileStack.contains(file.getCanonicalPath())) {
98           throw new ConfigFailure("recursive inclusion of file "+file.getCanonicalPath(), getLocatorDescription(locator));
99         }
100
101         usedFiles.add(file);
102
103         parser=parserFactory.newSAXParser();
104
105         inputSource = new InputSource(new FileInputStream(file));
106         inputSource.setPublicId(file.getCanonicalPath());
107
108         includeFileStack.push(file.getCanonicalPath());
109         try {
110           parser.parse(inputSource, this);
111         }
112         finally {
113           includeFileStack.pop();
114         }
115       }
116       catch (ParserConfigurationException e) {
117         throw new ConfigFailure("Internal exception while including \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));
118       }
119       catch (SAXParseException e) {
120         throw e;
121       }
122       catch (ConfigFailure e) {
123         throw e;
124       }
125       catch (FileNotFoundException e) {
126         throw new ConfigFailure("Include file \""+aFileName+"\" not found: "+e.getMessage(), e, getLocatorDescription(locator));
127       }
128       catch (IOException e) {
129         throw new ConfigFailure("unable to open include file \""+aFileName+"\": "+e.getMessage(), e, getLocatorDescription(locator));
130       }
131     }
132
133     public void startElement(String aUri, String aTag, String aQualifiedName, Attributes anAttributes) throws SAXException {
134       Map attributesMap;
135       int i;
136
137       try {
138         if (aQualifiedName.equals("include")) {
139           String fileName=anAttributes.getValue("file");
140
141           if (fileName==null) {
142             throw new ConfigFailure("include has no file attribute", getLocatorDescription(locator));
143           }
144
145           includeFile(fileName);
146         }
147         else {
148           attributesMap = new HashMap();
149           for (i=0; i<anAttributes.getLength(); i++)
150             attributesMap.put(anAttributes.getQName(i), anAttributes.getValue(i));
151
152           manager.pushHandler( manager.currentHandler().startElement(aQualifiedName, attributesMap) );
153         }
154       }
155       catch (Exception e) {
156         e.printStackTrace(System.out);
157         throw new SAXException(e);
158       }
159     }
160
161     public void endElement(String aUri, String aTag, String aQualifiedName) throws SAXException {
162       try
163       {
164         if (!aQualifiedName.equals("include")) {
165           SectionHandler handler = manager.popHandler();
166
167           handler.finishSection();
168
169           if (!manager.isEmpty()) {
170             manager.currentHandler().endElement(handler);
171           }
172         }
173       }
174       catch (Exception e) {
175         e.printStackTrace(System.out);
176         throw new SAXException(e);
177       }
178     }
179
180     public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXParseException {
181       String text = new String(aBuffer, aStart, anEnd).trim();
182       if ( text.length() > 0) {
183         throw new SAXParseException("Text not allowed", locator, new ConfigFailure("text not allowed", getLocatorDescription(locator)));
184       }
185     }
186
187   }
188   public class SectionsManager {
189     Stack handlerStack;
190
191     public SectionsManager() {
192       handlerStack = new Stack();
193     }
194
195     public void pushHandler(SectionHandler aSectionHandler) {
196       handlerStack.push(aSectionHandler);
197     }
198
199     public SectionHandler popHandler() {
200       return (SectionHandler) handlerStack.pop();
201     }
202
203     public SectionHandler currentHandler() {
204       return (SectionHandler) handlerStack.peek();
205     }
206
207     public boolean isEmpty() {
208       return handlerStack.isEmpty();
209     }
210   }
211
212   public abstract class SectionHandler {
213     public abstract SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc;
214
215     public abstract void endElement(SectionHandler aHandler) throws ProducerConfigExc;
216 //    {
217 //    }
218
219     public void finishSection() throws ProducerConfigExc {
220     }
221   }
222
223   public class RootSectionHandler extends SectionHandler {
224     private Map producers;
225
226     public RootSectionHandler(Map aProducers) {
227       producers = aProducers;
228     }
229
230     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
231       if (aTag.equals("producers")) {
232         return new ProducersSectionHandler(producers);
233       }
234       else
235         throw new ProducerConfigExc ("Tag 'producers' expected, tag '"+aTag+"' found");
236     }
237
238     public void endElement(SectionHandler aHandler) {
239     }
240
241     public void finishSection() throws ProducerConfigExc {
242     }
243   }
244
245
246   private final static String   PRODUCER_NAME_ATTRIBUTE = "name";
247   private final static String[] PRODUCER_REQUIRED_ATTRIBUTES = { PRODUCER_NAME_ATTRIBUTE };
248   private final static String[] PRODUCER_OPTIONAL_ATTRIBUTES = { };
249
250   private final static String   NODE_DEFINITION_NAME_ATTRIBUTE = "name";
251   private final static String[] NODE_DEFINITION_REQUIRED_ATTRIBUTES = { NODE_DEFINITION_NAME_ATTRIBUTE };
252   private final static String[] NODE_DEFINITION_OPTIONAL_ATTRIBUTES = {  };
253
254   public class ProducersSectionHandler extends SectionHandler {
255     private Map producers;
256     private String name;
257
258     public ProducersSectionHandler(Map aProducers) {
259       producers = aProducers;
260     }
261
262     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
263
264       if (aTag.equals("producer")) {
265         ReaderTool.checkAttributes(anAttributes, PRODUCER_REQUIRED_ATTRIBUTES, PRODUCER_OPTIONAL_ATTRIBUTES);
266
267         name = (String) anAttributes.get(PRODUCER_NAME_ATTRIBUTE);
268         ReaderTool.checkValidIdentifier( name );
269
270         if (producers.containsKey(name))
271           throw new ProducerConfigExc("Duplicate producer name: '" + name + "'");
272
273         name = (String) anAttributes.get(PRODUCER_NAME_ATTRIBUTE);
274
275         return new ProducerSectionHandler();
276       }
277       else if (aTag.equals("nodedefinition")) {
278         ReaderTool.checkAttributes(anAttributes, NODE_DEFINITION_REQUIRED_ATTRIBUTES, NODE_DEFINITION_OPTIONAL_ATTRIBUTES);
279
280         name = (String) anAttributes.get(NODE_DEFINITION_NAME_ATTRIBUTE);
281         ReaderTool.checkValidIdentifier( name );
282
283         if (producers.containsKey(name))
284           throw new ProducerConfigExc("Duplicate producer name: '" + name + "'");
285
286         name = (String) anAttributes.get(NODE_DEFINITION_NAME_ATTRIBUTE);
287
288         return new NodeDefinitionSectionHandler(name);
289       }
290
291       throw new ProducerConfigExc("Unexpected tag: "+aTag );
292     }
293
294     public void endElement(SectionHandler aHandler) throws ProducerConfigExc {
295       if (aHandler instanceof ProducerSectionHandler) {
296         producers.put(name, ((ProducerSectionHandler) aHandler).getProducerFactory());
297       }
298       else if (aHandler instanceof NodeDefinitionSectionHandler) {
299
300         scriptedNodeBuilderLibrary.registerFactory(name,
301             new DefaultProducerNodeBuilders.ScriptedProducerNodeBuilder.factory(
302                 ((NodeDefinitionSectionHandler) aHandler).getDefinition()));
303       }
304       else throw new ProducerConfigExc("ProducersSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
305     }
306
307     public void finishSection() throws ProducerConfigExc {
308     }
309   }
310
311   public class ProducerSectionHandler extends SectionHandler {
312     private ProducerFactory producerFactory;
313
314     private ProducerNode body;
315     private Map verbs;
316     private String defaultVerb;
317
318     public SectionHandler startElement(String aTag, Map anAttributes)  throws ProducerConfigExc {
319       if (aTag.equals("verbs")) {
320         if (verbs!=null)
321           throw new ProducerConfigExc("Verbs already processed");
322         if (body!=null)
323           throw new ProducerConfigExc("Verbs should come before body");
324         else
325           return new ProducerVerbsSectionHandler();
326       }
327       else if (aTag.equals("body")) {
328         if (body==null)
329           return new ProducerNodeSectionHandler();
330         else
331           throw new ProducerConfigExc("Body already processed");
332       }
333       throw new ProducerConfigExc("Unexpected tag: '"+aTag+"'");
334     }
335
336     public void endElement(SectionHandler aHandler) throws ProducerConfigExc {
337       if (aHandler instanceof ProducerNodeSectionHandler) {
338         body = ((ProducerNodeSectionHandler) aHandler).getProducerNode();
339       }
340       else if (aHandler instanceof ProducerVerbsSectionHandler)
341       {
342         verbs = ((ProducerVerbsSectionHandler) aHandler).getVerbs();
343         defaultVerb = ((ProducerVerbsSectionHandler) aHandler).getDefaultVerb();
344       }
345       else throw new ProducerConfigExc("ProducerSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
346     }
347
348     public void finishSection() throws ProducerConfigExc {
349       if (verbs==null)
350         throw new ProducerConfigExc("No verbs defined");
351
352       if (body==null)
353         throw new ProducerConfigExc("No body defined");
354
355       producerFactory = new ScriptedProducerFactory(verbs, body, defaultVerb);
356     }
357
358     public ProducerFactory getProducerFactory() {
359       return producerFactory;
360     }
361   }
362
363   private final static String   PRODUCER_VERB_NAME_ATTRIBUTE = "name";
364   private final static String   PRODUCER_VERB_DEFAULT_ATTRIBUTE = "default";
365   private final static String[] PRODUCER_VERB_REQUIRED_ATTRIBUTES = { PRODUCER_VERB_NAME_ATTRIBUTE };
366   private final static String[] PRODUCER_VERB_OPTIONAL_ATTRIBUTES = { PRODUCER_VERB_DEFAULT_ATTRIBUTE };
367
368   public class ProducerVerbsSectionHandler extends SectionHandler {
369     private Map verbs;
370     private String defaultVerb;
371     private String currentVerb;
372
373     public ProducerVerbsSectionHandler() {
374       verbs = new HashMap();
375       defaultVerb = null;
376     }
377
378     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
379       if (aTag.equals("verb")) {
380         ReaderTool.checkAttributes(anAttributes, PRODUCER_VERB_REQUIRED_ATTRIBUTES, PRODUCER_VERB_OPTIONAL_ATTRIBUTES);
381         currentVerb = (String) anAttributes.get( PRODUCER_VERB_NAME_ATTRIBUTE );
382
383         ReaderTool.checkValidIdentifier( currentVerb );
384
385         if (verbs.containsKey(currentVerb))
386           throw new ProducerConfigExc( "Duplicate definition of verb '" + currentVerb + "'" );
387
388         if (anAttributes.containsKey(PRODUCER_VERB_DEFAULT_ATTRIBUTE)) {
389           if (defaultVerb!=null)
390             throw new ProducerConfigExc( "Default verb already declared" );
391
392           defaultVerb = currentVerb;
393         }
394
395         return new ProducerNodeSectionHandler();
396       }
397       else throw new ProducerConfigExc("Only 'verb' tags allowed here, '" + aTag + "' encountered.");
398     }
399
400     public void endElement(SectionHandler aHandler) {
401       verbs.put(currentVerb, ((ProducerNodeSectionHandler) aHandler).getProducerNode());
402     }
403
404     public void finishSection() {
405     }
406
407     public String getDefaultVerb() {
408       return defaultVerb;
409     }
410
411     public Map getVerbs() {
412       return verbs;
413     }
414   }
415
416   public class EmptySectionHandler extends SectionHandler {
417     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
418       throw new ProducerConfigExc("No tags are allowed here");
419     }
420
421     public void endElement(SectionHandler aHandler) {
422     }
423
424   }
425
426   public class MultiProducerNodeSectionHandler extends SectionHandler {
427     private Map nodeParameters;
428     private Set validNodeParameters;
429     private String currentNodeParameter;
430     private String scriptedNodeName;
431     private Set allowedNodeParameterReferences;
432
433     public MultiProducerNodeSectionHandler(String aScriptedNodeName, Set anAllowedNodeParameterReferences, Set aValidNodeParameters) {
434       allowedNodeParameterReferences = anAllowedNodeParameterReferences;
435       scriptedNodeName = aScriptedNodeName;
436       validNodeParameters = aValidNodeParameters;
437       nodeParameters = new HashMap();
438     }
439     public MultiProducerNodeSectionHandler(Set aValidNodeParameters) {
440       this("", new HashSet(), aValidNodeParameters);
441     }
442
443     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
444       if (!validNodeParameters.contains(aTag))
445         throw new ProducerConfigExc("Invalid node parameter: '" + aTag + "'");
446       else if (nodeParameters.containsKey(aTag))
447         throw new ProducerConfigExc("Node parameter: '" + aTag + "' already specified");
448       else if (anAttributes.size()>0)
449         throw new ProducerConfigExc("No parameters are allowed here");
450
451       currentNodeParameter = aTag;
452
453       return new ProducerNodeSectionHandler(scriptedNodeName, validNodeParameters);
454     }
455
456     public void endElement(SectionHandler aHandler) throws ProducerConfigExc  {
457       if (aHandler instanceof ProducerNodeSectionHandler) {
458         nodeParameters.put(currentNodeParameter, ((ProducerNodeSectionHandler) aHandler).getProducerNode());
459       }
460       else {
461         throw new ProducerConfigExc("Internal error: unknown section handler '" + aHandler.getClass().getName() + "'" );
462       }
463     }
464
465     public Map getNodeParameters() {
466       return nodeParameters;
467     }
468   }
469
470   public class ProducerNodeSectionHandler extends SectionHandler {
471     private CompositeProducerNode producerNode;
472     private ProducerNodeBuilder currentBuilder;
473     private String scriptedNodeName;
474     private Set allowedNodeParameterReferences;
475
476     public ProducerNodeSectionHandler(String aScriptedNodeName, Set anAllowedNodeParameterReferences) {
477       producerNode = new CompositeProducerNode();
478       scriptedNodeName = aScriptedNodeName;
479       allowedNodeParameterReferences = anAllowedNodeParameterReferences;
480     }
481
482     public ProducerNodeSectionHandler() {
483       this("", new HashSet());
484     }
485
486     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
487       if (allowedNodeParameterReferences.contains((aTag))) {
488         if (!anAttributes.isEmpty()) {
489           throw new ProducerConfigExc( "No attributes allowed" );
490         }
491         producerNode.addSubNode(new ScriptedProducerNodeDefinition.NodeParameterProducerNode(scriptedNodeName, aTag));
492
493         return new EmptySectionHandler();
494       }
495       else if (scriptedNodeBuilderLibrary.hasBuilderForName(aTag) || builderLibrary.hasBuilderForName((aTag))) {
496
497         if (scriptedNodeBuilderLibrary.hasBuilderForName(aTag))
498           currentBuilder = scriptedNodeBuilderLibrary.constructBuilder(aTag);
499         else
500           currentBuilder = builderLibrary.constructBuilder(aTag);
501
502         currentBuilder.setAttributes(anAttributes);
503         if (currentBuilder.getAvailableSubNodes().isEmpty())  {
504           return new EmptySectionHandler();
505         }
506         if (currentBuilder.getAvailableSubNodes().size()>1)
507           return new MultiProducerNodeSectionHandler(scriptedNodeName, allowedNodeParameterReferences, currentBuilder.getAvailableSubNodes());
508         else if (currentBuilder.getAvailableSubNodes().size()<1)
509           return new EmptySectionHandler();
510         else {
511           return new ProducerNodeSectionHandler(scriptedNodeName, allowedNodeParameterReferences);
512         }
513       }
514       else
515         throw new ProducerConfigExc("Unknown producer node tag: '" + aTag + "'");
516     }
517
518     public void endElement(SectionHandler aHandler) throws ProducerConfigExc  {
519       if (aHandler instanceof ProducerNodeSectionHandler) {
520         currentBuilder.setSubNode((String) (currentBuilder.getAvailableSubNodes().iterator().next()),
521                     ((ProducerNodeSectionHandler) aHandler).getProducerNode());
522       }
523       else if (aHandler instanceof MultiProducerNodeSectionHandler) {
524         Iterator i;
525         Map nodeParameters;
526         Map.Entry entry;
527
528         nodeParameters = ((MultiProducerNodeSectionHandler) aHandler).getNodeParameters();
529         i = nodeParameters.entrySet().iterator();
530         while (i.hasNext()) {
531           entry = (Map.Entry) i.next();
532           currentBuilder.setSubNode((String) entry.getKey(), (ProducerNode) entry.getValue());
533         }
534       }
535       else if (aHandler instanceof EmptySectionHandler) {
536         // deliberately empty: nothing expected, so nothing to process
537       }
538       else {
539         throw new ProducerConfigExc("Internal error: unknown section handler '" + aHandler.getClass().getName() + "'" );
540       }
541
542       producerNode.addSubNode(currentBuilder.constructNode());
543       currentBuilder = null;
544     }
545
546     public ProducerNode getProducerNode() {
547       if (producerNode.getNrSubNodes()==1) {
548         return producerNode.getSubNode(0);
549       }
550       else {
551         return producerNode;
552       }
553     }
554   }
555
556   public class NodeDefinitionSectionHandler extends SectionHandler {
557     private ScriptedProducerNodeDefinition nodeDefinition;
558     private ProducerNode definition;
559     private Map stringParameters;
560     private Map nodeParameters;
561     private String name;
562
563     public NodeDefinitionSectionHandler(String aName) {
564       definition = null;
565       nodeParameters = null;
566       stringParameters = null;
567       name = aName;
568     }
569
570     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
571       if (aTag.equals("parameters")) {
572         if (!anAttributes.isEmpty()) {
573           throw new ProducerConfigExc( "No attributes allowed for tag 'parameters'" );
574         }
575         if (nodeParameters!=null) {
576           throw new ProducerConfigExc( "Parameters have already been declared" );
577         }
578         if (definition!=null) {
579           throw new ProducerConfigExc( "Parameters should come before definition" );
580         }
581
582         return new NodeDefinitionParametersSectionHandler();
583       }
584       else if (aTag.equals("definition")) {
585         return new ProducerNodeSectionHandler(name, nodeParameters.keySet());
586       }
587       else throw new ProducerConfigExc("Only 'verb' tags allowed here, '" + aTag + "' encountered.");
588     }
589
590     public void endElement(SectionHandler aHandler) {
591       if (aHandler instanceof NodeDefinitionParametersSectionHandler) {
592         stringParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getStringParameters();
593         nodeParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getNodeParameters();
594       }
595       else if (aHandler instanceof ProducerNodeSectionHandler) {
596         definition = ((ProducerNodeSectionHandler) aHandler).getProducerNode();
597       }
598     }
599
600     public void finishSection() throws ProducerConfigExc {
601       Iterator i;
602       if (definition == null)
603         throw new ProducerConfigExc( "Definition missing" );
604
605       nodeDefinition = new ScriptedProducerNodeDefinition(name);
606
607       i = nodeParameters.keySet().iterator();
608       while (i.hasNext()) {
609         nodeDefinition.addNodeParameter((String) i.next());
610       }
611
612       i = stringParameters.entrySet().iterator();
613       while (i.hasNext()) {
614         Map.Entry entry = (Map.Entry) i.next();
615         nodeDefinition.addParameter((String) entry.getKey(), (String) entry.getValue());
616       }
617     }
618
619     public ScriptedProducerNodeDefinition getDefinition() {
620       return nodeDefinition;
621     }
622   }
623
624   private final static String   NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE = "name";
625   private final static String   NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE = "defaultvalue";
626   private final static String[] NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES = { NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE };
627   private final static String[] NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES = { NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE };
628   private final static String[] NODE_DEFINITION_NODE_PARAMETER_OPTIONAL_ATTRIBUTES = { };
629
630   public class NodeDefinitionParametersSectionHandler extends SectionHandler {
631     private Map nodeParameters;
632     private Map stringParameters;
633
634     public NodeDefinitionParametersSectionHandler() {
635       nodeParameters = new HashMap();
636       stringParameters = new HashMap();
637     }
638
639     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
640       String parameterName;
641       String defaultValue;
642
643       if (aTag.equals("node")) {
644         ReaderTool.checkAttributes(anAttributes, NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES, NODE_DEFINITION_NODE_PARAMETER_OPTIONAL_ATTRIBUTES);
645         parameterName = (String) anAttributes.get( NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE );
646
647         if (nodeParameters.containsKey(parameterName))
648           throw new ProducerConfigExc("Duplicate parameter name: '" + parameterName + "'");
649
650         ReaderTool.checkValidIdentifier( parameterName );
651
652         nodeParameters.put(parameterName, parameterName);
653
654         return new EmptySectionHandler();
655       }
656       else if (aTag.equals("string")) {
657         ReaderTool.checkAttributes(anAttributes, NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES, NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES);
658         parameterName = (String) anAttributes.get( NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE );
659
660         if (stringParameters.containsKey(parameterName))
661           throw new ProducerConfigExc("Duplicate parameter name: '" + parameterName + "'");
662
663         ReaderTool.checkValidIdentifier( parameterName );
664
665         defaultValue = (String) anAttributes.get( NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE );
666
667         stringParameters.put(parameterName, defaultValue);
668
669         return new EmptySectionHandler();
670       }
671       else throw new ProducerConfigExc("Only 'string' and 'node' tags allowed here, '" + aTag + "' encountered.");
672
673     }
674
675     public void endElement(SectionHandler aHandler) {
676     }
677
678     public void finishSection() {
679     }
680
681     public Map getNodeParameters() {
682       return nodeParameters;
683     }
684
685     public Map getStringParameters() {
686       return stringParameters;
687     }
688   }
689 }
690
691
692 /*
693  /                 (expecting producers)
694  producers/        (expecting nodedefinition, producer)
695    nodedefinition  (expecting parameters, definition)
696      parameters    (expecting parameter declarations)
697      definition    (expecting nodes, subnodes)
698 */
699