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