merge of localization branch into HEAD. mh and zap
[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         scriptedNodeBuilderLibrary.registerFactory(name,
300             new DefaultProducerNodeBuilders.ScriptedProducerNodeBuilder.factory(
301                 ((NodeDefinitionSectionHandler) aHandler).getDefinition()));
302       }
303       else throw new ProducerConfigExc("ProducersSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
304     }
305
306     public void finishSection() throws ProducerConfigExc {
307     }
308   }
309
310   public class ProducerSectionHandler extends SectionHandler {
311     private ProducerFactory producerFactory;
312
313     private ProducerNode body;
314     private Map verbs;
315     private String defaultVerb;
316
317     public SectionHandler startElement(String aTag, Map anAttributes)  throws ProducerConfigExc {
318       if (aTag.equals("verbs")) {
319         if (verbs!=null)
320           throw new ProducerConfigExc("Verbs already processed");
321         if (body!=null)
322           throw new ProducerConfigExc("Verbs should come before body");
323         else
324           return new ProducerVerbsSectionHandler();
325       }
326       else if (aTag.equals("body")) {
327         if (body==null)
328           return new ProducerNodeSectionHandler();
329         else
330           throw new ProducerConfigExc("Body already processed");
331       }
332       throw new ProducerConfigExc("Unexpected tag: '"+aTag+"'");
333     }
334
335     public void endElement(SectionHandler aHandler) throws ProducerConfigExc {
336       if (aHandler instanceof ProducerNodeSectionHandler) {
337         body = ((ProducerNodeSectionHandler) aHandler).getProducerNode();
338       }
339       else if (aHandler instanceof ProducerVerbsSectionHandler)
340       {
341         verbs = ((ProducerVerbsSectionHandler) aHandler).getVerbs();
342         defaultVerb = ((ProducerVerbsSectionHandler) aHandler).getDefaultVerb();
343       }
344       else throw new ProducerConfigExc("ProducerSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
345     }
346
347     public void finishSection() throws ProducerConfigExc {
348       if (verbs==null)
349         throw new ProducerConfigExc("No verbs defined");
350
351       if (body==null)
352         throw new ProducerConfigExc("No body defined");
353
354       producerFactory = new ScriptedProducerFactory(verbs, body, defaultVerb);
355     }
356
357     public ProducerFactory getProducerFactory() {
358       return producerFactory;
359     }
360   }
361
362   private final static String   PRODUCER_VERB_NAME_ATTRIBUTE = "name";
363   private final static String   PRODUCER_VERB_DEFAULT_ATTRIBUTE = "default";
364   private final static String[] PRODUCER_VERB_REQUIRED_ATTRIBUTES = { PRODUCER_VERB_NAME_ATTRIBUTE };
365   private final static String[] PRODUCER_VERB_OPTIONAL_ATTRIBUTES = { PRODUCER_VERB_DEFAULT_ATTRIBUTE };
366
367   public class ProducerVerbsSectionHandler extends SectionHandler {
368     private Map verbs;
369     private String defaultVerb;
370     private String currentVerb;
371
372     public ProducerVerbsSectionHandler() {
373       verbs = new HashMap();
374       defaultVerb = null;
375     }
376
377     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
378       if (aTag.equals("verb")) {
379         ReaderTool.checkAttributes(anAttributes, PRODUCER_VERB_REQUIRED_ATTRIBUTES, PRODUCER_VERB_OPTIONAL_ATTRIBUTES);
380         currentVerb = (String) anAttributes.get( PRODUCER_VERB_NAME_ATTRIBUTE );
381
382         ReaderTool.checkValidIdentifier( currentVerb );
383
384         if (verbs.containsKey(currentVerb))
385           throw new ProducerConfigExc( "Duplicate definition of verb '" + currentVerb + "'" );
386
387         if (anAttributes.containsKey(PRODUCER_VERB_DEFAULT_ATTRIBUTE)) {
388           if (defaultVerb!=null)
389             throw new ProducerConfigExc( "Default verb already declared" );
390
391           defaultVerb = currentVerb;
392         }
393
394         return new ProducerNodeSectionHandler();
395       }
396       else throw new ProducerConfigExc("Only 'verb' tags allowed here, '" + aTag + "' encountered.");
397     }
398
399     public void endElement(SectionHandler aHandler) {
400       verbs.put(currentVerb, ((ProducerNodeSectionHandler) aHandler).getProducerNode());
401     }
402
403     public void finishSection() {
404     }
405
406     public String getDefaultVerb() {
407       return defaultVerb;
408     }
409
410     public Map getVerbs() {
411       return verbs;
412     }
413   }
414
415   public class EmptySectionHandler extends SectionHandler {
416     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
417       throw new ProducerConfigExc("No tags are allowed here");
418     }
419
420     public void endElement(SectionHandler aHandler) {
421     }
422
423   }
424
425   public class MultiProducerNodeSectionHandler extends SectionHandler {
426     private Map nodeParameters;
427     private Set validNodeParameters;
428     private String currentNodeParameter;
429     private String scriptedNodeName;
430     private Set allowedNodeParameterReferences;
431
432     public MultiProducerNodeSectionHandler(String aScriptedNodeName, Set anAllowedNodeParameterReferences, Set aValidNodeParameters) {
433       allowedNodeParameterReferences = anAllowedNodeParameterReferences;
434       scriptedNodeName = aScriptedNodeName;
435       validNodeParameters = aValidNodeParameters;
436       nodeParameters = new HashMap();
437     }
438     public MultiProducerNodeSectionHandler(Set aValidNodeParameters) {
439       this("", new HashSet(), aValidNodeParameters);
440     }
441
442     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
443       if (!validNodeParameters.contains(aTag))
444         throw new ProducerConfigExc("Invalid node parameter: '" + aTag + "'");
445       else if (nodeParameters.containsKey(aTag))
446         throw new ProducerConfigExc("Node parameter: '" + aTag + "' already specified");
447       else if (anAttributes.size()>0)
448         throw new ProducerConfigExc("No parameters are allowed here");
449
450       currentNodeParameter = aTag;
451
452       return new ProducerNodeSectionHandler(scriptedNodeName, validNodeParameters);
453     }
454
455     public void endElement(SectionHandler aHandler) throws ProducerConfigExc  {
456       if (aHandler instanceof ProducerNodeSectionHandler) {
457         nodeParameters.put(currentNodeParameter, ((ProducerNodeSectionHandler) aHandler).getProducerNode());
458       }
459       else {
460         throw new ProducerConfigExc("Internal error: unknown section handler '" + aHandler.getClass().getName() + "'" );
461       }
462     }
463
464     public Map getNodeParameters() {
465       return nodeParameters;
466     }
467   }
468
469   public class ProducerNodeSectionHandler extends SectionHandler {
470     private CompositeProducerNode producerNode;
471     private ProducerNodeBuilder currentBuilder;
472     private String scriptedNodeName;
473     private Set allowedNodeParameterReferences;
474
475     public ProducerNodeSectionHandler(String aScriptedNodeName, Set anAllowedNodeParameterReferences) {
476       producerNode = new CompositeProducerNode();
477       scriptedNodeName = aScriptedNodeName;
478       allowedNodeParameterReferences = anAllowedNodeParameterReferences;
479     }
480
481     public ProducerNodeSectionHandler() {
482       this("", new HashSet());
483     }
484
485     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
486       if (allowedNodeParameterReferences.contains((aTag))) {
487         if (!anAttributes.isEmpty()) {
488           throw new ProducerConfigExc( "No attributes allowed" );
489         }
490
491         currentBuilder = new DefaultProducerNodeBuilders.ScriptedProducerParameterNodeBuilder(scriptedNodeName, aTag);
492 //        producerNode.addSubNode(
493 //        new ScriptedProducerNodeDefinition.NodeParameterProducerNode(scriptedNodeName, aTag));
494         return new EmptySectionHandler();
495       }
496       else if (scriptedNodeBuilderLibrary.hasBuilderForName(aTag) || builderLibrary.hasBuilderForName((aTag))) {
497
498         if (scriptedNodeBuilderLibrary.hasBuilderForName(aTag))
499           currentBuilder = scriptedNodeBuilderLibrary.constructBuilder(aTag);
500         else
501           currentBuilder = builderLibrary.constructBuilder(aTag);
502
503         currentBuilder.setAttributes(anAttributes);
504         if (currentBuilder.getAvailableSubNodes().isEmpty())  {
505           return new EmptySectionHandler();
506         }
507         if (currentBuilder.getAvailableSubNodes().size()>1)
508           return new MultiProducerNodeSectionHandler(scriptedNodeName, allowedNodeParameterReferences, currentBuilder.getAvailableSubNodes());
509         else if (currentBuilder.getAvailableSubNodes().size()<1)
510           return new EmptySectionHandler();
511         else {
512           return new ProducerNodeSectionHandler(scriptedNodeName, allowedNodeParameterReferences);
513         }
514       }
515       else
516         throw new ProducerConfigExc("Unknown producer node tag: '" + aTag + "'");
517     }
518
519     public void endElement(SectionHandler aHandler) throws ProducerConfigExc  {
520       if (aHandler instanceof ProducerNodeSectionHandler) {
521         currentBuilder.setSubNode((String) (currentBuilder.getAvailableSubNodes().iterator().next()),
522                     ((ProducerNodeSectionHandler) aHandler).getProducerNode());
523       }
524       else if (aHandler instanceof MultiProducerNodeSectionHandler) {
525         Iterator i;
526         Map nodeParameters;
527         Map.Entry entry;
528
529         nodeParameters = ((MultiProducerNodeSectionHandler) aHandler).getNodeParameters();
530         i = nodeParameters.entrySet().iterator();
531         while (i.hasNext()) {
532           entry = (Map.Entry) i.next();
533           currentBuilder.setSubNode((String) entry.getKey(), (ProducerNode) entry.getValue());
534         }
535       }
536       else if (aHandler instanceof EmptySectionHandler) {
537         // deliberately empty: nothing expected, so nothing to process
538       }
539       else {
540         throw new ProducerConfigExc("Internal error: unknown section handler '" + aHandler.getClass().getName() + "'" );
541       }
542
543       producerNode.addSubNode(currentBuilder.constructNode());
544       currentBuilder = null;
545     }
546
547     public ProducerNode getProducerNode() {
548       if (producerNode.getNrSubNodes()==1) {
549         return producerNode.getSubNode(0);
550       }
551       else {
552         return producerNode;
553       }
554     }
555   }
556
557   public class NodeDefinitionSectionHandler extends SectionHandler {
558     private ScriptedProducerNodeDefinition nodeDefinition;
559     private ProducerNode body;
560     private Map stringParameters;
561     private Map nodeParameters;
562     private String name;
563
564     public NodeDefinitionSectionHandler(String aName) {
565       body = null;
566       nodeParameters = null;
567       stringParameters = null;
568       name = aName;
569     }
570
571     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
572       if (aTag.equals("parameters")) {
573         if (!anAttributes.isEmpty()) {
574           throw new ProducerConfigExc( "No attributes allowed for tag 'parameters'" );
575         }
576         if (nodeParameters!=null) {
577           throw new ProducerConfigExc( "Parameters have already been declared" );
578         }
579         if (body!=null) {
580           throw new ProducerConfigExc( "Parameters should come before definition" );
581         }
582
583         return new NodeDefinitionParametersSectionHandler();
584       }
585       else if (aTag.equals("definition")) {
586         return new ProducerNodeSectionHandler(name, nodeParameters.keySet());
587       }
588       else throw new ProducerConfigExc("Only 'definition' or 'parameters' tags allowed here, '" + aTag + "' encountered.");
589     }
590
591     public void endElement(SectionHandler aHandler) {
592       if (aHandler instanceof NodeDefinitionParametersSectionHandler) {
593         stringParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getStringParameters();
594         nodeParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getNodeParameters();
595       }
596       else if (aHandler instanceof ProducerNodeSectionHandler) {
597         body = ((ProducerNodeSectionHandler) aHandler).getProducerNode();
598       }
599     }
600
601     public void finishSection() throws ProducerConfigExc {
602       Iterator i;
603       if (body == null)
604         throw new ProducerConfigExc( "Definition missing" );
605
606       nodeDefinition = new ScriptedProducerNodeDefinition(name);
607
608       nodeDefinition.setBody(body);
609
610       i = nodeParameters.keySet().iterator();
611       while (i.hasNext()) {
612         nodeDefinition.addNodeParameter((String) i.next());
613       }
614
615       i = stringParameters.entrySet().iterator();
616       while (i.hasNext()) {
617         Map.Entry entry = (Map.Entry) i.next();
618         nodeDefinition.addParameter((String) entry.getKey(), (String) entry.getValue());
619       }
620     }
621
622     public ScriptedProducerNodeDefinition getDefinition() {
623       return nodeDefinition;
624     }
625   }
626
627   private final static String   NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE = "name";
628   private final static String   NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE = "defaultvalue";
629   private final static String[] NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES = { NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE };
630   private final static String[] NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES = { NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE };
631   private final static String[] NODE_DEFINITION_NODE_PARAMETER_OPTIONAL_ATTRIBUTES = { };
632
633   public class NodeDefinitionParametersSectionHandler extends SectionHandler {
634     private Map nodeParameters;
635     private Map stringParameters;
636
637     public NodeDefinitionParametersSectionHandler() {
638       nodeParameters = new HashMap();
639       stringParameters = new HashMap();
640     }
641
642     public SectionHandler startElement(String aTag, Map anAttributes) throws ProducerConfigExc {
643       String parameterName;
644       String defaultValue;
645
646       if (aTag.equals("node")) {
647         ReaderTool.checkAttributes(anAttributes, NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES, NODE_DEFINITION_NODE_PARAMETER_OPTIONAL_ATTRIBUTES);
648         parameterName = (String) anAttributes.get( NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE );
649
650         if (nodeParameters.containsKey(parameterName))
651           throw new ProducerConfigExc("Duplicate parameter name: '" + parameterName + "'");
652
653         ReaderTool.checkValidIdentifier( parameterName );
654
655         nodeParameters.put(parameterName, parameterName);
656
657         return new EmptySectionHandler();
658       }
659       else if (aTag.equals("string")) {
660         ReaderTool.checkAttributes(anAttributes, NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES, NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES);
661         parameterName = (String) anAttributes.get( NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE );
662
663         if (stringParameters.containsKey(parameterName))
664           throw new ProducerConfigExc("Duplicate parameter name: '" + parameterName + "'");
665
666         ReaderTool.checkValidIdentifier( parameterName );
667
668         defaultValue = (String) anAttributes.get( NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE );
669
670         stringParameters.put(parameterName, defaultValue);
671
672         return new EmptySectionHandler();
673       }
674       else throw new ProducerConfigExc("Only 'string' and 'node' tags allowed here, '" + aTag + "' encountered.");
675
676     }
677
678     public void endElement(SectionHandler aHandler) {
679     }
680
681     public void finishSection() {
682     }
683
684     public Map getNodeParameters() {
685       return nodeParameters;
686     }
687
688     public Map getStringParameters() {
689       return stringParameters;
690     }
691   }
692 }
693
694
695 /*
696  /                 (expecting producers)
697  producers/        (expecting nodedefinition, producer)
698    nodedefinition  (expecting parameters, definition)
699      parameters    (expecting parameter declarations)
700      definition    (expecting nodes, subnodes)
701 */
702