reintroduced StringUtil.regexpReplace
[mir.git] / source / mir / producer / reader / ProducerConfigReader.java
index c168836..988bb38 100755 (executable)
-/*\r
- * Copyright (C) 2001, 2002  The Mir-coders group\r
- *\r
- * This file is part of Mir.\r
- *\r
- * Mir is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License as published by\r
- * the Free Software Foundation; either version 2 of the License, or\r
- * (at your option) any later version.\r
- *\r
- * Mir is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with Mir; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- *\r
- * In addition, as a special exception, The Mir-coders gives permission to link\r
- * the code of this program with the com.oreilly.servlet library, any library\r
- * licensed under the Apache Software License, The Sun (tm) Java Advanced\r
- * Imaging library (JAI), The Sun JIMI library (or with modified versions of\r
- * the above that use the same license as the above), and distribute linked\r
- * combinations including the two.  You must obey the GNU General Public\r
- * License in all respects for all of the code used other than the above\r
- * mentioned libraries.  If you modify this file, you may extend this exception\r
- * to your version of the file, but you are not obligated to do so.  If you do\r
- * not wish to do so, delete this exception statement from your version.\r
- */\r
-\r
-package  mir.producer.reader;\r
-\r
-import java.io.File;\r
-import java.io.FileInputStream;\r
-import java.io.FileNotFoundException;\r
-import java.io.IOException;\r
-import java.util.HashMap;\r
-import java.util.HashSet;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Set;\r
-import java.util.Stack;\r
-import java.util.Vector;\r
-\r
-import mir.producer.CompositeProducerNode;\r
-import mir.producer.ProducerFactory;\r
-import mir.producer.ProducerNode;\r
-import mir.producer.SimpleProducerVerb;\r
-\r
-import mir.util.*;\r
-\r
-public class ProducerConfigReader {\r
-  private ProducerNodeBuilderLibrary builderLibrary;\r
-  private ProducerNodeBuilderLibrary scriptedNodeBuilderLibrary;\r
-\r
-  public ProducerConfigReader() {\r
-    super();\r
-  };\r
-\r
-  public void parseFile(String aFileName, ProducerNodeBuilderLibrary aBuilderLibrary, List aProducerFactories) throws ProducerConfigFailure {\r
-    parseFile(aFileName, aBuilderLibrary, aProducerFactories, new Vector());\r
-  }\r
-\r
-  public void parseFile(String aFileName, ProducerNodeBuilderLibrary aBuilderLibrary, List aProducerFactories, List aUsedFiles) throws ProducerConfigFailure {\r
-    try {\r
-      XMLReader reader = new XMLReader();\r
-\r
-      builderLibrary = aBuilderLibrary;\r
-      scriptedNodeBuilderLibrary = new ProducerNodeBuilderLibrary();\r
-\r
-      reader.parseFile(aFileName, new RootSectionHandler(aProducerFactories), aUsedFiles);\r
-    }\r
-    catch (Throwable e) {\r
-      if ((e instanceof XMLReader.XMLReaderExc) && ((XMLReader.XMLReaderExc) e).getHasLocation()) {\r
-        XMLReader.XMLReaderExc f = (XMLReader.XMLReaderExc) e;\r
-        throw new ProducerConfigFailure("'" + f.getMessage()+"' in " + f.getFilename()+"(line " + f.getLineNr()+", column " + f.getColumnNr() + ")", e);\r
-      }\r
-      throw new ProducerConfigFailure( e );\r
-    }\r
-  }\r
-\r
-\r
-  public class RootSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private List producers;\r
-\r
-    public RootSectionHandler(List aProducers) {\r
-      producers = aProducers;\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      if (aTag.equals("producers")) {\r
-        return new ProducersSectionHandler(producers);\r
-      }\r
-      else\r
-        throw new XMLReader.XMLReaderExc("Tag 'producers' expected, tag '"+aTag+"' found");\r
-    }\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) {\r
-    }\r
-\r
-    public void finishSection() {\r
-    }\r
-  }\r
-\r
-\r
-  private final static String   PRODUCER_NAME_ATTRIBUTE = "name";\r
-  private final static String[] PRODUCER_REQUIRED_ATTRIBUTES = { PRODUCER_NAME_ATTRIBUTE };\r
-  private final static String[] PRODUCER_OPTIONAL_ATTRIBUTES = { };\r
-\r
-  private final static String   NODE_DEFINITION_NAME_ATTRIBUTE = "name";\r
-  private final static String[] NODE_DEFINITION_REQUIRED_ATTRIBUTES = { NODE_DEFINITION_NAME_ATTRIBUTE };\r
-  private final static String[] NODE_DEFINITION_OPTIONAL_ATTRIBUTES = {  };\r
-\r
-  public class ProducersSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private List producers;\r
-    private Set producerNames;\r
-    private String name;\r
-\r
-    public ProducersSectionHandler(List aProducers) {\r
-      producers = aProducers;\r
-      producerNames = new HashSet();\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      if (aTag.equals("producer")) {\r
-        XMLReaderTool.checkAttributes(anAttributes,\r
-                                      PRODUCER_REQUIRED_ATTRIBUTES,\r
-                                      PRODUCER_OPTIONAL_ATTRIBUTES);\r
-\r
-        name = (String) anAttributes.get(PRODUCER_NAME_ATTRIBUTE);\r
-        XMLReaderTool.checkValidIdentifier(name);\r
-\r
-        if (producerNames.contains(name))\r
-          throw new XMLReader.XMLReaderExc("Duplicate producer name: '" +\r
-                                           name + "'");\r
-\r
-        name = (String) anAttributes.get(PRODUCER_NAME_ATTRIBUTE);\r
-\r
-        return new ProducerSectionHandler(name);\r
-      }\r
-      else if (aTag.equals("nodedefinition")) {\r
-        XMLReaderTool.checkAttributes(anAttributes,\r
-                                      NODE_DEFINITION_REQUIRED_ATTRIBUTES,\r
-                                      NODE_DEFINITION_OPTIONAL_ATTRIBUTES);\r
-\r
-        name = (String) anAttributes.get(NODE_DEFINITION_NAME_ATTRIBUTE);\r
-        XMLReaderTool.checkValidIdentifier(name);\r
-\r
-        name = (String) anAttributes.get(NODE_DEFINITION_NAME_ATTRIBUTE);\r
-\r
-        return new NodeDefinitionSectionHandler(name);\r
-      }\r
-      throw new XMLReader.XMLReaderExc("Unexpected tag: " + aTag);\r
-    }\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-      if (aHandler instanceof ProducerSectionHandler) {\r
-        producers.add(((ProducerSectionHandler) aHandler).getProducerFactory());\r
-        producerNames.add(((ProducerSectionHandler) aHandler).getProducerFactory().getName());\r
-      }\r
-      else if (aHandler instanceof NodeDefinitionSectionHandler) {\r
-        scriptedNodeBuilderLibrary.registerFactory(name,\r
-            new DefaultProducerNodeBuilders.ScriptedProducerNodeBuilder.factory(\r
-                ((NodeDefinitionSectionHandler) aHandler).getDefinition()));\r
-      }\r
-      else throw new XMLReader.XMLReaderExc("ProducersSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());\r
-    }\r
-\r
-    public void finishSection() {\r
-    }\r
-  }\r
-\r
-  public class ProducerSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private ProducerFactory producerFactory;\r
-    private String factoryName;\r
-\r
-    private ProducerNode body;\r
-    private Map verbNodes;\r
-    private List verbs;\r
-    private String defaultVerb;\r
-\r
-    public ProducerSectionHandler(String aName) {\r
-      factoryName = aName;\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      if (aTag.equals("verbs")) {\r
-        if (verbs!=null)\r
-          throw new XMLReader.XMLReaderExc("Verbs already processed");\r
-        if (body!=null)\r
-          throw new XMLReader.XMLReaderExc("Verbs should come before body");\r
-        else\r
-          return new ProducerVerbsSectionHandler();\r
-      }\r
-      else if (aTag.equals("body")) {\r
-        if (body==null)\r
-          return new ProducerNodeSectionHandler();\r
-        else\r
-          throw new XMLReader.XMLReaderExc("Body already processed");\r
-      }\r
-      throw new XMLReader.XMLReaderExc("Unexpected tag: '"+aTag+"'");\r
-    }\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
-      if (aHandler instanceof ProducerNodeSectionHandler) {\r
-        body = ((ProducerNodeSectionHandler) aHandler).getProducerNode();\r
-      }\r
-      else if (aHandler instanceof ProducerVerbsSectionHandler)\r
-      {\r
-        verbs = ((ProducerVerbsSectionHandler) aHandler).getVerbs();\r
-        verbNodes = ((ProducerVerbsSectionHandler) aHandler).getVerbNodes();\r
-        defaultVerb = ((ProducerVerbsSectionHandler) aHandler).getDefaultVerb();\r
-      }\r
-      else throw new XMLReader.XMLReaderExc("ProducerSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());\r
-    }\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-      if (verbs==null)\r
-        throw new XMLReader.XMLReaderExc("No verbs defined");\r
-\r
-      if (body==null)\r
-        throw new XMLReader.XMLReaderExc("No body defined");\r
-\r
-      producerFactory = new ScriptedProducerFactory(factoryName, verbs, verbNodes, body, defaultVerb);\r
-    }\r
-\r
-    public ProducerFactory getProducerFactory() {\r
-      return producerFactory;\r
-    }\r
-  }\r
-\r
-  private final static String   PRODUCER_VERB_NAME_ATTRIBUTE = "name";\r
-  private final static String   PRODUCER_VERB_DESCRIPTION_ATTRIBUTE = "description";\r
-  private final static String   PRODUCER_VERB_DEFAULT_ATTRIBUTE = "default";\r
-  private final static String[] PRODUCER_VERB_REQUIRED_ATTRIBUTES = { PRODUCER_VERB_NAME_ATTRIBUTE };\r
-  private final static String[] PRODUCER_VERB_OPTIONAL_ATTRIBUTES = { PRODUCER_VERB_DEFAULT_ATTRIBUTE, PRODUCER_VERB_DESCRIPTION_ATTRIBUTE };\r
-\r
-  public class ProducerVerbsSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private Map verbNodes;\r
-    private List verbs;\r
-    private String defaultVerb;\r
-    private String currentVerb;\r
-    private String currentVerbDescription;\r
-\r
-    public ProducerVerbsSectionHandler() {\r
-      verbNodes = new HashMap();\r
-      verbs = new Vector();\r
-      defaultVerb = null;\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      if (aTag.equals("verb")) {\r
-        XMLReaderTool.checkAttributes(anAttributes,\r
-                                      PRODUCER_VERB_REQUIRED_ATTRIBUTES,\r
-                                      PRODUCER_VERB_OPTIONAL_ATTRIBUTES);\r
-        currentVerb = (String) anAttributes.get(PRODUCER_VERB_NAME_ATTRIBUTE);\r
-\r
-        XMLReaderTool.checkValidIdentifier(currentVerb);\r
-\r
-        if (verbNodes.containsKey(currentVerb))\r
-          throw new XMLReader.XMLReaderExc("Duplicate definition of verb '" +\r
-                                           currentVerb + "'");\r
-\r
-        if (anAttributes.containsKey(PRODUCER_VERB_DEFAULT_ATTRIBUTE)) {\r
-          if (defaultVerb != null)\r
-            throw new XMLReader.XMLReaderExc("Default verb already declared");\r
-\r
-          defaultVerb = currentVerb;\r
-        }\r
-\r
-        if (anAttributes.containsKey(PRODUCER_VERB_DESCRIPTION_ATTRIBUTE))\r
-          currentVerbDescription = (String) anAttributes.get(\r
-              PRODUCER_VERB_DESCRIPTION_ATTRIBUTE);\r
-        else\r
-          currentVerbDescription = "";\r
-\r
-        return new ProducerNodeSectionHandler();\r
-      }\r
-      else\r
-        throw new XMLReader.XMLReaderExc("Only 'verb' tags allowed here, '" +\r
-                                         aTag + "' encountered.");\r
-    }\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) {\r
-      verbNodes.put(currentVerb, ((ProducerNodeSectionHandler) aHandler).getProducerNode());\r
-      verbs.add(new SimpleProducerVerb(currentVerb, currentVerbDescription));\r
-    }\r
-\r
-    public void finishSection() {\r
-    }\r
-\r
-    public String getDefaultVerb() {\r
-      return defaultVerb;\r
-    }\r
-\r
-    public List getVerbs() {\r
-      return verbs;\r
-    }\r
-\r
-    public Map getVerbNodes() {\r
-      return verbNodes;\r
-    }\r
-  }\r
-\r
-  public class EmptySectionHandler extends XMLReader.AbstractSectionHandler {\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      throw new XMLReader.XMLReaderExc("No tags are allowed here");\r
-    }\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) {\r
-    }\r
-\r
-    public void finishSection() {\r
-    }\r
-  }\r
-\r
-  public class MultiProducerNodeSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private Map nodeParameters;\r
-    private Set validNodeParameters;\r
-    private String currentNodeParameter;\r
-    private String scriptedNodeName;\r
-    private Set allowedNodeParameterReferences;\r
-\r
-    public MultiProducerNodeSectionHandler(String aScriptedNodeName, Set anAllowedNodeParameterReferences, Set aValidNodeParameters) {\r
-      allowedNodeParameterReferences = anAllowedNodeParameterReferences;\r
-      scriptedNodeName = aScriptedNodeName;\r
-      validNodeParameters = aValidNodeParameters;\r
-      nodeParameters = new HashMap();\r
-    }\r
-    public MultiProducerNodeSectionHandler(Set aValidNodeParameters) {\r
-      this("", new HashSet(), aValidNodeParameters);\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      if (!validNodeParameters.contains(aTag))\r
-        throw new XMLReader.XMLReaderExc("Invalid node parameter: '" + aTag + "'");\r
-      else if (nodeParameters.containsKey(aTag))\r
-        throw new XMLReader.XMLReaderExc("Node parameter: '" + aTag + "' already specified");\r
-      else if (anAttributes.size()>0)\r
-        throw new XMLReader.XMLReaderExc("No parameters are allowed here");\r
-\r
-      currentNodeParameter = aTag;\r
-\r
-      return new ProducerNodeSectionHandler(scriptedNodeName, validNodeParameters);\r
-    }\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc  {\r
-      if (aHandler instanceof ProducerNodeSectionHandler) {\r
-        nodeParameters.put(currentNodeParameter, ((ProducerNodeSectionHandler) aHandler).getProducerNode());\r
-      }\r
-      else {\r
-        throw new XMLReader.XMLReaderExc("Internal error: unknown section handler '" + aHandler.getClass().getName() + "'" );\r
-      }\r
-    }\r
-\r
-    public Map getNodeParameters() {\r
-      return nodeParameters;\r
-    }\r
-\r
-    public void finishSection() {\r
-    }\r
-  }\r
-\r
-  public class ProducerNodeSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private CompositeProducerNode producerNode;\r
-    private ProducerNodeBuilder currentBuilder;\r
-    private String scriptedNodeName;\r
-    private Set allowedNodeParameterReferences;\r
-\r
-    public ProducerNodeSectionHandler(String aScriptedNodeName, Set anAllowedNodeParameterReferences) {\r
-      producerNode = new CompositeProducerNode();\r
-      scriptedNodeName = aScriptedNodeName;\r
-      allowedNodeParameterReferences = anAllowedNodeParameterReferences;\r
-    }\r
-\r
-    public ProducerNodeSectionHandler() {\r
-      this("", new HashSet());\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      try {\r
-        if (allowedNodeParameterReferences.contains( (aTag))) {\r
-          if (!anAttributes.isEmpty()) {\r
-            throw new XMLReader.XMLReaderExc("No attributes allowed");\r
-          }\r
-\r
-          currentBuilder = new DefaultProducerNodeBuilders.\r
-              ScriptedProducerParameterNodeBuilder(scriptedNodeName, aTag);\r
-          return new EmptySectionHandler();\r
-        }\r
-        else if (scriptedNodeBuilderLibrary.hasBuilderForName(aTag) ||\r
-                 builderLibrary.hasBuilderForName( (aTag))) {\r
-\r
-          if (scriptedNodeBuilderLibrary.hasBuilderForName(aTag))\r
-            currentBuilder = scriptedNodeBuilderLibrary.constructBuilder(aTag);\r
-          else\r
-            currentBuilder = builderLibrary.constructBuilder(aTag);\r
-\r
-          currentBuilder.setAttributes(anAttributes);\r
-          if (currentBuilder.getAvailableSubNodes().isEmpty()) {\r
-            return new EmptySectionHandler();\r
-          }\r
-          if (currentBuilder.getAvailableSubNodes().size() > 1)\r
-            return new MultiProducerNodeSectionHandler(scriptedNodeName,\r
-                allowedNodeParameterReferences,\r
-                currentBuilder.getAvailableSubNodes());\r
-          else if (currentBuilder.getAvailableSubNodes().size() < 1)\r
-            return new EmptySectionHandler();\r
-          else {\r
-            return new ProducerNodeSectionHandler(scriptedNodeName,\r
-                allowedNodeParameterReferences);\r
-          }\r
-        }\r
-        else\r
-          throw new XMLReader.XMLReaderExc("Unknown producer node tag: '" +\r
-                                           aTag + "'");\r
-      }\r
-      catch (Throwable t) {\r
-        throw new XMLReader.XMLReaderFailure(t);\r
-      }\r
-    }\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc  {\r
-      try {\r
-        if (aHandler instanceof ProducerNodeSectionHandler) {\r
-          currentBuilder.setSubNode(\r
-                (String) (currentBuilder.getAvailableSubNodes().iterator().next()),\r
-                ((ProducerNodeSectionHandler) aHandler).getProducerNode());\r
-        }\r
-        else if (aHandler instanceof MultiProducerNodeSectionHandler) {\r
-          Iterator i;\r
-          Map nodeParameters;\r
-          Map.Entry entry;\r
-\r
-          nodeParameters = ( (MultiProducerNodeSectionHandler) aHandler).\r
-              getNodeParameters();\r
-          i = nodeParameters.entrySet().iterator();\r
-          while (i.hasNext()) {\r
-            entry = (Map.Entry) i.next();\r
-            currentBuilder.setSubNode( (String) entry.getKey(),\r
-                                      (ProducerNode) entry.getValue());\r
-          }\r
-        }\r
-        else if (aHandler instanceof EmptySectionHandler) {\r
-          // deliberately empty: nothing expected, so nothing to process\r
-        }\r
-        else {\r
-          throw new XMLReader.XMLReaderExc(\r
-              "Internal error: unknown section handler '" +\r
-              aHandler.getClass().getName() + "'");\r
-        }\r
-\r
-        producerNode.addSubNode(currentBuilder.constructNode());\r
-        currentBuilder = null;\r
-      }\r
-      catch (Throwable t) {\r
-        throw new XMLReader.XMLReaderFailure(t);\r
-      }\r
-    }\r
-\r
-    public ProducerNode getProducerNode() {\r
-      if (producerNode.getNrSubNodes()==1) {\r
-        return producerNode.getSubNode(0);\r
-      }\r
-      else {\r
-        return producerNode;\r
-      }\r
-    }\r
-\r
-    public void finishSection() {\r
-    }\r
-  }\r
-\r
-  public class NodeDefinitionSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private ScriptedProducerNodeDefinition nodeDefinition;\r
-    private ProducerNode body;\r
-    private Map stringParameters;\r
-    private Map integerParameters;\r
-    private Map nodeParameters;\r
-    private String name;\r
-\r
-    public NodeDefinitionSectionHandler(String aName) {\r
-      body = null;\r
-      nodeParameters = null;\r
-      stringParameters = null;\r
-      integerParameters = null;\r
-      name = aName;\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      if (aTag.equals("parameters")) {\r
-        if (!anAttributes.isEmpty()) {\r
-          throw new XMLReader.XMLReaderExc( "No attributes allowed for tag 'parameters'" );\r
-        }\r
-        if (nodeParameters!=null) {\r
-          throw new XMLReader.XMLReaderExc( "Parameters have already been declared" );\r
-        }\r
-        if (body!=null) {\r
-          throw new XMLReader.XMLReaderExc( "Parameters should come before definition in nodedefinition '" + name +"'" );\r
-        }\r
-\r
-        return new NodeDefinitionParametersSectionHandler();\r
-      }\r
-      else if (aTag.equals("definition")) {\r
-        if (nodeParameters==null)\r
-          throw new XMLReader.XMLReaderExc( "Parameters should come before definition in nodedefinition '" + name +"'"  );\r
-\r
-        return new ProducerNodeSectionHandler(name, nodeParameters.keySet());\r
-      }\r
-      else throw new XMLReader.XMLReaderExc("Only 'definition' or 'parameters' tags allowed here, '" + aTag + "' encountered.");\r
-    }\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) {\r
-      if (aHandler instanceof NodeDefinitionParametersSectionHandler) {\r
-        stringParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getStringParameters();\r
-        integerParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getIntegerParameters();\r
-        nodeParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getNodeParameters();\r
-      }\r
-      else if (aHandler instanceof ProducerNodeSectionHandler) {\r
-        body = ((ProducerNodeSectionHandler) aHandler).getProducerNode();\r
-      }\r
-    }\r
-\r
-    public void finishSection() throws XMLReader.XMLReaderExc {\r
-      Iterator i;\r
-      if (body == null)\r
-        throw new XMLReader.XMLReaderExc( "Definition missing" );\r
-\r
-      nodeDefinition = new ScriptedProducerNodeDefinition(name);\r
-\r
-      nodeDefinition.setBody(body);\r
-\r
-      i = nodeParameters.keySet().iterator();\r
-      while (i.hasNext()) {\r
-        nodeDefinition.addNodeParameter((String) i.next());\r
-      }\r
-\r
-      i = stringParameters.entrySet().iterator();\r
-      while (i.hasNext()) {\r
-        Map.Entry entry = (Map.Entry) i.next();\r
-        nodeDefinition.addStringParameter((String) entry.getKey(), (String) entry.getValue());\r
-      }\r
-\r
-      i = integerParameters.entrySet().iterator();\r
-      while (i.hasNext()) {\r
-        Map.Entry entry = (Map.Entry) i.next();\r
-        nodeDefinition.addIntegerParameter((String) entry.getKey(), (String) entry.getValue());\r
-      }\r
-    }\r
-\r
-    public ScriptedProducerNodeDefinition getDefinition() {\r
-      return nodeDefinition;\r
-    }\r
-  }\r
-\r
-  private final static String   NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE = "name";\r
-  private final static String   NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE = "defaultvalue";\r
-  private final static String[] NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES = { NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE };\r
-  private final static String[] NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES = { NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE };\r
-  private final static String[] NODE_DEFINITION_NODE_PARAMETER_OPTIONAL_ATTRIBUTES = { };\r
-\r
-  public class NodeDefinitionParametersSectionHandler extends XMLReader.AbstractSectionHandler {\r
-    private Map nodeParameters;\r
-    private Map stringParameters;\r
-    private Map integerParameters;\r
-\r
-    public NodeDefinitionParametersSectionHandler() {\r
-      nodeParameters = new HashMap();\r
-      stringParameters = new HashMap();\r
-      integerParameters = new HashMap();\r
-    }\r
-\r
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
-      String parameterName;\r
-      String defaultValue;\r
-\r
-      if (aTag.equals("node")) {\r
-        XMLReaderTool.checkAttributes(anAttributes,\r
-            NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES,\r
-            NODE_DEFINITION_NODE_PARAMETER_OPTIONAL_ATTRIBUTES);\r
-        parameterName = (String) anAttributes.get(\r
-            NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE);\r
-\r
-        if (nodeParameters.containsKey(parameterName))\r
-          throw new XMLReader.XMLReaderExc("Duplicate parameter name: '" +\r
-                                           parameterName + "'");\r
-\r
-        XMLReaderTool.checkValidIdentifier(parameterName);\r
-\r
-        nodeParameters.put(parameterName, parameterName);\r
-\r
-        return new EmptySectionHandler();\r
-      }\r
-      else if (aTag.equals("string") || aTag.equals("integer")) {\r
-        XMLReaderTool.checkAttributes(anAttributes,\r
-            NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES,\r
-            NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES);\r
-        parameterName = (String) anAttributes.get(\r
-            NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE);\r
-\r
-        if (stringParameters.containsKey(parameterName) ||\r
-            integerParameters.containsKey(parameterName))\r
-          throw new XMLReader.XMLReaderExc("Duplicate parameter name: '" +\r
-                                           parameterName + "'");\r
-\r
-        XMLReaderTool.checkValidIdentifier(parameterName);\r
-\r
-        defaultValue = (String) anAttributes.get(\r
-            NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE);\r
-\r
-        if (aTag.equals("string"))\r
-          stringParameters.put(parameterName, defaultValue);\r
-        else\r
-          integerParameters.put(parameterName, defaultValue);\r
-\r
-        return new EmptySectionHandler();\r
-      }\r
-      else\r
-        throw new XMLReader.XMLReaderExc(\r
-            "Only 'string', 'integer' and 'node' tags allowed here, '" + aTag + "' encountered.");\r
-    }\r
-\r
-    public void endElement(XMLReader.SectionHandler aHandler) {\r
-    }\r
-\r
-    public void finishSection() {\r
-    }\r
-\r
-    public Map getNodeParameters() {\r
-      return nodeParameters;\r
-    }\r
-\r
-    public Map getStringParameters() {\r
-      return stringParameters;\r
-    }\r
-\r
-    public Map getIntegerParameters() {\r
-      return integerParameters;\r
-    }\r
-  }\r
-}\r
+/*
+ * Copyright (C) 2001-2006 The Mir-coders group
+ *
+ * This file is part of Mir.
+ *
+ * Mir is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Mir is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mir; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * In addition, as a special exception, The Mir-coders gives permission to link
+ * the code of this program with  any library licensed under the Apache Software License,
+ * and distribute linked combinations including the two.  You must obey the
+ * GNU General Public License in all respects for all of the code used other than
+ * the above mentioned libraries.  If you modify this file, you may extend this
+ * exception to your version of the file, but you are not obligated to do so.
+ * If you do not wish to do so, delete this exception statement from your version.
+ */
+package  mir.producer.reader;
+
+import mir.producer.CompositeProducerNode;
+import mir.producer.ProducerFactory;
+import mir.producer.ProducerNode;
+import mir.producer.SimpleProducerVerb;
+import mir.util.ExceptionRoutines;
+import mir.util.xml.XMLParserEngine;
+import mir.util.xml.XMLParserExc;
+import mir.util.xml.XMLParserFailure;
+
+import java.io.File;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ProducerConfigReader {
+  private ProducerNodeBuilderLibrary builderLibrary;
+  private ProducerNodeBuilderLibrary scriptedNodeBuilderLibrary;
+
+  public ProducerConfigReader() {
+    super();
+  }
+
+  public void parse(Reader aReader, ProducerNodeBuilderLibrary aBuilderLibrary, List aProducerFactories) throws ProducerConfigFailure {
+    try {
+      builderLibrary = aBuilderLibrary;
+      scriptedNodeBuilderLibrary = new ProducerNodeBuilderLibrary();
+
+      XMLParserEngine.getInstance().parse("", aReader, new RootSectionHandler(aProducerFactories));
+
+    }
+    catch (Throwable e) {
+      Throwable root = ExceptionRoutines.traceCauseException(e);
+
+      if ((root instanceof XMLParserExc) && ((XMLParserExc) root).getHasLocation()) {
+        XMLParserExc f = (XMLParserExc) root;
+        throw new ProducerConfigFailure(f.getMessage()+" on line " + f.getLineNr()+", column " + f.getColumnNr(), e);
+      }
+      throw new ProducerConfigFailure(root);
+    }
+  }
+  public void parse(File aFile, ProducerNodeBuilderLibrary aBuilderLibrary, List aProducerFactories) throws ProducerConfigFailure {
+    try {
+      builderLibrary = aBuilderLibrary;
+      scriptedNodeBuilderLibrary = new ProducerNodeBuilderLibrary();
+
+      XMLParserEngine.getInstance().parse("", aFile, new RootSectionHandler(aProducerFactories));
+
+    }
+    catch (Throwable e) {
+      Throwable root = ExceptionRoutines.traceCauseException(e);
+
+      if ((root instanceof XMLParserExc) && ((XMLParserExc) root).getHasLocation()) {
+        XMLParserExc f = (XMLParserExc) root;
+        throw new ProducerConfigFailure(f.getMessage()+" on line " + f.getLineNr()+", column " + f.getColumnNr(), e);
+      }
+      throw new ProducerConfigFailure(root);
+    }
+  }
+
+  public class RootSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private List producers;
+
+    public RootSectionHandler(List aProducers) {
+      producers = aProducers;
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      if (aTag.equals("producers")) {
+        return new ProducersSectionHandler(producers);
+      }
+                       throw new XMLParserExc("Tag 'producers' expected, tag '"+aTag+"' found");
+    }
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) {
+    }
+
+    public void finishSection() {
+    }
+  }
+
+  private final static String   PRODUCER_NAME_ATTRIBUTE = "name";
+  private final static String[] PRODUCER_REQUIRED_ATTRIBUTES = { PRODUCER_NAME_ATTRIBUTE };
+  private final static String[] PRODUCER_OPTIONAL_ATTRIBUTES = { };
+
+  private final static String   NODE_DEFINITION_NAME_ATTRIBUTE = "name";
+  private final static String[] NODE_DEFINITION_REQUIRED_ATTRIBUTES = { NODE_DEFINITION_NAME_ATTRIBUTE };
+  private final static String[] NODE_DEFINITION_OPTIONAL_ATTRIBUTES = {  };
+
+  public class ProducersSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private List producers;
+    private Set producerNames;
+    private String name;
+
+    public ProducersSectionHandler(List aProducers) {
+      producers = aProducers;
+      producerNames = new HashSet();
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      if (aTag.equals("producer")) {
+        mir.util.xml.XMLReaderTool.checkAttributes(anAttributes,
+                                      PRODUCER_REQUIRED_ATTRIBUTES,
+                                      PRODUCER_OPTIONAL_ATTRIBUTES);
+
+        name = (String) anAttributes.get(PRODUCER_NAME_ATTRIBUTE);
+        mir.util.xml.XMLReaderTool.checkValidIdentifier(name);
+
+        if (producerNames.contains(name))
+          throw new XMLParserExc("Duplicate producer name: '" +
+                                           name + "'");
+
+        name = (String) anAttributes.get(PRODUCER_NAME_ATTRIBUTE);
+
+        return new ProducerSectionHandler(name);
+      }
+      else if (aTag.equals("nodedefinition")) {
+        mir.util.xml.XMLReaderTool.checkAttributes(anAttributes,
+                                      NODE_DEFINITION_REQUIRED_ATTRIBUTES,
+                                      NODE_DEFINITION_OPTIONAL_ATTRIBUTES);
+
+        name = (String) anAttributes.get(NODE_DEFINITION_NAME_ATTRIBUTE);
+        mir.util.xml.XMLReaderTool.checkValidIdentifier(name);
+
+        name = (String) anAttributes.get(NODE_DEFINITION_NAME_ATTRIBUTE);
+
+        return new NodeDefinitionSectionHandler(name);
+      }
+      throw new XMLParserExc("Unexpected tag: " + aTag);
+    }
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+      if (aHandler instanceof ProducerSectionHandler) {
+        producers.add(((ProducerSectionHandler) aHandler).getProducerFactory());
+        producerNames.add(((ProducerSectionHandler) aHandler).getProducerFactory().getName());
+      }
+      else if (aHandler instanceof NodeDefinitionSectionHandler) {
+        scriptedNodeBuilderLibrary.registerFactory(name,
+            new DefaultProducerNodeBuilders.ScriptedProducerNodeBuilder.factory(
+                ((NodeDefinitionSectionHandler) aHandler).getDefinition()));
+      }
+      else throw new XMLParserExc("ProducersSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
+    }
+
+    public void finishSection() {
+    }
+  }
+
+  public class ProducerSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private ProducerFactory producerFactory;
+    private String factoryName;
+
+    private ProducerNode body;
+    private Map verbNodes;
+    private List verbs;
+    private String defaultVerb;
+
+    public ProducerSectionHandler(String aName) {
+      factoryName = aName;
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      if (aTag.equals("verbs")) {
+        if (verbs!=null)
+          throw new XMLParserExc("Verbs already processed");
+        if (body!=null)
+          throw new XMLParserExc("Verbs should come before body");
+                               return new ProducerVerbsSectionHandler();
+      }
+      else if (aTag.equals("body")) {
+        if (body==null)
+          return new ProducerNodeSectionHandler();
+                               throw new XMLParserExc("Body already processed");
+      }
+      throw new XMLParserExc("Unexpected tag: '"+aTag+"'");
+    }
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+      if (aHandler instanceof ProducerNodeSectionHandler) {
+        body = ((ProducerNodeSectionHandler) aHandler).getProducerNode();
+      }
+      else if (aHandler instanceof ProducerVerbsSectionHandler)
+      {
+        verbs = ((ProducerVerbsSectionHandler) aHandler).getVerbs();
+        verbNodes = ((ProducerVerbsSectionHandler) aHandler).getVerbNodes();
+        defaultVerb = ((ProducerVerbsSectionHandler) aHandler).getDefaultVerb();
+      }
+      else throw new XMLParserExc("ProducerSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
+    }
+
+    public void finishSection() throws XMLParserExc {
+      if (verbs==null)
+        throw new XMLParserExc("No verbs defined");
+
+      if (body==null)
+        throw new XMLParserExc("No body defined");
+
+      producerFactory = new ScriptedProducerFactory(factoryName, verbs, verbNodes, body, defaultVerb);
+    }
+
+    public ProducerFactory getProducerFactory() {
+      return producerFactory;
+    }
+  }
+
+  private final static String   PRODUCER_VERB_NAME_ATTRIBUTE = "name";
+  private final static String   PRODUCER_VERB_DESCRIPTION_ATTRIBUTE = "description";
+  private final static String   PRODUCER_VERB_DEFAULT_ATTRIBUTE = "default";
+  private final static String[] PRODUCER_VERB_REQUIRED_ATTRIBUTES = { PRODUCER_VERB_NAME_ATTRIBUTE };
+  private final static String[] PRODUCER_VERB_OPTIONAL_ATTRIBUTES = { PRODUCER_VERB_DEFAULT_ATTRIBUTE, PRODUCER_VERB_DESCRIPTION_ATTRIBUTE };
+
+  public class ProducerVerbsSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private Map verbNodes;
+    private List verbs;
+    private String defaultVerb;
+    private String currentVerb;
+    private String currentVerbDescription;
+
+    public ProducerVerbsSectionHandler() {
+      verbNodes = new HashMap();
+      verbs = new ArrayList();
+      defaultVerb = null;
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      if (aTag.equals("verb")) {
+        mir.util.xml.XMLReaderTool.checkAttributes(anAttributes,
+                                      PRODUCER_VERB_REQUIRED_ATTRIBUTES,
+                                      PRODUCER_VERB_OPTIONAL_ATTRIBUTES);
+        currentVerb = (String) anAttributes.get(PRODUCER_VERB_NAME_ATTRIBUTE);
+
+        mir.util.xml.XMLReaderTool.checkValidIdentifier(currentVerb);
+
+        if (verbNodes.containsKey(currentVerb))
+          throw new XMLParserExc("Duplicate definition of verb '" +
+                                           currentVerb + "'");
+
+        if (anAttributes.containsKey(PRODUCER_VERB_DEFAULT_ATTRIBUTE)) {
+          if (defaultVerb != null)
+            throw new XMLParserExc("Default verb already declared");
+
+          defaultVerb = currentVerb;
+        }
+
+        if (anAttributes.containsKey(PRODUCER_VERB_DESCRIPTION_ATTRIBUTE))
+          currentVerbDescription = (String) anAttributes.get(
+              PRODUCER_VERB_DESCRIPTION_ATTRIBUTE);
+        else
+          currentVerbDescription = "";
+
+        return new ProducerNodeSectionHandler();
+      }
+                       throw new XMLParserExc("Only 'verb' tags allowed here, '" + aTag + "' encountered.");
+    }
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) {
+      verbNodes.put(currentVerb, ((ProducerNodeSectionHandler) aHandler).getProducerNode());
+      verbs.add(new SimpleProducerVerb(currentVerb, currentVerbDescription));
+    }
+
+    public void finishSection() {
+    }
+
+    public String getDefaultVerb() {
+      return defaultVerb;
+    }
+
+    public List getVerbs() {
+      return verbs;
+    }
+
+    public Map getVerbNodes() {
+      return verbNodes;
+    }
+  }
+
+  public class EmptySectionHandler extends mir.util.xml.AbstractSectionHandler {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      throw new XMLParserExc("No tags are allowed here");
+    }
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) {
+    }
+
+    public void finishSection() {
+    }
+  }
+
+  public class MultiProducerNodeSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private Map nodeParameters;
+    private Set validNodeParameters;
+    private String currentNodeParameter;
+    private String scriptedNodeName;
+    private Set allowedNodeParameterReferences;
+
+    public MultiProducerNodeSectionHandler(String aScriptedNodeName, Set anAllowedNodeParameterReferences, Set aValidNodeParameters) {
+      allowedNodeParameterReferences = anAllowedNodeParameterReferences;
+      scriptedNodeName = aScriptedNodeName;
+      validNodeParameters = aValidNodeParameters;
+      nodeParameters = new HashMap();
+    }
+    public MultiProducerNodeSectionHandler(Set aValidNodeParameters) {
+      this("", new HashSet(), aValidNodeParameters);
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      if (!validNodeParameters.contains(aTag))
+        throw new XMLParserExc("Invalid node parameter: '" + aTag + "'");
+      else if (nodeParameters.containsKey(aTag))
+        throw new XMLParserExc("Node parameter: '" + aTag + "' already specified");
+      else if (anAttributes.size()>0)
+        throw new XMLParserExc("No parameters are allowed here");
+
+      currentNodeParameter = aTag;
+
+      return new ProducerNodeSectionHandler(scriptedNodeName, allowedNodeParameterReferences);
+    }
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc  {
+      if (aHandler instanceof ProducerNodeSectionHandler) {
+        nodeParameters.put(currentNodeParameter, ((ProducerNodeSectionHandler) aHandler).getProducerNode());
+      }
+      else {
+        throw new XMLParserExc("Internal error: unknown section handler '" + aHandler.getClass().getName() + "'" );
+      }
+    }
+
+    public Map getNodeParameters() {
+      return nodeParameters;
+    }
+
+    public void finishSection() {
+    }
+  }
+
+  public class ProducerNodeSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private CompositeProducerNode producerNode;
+    private ProducerNodeBuilder currentBuilder;
+    private String scriptedNodeName;
+    private Set allowedNodeParameterReferences;
+
+    public ProducerNodeSectionHandler(String aScriptedNodeName, Set anAllowedNodeParameterReferences) {
+      producerNode = new CompositeProducerNode();
+      scriptedNodeName = aScriptedNodeName;
+      allowedNodeParameterReferences = anAllowedNodeParameterReferences;
+    }
+
+    public ProducerNodeSectionHandler() {
+      this("", new HashSet());
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      try {
+        if (allowedNodeParameterReferences.contains( (aTag))) {
+          if (!anAttributes.isEmpty()) {
+            throw new XMLParserExc("No attributes allowed");
+          }
+
+          currentBuilder = new DefaultProducerNodeBuilders.
+              ScriptedProducerParameterNodeBuilder(scriptedNodeName, aTag);
+          return new EmptySectionHandler();
+        }
+        else if (scriptedNodeBuilderLibrary.hasBuilderForName(aTag) ||
+                 builderLibrary.hasBuilderForName( (aTag))) {
+
+          if (scriptedNodeBuilderLibrary.hasBuilderForName(aTag))
+            currentBuilder = scriptedNodeBuilderLibrary.constructBuilder(aTag);
+          else
+            currentBuilder = builderLibrary.constructBuilder(aTag);
+
+          currentBuilder.setAttributes(anAttributes);
+          if (currentBuilder.getAvailableSubNodes().isEmpty()) {
+            return new EmptySectionHandler();
+          }
+          if (currentBuilder.getAvailableSubNodes().size() > 1)
+            return new MultiProducerNodeSectionHandler(scriptedNodeName,
+                allowedNodeParameterReferences,
+                currentBuilder.getAvailableSubNodes());
+          else if (currentBuilder.getAvailableSubNodes().size() < 1)
+            return new EmptySectionHandler();
+          else {
+            return new ProducerNodeSectionHandler(scriptedNodeName,
+                allowedNodeParameterReferences);
+          }
+        }
+        else
+          throw new XMLParserExc("Unknown producer node tag: '" + aTag + "'");
+      }
+      catch (Throwable t) {
+        throw new XMLParserFailure(t);
+      }
+    }
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc  {
+      try {
+        if (aHandler instanceof ProducerNodeSectionHandler) {
+          currentBuilder.setSubNode(
+                (String) (currentBuilder.getAvailableSubNodes().iterator().next()),
+                ((ProducerNodeSectionHandler) aHandler).getProducerNode());
+        }
+        else if (aHandler instanceof MultiProducerNodeSectionHandler) {
+          Iterator i;
+          Map nodeParameters;
+          Map.Entry entry;
+
+          nodeParameters = ( (MultiProducerNodeSectionHandler) aHandler).
+              getNodeParameters();
+          i = nodeParameters.entrySet().iterator();
+          while (i.hasNext()) {
+            entry = (Map.Entry) i.next();
+            currentBuilder.setSubNode( (String) entry.getKey(),
+                                      (ProducerNode) entry.getValue());
+          }
+        }
+        else if (aHandler instanceof EmptySectionHandler) {
+          // deliberately empty: nothing expected, so nothing to process
+        }
+        else {
+          throw new XMLParserExc(
+              "Internal error: unknown section handler '" +
+              aHandler.getClass().getName() + "'");
+        }
+
+        producerNode.addSubNode(currentBuilder.constructNode());
+        currentBuilder = null;
+      }
+      catch (Throwable t) {
+        throw new XMLParserFailure(t);
+      }
+    }
+
+    public ProducerNode getProducerNode() {
+      if (producerNode.getNrSubNodes()==1) {
+        return producerNode.getSubNode(0);
+      }
+                       return producerNode;
+    }
+
+    public void finishSection() {
+    }
+  }
+
+  public class NodeDefinitionSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private ScriptedProducerNodeDefinition nodeDefinition;
+    private ProducerNode body;
+    private Map stringParameters;
+    private Map integerParameters;
+    private Map nodeParameters;
+    private String name;
+
+    public NodeDefinitionSectionHandler(String aName) {
+      body = null;
+      nodeParameters = null;
+      stringParameters = null;
+      integerParameters = null;
+      name = aName;
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      if (aTag.equals("parameters")) {
+        if (!anAttributes.isEmpty()) {
+          throw new XMLParserExc( "No attributes allowed for tag 'parameters'" );
+        }
+        if (nodeParameters!=null) {
+          throw new XMLParserExc( "Parameters have already been declared" );
+        }
+        if (body!=null) {
+          throw new XMLParserExc( "Parameters should come before definition in nodedefinition '" + name +"'" );
+        }
+
+        return new NodeDefinitionParametersSectionHandler();
+      }
+      else if (aTag.equals("definition")) {
+        if (nodeParameters==null)
+          throw new XMLParserExc( "Parameters should come before definition in nodedefinition '" + name +"'"  );
+
+        return new ProducerNodeSectionHandler(name, nodeParameters.keySet());
+      }
+      else throw new XMLParserExc("Only 'definition' or 'parameters' tags allowed here, '" + aTag + "' encountered.");
+    }
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) {
+      if (aHandler instanceof NodeDefinitionParametersSectionHandler) {
+        stringParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getStringParameters();
+        integerParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getIntegerParameters();
+        nodeParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getNodeParameters();
+      }
+      else if (aHandler instanceof ProducerNodeSectionHandler) {
+        body = ((ProducerNodeSectionHandler) aHandler).getProducerNode();
+      }
+    }
+
+    public void finishSection() throws XMLParserExc {
+      Iterator i;
+      if (body == null)
+        throw new XMLParserExc( "Definition missing" );
+
+      nodeDefinition = new ScriptedProducerNodeDefinition(name);
+
+      nodeDefinition.setBody(body);
+
+      i = nodeParameters.keySet().iterator();
+      while (i.hasNext()) {
+        nodeDefinition.addNodeParameter((String) i.next());
+      }
+
+      i = stringParameters.entrySet().iterator();
+      while (i.hasNext()) {
+        Map.Entry entry = (Map.Entry) i.next();
+        nodeDefinition.addStringParameter((String) entry.getKey(), (String) entry.getValue());
+      }
+
+      i = integerParameters.entrySet().iterator();
+      while (i.hasNext()) {
+        Map.Entry entry = (Map.Entry) i.next();
+        nodeDefinition.addIntegerParameter((String) entry.getKey(), (String) entry.getValue());
+      }
+    }
+
+    public ScriptedProducerNodeDefinition getDefinition() {
+      return nodeDefinition;
+    }
+  }
+
+  private final static String   NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE = "name";
+  private final static String   NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE = "defaultvalue";
+  private final static String[] NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES = { NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE };
+  private final static String[] NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES = { NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE };
+  private final static String[] NODE_DEFINITION_NODE_PARAMETER_OPTIONAL_ATTRIBUTES = { };
+
+  public class NodeDefinitionParametersSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    private Map nodeParameters;
+    private Map stringParameters;
+    private Map integerParameters;
+
+    public NodeDefinitionParametersSectionHandler() {
+      nodeParameters = new HashMap();
+      stringParameters = new HashMap();
+      integerParameters = new HashMap();
+    }
+
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      String parameterName;
+      String defaultValue;
+
+      if (aTag.equals("node")) {
+        mir.util.xml.XMLReaderTool.checkAttributes(anAttributes,
+            NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES,
+            NODE_DEFINITION_NODE_PARAMETER_OPTIONAL_ATTRIBUTES);
+        parameterName = (String) anAttributes.get(
+            NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE);
+
+        if (nodeParameters.containsKey(parameterName))
+          throw new XMLParserExc("Duplicate parameter name: '" +
+                                           parameterName + "'");
+
+        mir.util.xml.XMLReaderTool.checkValidIdentifier(parameterName);
+
+        nodeParameters.put(parameterName, parameterName);
+
+        return new EmptySectionHandler();
+      }
+      else if (aTag.equals("string") || aTag.equals("integer")) {
+        mir.util.xml.XMLReaderTool.checkAttributes(anAttributes,
+            NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES,
+            NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES);
+        parameterName = (String) anAttributes.get(
+            NODE_DEFINITION_PARAMETER_NAME_ATTRIBUTE);
+
+        if (stringParameters.containsKey(parameterName) ||
+            integerParameters.containsKey(parameterName))
+          throw new XMLParserExc("Duplicate parameter name: '" +
+                                           parameterName + "'");
+
+        mir.util.xml.XMLReaderTool.checkValidIdentifier(parameterName);
+
+        defaultValue = (String) anAttributes.get(
+            NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE);
+
+        if (aTag.equals("string"))
+          stringParameters.put(parameterName, defaultValue);
+        else
+          integerParameters.put(parameterName, defaultValue);
+
+        return new EmptySectionHandler();
+      }
+      else
+        throw new XMLParserExc(
+            "Only 'string', 'integer' and 'node' tags allowed here, '" + aTag + "' encountered.");
+    }
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) {
+    }
+
+    public void finishSection() {
+    }
+
+    public Map getNodeParameters() {
+      return nodeParameters;
+    }
+
+    public Map getStringParameters() {
+      return stringParameters;
+    }
+
+    public Map getIntegerParameters() {
+      return integerParameters;
+    }
+  }
+}