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