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