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