rebuilding head
authoridfx <idfx>
Sat, 6 Nov 2004 19:14:13 +0000 (19:14 +0000)
committeridfx <idfx>
Sat, 6 Nov 2004 19:14:13 +0000 (19:14 +0000)
153 files changed:
source/mir/bundle/BasicBundleFactory.java [new file with mode: 0755]
source/mir/bundle/Bundle.java [new file with mode: 0755]
source/mir/bundle/BundleFactory.java [new file with mode: 0755]
source/mir/bundle/BundleLoader.java [new file with mode: 0755]
source/mir/bundle/CascadingBundleFactory.java [new file with mode: 0755]
source/mir/bundle/PropertiesBundle.java [new file with mode: 0755]
source/mir/bundle/PropertiesFileBundleLoader.java [new file with mode: 0755]
source/mir/config/MirPropertiesConfiguration.java
source/mir/entity/AbstractEntity.java [new file with mode: 0755]
source/mir/entity/Entity.java
source/mir/entity/EntityBrowser.java
source/mir/entity/EntityList.java
source/mir/entity/GenericEntity.java
source/mir/entity/StorableObjectEntity.java
source/mir/entity/adapter/EntityAdapter.java
source/mir/entity/adapter/EntityAdapterDefinition.java
source/mir/entity/adapter/EntityAdapterEngine.java
source/mir/entity/adapter/EntityIteratorAdapter.java
source/mir/entity/adapter/EntityListAdapter.java
source/mir/generator/CompositeGeneratorLibrary.java
source/mir/generator/FreemarkerGenerator.java
source/mir/generator/Generator.java
source/mir/generator/GeneratorHelper.java [new file with mode: 0755]
source/mir/generator/GeneratorLibraryRepository.java
source/mir/generator/TALGenerator.java [new file with mode: 0755]
source/mir/generator/VelocityGenerator.java [new file with mode: 0755]
source/mir/generator/tal/CachingFileLoader.java [new file with mode: 0755]
source/mir/generator/tal/MirExpressionParser.java [new file with mode: 0755]
source/mir/generator/tal/SimpleTemplateNodeLibraryRegistry.java [new file with mode: 0755]
source/mir/generator/tal/TALExc.java [new file with mode: 0755]
source/mir/generator/tal/TALFailure.java [new file with mode: 0755]
source/mir/generator/tal/TALTemplateEngine.java [new file with mode: 0755]
source/mir/generator/tal/TALTemplateParser.java [new file with mode: 0755]
source/mir/generator/tal/TALTest.java [new file with mode: 0755]
source/mir/generator/tal/interfaces/TALExpressionParser.java [new file with mode: 0755]
source/mir/generator/tal/interfaces/TALLogger.java [new file with mode: 0755]
source/mir/generator/tal/template/CompositeTemplateNode.java [new file with mode: 0755]
source/mir/generator/tal/template/CoreTemplateNodeLibrary.java [new file with mode: 0755]
source/mir/generator/tal/template/MacroTemplateNodeLibrary.java [new file with mode: 0755]
source/mir/generator/tal/template/PlainTextTemplateNode.java [new file with mode: 0755]
source/mir/generator/tal/template/Template.java [new file with mode: 0755]
source/mir/generator/tal/template/TemplateLibrary.java [new file with mode: 0755]
source/mir/generator/tal/template/TemplateNode.java [new file with mode: 0755]
source/mir/generator/tal/template/TemplateNodeLibrary.java [new file with mode: 0755]
source/mir/generator/tal/template/TemplateNodeLibraryRegistry.java [new file with mode: 0755]
source/mir/generator/tal/template/TemplateProcessingException.java [new file with mode: 0755]
source/mir/log/Log.java [deleted file]
source/mir/log/Logger.java
source/mir/log/LoggerEngine.java [new file with mode: 0755]
source/mir/log/LoggerExc.java [new file with mode: 0755]
source/mir/log/LoggerFailure.java [new file with mode: 0755]
source/mir/log/LoggerWrapper.java
source/mir/log/TestFramework.java [deleted file]
source/mir/log/log4j/LoggerImpl.java
source/mir/media/MediaHandler.java [new file with mode: 0755]
source/mir/media/MediaHelper.java [deleted file]
source/mir/media/MirMedia.java [deleted file]
source/mir/misc/FileUtil.java
source/mir/misc/HTMLParseException.java [deleted file]
source/mir/misc/LineFilterWriter.java [deleted file]
source/mir/misc/PDFUtil.java
source/mir/misc/StringUtil.java
source/mir/module/AbstractModule.java
source/mir/producer/BundleProducerNode.java [new file with mode: 0755]
source/mir/producer/CompositeProducerNode.java
source/mir/producer/DirCopyingProducerNode.java
source/mir/producer/EntityBatchingProducerNode.java
source/mir/producer/EntityDeletingProducerNode.java
source/mir/producer/EntityEnumeratingProducerNode.java
source/mir/producer/EntityListProducerNode.java
source/mir/producer/EntityModifyingProducerNode.java
source/mir/producer/ExecuteProgramProducerNode.java [new file with mode: 0755]
source/mir/producer/ExternalDbProducerNode.java [new file with mode: 0755]
source/mir/producer/FileDateSettingProducerNode.java
source/mir/producer/GeneratingProducerNode.java
source/mir/producer/ListEnumeratingProducerNode.java
source/mir/producer/NodedProducerFactory.java [deleted file]
source/mir/producer/ProducerFactory.java
source/mir/producer/ProducerNode.java
source/mir/producer/RDFAggregatorProducerNode.java
source/mir/producer/RSSProducerNode.java
source/mir/producer/ResourceBundleProducerNode.java [deleted file]
source/mir/producer/ScriptCallingProducerNode.java [deleted file]
source/mir/producer/reader/DefaultProducerNodeBuilders.java
source/mir/producer/reader/ProducerConfigReader.java
source/mir/producer/reader/ProducerNodeBuilder.java
source/mir/producer/reader/ScriptedProducerFactory.java
source/mir/rss/RDFResource.java
source/mir/rss/RSS091Reader.java
source/mir/rss/RSSAggregator.java
source/mir/rss/RSSData.java
source/mir/rss/RSSReader.java
source/mir/rss/RSSTest.java [deleted file]
source/mir/servlet/AbstractServlet.java
source/mir/servlet/ServletModule.java
source/mir/session/CommonsUploadedFileAdapter.java
source/mir/session/HTTPAdapters.java
source/mir/session/Request.java
source/mir/session/UploadedFile.java
source/mir/session/ValidationHelper.java
source/mir/storage/Database.java
source/mir/storage/StorageObject.java
source/mir/storage/store/ObjectStore.java
source/mir/storage/store/StoreContainer.java
source/mir/storage/store/StoreContainerType.java
source/mir/storage/store/StoreIdentifier.java
source/mir/storage/store/StoreUtil.java
source/mir/util/CachingRewindableIterator.java
source/mir/util/DateTimeFunctions.java
source/mir/util/EntityUtility.java [new file with mode: 0755]
source/mir/util/ExceptionFunctions.java
source/mir/util/FileFunctions.java
source/mir/util/GeneratorDateTimeFunctions.java
source/mir/util/GeneratorExpressionFunctions.java [deleted file]
source/mir/util/GeneratorFormatAdapters.java
source/mir/util/GeneratorHTMLFunctions.java [deleted file]
source/mir/util/GeneratorIntegerFunctions.java [deleted file]
source/mir/util/GeneratorListFunctions.java [deleted file]
source/mir/util/GeneratorRegularExpressionFunctions.java [deleted file]
source/mir/util/GeneratorStringFunctions.java [deleted file]
source/mir/util/HTMLRoutines.java
source/mir/util/HTTPClientHelper.java [new file with mode: 0755]
source/mir/util/HTTPParsedRequest.java
source/mir/util/HTTPRequestParser.java
source/mir/util/InternetFunctions.java
source/mir/util/JDBCStringRoutines.java
source/mir/util/ParameterExpander.java
source/mir/util/PropertiesManipulator.java
source/mir/util/ReflectionRoutines.java [new file with mode: 0755]
source/mir/util/ResourceBundleGeneratorFunction.java [deleted file]
source/mir/util/StreamCopier.java [new file with mode: 0755]
source/mir/util/StringParseRoutines.java
source/mir/util/StringRoutines.java
source/mir/util/StructuredContentParser.java
source/mir/util/XMLReader.java [deleted file]
source/mir/util/XMLReaderTool.java [deleted file]
source/mir/util/generator/BundleGeneratorFunction.java [new file with mode: 0755]
source/mir/util/generator/ReflectionGeneratorFunctionAdapter.java [new file with mode: 0755]
source/mir/util/generator/ReflectionGeneratorFunctionsAdapter.java [new file with mode: 0755]
source/mir/util/xml/AbstractSectionHandler.java [new file with mode: 0755]
source/mir/util/xml/SectionHandler.java [new file with mode: 0755]
source/mir/util/xml/XMLName.java [new file with mode: 0755]
source/mir/util/xml/XMLParserEngine.java [new file with mode: 0755]
source/mir/util/xml/XMLParserExc.java [new file with mode: 0755]
source/mir/util/xml/XMLParserFailure.java [new file with mode: 0755]
source/mir/util/xml/XMLReaderTool.java [new file with mode: 0755]
source/mir/util/xml/XMLSAXParserProvider.java [new file with mode: 0755]
source/mir/util/xml/html/HTMLParser.java [new file with mode: 0755]
source/mir/util/xml/html/HTMLParserExc.java [new file with mode: 0755]
source/mir/util/xml/html/HTMLParserFailure.java [new file with mode: 0755]
source/mir/util/xml/html/HTMLScanner.java [new file with mode: 0755]
source/mir/util/xml/html/HTMLSchemaInformation.java [new file with mode: 0755]
source/mir/util/xml/html/XMLHTMLParserProvider.java [new file with mode: 0755]

diff --git a/source/mir/bundle/BasicBundleFactory.java b/source/mir/bundle/BasicBundleFactory.java
new file mode 100755 (executable)
index 0000000..ac9aeb9
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.bundle;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The <code>BasicBundleFactory</code> is responsible for managing
+ * loaded bundles. It caches previously retrieved bundles to improve
+ * performance.
+ */
+public class BasicBundleFactory implements BundleFactory {
+  private Map directories;
+  private BundleLoader loader;
+
+  public BasicBundleFactory(BundleLoader aLoader) {
+    directories = new HashMap();
+    loader = aLoader;
+  }
+
+  private Map getBundleDirectory(String aDirectory) {
+    synchronized (directories) {
+      Map result = (Map) directories.get(aDirectory);
+
+      if (result == null) {
+        result = new HashMap();
+        directories.put(aDirectory, result);
+      }
+
+      return result;
+    }
+  }
+
+  private Bundle loadBundle(String aDirectory, String[] aParameters) {
+    return loader.loadBundle(aDirectory, aParameters);
+  }
+
+  public Bundle getBundle(String aDirectory, String[] aParameters) {
+    Map directory = getBundleDirectory(aDirectory);
+    List parameters = java.util.Arrays.asList(aParameters);
+
+    Bundle result = (Bundle) directory.get(parameters);
+
+    if (result==null) {
+      result = loadBundle(aDirectory, aParameters);
+      directory.put(parameters, result);
+    }
+
+    return result;
+  }
+
+  public void reload() {
+    synchronized (directories) {
+      directories.clear();
+    }
+  }
+}
diff --git a/source/mir/bundle/Bundle.java b/source/mir/bundle/Bundle.java
new file mode 100755 (executable)
index 0000000..cec44e4
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.bundle;
+
+import java.util.List;
+
+public interface Bundle {
+  public String getValue(String aKey, List anArguments);
+}
diff --git a/source/mir/bundle/BundleFactory.java b/source/mir/bundle/BundleFactory.java
new file mode 100755 (executable)
index 0000000..7df1476
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.bundle;
+
+public interface BundleFactory {
+  /**
+   * Retrieves a bundle
+   */
+  public Bundle getBundle(String aDirectory, String[] aParameters);
+
+  /**
+   * Invalidates the bundle cache
+   */
+  public void reload();
+}
diff --git a/source/mir/bundle/BundleLoader.java b/source/mir/bundle/BundleLoader.java
new file mode 100755 (executable)
index 0000000..7674e94
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.bundle;
+
+/**
+ * <p>
+ * The BundleLoader is responsible for the physical loading of (abstract)
+ * {@link Bundle}s. A <code>Bundle</code> is identified by a directory
+ * and a set of parameters. The directory typically denotes the base of
+ * a set of <code>Bundles</code>, the parameters stand for a particular
+ * instance. E.g. the directory might stand for the purpose of the bundles,
+ * the parameters for the locale.
+ * </p>
+ * <p>
+ * <code>BundleLoader</code>s should not do any caching, since that's the
+ * responsibility of the {@link BasicBundleFactory}.
+ * </p>
+ */
+public interface BundleLoader {
+  /**
+   * Loads the bundle specified by <code>aDirectory</code> and
+   * <code>aParameters</code>.
+   */
+  public Bundle loadBundle(String aDirectory, String[] aParameters);
+}
diff --git a/source/mir/bundle/CascadingBundleFactory.java b/source/mir/bundle/CascadingBundleFactory.java
new file mode 100755 (executable)
index 0000000..b3a9920
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.bundle;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class CascadingBundleFactory implements BundleFactory {
+  private BundleFactory masterFactory;
+
+  /** {@inheritDoc} */
+  public CascadingBundleFactory(BundleFactory aMasterFactory) {
+    masterFactory = aMasterFactory;
+  }
+
+  /** {@inheritDoc} */
+  public Bundle getBundle(final String aDirectory, final String[] aParameters) {
+    return
+      new Bundle() {
+        public String getValue(String aKey, List anArguments) {
+          String result = masterFactory.getBundle(aDirectory, aParameters).getValue(aKey, anArguments);
+
+          if (aParameters.length>0 && result==null) {
+            List parameters = new ArrayList(Arrays.asList(aParameters));
+
+            while (result==null && parameters.size()>0) {
+              parameters.remove(parameters.size()-1);
+              result = masterFactory.getBundle(
+                  aDirectory, (String[]) parameters.toArray(new String[0])).getValue(aKey, anArguments);
+            }
+          }
+
+          return result;
+        }
+      };
+  }
+
+  /** {@inheritDoc} */
+  public void reload() {
+    masterFactory.reload();
+  }
+}
diff --git a/source/mir/bundle/PropertiesBundle.java b/source/mir/bundle/PropertiesBundle.java
new file mode 100755 (executable)
index 0000000..a795285
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.bundle;
+
+import java.util.Properties;
+import java.util.List;
+import java.util.Iterator;
+
+import mir.util.StringParseRoutines;
+
+/**
+ * Bundle implementation using a {@link Properties}
+ * object.
+ */
+
+public class PropertiesBundle implements Bundle {
+  private Properties properties;
+
+  public PropertiesBundle(Properties aProperties) {
+    properties = aProperties;
+  }
+
+  private String formatValue(String anExpression, List anArguments) {
+    StringBuffer result = new StringBuffer();
+
+    List parts = StringParseRoutines.parseBracketedExpression(
+        anExpression, '\\', "{", "}" );
+
+    Iterator i = parts.iterator();
+    while (i.hasNext()) {
+      result.append(i.next());
+      if (i.hasNext()) {
+        String expression = (String) i.next();
+        try {
+          int parameterNr = Integer.parseInt(expression);
+          if (parameterNr>=0 && parameterNr<anArguments.size()) {
+            result.append(anArguments.get(parameterNr));
+          }
+        }
+        catch (Throwable t) {
+        }
+      }
+    }
+
+    return result.toString();
+  }
+
+  /** {@inheritDoc} */
+  public String getValue(String aKey, List anArguments) {
+    String result = (String) properties.get(aKey);
+
+    if (result==null || result.trim().length()==0)
+      return null;
+    else
+      return formatValue(result, anArguments);
+  }
+}
diff --git a/source/mir/bundle/PropertiesFileBundleLoader.java b/source/mir/bundle/PropertiesFileBundleLoader.java
new file mode 100755 (executable)
index 0000000..5e88976
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.bundle;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileInputStream;
+import java.util.Properties;
+
+/**
+ * Loads properties files relative to a base directory as {@link Bundle}s
+ */
+public class PropertiesFileBundleLoader implements BundleLoader {
+  private File baseDirectory;
+
+  /** {@inheritDoc} */
+  public PropertiesFileBundleLoader(File aBaseDirectory) {
+    baseDirectory = aBaseDirectory;
+  }
+
+  /** {@inheritDoc} */
+  public Bundle loadBundle(String aDirectory, String[] aParameters) {
+    Properties properties = new Properties();
+    String fileName = aDirectory;
+    for (int i=0; i<aParameters.length; i++) {
+      fileName = fileName + "_" + aParameters[i];
+    }
+    fileName = fileName + ".properties";
+
+    File file = new File(baseDirectory, fileName);
+
+    try {
+      properties.load(new FileInputStream(file));
+    }
+    catch (IOException e) {
+    }
+
+    return new PropertiesBundle(properties);
+  }
+}
index 2d5c038..80ece21 100755 (executable)
 package mir.config;
 
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-
 import javax.servlet.ServletContext;
 
 import multex.Exc;
 import multex.Failure;
-
 import org.apache.commons.collections.ExtendedProperties;
 
-
 /**
  * @author idefix
  */
 public class MirPropertiesConfiguration extends ExtendedProperties {
   private static MirPropertiesConfiguration instance;
   private static ServletContext context;
-  private static String contextPath;
 
-  //if one of these properties is not present a new
-  //property is added with its default value;
-  private static NeededProperty[] neededWithValue =
-  {
-    new NeededProperty("Producer.DocRoot", ""),
-    new NeededProperty("Producer.ImageRoot", ""),
-    new NeededProperty("Producer.Image.Path", ""),
-    new NeededProperty("Producer.Media.Path", ""),
-    new NeededProperty("Producer.RealMedia.Path", ""),
-    new NeededProperty("Producer.Image.IconPath", "")
-  };
+  private File home;
 
   /**
    * Constructor for MirPropertiesConfiguration.
    */
-  private MirPropertiesConfiguration(ServletContext ctx, String ctxPath)
-    throws IOException {
+  private MirPropertiesConfiguration(ServletContext ctx) throws IOException {
     //loading the defaults-config
     super(ctx.getRealPath("/WEB-INF/") + "/default.properties");
+
     //loading the user-config
     ExtendedProperties userConfig =
       new ExtendedProperties(ctx.getRealPath("/WEB-INF/etc/") + "/config.properties");
+
     //merging them to one config while overriding the defaults
     this.combine(userConfig);
-    addProperty("Home", ctx.getRealPath("/WEB-INF/") + "/");
-    checkMissing();
+
+    home = new File(ctx.getRealPath("/WEB-INF/")+"/");
   }
 
-  public static synchronized MirPropertiesConfiguration instance()
-    throws PropertiesConfigExc {
+  public static synchronized MirPropertiesConfiguration instance() {
     if (instance == null) {
       if (context == null) {
-        throw new MirPropertiesConfiguration.PropertiesConfigExc(
-          "Context was not set");
+        throw new Error("Context was not set");
       }
 
       try {
-        instance = new MirPropertiesConfiguration(context, contextPath);
+        instance = new MirPropertiesConfiguration(context);
       }
       catch (IOException e) {
-        throw new RuntimeException(e.toString());
+        throw new Error("cannot load configuration: " + e.toString());
       }
     }
 
@@ -101,6 +85,7 @@ public class MirPropertiesConfiguration extends ExtendedProperties {
 
   /**
    * Sets the context.
+   *
    * @param context The context to set
    */
   public static void setContext(ServletContext context) {
@@ -109,6 +94,7 @@ public class MirPropertiesConfiguration extends ExtendedProperties {
 
   /**
    * Returns the context.
+   *
    * @return ServletContext
    */
   public static ServletContext getContext() {
@@ -126,58 +112,51 @@ public class MirPropertiesConfiguration extends ExtendedProperties {
       String key = (String) iterator.next();
       Object o = this.getProperty(key);
 
-      if (o == null) {
-        o = new Object();
-      }
-
       returnMap.put(key, o);
     }
 
+    // ML: hack for now
+    if (!returnMap.containsKey("Producer.DocRoot")) {
+      returnMap.put("Producer.DocRoot", "");
+    }
+
     return returnMap;
   }
 
   /**
-   * Returns a String-property concatenated with the home-dir of the
-   * installation
-   * @param key
-   * @return String
+   * Return mir's home directory.
+   * Normally this is the <code>WEB-INF</code> dir of the
+   * deployed mir servlets.
    */
-  public String getStringWithHome(String key) {
-    String returnString = getString(key);
-
-    if (returnString == null) {
-      returnString = new String();
-    }
-
-    return getString("Home") + returnString;
+  public File getHome() {
+    return home;
   }
 
   /**
-   * Checks if one property is missing and adds a default value
+   * Returns a file based on a configuration setting.
+   *
+   * The file may be configured with an absolute path, or
+   * it may be a relative path.
+   *
+   * Relative paths work relative to {@link #home} :
+   * normally this is the <code>WEB-INF</code> dir in a
+   * deployed java servlet.
    */
-  private void checkMissing() {
-    for (int i = 0; i < neededWithValue.length; i++) {
-      if (super.getProperty(neededWithValue[i].getKey()) == null) {
-        addProperty(neededWithValue[i].getKey(), neededWithValue[i].getValue());
-      }
-    }
-  }
+  public File getFile(String aKey) {
+    String path = getString(aKey);
 
-  public File getFile(String key) throws FileNotFoundException {
-    String path = getStringWithHome(key);
-    File returnFile = new File(path);
-
-    if (returnFile.exists()) {
-      return returnFile;
-    } else {
-      throw new FileNotFoundException();
+    File result = new File(path);
+    if (result.isAbsolute()) {
+      return result;
+    }
+    else {
+      return new File(home, path);
     }
   }
 
   /**
    * @return the vlaue of this property as String
    * @param key the key of this property
-   * @see org.apache.commons.configuration.Configuration#getString(java.lang.String)
    */
   public String getString(String key) {
     return getString(key, "");
@@ -204,11 +183,26 @@ public class MirPropertiesConfiguration extends ExtendedProperties {
     return object.toString();
   }
 
+  public boolean getBoolean(String aKey, boolean aDefaultValue) {
+    try {
+      return getBoolean(aKey);
+    }
+    catch (Throwable t) {
+      return aDefaultValue;
+    }
+  }
+
+  public boolean getBoolean(String aKey) {
+    String value = getString(aKey).trim();
+
+    return "1".equals(value) || "y".equalsIgnoreCase(value) ||
+        "yes".equalsIgnoreCase(value) || "true".equalsIgnoreCase(value);
+  }
+
   /**
    * Returns a property according to the given key
    * @param key the key of the property
    * @return the value of the property as Object, if no property available it returns a empty String
-   * @see org.apache.commons.configuration.Configuration#getString(java.lang.String)
    */
   public Object getProperty(String key) {
     if (super.getProperty(key) == null) {
@@ -224,7 +218,6 @@ public class MirPropertiesConfiguration extends ExtendedProperties {
   public static class PropertiesConfigExc extends Exc {
     /**
      * Constructor for PropertiesConfigExc.
-     * @param arg0
      */
     public PropertiesConfigExc(String msg) {
       super(msg);
@@ -237,32 +230,9 @@ public class MirPropertiesConfiguration extends ExtendedProperties {
   public static class PropertiesConfigFailure extends Failure {
     /**
      * Constructor for PropertiesConfigExc.
-     * @param arg0
      */
     public PropertiesConfigFailure(String msg, Throwable cause) {
       super(msg, cause);
     }
   }
-
-  /**
-   * A Class for properties to be checked
-   * @author idefix
-   */
-  private static class NeededProperty {
-    private String _key;
-    private String _value;
-
-    public NeededProperty(String key, String value) {
-      _key = key;
-      _value = value;
-    }
-
-    public String getKey() {
-      return _key;
-    }
-
-    public String getValue() {
-      return _value;
-    }
-  }
 }
diff --git a/source/mir/entity/AbstractEntity.java b/source/mir/entity/AbstractEntity.java
new file mode 100755 (executable)
index 0000000..ec6d9b0
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.entity;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import mir.config.MirPropertiesConfiguration;
+import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;
+import mir.log.LoggerWrapper;
+import mir.storage.StorageObject;
+import mir.storage.StorageObjectExc;
+import mir.storage.StorageObjectFailure;
+
+/**
+ * Base class the entities are derived from. Provides base functionality of
+ * an entity.
+ *
+ * @version $Id: AbstractEntity.java,v 1.9 2004/11/06 19:18:12 idfx Exp $
+ */
+
+public class AbstractEntity implements Entity {
+  protected static MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();
+
+  protected Map values;
+  protected StorageObject storageObject;
+  protected LoggerWrapper logger;
+
+  public AbstractEntity() {
+    logger = new LoggerWrapper("Entity");
+
+    values = new HashMap();
+  }
+
+  /**
+   * Constructor
+   * @param StorageObject The StorageObject of the Entity.
+   */
+  public AbstractEntity(StorageObject StorageObject) {
+    this();
+
+    setStorage(StorageObject);
+  }
+
+  public void setStorage(StorageObject storage) {
+    this.storageObject = storage;
+  }
+
+  /** {@inheritDoc} */
+  public void setFieldValues(Map aMap) {
+    if (aMap!=null) {
+      Iterator i = aMap.entrySet().iterator();
+      synchronized(this) {
+        while (i.hasNext()) {
+          Map.Entry entry = (Map.Entry) i.next();
+
+          setFieldValue( (String) entry.getKey(), (String) entry.getValue());
+        }
+      }
+    }
+  }
+
+  /** {@inheritDoc} */
+  public String getId() {
+    return getFieldValue(storageObject.getIdName());
+  }
+
+  /** {@inheritDoc} */
+  public void setId(String id) {
+    setFieldValue(storageObject.getIdName(), id);
+  }
+
+  /** {@inheritDoc} */
+  public String insert() throws StorageObjectExc {
+    logger.debug("Entity: trying to insert ...");
+
+    if (storageObject != null) {
+      return storageObject.insert(this);
+    }
+    else
+      throw new StorageObjectExc("storageObject == null!");
+  }
+
+  /** {@inheritDoc} */
+  public void update() throws StorageObjectFailure {
+    storageObject.update(this);
+  }
+
+  /** {@inheritDoc} */
+  public String getFieldValue(String aFieldName) {
+    String returnValue = null;
+
+    if (aFieldName != null) {
+      returnValue = (String) values.get(aFieldName);
+    }
+    return returnValue;
+  }
+
+  /** {@inheritDoc} */
+  public boolean hasFieldValue(String aFieldName) {
+    return values.containsKey(aFieldName);
+  }
+
+  /**
+   * Sets the value for a field. Issues a log message if the field name
+   * supplied was not found in the Entity.
+   * @param theProp The field name whose value has to be set
+   * @param theValue The new value of the field
+   * @exception StorageObjectFailure
+   */
+  public void setFieldValue(String theProp, String theValue) throws StorageObjectFailure {
+    if (hasField(theProp))
+      values.put(theProp, theValue);
+    else {
+      logger.warn("Entity.setFieldValue: Property not found: " + theProp + " (" + theValue + ")");
+    }
+  }
+
+  /**
+   * Returns the field names of the Entity
+   */
+  public List getFieldNames() throws StorageObjectFailure {
+    return storageObject.getFields();
+  }
+
+  /** Returns whether fieldName is a valid field name of this Entity.
+   * @param fieldName
+   * @return true in case fieldName is a field name, else false.
+   * @exception StorageObjectFailure
+   */
+  public boolean hasField(String fieldName) throws StorageObjectFailure {
+    return getFieldNames().contains(fieldName);
+  }
+}
+
index 30823c0..6a66881 100755 (executable)
 package  mir.entity;
 
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
-import java.util.*;
+import java.util.Map;
 
 import mir.config.MirPropertiesConfiguration;
 import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;
 import mir.log.LoggerWrapper;
-import mir.misc.StringUtil;
 import mir.storage.StorageObject;
 import mir.storage.StorageObjectExc;
 import mir.storage.StorageObjectFailure;
 
 /**
- * Base class the entities are derived from. Provides base functionality of
- * an entity. Entities are used to represent rows of a database table.<p>
- *
- * @version $Id: Entity.java,v 1.22 2003/09/03 18:29:01 zapata Exp $
- * @author rk
+ * An <code>Entity</code> represents a persistent data object, typically
+ *   stored in a database.<p>
  *
+ * @version $Id: Entity.java,v 1.23 2004/11/06 19:18:12 idfx Exp $
  */
 
-public class Entity
+public interface Entity
 {
-  protected static MirPropertiesConfiguration configuration;
-
-//  protected Map theValuesHash; // tablekey / value
-  protected Map values;
-  protected StorageObject theStorageObject;
-  protected List streamedInput = null;
-  protected LoggerWrapper logger;
-
-  static {
-    try {
-      configuration = MirPropertiesConfiguration.instance();
-    }
-    catch (PropertiesConfigExc e) {
-      throw new RuntimeException(e.getMessage());
-    }
-  }
-
-  public Entity() {
-    logger = new LoggerWrapper("Entity");
-
-    values = new HashMap();
-  }
-
-  /**
-   * Constructor
-   * @param StorageObject The StorageObject of the Entity.
-   */
-
-  public Entity(StorageObject StorageObject) {
-    this();
-
-    setStorage(StorageObject);
-  }
-
-  /**
-   *
-   * @param storage
-   */
-
-  public void setStorage(StorageObject storage) {
-    this.theStorageObject = storage;
-  }
+  public void setStorage(StorageObject storage);
 
   /**
    * Sets the values of the Entity. (Only to be called by the Storage Object)
@@ -101,157 +58,58 @@ public class Entity
    * @param aMap Map containing the new values of the Entity
    */
 
-  public void setValues(Map aMap) {
-    if (aMap!=null) {
-      Iterator i = aMap.entrySet().iterator();
-      synchronized(this) {
-        while (i.hasNext()) {
-          Map.Entry entry = (Map.Entry) i.next();
-
-          setValueForProperty( (String) entry.getKey(), (String) entry.getValue());
-        }
-      }
-    }
-  }
+  public void setFieldValues(Map aMap);
 
   /**
    * Returns the primary key of the Entity.
    * @return String Id
    */
-  public String getId() {
-    return (String) getValue(theStorageObject.getIdName());
-  }
+  public String getId();
 
   /**
    * Defines the primary key of the Entity (only to be set by the StorageObject)
    * @param id
    */
-  public void setId(String id) {
-    setValueForProperty(theStorageObject.getIdName(), id);
-  }
-
-  /**
-   * Returns the value of a field by field name.
-   * @param field The name of the field
-   * @return value of the field
-   */
-  public String getValue(String field) {
-    String returnValue = null;
-
-    if (field != null) {
-      returnValue = (String) values.get(field);
-    }
-    return returnValue;
-  }
-
-  public boolean hasValueForField(String field) {
-    return values.containsKey(field);
-  }
+  public void setId(String id);
 
   /**
    * Insers Entity into the database via StorageObject
    * @return Primary Key of the Entity
-   * @exception StorageObjectException
+   * @exception StorageObjectExc
    */
-  public String insert() throws StorageObjectExc {
-    logger.debug("Entity: trying to insert ...");
-
-    if (theStorageObject != null) {
-      return theStorageObject.insert(this);
-    }
-    else
-      throw new StorageObjectExc("theStorageObject == null!");
-  }
+  public String insert() throws StorageObjectExc;
 
   /**
    * Saves changes of this Entity to the database
-   * @exception StorageObjectException
+   * @exception StorageObjectFailure
    */
-  public void update() throws StorageObjectFailure {
-    theStorageObject.update(this);
-  }
+  public void update() throws StorageObjectFailure;
 
   /**
    * Sets the value for a field. Issues a log message if the field name
    * supplied was not found in the Entity.
    * @param theProp The field name whose value has to be set
    * @param theValue The new value of the field
-   * @exception StorageObjectException
+   * @exception StorageObjectFailure
    */
-  public void setValueForProperty(String theProp, String theValue) throws StorageObjectFailure {
-    try {
-      if (isField(theProp))
-        values.put(theProp, theValue);
-      else {
-        logger.warn("Entity.setValueForProperty: Property not found: " + theProp + " (" + theValue + ")");
-      }
-    }
-    catch (Throwable t) {
-      logger.error("Entity.setValueForProperty: " + t.toString());
-      t.printStackTrace(logger.asPrintWriter(logger.DEBUG_MESSAGE));
-
-      throw new StorageObjectFailure(t);
-    }
-  }
+  public void setFieldValue(String theProp, String theValue);
 
   /**
-   * Returns the field names of the Entity as ArrayListe.
-   * @return ArrayList with field names
-       * @exception StorageObjectException is throuwn if database access was impossible
+   * Returns the field names of the Entity
    */
-  public List getFields() throws StorageObjectFailure {
-    return theStorageObject.getFields();
-  }
+  public List getFieldNames() throws StorageObjectFailure;
 
   /**
-   * Returns an int[] with the types of the fields
-   * @return int[] that contains the types of the fields
-   * @exception StorageObjectException
-   */
-  public int[] getTypes() throws StorageObjectFailure {
-    return theStorageObject.getTypes();
-  }
-
-  /**
-   * Returns an ArrayList with field names
-   * @return List with field names
-   * @exception StorageObjectException
-   */
-  public List getLabels() throws StorageObjectFailure {
-    return theStorageObject.getLabels();
-  }
-
-
-  /**
-   * Returns an ArrayList with all database fields that can
-   * be evaluated as streamedInput.
-   * Could be automated by the types (blob, etc.)
-   * Until now to be created manually in the inheriting class
-   *
-   *  Liefert einen ArrayList mit allen Datenbankfeldern, die
-   *  als streamedInput ausgelesen werden muessen.
-   *  Waere automatisierbar ueber die types (blob, etc.)
-   *  Bisher manuell anzulegen in der erbenden Klasse
+   * Returns the value of a field by field name.
+   * @param field The name of the field
+   * @return value of the field
    */
+  public String getFieldValue(String field);
 
-  public List streamedInput() {
-    return streamedInput;
-  }
+  public boolean hasFieldValue(String field);
 
   /** Returns whether fieldName is a valid field name of this Entity.
-   * @param fieldName
-   * @return true in case fieldName is a field name, else false.
-   * @exception StorageObjectException
    */
-  public boolean isField(String fieldName) throws StorageObjectFailure {
-    return theStorageObject.getFields().contains(fieldName);
-  }
-
-  protected void throwStorageObjectFailure(Throwable e, String wo) throws StorageObjectFailure {
-    logger.error(e.toString() + " function: " + wo);
-    e.printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
-
-    throw new StorageObjectFailure("Storage Object Exception in entity", e);
-  }
+  public boolean hasField(String aFieldName) throws StorageObjectFailure;
 }
 
index 44b21f4..77bc559 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.entity;
 
+import java.util.List;
+
 import mir.storage.StorageObject;
 import mir.storage.StorageObjectFailure;
 import mir.util.RewindableIterator;
@@ -37,10 +39,11 @@ import mir.util.RewindableIterator;
 public class EntityBrowser implements RewindableIterator {
 
   private StorageObject storage;
+  private String mainTablePrefix;
+  private List extraTables;
   private String whereClause;
   private String orderByClause;
   private int batchSize;
-  private int toFetch;
   private EntityList currentBatch;
 
   private int skip;
@@ -49,10 +52,13 @@ public class EntityBrowser implements RewindableIterator {
   private int batchPosition;
   private int positionInBatch;
 
-  public EntityBrowser(StorageObject aStorage, String aWhereClause, String anOrderByClause,
-                       int aBatchSize, int aLimit, int aSkip) throws StorageObjectFailure {
+  public EntityBrowser(StorageObject aStorage, String aMainTablePrefix, List someExtraTables,
+     String aWhereClause, String anOrderByClause,
+     int aBatchSize, int aLimit, int aSkip) throws StorageObjectFailure {
 
     storage=aStorage;
+    mainTablePrefix=aMainTablePrefix;
+    extraTables=someExtraTables;
     whereClause=aWhereClause;
     orderByClause=anOrderByClause;
     batchSize=aBatchSize;
@@ -62,6 +68,11 @@ public class EntityBrowser implements RewindableIterator {
     rewind();
   }
 
+  public EntityBrowser(StorageObject aStorage, String aWhereClause, String anOrderByClause,
+                       int aBatchSize, int aLimit, int aSkip) throws StorageObjectFailure {
+    this(aStorage, "", null, aWhereClause, anOrderByClause, aBatchSize, aLimit, aSkip);
+  }
+
   public EntityBrowser(StorageObject aStorage,
           String aWhereClause, String anOrderByClause,
           int aBatchSize) throws StorageObjectFailure {
@@ -69,7 +80,7 @@ public class EntityBrowser implements RewindableIterator {
   }
 
   public void readCurrentBatch(int aSkip) throws StorageObjectFailure {
-    currentBatch = storage.selectByWhereClause(whereClause, orderByClause, aSkip, batchSize);
+    currentBatch = storage.selectByWhereClause(mainTablePrefix, extraTables, whereClause, orderByClause, aSkip, batchSize);
     batchPosition = aSkip;
     positionInBatch = 0;
   }
index f792413..e9c839a 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  any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two.  You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries.  If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-package  mir.entity;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Set;\r
-\r
-import mir.config.MirPropertiesConfiguration;\r
-import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;\r
-import mir.log.LoggerWrapper;\r
-import mir.storage.StorageObject;\r
-import mir.storage.store.StorableObject;\r
-import mir.storage.store.StoreContainerType;\r
-import mir.storage.store.StoreIdentifier;\r
-import mir.storage.store.StoreUtil;\r
-\r
-/**\r
- *\r
- * Container class for lists of Entities.\r
- * Now implements @see mir.storage.store.StorableObject.\r
- *\r
- * @author <RK>\r
- * first version       27.6.1999\r
- *\r
- * @version 1.1 (cleaned up)\r
- */\r
-public class EntityList implements StorableObject {\r
-  protected static MirPropertiesConfiguration configuration;\r
-  protected LoggerWrapper logger;\r
-  private ArrayList           theEntityArrayList = new ArrayList();\r
-  private String              whereClause, orderClause;\r
-  private StorageObject       theStorage;\r
-  private int                 count, offset, limit;\r
-  private int                 offsetnext = -1, offsetprev = -1;\r
-\r
-  static {\r
-    try {\r
-      configuration = MirPropertiesConfiguration.instance();\r
-    }\r
-    catch (PropertiesConfigExc e) {\r
-      throw new RuntimeException("Unable to get configuration: " + e.getMessage());\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Constructor.\r
-   */\r
-  public EntityList(){\r
-    logger = new LoggerWrapper("Entity.List");\r
-  }\r
-\r
-/* get/set EntityClass of Objects stored in EntityList */\r
-  public void setStorage(StorageObject storage) { this.theStorage=storage; }\r
-  public StorageObject getStorage() { return theStorage; }\r
-\r
-  public void setLimit(int limit) { this.limit = limit; }\r
-\r
-  /**\r
-   * Sets the WHERE clause that fetched the Entities of this EntityList from the database.\r
-   * @param wc The string that contains the WHERE clause\r
-   */\r
-  public void setWhere(String wc) {\r
-    this.whereClause = wc;\r
-  }\r
-\r
-  /**\r
-   * Returns the WHERE clause that returned this EntityList from the database\r
-   * @return whereClause The WHERE clause\r
-   */\r
-  public String getWhere() {\r
-    return whereClause;\r
-  }\r
-\r
-\r
-  /**\r
-   * Sets the sorting criterium of this EntityList\r
-   * @param oc\r
-   */\r
-  public void setOrder(String oc) {\r
-    this.orderClause = oc;\r
-  }\r
-\r
-  /**\r
-   * Returns the sorting criterium.\r
-   * @return orderClause The sort order\r
-   */\r
-  public String getOrder() {\r
-    return orderClause;\r
-  }\r
-\r
-  /**\r
-   * Sets the number of rows that match the WHERE clause\r
-   * @param i The number of rows that match the WHERE clause\r
-   */\r
-  public void setCount(int i) {\r
-    this.count = i;\r
-  }\r
-\r
-  /**\r
-   * Returns the number of rows that match the WHERE clause\r
-   * @return The number of rows ...\r
-   */\r
-  public int getCount() {\r
-    return count;\r
-  }\r
-\r
-  /**\r
-   * Sets the offset\r
-   * @param i The offset\r
-   */\r
-  public void setOffset(int i) {\r
-    offset = i;\r
-  }\r
-\r
-  /**\r
-   * Returns the offset\r
-   * @return offset\r
-   */\r
-  public int getOffset() {\r
-    return offset;\r
-  }\r
-\r
-  /**\r
-   * Sets the offset of the next batch of Entities.\r
-   * @param i The next offset\r
-   */\r
-  public void setNextBatch(int i) {\r
-    offsetnext = i;\r
-  }\r
-\r
-  /**\r
-   * Returns the offset of the next batch of Entities.\r
-   * @return offset of the next batch\r
-   */\r
-  public int getNextBatch() {\r
-    return offsetnext;\r
-  }\r
-\r
-  /**\r
-   * Returns whether there is a next batch within the WHERE clause\r
-   * @return true if yes, false if no.\r
-   */\r
-  public boolean hasNextBatch() {\r
-    return (offsetnext >= 0);\r
-  }\r
-\r
-  /**\r
-   * Sets the offset of the previous batch.\r
-   * @param i the previous offset\r
-   */\r
-  public void setPrevBatch(int i) {\r
-    offsetprev = i;\r
-  }\r
-\r
-  /**\r
-   * Returns the offset of the previous batch.\r
-   * @return offset of the previous batch\r
-   */\r
-  public int getPrevBatch() {\r
-    return offsetprev;\r
-  }\r
-\r
-  /**\r
-   * Returns whether there is a previous batch.\r
-   * @return true if yes, false if no\r
-   */\r
-  public boolean hasPrevBatch() {\r
-    return (offsetprev >= 0);\r
-  }\r
-\r
-  /**\r
-   * Returns the start index of the batch.\r
-   * @return\r
-   */\r
-  public int getFrom() {\r
-    return offset+1;\r
-  }\r
-\r
-  /**\r
-   * Returns the end index of the batch.\r
-   * @return\r
-   */\r
-  public int getTo() {\r
-    if (hasNextBatch())\r
-      return offsetnext;\r
-    else\r
-      return count;\r
-  }\r
-\r
-  /**\r
-   * Inserts an Entity into the EntityList.\r
-   * @param anEntity The entity to be inserted.\r
-   */\r
-\r
-  public void add (Entity anEntity) {\r
-    if (anEntity!=null)\r
-      theEntityArrayList.add(anEntity);\r
-    else\r
-      logger.warn("EntityList: add called with empty Entity");\r
-  }\r
-\r
-\r
-  /**\r
-   * @return The number of Entities in the EntityList.\r
-   */\r
-\r
-  public int size() {\r
-    return theEntityArrayList.size();\r
-  }\r
-\r
-\r
-  /**\r
-   * Returns the element at position i in the EntityList as Entity\r
-   * @param i the position of the element in question\r
-   * @return The element at position i.\r
-   */\r
-\r
-  public Entity elementAt(int i) {\r
-    /** @todo check if i is in list.size() */\r
-    return (Entity)theEntityArrayList.get(i);\r
-  }\r
-\r
-\r
-\r
-// Methods to implement StorableObject\r
-\r
-  public Set getNotifyOnReleaseSet() { return null; }\r
-\r
-  public StoreIdentifier getStoreIdentifier() {\r
-    if ( theStorage!=null ) {\r
-      return\r
-      new StoreIdentifier( this, StoreContainerType.STOC_TYPE_ENTITYLIST,\r
-      StoreUtil.getEntityListUniqueIdentifierFor( theStorage.getTableName(),\r
-      whereClause, orderClause, offset, limit ));\r
-    }\r
-    logger.warn("EntityList could not return StoreIdentifier");\r
-    return null;\r
-  }\r
-\r
-}\r
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.entity;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+import mir.config.MirPropertiesConfiguration;
+import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;
+import mir.log.LoggerWrapper;
+import mir.storage.StorageObject;
+import mir.storage.store.StorableObject;
+import mir.storage.store.StoreContainerType;
+import mir.storage.store.StoreIdentifier;
+import mir.storage.store.StoreUtil;
+
+/**
+ *
+ * Container class for lists of Entities.
+ * Now implements @see mir.storage.store.StorableObject.
+ *
+ * @author <RK>
+ * first version       27.6.1999
+ *
+ * @version 1.1 (cleaned up)
+ */
+public class EntityList implements StorableObject {
+  protected static MirPropertiesConfiguration configuration  = MirPropertiesConfiguration.instance();
+  protected LoggerWrapper logger;
+  private ArrayList           theEntityArrayList = new ArrayList();
+  private String              whereClause, orderClause;
+  private StorageObject       theStorage;
+  private int                 count, offset, limit;
+  private int                 offsetnext = -1, offsetprev = -1;
+
+  public EntityList(){
+    logger = new LoggerWrapper("Entity.List");
+  }
+
+/* get/set EntityClass of Objects stored in EntityList */
+  public void setStorage(StorageObject storage) { this.theStorage=storage; }
+  public StorageObject getStorage() { return theStorage; }
+
+  public void setLimit(int limit) { this.limit = limit; }
+
+  /**
+   * Sets the WHERE clause that fetched the Entities of this EntityList from the database.
+   * @param wc The string that contains the WHERE clause
+   */
+  public void setWhere(String wc) {
+    this.whereClause = wc;
+  }
+
+  /**
+   * Returns the WHERE clause that returned this EntityList from the database
+   * @return whereClause The WHERE clause
+   */
+  public String getWhere() {
+    return whereClause;
+  }
+
+  /**
+   * Sets the sorting criterium of this EntityList
+   * @param oc
+   */
+  public void setOrder(String oc) {
+    this.orderClause = oc;
+  }
+
+  /**
+   * Returns the sorting criterium.
+   * @return orderClause The sort order
+   */
+  public String getOrder() {
+    return orderClause;
+  }
+
+  /**
+   * Sets the number of rows that match the WHERE clause
+   * @param i The number of rows that match the WHERE clause
+   */
+  public void setCount(int i) {
+    this.count = i;
+  }
+
+  /**
+   * Returns the number of rows that match the WHERE clause
+   * @return The number of rows ...
+   */
+  public int getCount() {
+    return count;
+  }
+
+  /**
+   * Sets the offset
+   * @param i The offset
+   */
+  public void setOffset(int i) {
+    offset = i;
+  }
+
+  /**
+   * Returns the offset
+   * @return offset
+   */
+  public int getOffset() {
+    return offset;
+  }
+
+  /**
+   * Sets the offset of the next batch of Entities.
+   * @param i The next offset
+   */
+  public void setNextBatch(int i) {
+    offsetnext = i;
+  }
+
+  /**
+   * Returns the offset of the next batch of Entities.
+   * @return offset of the next batch
+   */
+  public int getNextBatch() {
+    return offsetnext;
+  }
+
+  /**
+   * Returns whether there is a next batch within the WHERE clause
+   * @return true if yes, false if no.
+   */
+  public boolean hasNextBatch() {
+    return (offsetnext >= 0);
+  }
+
+  /**
+   * Sets the offset of the previous batch.
+   * @param i the previous offset
+   */
+  public void setPrevBatch(int i) {
+    offsetprev = i;
+  }
+
+  /**
+   * Returns the offset of the previous batch.
+   * @return offset of the previous batch
+   */
+  public int getPrevBatch() {
+    return offsetprev;
+  }
+
+  /**
+   * Returns whether there is a previous batch.
+   * @return true if yes, false if no
+   */
+  public boolean hasPrevBatch() {
+    return (offsetprev >= 0);
+  }
+
+  /**
+   * Returns the start index of the batch.
+   * @return
+   */
+  public int getFrom() {
+    return offset+1;
+  }
+
+  /**
+   * Returns the end index of the batch.
+   * @return
+   */
+  public int getTo() {
+    if (hasNextBatch())
+      return offsetnext;
+    else
+      return count;
+  }
+
+  /**
+   * Inserts an Entity into the EntityList.
+   * @param anEntity The entity to be inserted.
+   */
+
+  public void add (Entity anEntity) {
+    if (anEntity!=null)
+      theEntityArrayList.add(anEntity);
+    else
+      logger.warn("EntityList: add called with empty Entity");
+  }
+
+
+  /**
+   * @return The number of Entities in the EntityList.
+   */
+
+  public int size() {
+    return theEntityArrayList.size();
+  }
+
+
+  /**
+   * Returns the element at position i in the EntityList as Entity
+   * @param i the position of the element in question
+   * @return The element at position i.
+   */
+
+  public Entity elementAt(int i) {
+    /** todo check if i is in list.size() */
+    return (Entity) theEntityArrayList.get(i);
+  }
+
+
+
+// Methods to implement StorableObject
+
+  public Set getNotifyOnReleaseSet() { return null; }
+
+  public StoreIdentifier getStoreIdentifier() {
+    if ( theStorage!=null ) {
+      return
+      new StoreIdentifier( this, StoreContainerType.STOC_TYPE_ENTITYLIST,
+      StoreUtil.getEntityListUniqueIdentifierFor( theStorage.getTableName(),
+      whereClause, orderClause, offset, limit ));
+    }
+    logger.warn("EntityList could not return StoreIdentifier");
+    return null;
+  }
+
+}
index d5632e1..2a9f7b3 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.entity;
@@ -38,7 +38,7 @@ package mir.entity;
  * @author /rk
  * @version 1.2
  */
-public class GenericEntity extends Entity {}
+public class GenericEntity extends AbstractEntity {}
 
 
 
index 79dc3bd..b955d68 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.entity;
@@ -38,13 +38,16 @@ package mir.entity;
  * @version       1.0
  */
 
+import java.sql.ResultSet;
+import java.sql.SQLException;
 import java.util.Set;
 
+import mir.storage.Database;
 import mir.storage.store.StorableObject;
 import mir.storage.store.StoreIdentifier;
 
 
-public class StorableObjectEntity extends Entity
+public class StorableObjectEntity extends AbstractEntity
                implements StorableObject {
 
   /**
@@ -56,11 +59,34 @@ public class StorableObjectEntity extends Entity
    */
   public StoreIdentifier getStoreIdentifier() {
     String id = getId();
-    if ( id!=null && theStorageObject!= null )
-     return new StoreIdentifier(this, id+"@"+theStorageObject.getTableName());
+    if ( id!=null && storageObject!= null )
+     return new StoreIdentifier(this, id+"@"+storageObject.getTableName());
     return null;
   }
 
+  public static final StoreIdentifier getStoreIdentifier(
+     Class theEntityClass, String theTable, String id) {
+     if (id == null) {
+        return null;
+     } else {
+        return new StoreIdentifier(theEntityClass, id + "@" + theTable);
+     }
+  }
+
+  public static final StoreIdentifier getStoreIdentifier(Database theStorage,
+     Class theEntityClass, ResultSet rs) throws SQLException {
+
+        String idcol = theStorage.getIdName();
+        String idval = rs.getObject(idcol).toString();
+
+        if (idval != null) {
+           return getStoreIdentifier(theEntityClass,
+              theStorage.getTableName(), idval);
+        }
+
+     return null;
+  }
+
   /**
    *  Method:       getNotifyOnReleaseSet()
    *  Description:  returns empty Set, GenericContainer does not implement
index 42faf0b..ee997e2 100755 (executable)
@@ -32,6 +32,7 @@ package mir.entity.adapter;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -54,9 +55,8 @@ public class EntityAdapter implements Map {
   public boolean containsKey(Object aKey) {
     try {
       if (aKey instanceof String)
-        return     entity.hasValueForField((String) aKey)
-                || definition.hasCalculatedField((String) aKey)
-                || entity.getFields().contains(aKey);
+        return     entity.hasField((String) aKey)
+                || definition.hasCalculatedField((String) aKey);
     }
     catch (Throwable t) {
     }
@@ -94,7 +94,7 @@ public class EntityAdapter implements Map {
       return result;
     }
     else if (aKey instanceof String) {
-      return entity.getValue((String) aKey);
+      return entity.getFieldValue((String) aKey);
     }
     else {
       return null;
@@ -141,6 +141,22 @@ public class EntityAdapter implements Map {
     throw new UnsupportedOperationException("EntityAdapter.entrySet()");
   }
 
+  public Object getComplexRelation(String aMainTablePrefix, List someExtraTables,
+    String aWhereClause, String anOrderByClause, String aDefinition) {
+    try {
+      return
+          new CachingRewindableIterator(
+            new EntityIteratorAdapter(aMainTablePrefix, someExtraTables,
+                aWhereClause, anOrderByClause,
+                -1, getModel(), aDefinition, -1, 0)
+            );
+    }
+    catch (Throwable t) {
+      throw new RuntimeException(t.getMessage());
+    }
+  }
+
+
   public Object getRelation(String aWhereClause, String anOrderByClause, String aDefinition) {
     try {
       return
@@ -155,7 +171,7 @@ public class EntityAdapter implements Map {
 
   public EntityAdapter getToOneRelation(String aWhereClause, String anOrderByClause, String aDefinition) {
     try {
-      Iterator i = new EntityIteratorAdapter(aWhereClause, anOrderByClause, -1, getModel(), aDefinition);
+      Iterator i = new EntityIteratorAdapter(aWhereClause, anOrderByClause, 1, getModel(), aDefinition, 1, 0);
 
       if (i.hasNext())
         return (EntityAdapter) i.next();
@@ -166,4 +182,21 @@ public class EntityAdapter implements Map {
       throw new RuntimeException(t.getMessage());
     }
   }
+
+  public EntityAdapter getComplexToOneRelation(String aMainTablePrefix, List someExtraTables,
+                                               String aWhereClause, String anOrderByClause, String aDefinition) {
+    try {
+      Iterator i = new EntityIteratorAdapter(aMainTablePrefix, someExtraTables, aWhereClause, anOrderByClause, -1,
+          getModel(), aDefinition, 1, 0);
+
+      if (i.hasNext())
+        return (EntityAdapter) i.next();
+      else
+        return null;
+    }
+    catch (Throwable t) {
+      throw new RuntimeException(t.getMessage());
+    }
+  }
+
 }
\ No newline at end of file
index 68cdf2f..571df52 100755 (executable)
  */
 package mir.entity.adapter;
 
-import java.util.Calendar;\r
-import java.util.Date;\r
-import java.util.GregorianCalendar;\r
-import java.util.HashMap;\r
-import java.util.Map;\r
-import java.util.TimeZone;\r
-\r
-import mir.entity.Entity;\r
-import mir.misc.StringUtil;\r
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+import mir.entity.Entity;
+import mir.misc.StringUtil;
 import mir.util.GeneratorFormatAdapters;
 
+/**
+ * <code>EntityAdapterDefinition</code> defines the fields for an entity adapter of
+ *  a particular "type". Custom calculated fields can be defined.
+ *
+ */
 public class EntityAdapterDefinition {
   private Map calculatedFields;
 
@@ -47,31 +52,76 @@ public class EntityAdapterDefinition {
     calculatedFields = new HashMap();
   }
 
+  /**
+   *
+   *
+   * @param anEntity the entity that will be wrapped by the entity adapter
+   * @param aModel the base model
+   * @return the resulting entity adapter
+   */
   public EntityAdapter makeEntityAdapter(Entity anEntity, EntityAdapterModel aModel) {
     return new EntityAdapter(anEntity, this, aModel);
   }
 
+  /**
+   *
+   * @param aFieldName
+   * @return the <code>CalculatedField</code> if it exists. <code>null</code> otherwise
+   */
   public CalculatedField getCalculatedField(String aFieldName) {
     return (CalculatedField) calculatedFields.get(aFieldName);
   }
 
+  /**
+   *
+   * @param aFieldName
+   * @return
+   */
   public boolean hasCalculatedField(String aFieldName) {
     return calculatedFields.containsKey(aFieldName);
   }
 
+  /**
+   *
+   * @param aFieldName
+   * @param aField
+   */
   public void addCalculatedField(String aFieldName, CalculatedField aField) {
     calculatedFields.put(aFieldName, aField);
   }
 
+  /**
+   * To add a calculated field based on a "mir" date field: a string field of the form yyyyMMdd[hhmm]
+   *
+   * @param aDestinationFieldName
+   * @param aSourceFieldName
+   * @param aDefaultTimezone
+   */
   public void addMirDateField(String aDestinationFieldName, String aSourceFieldName, String aDefaultTimezone) {
     addCalculatedField(aDestinationFieldName, new MirDateField(aSourceFieldName, aDefaultTimezone));
   }
 
+  /**
+   * Adds a calculated field based on a db date field
+   *
+   * @param aDestinationFieldName the field name of the calculated field
+   * @param aSourceFieldName the field name of the entity (must be a date field)
+   * @param aDefaultTimezone the default timezone to use
+   */
   public void addDBDateField(String aDestinationFieldName, String aSourceFieldName, String aDefaultTimezone) {
     addCalculatedField(aDestinationFieldName, new DBDateField(aSourceFieldName, aDefaultTimezone));
   }
 
+  /**
+   * a calculated field: field gets its value from other fields.
+   */
   public interface CalculatedField {
+    /**
+     * Method to retrieve the calculated value of the field.
+     *
+     * @param anEntityAdapter the entity
+     * @return the value of the field.
+     */
     public Object getValue(EntityAdapter anEntityAdapter);
   }
 
@@ -87,7 +137,7 @@ public class EntityAdapterDefinition {
     public Object getValue(EntityAdapter anEntityAdapter) {
 
          Object result = null;
-         String textValue = anEntityAdapter.getEntity().getValue(fieldName);
+         String textValue = anEntityAdapter.getEntity().getFieldValue(fieldName);
          Calendar calendar = GregorianCalendar.getInstance();
          int year;
          int month;
@@ -126,7 +176,7 @@ public class EntityAdapterDefinition {
 
     public Object getValue(EntityAdapter anEntityAdapter) {
       Object result = null;
-      String text = anEntityAdapter.getEntity().getValue(fieldName);
+      String text = anEntityAdapter.getEntity().getFieldValue(fieldName);
 
       if (text!=null) {
         try {
index 4237c27..2ef7c69 100755 (executable)
@@ -1,71 +1,71 @@
-/*\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  any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two.  You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries.  If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-\r
-package mir.entity.adapter;\r
-\r
-import java.util.List;\r
-\r
-import mir.entity.EntityBrowser;\r
-import mir.storage.*;\r
-\r
-/**\r
- * <p>Title: </p>\r
- * <p>Description: </p>\r
- * <p>Copyright: Copyright (c) 2003</p>\r
- * <p>Company: </p>\r
- * @author not attributable\r
- * @version 1.0\r
- */\r
-\r
-public class EntityAdapterEngine {\r
-  private EntityAdapterEngine() {\r
-  }\r
-\r
-  /**\r
-   *\r
-   * @param aStorage\r
-   * @param aDefinition\r
-   * @param aQualifier\r
-   * @param anOrder\r
-   * @param aLimit\r
-   * @param anOffset\r
-   * @return\r
-   */\r
-  static public List retrieveAdapterList(EntityAdapterModel aModel, String aDefinition, String aQualifier, String anOrder, int aLimit, int anOffset) {\r
-    try {\r
-      EntityBrowser browser = new EntityBrowser(aModel.getMappingForName(aDefinition).getStorage(), aQualifier, anOrder, 30, aLimit, anOffset);\r
-\r
-      return new EntityListAdapter(aModel, aDefinition, browser, aLimit);\r
-    }\r
-    catch (Throwable t) {\r
-      throw new StorageObjectFailure(t);\r
-    }\r
-  }\r
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.entity.adapter;
+
+import java.util.List;
+
+import mir.entity.EntityBrowser;
+import mir.storage.StorageObjectFailure;
+
+/**
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2003</p>
+ * <p>Company: </p>
+ * @author not attributable
+ * @version 1.0
+ */
+
+public class EntityAdapterEngine {
+  private EntityAdapterEngine() {
+  }
+
+  /**
+   *
+   * @param aStorage
+   * @param aDefinition
+   * @param aQualifier
+   * @param anOrder
+   * @param aLimit
+   * @param anOffset
+   * @return
+   */
+  static public List retrieveAdapterList(EntityAdapterModel aModel, String aDefinition, String aQualifier, String anOrder, int aLimit, int anOffset) {
+    try {
+      EntityBrowser browser = new EntityBrowser(aModel.getMappingForName(aDefinition).getStorage(), aQualifier, anOrder, 30, aLimit, anOffset);
+
+      return new EntityListAdapter(aModel, aDefinition, browser, aLimit);
+    }
+    catch (Throwable t) {
+      throw new StorageObjectFailure(t);
+    }
+  }
 }
\ No newline at end of file
index 0b29d42..dfa9ae7 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.entity.adapter;
 
+import java.util.List;
+
 import mir.entity.Entity;
 import mir.entity.EntityBrowser;
 import mir.storage.StorageObjectFailure;
@@ -57,6 +59,14 @@ public class EntityIteratorAdapter implements RewindableIterator {
     this(new EntityBrowser(aModel.getMappingForName(aDefinitionName).getStorage(), aWhereClause, anOrderByClause, aBatchSize, aLimit, aSkip), aModel, aDefinitionName);
   }
 
+  public EntityIteratorAdapter(String aMainTablePrefix, List someExtraTables,
+          String aWhereClause, String anOrderByClause,
+          int aBatchSize, EntityAdapterModel aModel, String aDefinitionName,
+          int aLimit, int aSkip) throws StorageObjectFailure, EntityAdapterExc {
+    this(new EntityBrowser(aModel.getMappingForName(aDefinitionName).getStorage(), aMainTablePrefix, someExtraTables, aWhereClause, anOrderByClause, aBatchSize, aLimit, aSkip), aModel, aDefinitionName);
+  }
+
+
   public boolean hasNext() {
     return iterator.hasNext();
   }
index f7ae65d..19f37be 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  any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two.  You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries.  If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-package mir.entity.adapter;\r
-\r
-import java.util.AbstractList;\r
-import java.util.List;\r
-import java.util.Vector;\r
-\r
-import mir.entity.Entity;\r
-import mir.entity.EntityBrowser;\r
-\r
-public class EntityListAdapter extends AbstractList {\r
-  private int skip;\r
-  private int maximumLength;\r
-  private EntityBrowser browser;\r
-  private EntityAdapterModel model;\r
-  private String definition;\r
-  private boolean exhausted = false;\r
-  private boolean skipped = false;\r
-\r
-  private List cache;\r
-\r
-  protected EntityListAdapter(EntityAdapterModel aModel, String aDefinition, EntityBrowser aBrowser, int aSkip, int aMaximumLength) {\r
-    model = aModel;\r
-    definition = aDefinition;\r
-    browser = aBrowser;\r
-    skip = aSkip;\r
-    maximumLength = aMaximumLength;\r
-    cache = new Vector();\r
-  }\r
-\r
-  protected EntityListAdapter(EntityAdapterModel aModel, String aDefinition, EntityBrowser aBrowser, int aMaximumLength) {\r
-    this(aModel, aDefinition, aBrowser, 0, aMaximumLength);\r
-  }\r
-\r
-  protected EntityListAdapter(EntityAdapterModel aModel, String  aDefinition, EntityBrowser aBrowser) {\r
-    this(aModel, aDefinition, aBrowser, 0, -1);\r
-  }\r
-\r
-  private void skip() {\r
-    int i;\r
-\r
-    try {\r
-      if (!skipped) {\r
-        for(i=0; i<skip; i++)\r
-          if (browser.hasNext())\r
-            browser.next();\r
-      }\r
-      skipped=true;\r
-    }\r
-    catch (Throwable t) {\r
-      throw new RuntimeException(t.getMessage());\r
-    }\r
-  }\r
-\r
-  private void fetchNext() {\r
-    try {\r
-      if (!exhausted) {\r
-        if (browser.hasNext())\r
-          cache.add(model.makeEntityAdapter(definition, (Entity) browser.next()));\r
-\r
-        exhausted = !browser.hasNext() || (maximumLength>0 && cache.size()>=maximumLength) ;\r
-      }\r
-    }\r
-    catch (Throwable t) {\r
-      throw new RuntimeException(t.getMessage());\r
-    }\r
-\r
-  }\r
-\r
-  private void exhaust() {\r
-    skip();\r
-\r
-    while (!exhausted)\r
-      fetchNext();\r
-  }\r
-\r
-  private void fetchUntil(int anIndex) {\r
-    skip();\r
-\r
-    while (!exhausted && anIndex>=cache.size())\r
-      fetchNext();\r
-  }\r
-\r
-  public int size() {\r
-    exhaust();\r
-\r
-    return cache.size();\r
-  }\r
-\r
-  public Object get(int anIndex) {\r
-    fetchUntil(anIndex);\r
-    return cache.get(anIndex);\r
-  }\r
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.entity.adapter;
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.List;
+
+import mir.entity.Entity;
+import mir.entity.EntityBrowser;
+
+public class EntityListAdapter extends AbstractList {
+  private int skip;
+  private int maximumLength;
+  private EntityBrowser browser;
+  private EntityAdapterModel model;
+  private String definition;
+  private boolean exhausted = false;
+  private boolean skipped = false;
+
+  private List cache;
+
+  protected EntityListAdapter(EntityAdapterModel aModel, String aDefinition, EntityBrowser aBrowser, int aSkip, int aMaximumLength) {
+    model = aModel;
+    definition = aDefinition;
+    browser = aBrowser;
+    skip = aSkip;
+    maximumLength = aMaximumLength;
+    cache = new ArrayList();
+  }
+
+  protected EntityListAdapter(EntityAdapterModel aModel, String aDefinition, EntityBrowser aBrowser, int aMaximumLength) {
+    this(aModel, aDefinition, aBrowser, 0, aMaximumLength);
+  }
+
+  protected EntityListAdapter(EntityAdapterModel aModel, String  aDefinition, EntityBrowser aBrowser) {
+    this(aModel, aDefinition, aBrowser, 0, -1);
+  }
+
+  private void skip() {
+    int i;
+
+    try {
+      if (!skipped) {
+        for(i=0; i<skip; i++)
+          if (browser.hasNext())
+            browser.next();
+      }
+      skipped=true;
+    }
+    catch (Throwable t) {
+      throw new RuntimeException(t.getMessage());
+    }
+  }
+
+  private void fetchNext() {
+    try {
+      if (!exhausted) {
+        if (browser.hasNext())
+          cache.add(model.makeEntityAdapter(definition, (Entity) browser.next()));
+
+        exhausted = !browser.hasNext() || (maximumLength>0 && cache.size()>=maximumLength) ;
+      }
+    }
+    catch (Throwable t) {
+      throw new RuntimeException(t.getMessage());
+    }
+
+  }
+
+  private void exhaust() {
+    skip();
+
+    while (!exhausted)
+      fetchNext();
+  }
+
+  private void fetchUntil(int anIndex) {
+    skip();
+
+    while (!exhausted && anIndex>=cache.size())
+      fetchNext();
+  }
+
+  public int size() {
+    exhaust();
+
+    return cache.size();
+  }
+
+  public Object get(int anIndex) {
+    fetchUntil(anIndex);
+    return cache.get(anIndex);
+  }
 }
\ No newline at end of file
index d1c5651..324363f 100755 (executable)
@@ -32,16 +32,16 @@ package mir.generator;
 import java.util.HashMap;
 import java.util.Map;
 
-public class CompositeGeneratorLibrary implements Generator.GeneratorLibrary {
+public class CompositeGeneratorLibrary implements Generator.Library {
   private Map generatorLibraries;
-  private Generator.GeneratorLibrary defaultLibrary = null;
+  private Generator.Library defaultLibrary = null;
   private static String LIBRARY_QUALIFIER_SEPARATOR = "::";
 
   public CompositeGeneratorLibrary() {
     generatorLibraries = new HashMap();
   }
 
-  public void addLibrary(String aQualifier, Generator.GeneratorLibrary aLibrary, boolean anIsDefault) {
+  public void addLibrary(String aQualifier, Generator.Library aLibrary, boolean anIsDefault) {
     if (anIsDefault || defaultLibrary == null) {
       defaultLibrary = aLibrary;
     }
@@ -53,14 +53,14 @@ public class CompositeGeneratorLibrary implements Generator.GeneratorLibrary {
     String qualifier;
     String libraryName;
     int position;
-    Generator.GeneratorLibrary library;
+    Generator.Library library;
 
     position = anIdentifier.indexOf( LIBRARY_QUALIFIER_SEPARATOR );
     if (position>=0) {
       libraryName = anIdentifier.substring(0, position);
       qualifier = anIdentifier.substring(position + LIBRARY_QUALIFIER_SEPARATOR.length());
 
-      library = (Generator.GeneratorLibrary) generatorLibraries.get(libraryName);
+      library = (Generator.Library) generatorLibraries.get(libraryName);
       if (library==null)
         throw new GeneratorExc("CompositeGeneratorLibrary: library '"+libraryName+"' not found");
 
index a786a71..d4a4ee7 100755 (executable)
 package mir.generator;
 
 import java.io.PrintWriter;
-import java.util.Arrays;
+import java.io.File;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Vector;
-
-import mir.log.LoggerWrapper;
-import mir.util.GeneratorFormatAdapters;
-import mir.util.RewindableIterator;
-
-import org.apache.commons.beanutils.MethodUtils;
-import org.apache.commons.beanutils.PropertyUtils;
 
 import freemarker.template.FileTemplateCache;
 import freemarker.template.SimpleScalar;
@@ -55,6 +48,11 @@ import freemarker.template.TemplateModel;
 import freemarker.template.TemplateModelException;
 import freemarker.template.TemplateModelRoot;
 import freemarker.template.TemplateScalarModel;
+import mir.log.LoggerWrapper;
+import mir.util.GeneratorFormatAdapters;
+import mir.util.RewindableIterator;
+import org.apache.commons.beanutils.MethodUtils;
+import org.apache.commons.beanutils.PropertyUtils;
 
 
 public class FreemarkerGenerator implements Generator {
@@ -91,7 +89,7 @@ public class FreemarkerGenerator implements Generator {
     return new IteratorAdapter(anIterator);
   }
 
-  private static TemplateMethodModel makeFunctionAdapter(Generator.GeneratorFunction aFunction) {
+  private static TemplateMethodModel makeFunctionAdapter(Generator.Function aFunction) {
     return new FunctionAdapter(aFunction);
   }
 
@@ -102,12 +100,13 @@ public class FreemarkerGenerator implements Generator {
   public static TemplateModel makeAdapter(Object anObject) throws TemplateModelException {
     if (anObject == null)
       return null;
+
     if (anObject instanceof TemplateModel)
       return (TemplateModel) anObject;
-    else if (anObject instanceof Generator.GeneratorFunction)
-      return makeFunctionAdapter((Generator.GeneratorFunction) anObject);
+    else if (anObject instanceof Generator.Function)
+      return makeFunctionAdapter((Generator.Function) anObject);
     else if (anObject instanceof Integer)
-      return makeStringAdapter(((Integer) anObject).toString());
+      return makeStringAdapter(anObject.toString());
     else if (anObject instanceof Boolean) {
       if (((Boolean) anObject).booleanValue())
         return makeStringAdapter("1");
@@ -122,14 +121,6 @@ public class FreemarkerGenerator implements Generator {
       return makeIteratorAdapter((Iterator) anObject);
     else if (anObject instanceof List)
       return makeIteratorAdapter(((List) anObject).iterator());
-               else if (anObject instanceof Object[]){
-                       if(((Object[])anObject).length <= 1){
-                               Object[] array = (Object[]) anObject;                           
-                               return makeAdapter(array[0]);
-                       } else {
-                               return makeIteratorAdapter(Arrays.asList((Object[]) anObject).iterator());                              
-                       }
-               }
     else if (anObject instanceof Number)
       return makeAdapter(new GeneratorFormatAdapters.NumberFormatAdapter((Number) anObject));
     else if (anObject instanceof Date)
@@ -189,7 +180,7 @@ public class FreemarkerGenerator implements Generator {
     private IteratorAdapter(Iterator anIterator) {
       iterator = anIterator;
 
-      valuesCache = new Vector();
+      valuesCache = new ArrayList();
       position=0;
 
 
@@ -257,7 +248,7 @@ public class FreemarkerGenerator implements Generator {
 
     private ListAdapter(List aList) {
       list = aList;
-      valuesCache = new Vector();
+      valuesCache = new ArrayList();
       position=0;
     }
 
@@ -307,9 +298,9 @@ public class FreemarkerGenerator implements Generator {
   }
 
   private static class FunctionAdapter implements TemplateMethodModel {
-    private Generator.GeneratorFunction function;
+    private Generator.Function function;
 
-    public FunctionAdapter(Generator.GeneratorFunction aFunction) {
+    public FunctionAdapter(Generator.Function aFunction) {
       function = aFunction;
     }
 
@@ -360,11 +351,11 @@ public class FreemarkerGenerator implements Generator {
     }
   }
 
-  public static class FreemarkerGeneratorLibrary implements GeneratorLibrary {
+  public static class FreemarkerGeneratorLibrary implements Library {
     private FileTemplateCache templateCache;
 
-    public FreemarkerGeneratorLibrary(String aTemplateRoot) {
-      templateCache = new FileTemplateCache( aTemplateRoot+"/" );
+    public FreemarkerGeneratorLibrary(File aTemplateRoot) {
+      templateCache = new FileTemplateCache(aTemplateRoot);
       templateCache.setLoadingPolicy(FileTemplateCache.LOAD_ON_DEMAND);
     }
 
@@ -372,22 +363,23 @@ public class FreemarkerGenerator implements Generator {
       Template template = (Template) templateCache.getItem(anIdentifier, "template");
 
       if (template==null) {
-        throw new GeneratorExc("FreemarkerGeneratorLibrary: Can't find template "+templateCache.getDirectory()+anIdentifier);
+        throw new GeneratorExc("FreemarkerGeneratorLibrary: Can't find template "+templateCache.getDirectory()+"/"+anIdentifier);
       }
 
       return new FreemarkerGenerator(template);
     }
   }
 
-  public static class FreemarkerGeneratorLibraryFactory implements GeneratorLibraryFactory {
-    private String basePath;
+  public static class FreemarkerGeneratorLibraryFactory implements LibraryFactory {
+    private File basePath;
 
-    public FreemarkerGeneratorLibraryFactory(String aBasePath) {
+    public FreemarkerGeneratorLibraryFactory(File aBasePath) {
       basePath = aBasePath;
     }
 
-    public GeneratorLibrary makeLibrary(String anInitializationString) {
-      return new FreemarkerGeneratorLibrary(basePath+anInitializationString);
+    public Library makeLibrary(String anInitializationString) {
+      // todo: the initialization string should be parsed
+      return new FreemarkerGeneratorLibrary(new File(basePath, anInitializationString));
     };
   }
 }
index 3f10ca7..805d0cc 100755 (executable)
 
 package mir.generator;
 
-import java.io.*;
+import java.io.PrintWriter;
+import java.io.Reader;
 import java.util.List;
 import java.util.Map;
 
 import mir.log.LoggerWrapper;
 
+/**
+ * Interface representing a "generator", typically a template engine/
+ */
 public interface Generator {
   public void generate(Object anOutputWriter, Map aValues, LoggerWrapper aLogger) throws GeneratorExc, GeneratorFailure;
 
-  public static interface GeneratorLibrary {
+  public static interface Library {
     public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure;
   }
 
-  public static interface GeneratorLibraryFactory {
-    public GeneratorLibrary makeLibrary(String anInitializationString);
+  public static interface LibraryFactory {
+    public Library makeLibrary(String anInitializationString) throws GeneratorExc, GeneratorFailure ;
   }
 
-  public static interface GeneratorFunction {
+  /** interface for a generator implementation independent function */
+  public static interface Function {
+    /** performs the function with the given parameters */
     public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure;
   }
 
-  public static interface GeneratorTransformer {
+  public static interface Transformer {
     public void perform(Reader aSource, PrintWriter anOutput) throws GeneratorExc, GeneratorFailure;
   }
 }
diff --git a/source/mir/generator/GeneratorHelper.java b/source/mir/generator/GeneratorHelper.java
new file mode 100755 (executable)
index 0000000..298723d
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
+
+import mir.entity.adapter.EntityIteratorAdapter;
+import mir.util.CachingRewindableIterator;
+import mir.bundle.Bundle;
+import mir.util.generator.BundleGeneratorFunction;
+import mircoders.global.MirGlobal;
+
+
+
+public class GeneratorHelper {
+  /**
+   * Method to initialize the basic generation values for templates.  Does nothing which assumes a servlet context.
+   */
+
+  public static Map makeBasicGenerationData(Locale[] aLocales, String aBundle, String aDefaultBundle) throws GeneratorExc{
+    try {
+      Map result = new HashMap();
+      MirGlobal.localizer().producerAssistant().initializeGenerationValueSet(result);
+
+      Object languages = new CachingRewindableIterator(new EntityIteratorAdapter("", "id", 30, MirGlobal.localizer().dataModel().adapterModel(), "language"));
+
+      Object topics = new CachingRewindableIterator(new EntityIteratorAdapter("", "id", 30, MirGlobal.localizer().dataModel().adapterModel(), "topic"));
+
+      Object articleTypes = new CachingRewindableIterator(new EntityIteratorAdapter("", "id", 30, MirGlobal.localizer().dataModel().adapterModel(), "articleType"));
+
+      Object commentStatuses = new CachingRewindableIterator(new EntityIteratorAdapter("", "id", 30, MirGlobal.localizer().dataModel().adapterModel(), "commentStatus"));
+
+      result.put("commentstatuses", commentStatuses);
+      result.put("articletypes", articleTypes);
+      result.put("languages", languages);
+      result.put("topics", topics);
+
+      List bundles = new ArrayList();
+      for (int i=0; i<aLocales.length; i++) {
+        bundles.add(MirGlobal.getBundleFactory().getBundle(aBundle, new String[] { aLocales[i].getLanguage()} ));
+        bundles.add(MirGlobal.getBundleFactory().getBundle(aDefaultBundle, new String[] { aLocales[i].getLanguage()} ));
+      }
+      result.put("lang", new BundleGeneratorFunction((Bundle[]) bundles.toArray(new Bundle[0])));
+
+      return result;
+    }
+    catch (Throwable t) {
+      throw new GeneratorFailure(t);
+    }
+  }
+}
index 3f19fc0..7ee9630 100755 (executable)
@@ -44,15 +44,15 @@ public class GeneratorLibraryRepository {
     logger = new LoggerWrapper("Generator");
   }
 
-  public void registerLibraryFactory(String aName, Generator.GeneratorLibraryFactory aFactory) {
+  public void registerLibraryFactory(String aName, Generator.LibraryFactory aFactory) {
     factories.put(aName, aFactory);
   }
 
-  public Generator.GeneratorLibrary constructLibrary(String aName, String aParameters) throws GeneratorExc {
+  public Generator.Library constructLibrary(String aName, String aParameters) throws GeneratorExc {
     if (!factories.containsKey(aName))
       throw new GeneratorExc("Unknown library factory: "+aName);
 
-    return ((Generator.GeneratorLibraryFactory) factories.get(aName)).makeLibrary(aParameters);
+    return ((Generator.LibraryFactory) factories.get(aName)).makeLibrary(aParameters);
   }
 
   private final static String SPACE = "[\t\n\r ]*";
@@ -63,39 +63,40 @@ public class GeneratorLibraryRepository {
   private final static String FACTORY_PARAMETERS = "[^)]*";
   private final static String SEMICOLON = ";";
 
-  public Generator.GeneratorLibrary constructCompositeLibrary(String aSpecification) throws GeneratorExc, GeneratorFailure {
+  public Generator.Library constructCompositeLibrary(String aSpecification[]) throws GeneratorExc, GeneratorFailure {
     String identifier;
     String factory;
     String factoryParameters;
     CompositeGeneratorLibrary result = new CompositeGeneratorLibrary();
     boolean first=true;
 
-    SimpleParser parser = new SimpleParser(aSpecification);
-    try {
-      parser.skip(SPACE);
-      while (!parser.isAtEnd()) {
-        identifier = parser.parse(IDENTIFIER, "library key expected");
+    for (int i=0; i<aSpecification.length; i++) {
+      SimpleParser parser = new SimpleParser(aSpecification[i]);
+      try {
         parser.skip(SPACE);
-        parser.parse(EQUALS, "'=' expected");
-        parser.skip(SPACE);
-        factory = parser.parse(IDENTIFIER, "factory name expected");
-        parser.skip(SPACE);
-        parser.parse(LEFT_PARENTHESIS, "'(' expected");
-        factoryParameters = parser.parse(FACTORY_PARAMETERS, "parameters expected");
-        parser.parse(RIGHT_PARENTHESIS, "')' expected");
+        while (!parser.isAtEnd()) {
+          identifier = parser.parse(IDENTIFIER, "library key expected");
+          parser.skip(SPACE);
+          parser.parse(EQUALS, "'=' expected");
+          parser.skip(SPACE);
+          factory = parser.parse(IDENTIFIER, "factory name expected");
+          parser.skip(SPACE);
+          parser.parse(LEFT_PARENTHESIS, "'(' expected");
+          factoryParameters = parser.parse(FACTORY_PARAMETERS, "parameters expected");
+          parser.parse(RIGHT_PARENTHESIS, "')' expected");
 
-        result.addLibrary(identifier, constructLibrary(factory, factoryParameters), first);
-        first=false;
-        parser.skip(SPACE);
+          result.addLibrary(identifier, constructLibrary(factory, factoryParameters), first);
+          first=false;
+          parser.skip(SPACE);
 
-        if (!parser.isAtEnd()) {
-          parser.parse(SEMICOLON, "; expected");
+          if (!parser.isAtEnd()) {
+            parser.parse(SEMICOLON, "; expected");
+          }
         }
       }
-    }
-    catch (Exception e) {
-      e.printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
-      throw new GeneratorFailure("Failed to construct generator library: " + e.getMessage(), e);
+      catch (Exception e) {
+        throw new GeneratorFailure("Failed to construct generator library: " + e.getMessage(), e);
+      }
     }
 
     return result;
diff --git a/source/mir/generator/TALGenerator.java b/source/mir/generator/TALGenerator.java
new file mode 100755 (executable)
index 0000000..210267a
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator;
+
+import java.io.PrintWriter;
+import java.io.File;
+import java.util.Map;
+
+import mir.generator.tal.MirExpressionParser;
+import mir.generator.tal.template.Template;
+import mir.generator.tal.TALTemplateEngine;
+import mir.generator.tal.interfaces.TALLogger;
+import mir.log.LoggerWrapper;
+
+public class TALGenerator implements Generator {
+  private String templateIdentifier;
+  private TALGeneratorLibrary library;
+
+  public TALGenerator(String aTemplate, TALGeneratorLibrary aLibrary) {
+    templateIdentifier = aTemplate;
+    library = aLibrary;
+  }
+
+  public void generate(Object anOutputWriter, Map aValues, final LoggerWrapper aLogger) throws GeneratorExc, GeneratorFailure {
+    Template template;
+
+    try {
+      template = library.engine.loadTemplate(templateIdentifier);
+
+      if (template == null) {
+        throw new GeneratorExc("TALGeneratorLibrary: Can't find template " + templateIdentifier);
+      }
+
+      template.process(aValues, (PrintWriter) anOutputWriter,
+          new TALLogger() {
+            public void debug(String anObject, String aMessage) {
+              aLogger.debug(anObject + ": " + aMessage);
+            }
+
+            public void info(String anObject, String aMessage) {
+              aLogger.info(anObject + ": " + aMessage);
+            }
+
+            public void warning(String anObject, String aMessage) {
+              aLogger.warn(anObject + ": " + aMessage);
+            }
+
+            public void error(String anObject, String aMessage) {
+              aLogger.error(anObject + ": " + aMessage);
+            }
+
+            public void fatal(String anObject, String aMessage) {
+              aLogger.fatal(anObject + ": " + aMessage);
+            }
+          },
+          library.engine);
+        }
+    catch (Throwable t) {
+      ((PrintWriter) anOutputWriter).println("ERROR: " + t.toString());
+
+      throw new GeneratorFailure(t);
+    }
+  }
+
+  public static class TALGeneratorLibrary implements Library {
+    private TALTemplateEngine engine;
+
+    public TALGeneratorLibrary(File aTemplateRoot) throws GeneratorExc, GeneratorFailure {
+      engine = new TALTemplateEngine(new MirExpressionParser(), aTemplateRoot);
+    }
+
+    public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {
+      return new TALGenerator(anIdentifier, this);
+    }
+  }
+
+  public static class TALGeneratorLibraryFactory implements LibraryFactory {
+    private File basePath;
+
+    public TALGeneratorLibraryFactory(File aBasePath) {
+      basePath = aBasePath;
+    }
+
+    public Library makeLibrary(String anInitializationString) throws GeneratorExc, GeneratorFailure {
+      return new TALGeneratorLibrary(new File(basePath, anInitializationString));
+    };
+  }
+}
diff --git a/source/mir/generator/VelocityGenerator.java b/source/mir/generator/VelocityGenerator.java
new file mode 100755 (executable)
index 0000000..1735701
--- /dev/null
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.File;
+import java.util.AbstractList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.commons.beanutils.MethodUtils;
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.velocity.Template;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.log.LogSystem;
+import mir.log.LoggerWrapper;
+import mir.util.GeneratorFormatAdapters;
+import mir.util.RewindableIterator;
+
+public class VelocityGenerator implements Generator {
+  private String templateIdentifier;
+  private VelocityGeneratorLibrary library;
+  private static LoggerWrapper logger = new LoggerWrapper("Generator.velocity");
+
+  /**
+   *
+   * @param aTemplate
+   * @param aLibrary
+   */
+
+  public VelocityGenerator(String aTemplate, VelocityGeneratorLibrary aLibrary) {
+    templateIdentifier = aTemplate;
+    library = aLibrary;
+  }
+
+  /**
+   *
+   * @param anOutputWriter
+   * @param aValues
+   * @param aLogger
+   * @throws GeneratorExc
+   * @throws GeneratorFailure
+   */
+  public void generate(Object anOutputWriter, Map aValues, LoggerWrapper aLogger) throws GeneratorExc, GeneratorFailure {
+    Template template;
+    Context context = makeMapAdapter(aValues);
+    StringWriter stringWriter = new StringWriter();
+
+    try {
+      template = library.engine.getTemplate(templateIdentifier);
+      if (template == null) {
+        throw new GeneratorExc("VelocityGeneratorLibrary: Can't find template " + templateIdentifier);
+      }
+      template.merge(context, stringWriter);
+
+      ( (PrintWriter) anOutputWriter).print(stringWriter.toString());
+    }
+    catch (ResourceNotFoundException t) {
+      throw new GeneratorExc("VelocityGeneratorLibrary: Can't find template " + templateIdentifier);
+    }
+    catch (ParseErrorException t) {
+      ( (PrintWriter) anOutputWriter).print(t.toString());
+    }
+    catch (Throwable t) {
+      throw new GeneratorFailure(t);
+    }
+
+  }
+
+  /**
+   *
+   * @param aMap
+   * @return
+   */
+  private static Context makeMapAdapter(Map aMap)  {
+    return new MapAdapter(aMap);
+  }
+
+  /**
+   *
+   * @param anIterator
+   * @return
+   */
+  private static List makeIteratorAdapter(Iterator anIterator) {
+    return new IteratorAdapter(anIterator);
+  }
+
+  /**
+   *
+   * @param aList
+   * @return
+   */
+  private static List makeListAdapter(List aList) {
+    return new ListAdapter(aList);
+  }
+
+  /**
+   *
+   * @param aFunction
+   * @return
+   */
+  private static Object makeFunctionAdapter(Generator.Function aFunction) {
+    return new FunctionAdapter(aFunction);
+  }
+
+  /**
+   *
+   * @param anObject
+   * @return
+   */
+  private static Object makeBeanAdapter(Object anObject)  {
+    return new BeanAdapter(anObject);
+  }
+
+  /**
+   *
+   * <p>Title: </p>
+   * <p>Description: </p>
+   * <p>Copyright: Copyright (c) 2003</p>
+   * <p>Company: </p>
+   * @author not attributable
+   * @version 1.0
+   */
+  private interface VelocityAdapter {
+    public Object getOriginal();
+  }
+
+  /**
+   *
+   * @param anObject
+   * @return
+   */
+  public static Object unmakeAdapter(Object anObject) {
+    if (anObject instanceof VelocityAdapter) {
+      return ((VelocityAdapter) anObject).getOriginal();
+    }
+    else
+      return anObject;
+  }
+
+  /**
+   *
+   * @param anObject
+   * @return
+   */
+  public static Object makeAdapter(Object anObject) {
+    if (anObject == null)
+      return null;
+
+    if (anObject instanceof Context)
+      return anObject;
+
+    else if (anObject instanceof Generator.Function)
+      return makeFunctionAdapter((Generator.Function) anObject);
+    else if (anObject instanceof Integer)
+      return anObject;
+    else if (anObject instanceof Boolean)
+      return anObject;
+    else if (anObject instanceof String)
+      return anObject;
+    else if (anObject instanceof Map)
+      return makeMapAdapter((Map) anObject);
+    else if (anObject instanceof Iterator)
+      return makeIteratorAdapter((Iterator) anObject);
+    else if (anObject instanceof List)
+      return makeListAdapter(((List) anObject));
+    else if (anObject instanceof Number)
+      return makeAdapter(new GeneratorFormatAdapters.NumberFormatAdapter((Number) anObject));
+    else if (anObject instanceof Date)
+      return makeAdapter(new GeneratorFormatAdapters.DateFormatAdapter((Date) anObject));
+    else
+      return makeBeanAdapter(anObject);
+  }
+
+  /**
+   *
+   * <p>Title: </p>
+   * <p>Description: </p>
+   * <p>Copyright: Copyright (c) 2003</p>
+   * <p>Company: </p>
+   * @author not attributable
+   * @version 1.0
+   */
+  public static class FunctionAdapter implements VelocityAdapter {
+    private Function function;
+
+    public Object getOriginal() {
+      return function;
+    }
+
+    private FunctionAdapter(Function aFunction) {
+      function = aFunction;
+    }
+
+    public Object call(Object aParameters[]) throws GeneratorExc {
+      List parameters = new Vector();
+
+      for (int i = 0; i<aParameters.length; i++) {
+        parameters.add(unmakeAdapter(aParameters[i]));
+      }
+
+      return makeAdapter(function.perform(parameters));
+    }
+
+    public Object call() throws GeneratorExc {
+      return makeAdapter(function.perform(new Vector()));
+    }
+
+    public Object call(Object anObject) throws GeneratorExc {
+      return call(new Object[] { anObject });
+    }
+
+    public Object call(Object anObject1, Object anObject2) throws GeneratorExc {
+      return call(new Object[] { anObject1, anObject2 });
+    }
+
+    public Object call(Object anObject1, Object anObject2, Object anObject3) throws GeneratorExc {
+      return call(new Object[] { anObject1, anObject2, anObject3 });
+    }
+
+    public Object call(Object anObject1, Object anObject2, Object anObject3, Object anObject4) throws GeneratorExc {
+      return call(new Object[] { anObject1, anObject2, anObject3, anObject4 });
+    }
+  }
+
+
+  /**
+   *
+   * <p>Title: </p>
+   * <p>Description: </p>
+   * <p>Copyright: Copyright (c) 2003</p>
+   * <p>Company: </p>
+   * @author not attributable
+   * @version 1.0
+   */
+  private static class MapAdapter implements Context, VelocityAdapter  {
+    private Map map;
+    private Map valuesCache;
+
+    private MapAdapter(Map aMap) {
+      map = aMap;
+      valuesCache = new HashMap();
+    }
+
+    public Object getOriginal() {
+      return map;
+    }
+
+    public boolean containsKey(Object aKey) {
+      return map.containsKey(aKey);
+    }
+
+    public Object get(String aKey) {
+      try {
+        if (!valuesCache.containsKey(aKey)) {
+          Object value = map.get(aKey);
+
+          if (value == null && !map.containsKey(aKey)) {
+            return "no key "+aKey+" available";
+          }
+          else
+            valuesCache.put(aKey, makeAdapter(value));
+        }
+
+        return valuesCache.get(aKey);
+      }
+      catch (Throwable t) {
+        throw new GeneratorFailure(t);
+      }
+    }
+
+    public Object[] getKeys() {
+      return new Object[] {};
+    }
+
+    public Object put(String aKey, Object aValue) {
+      valuesCache.remove(aKey);
+      map.put(aKey, unmakeAdapter(aValue));
+
+      return aValue;
+    }
+
+    public Object remove(java.lang.Object key) {
+      return null;
+    }
+  }
+
+  /**
+   *
+   * <p>Title: </p>
+   * <p>Description: </p>
+   * <p>Copyright: Copyright (c) 2003</p>
+   * <p>Company: </p>
+   * @author not attributable
+   * @version 1.0
+   */
+  private static class IteratorAdapter extends AbstractList implements VelocityAdapter  {
+    private Iterator iterator;
+    private List valuesCache;
+
+    private IteratorAdapter(Iterator anIterator) {
+      iterator = anIterator;
+
+      valuesCache = new Vector();
+
+      if (iterator instanceof RewindableIterator) {
+        ((RewindableIterator) iterator).rewind();
+      }
+    }
+
+    private void getUntil(int anIndex) {
+      while ((anIndex==-1 || valuesCache.size()<=anIndex) && iterator.hasNext())
+      {
+        valuesCache.add(makeAdapter(iterator.next()));
+      }
+    };
+
+    public Object getOriginal() {
+      return iterator;
+    }
+
+    public Object get(int anIndex) {
+      Object result;
+
+      getUntil(anIndex);
+
+      if (anIndex<valuesCache.size())
+      {
+        result = valuesCache.get(anIndex);
+
+        return result;
+      }
+      else
+        throw new RuntimeException( "Iterator out of bounds" );
+    }
+
+    public int size() {
+      getUntil(-1);
+      return valuesCache.size();
+    }
+
+  }
+
+  /**
+   *
+   * <p>Title: </p>
+   * <p>Description: </p>
+   * <p>Copyright: Copyright (c) 2003</p>
+   * <p>Company: </p>
+   * @author not attributable
+   * @version 1.0
+   */
+  private static class ListAdapter extends AbstractList implements VelocityAdapter  {
+    private List list;
+    private List valuesCache;
+
+    private ListAdapter(List aList) {
+      list = aList;
+
+      valuesCache = new Vector();
+    }
+
+    private void getUntil(int anIndex) {
+      while ((anIndex==-1 || valuesCache.size()<=anIndex) && valuesCache.size()<list.size())
+      {
+        valuesCache.add(makeAdapter(list.get(valuesCache.size())));
+      }
+    };
+
+    public Object getOriginal() {
+      return list;
+    }
+
+    public Object get(int anIndex) {
+      Object result;
+
+      getUntil(anIndex);
+
+      if (anIndex<valuesCache.size())
+      {
+        result = valuesCache.get(anIndex);
+
+        return result;
+      }
+      else
+        throw new RuntimeException( "Iterator out of bounds" );
+    }
+
+    public int size() {
+      return list.size();
+    }
+
+  }
+
+  /**
+   *
+   * <p>Title: </p>
+   * <p>Description: </p>
+   * <p>Copyright: Copyright (c) 2003</p>
+   * <p>Company: </p>
+   * @author not attributable
+   * @version 1.0
+   */
+  private static class BeanAdapter implements Context, VelocityAdapter {
+    private Object object;
+
+    public BeanAdapter(Object anObject) {
+      object = anObject;
+    }
+
+    public boolean containsKey(Object key) {
+      return true;
+    }
+
+    public Object getOriginal() {
+      return object;
+    }
+
+    public Object get(String aKey) {
+      try {
+        if (PropertyUtils.isReadable(object, aKey))
+          return makeAdapter(PropertyUtils.getSimpleProperty(object, aKey));
+        else
+          return makeAdapter(MethodUtils.invokeExactMethod(object, "get", aKey));
+      }
+      catch (Throwable t) {
+        throw new GeneratorFailure(t);
+      }
+    }
+
+    public Object[] getKeys() {
+      return new Object[] {};
+    }
+
+    public Object put(String aKey, Object aValue) {
+      try {
+        if (PropertyUtils.isWriteable(object, aKey))
+          PropertyUtils.setSimpleProperty(object, aKey, unmakeAdapter(aValue));
+        else
+          MethodUtils.invokeExactMethod(object, "set", new Object[] {aKey, unmakeAdapter(aValue)});
+
+        return this;
+      }
+      catch (Throwable t) {
+        throw new GeneratorFailure(t);
+      }
+    }
+
+    public Object remove(Object aKey) {
+      throw new RuntimeException("BeanAdapter.remove not supported");
+    }
+  }
+
+  /**
+   *
+   * <p>Title: </p>
+   * <p>Description: </p>
+   * <p>Copyright: Copyright (c) 2003</p>
+   * <p>Company: </p>
+   * @author not attributable
+   * @version 1.0
+   */
+  private static class VelocityLoggerWrapper implements LogSystem {
+    private LoggerWrapper logger;
+
+    public VelocityLoggerWrapper(LoggerWrapper aLogger) {
+      logger = aLogger;
+    }
+
+    public void init(RuntimeServices aRuntimeServices) {
+    }
+
+    public void logVelocityMessage(int aLevel, String aMessage) {
+      switch (aLevel) {
+        case DEBUG_ID:
+          logger.debug(aMessage);
+          break;
+        case ERROR_ID:
+          logger.error(aMessage);
+          break;
+        case INFO_ID:
+          logger.info(aMessage);
+          break;
+        default:
+          logger.warn(aMessage);
+          break;
+      }
+    }
+  }
+
+  /**
+   *
+   * <p>Title: </p>
+   * <p>Description: </p>
+   * <p>Copyright: Copyright (c) 2003</p>
+   * <p>Company: </p>
+   * @author not attributable
+   * @version 1.0
+   */
+  public static class VelocityGeneratorLibrary implements Library {
+    private VelocityEngine engine;
+
+    public VelocityGeneratorLibrary(File aTemplateRoot) throws GeneratorExc, GeneratorFailure {
+      try {
+        engine = new VelocityEngine();
+        try {
+          engine.setProperty(VelocityEngine.RESOURCE_LOADER, "file");
+          engine.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+          engine.setProperty("file.resource.loader.path", aTemplateRoot.getAbsolutePath());
+          engine.setProperty("file.resource.loader.cache", "true");
+        }
+        catch (Throwable t) {
+          logger.error("Error while constructing library: " + t.toString());
+
+          throw new GeneratorFailure(t);
+        }
+
+        try {
+          engine.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM, new VelocityLoggerWrapper(logger));
+        }
+        catch (Throwable t) {
+          logger.error(VelocityEngine.RUNTIME_LOG_LOGSYSTEM);
+
+        }
+        engine.init();
+      }
+      catch (Throwable t) {
+        t.printStackTrace(logger.asPrintWriter(logger.ERROR_MESSAGE));
+
+        logger.error("Failed to set up a VelocityGeneratorLibrary: " + t.toString());
+        throw new GeneratorFailure(t);
+      }
+    }
+
+    public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {
+      return new VelocityGenerator(anIdentifier, this);
+    }
+  }
+
+  /**
+   *
+   * <p>Title: </p>
+   * <p>Description: </p>
+   * <p>Copyright: Copyright (c) 2003</p>
+   * <p>Company: </p>
+   * @author not attributable
+   * @version 1.0
+   */
+  public static class VelocityGeneratorLibraryFactory implements LibraryFactory {
+    private File basePath;
+
+    public VelocityGeneratorLibraryFactory(File aBasePath) {
+      basePath = aBasePath;
+    }
+
+    public Library makeLibrary(String anInitializationString) throws GeneratorExc, GeneratorFailure {
+      return new VelocityGeneratorLibrary(new File(basePath, anInitializationString));
+    };
+  }
+}
diff --git a/source/mir/generator/tal/CachingFileLoader.java b/source/mir/generator/tal/CachingFileLoader.java
new file mode 100755 (executable)
index 0000000..c9f042b
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class CachingFileLoader {
+  private Map cachedObjects;
+  private List history;
+  private int capacity;
+  private CachedFileObjectFactory factory;
+
+  public CachingFileLoader(int aCapacity, CachedFileObjectFactory aFactory) {
+    capacity = aCapacity;
+    cachedObjects = new HashMap();
+    history = new ArrayList();
+    factory = aFactory;
+  }
+
+  private void cacheObject(String aFilename, long aLastModified, Object anObject) {
+    synchronized (this) {
+      history.remove(aFilename);
+      history.add(aFilename);
+      while (history.size()>capacity && history.size()>0) {
+        history.remove(0);
+      }
+      cachedObjects.put(aFilename, new CachedObject(aFilename, aLastModified, anObject));
+    }
+  }
+
+  private Object constructObject(String aFilename) throws FileNotFoundException {
+    File file = new File(aFilename);
+    BufferedInputStream inputStream = new BufferedInputStream(
+      new FileInputStream(file), 8192);
+    try {
+      Object result = factory.constructObject(inputStream);
+      cacheObject(aFilename, file.lastModified(), result);
+
+      return result;
+    }
+    finally {
+      try {
+        inputStream.close();
+      }
+      catch (Throwable t) {
+      }
+    }
+  }
+
+  private void revatilize(String aFilename) {
+    synchronized (this) {
+      history.remove(aFilename);
+      history.add(aFilename);
+    }
+  }
+
+  private class CachedObject {
+    private String filename;
+    private long lastModified;
+    private Object object;
+
+    public CachedObject(String aFilename, long aLastModified, Object anObject) {
+      filename = aFilename;
+      lastModified = aLastModified;
+      object = anObject;
+    }
+
+    public Object getObject() {
+      return object;
+    }
+
+    public String getFilename() {
+      return filename;
+    }
+
+    public long getLastModified() {
+      return lastModified;
+    }
+  }
+
+  public Object retrieveFile(String aFilename) throws FileNotFoundException {
+    synchronized (this) {
+      if (!cachedObjects.containsKey(aFilename)) {
+        return constructObject(aFilename);
+      }
+
+      CachedObject cachedObject = (CachedObject) cachedObjects.get(aFilename);
+      File file = new File(aFilename);
+      if (file.lastModified() != cachedObject.getLastModified()) {
+        return constructObject(aFilename);
+      }
+
+      revatilize(aFilename);
+
+      return cachedObject.getObject();
+    }
+  }
+
+  public interface CachedFileObjectFactory {
+    Object constructObject(InputStream aStream);
+  }
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/MirExpressionParser.java b/source/mir/generator/tal/MirExpressionParser.java
new file mode 100755 (executable)
index 0000000..3413fc5
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import mir.generator.tal.interfaces.TALExpressionParser;
+import mir.util.ParameterExpander;
+import mir.util.RewindableIterator;
+
+public class MirExpressionParser implements TALExpressionParser {
+  public Object preparseExpression(String anExpression) {
+    return anExpression;
+  }
+  public Object preparseStringExpression(String anExpression)  {
+    return anExpression;
+  }
+
+  public Object preparseBooleanExpression(String anExpression) {
+    return anExpression;
+  }
+
+  public Object preparseReferenceExpression(String anExpression) {
+    return anExpression;
+  }
+
+  public Object preparseListExpression(String anExpression) {
+    return anExpression;
+  }
+
+  public Object preparseTRUE() {
+    return "1==1";
+  }
+
+  public Object preparseFALSE() {
+    return "0==1";
+  }
+
+  public Object evaluateExpression(Object aContext, Object aPreparsedExpression) {
+    try {
+      return ParameterExpander.evaluateExpression(aContext, (String) aPreparsedExpression);
+    }
+    catch (Throwable t) {
+      throw new TALFailure(t);
+    }
+  }
+
+  public String evaluateStringExpression(Object aContext, Object aPreparsedExpression) {
+    try {
+      return ParameterExpander.expandExpression(aContext, (String) aPreparsedExpression);
+    }
+    catch (Throwable t) {
+      throw new TALFailure(t);
+    }
+  }
+
+  public boolean evaluateBooleanExpression(Object aContext, Object aPreparsedExpression) {
+    try {
+      return ParameterExpander.evaluateBooleanExpression(aContext, (String) aPreparsedExpression);
+    }
+    catch (Throwable t) {
+      throw new TALFailure(t);
+    }
+  }
+
+  public Iterator evaluateListExpression(Object aContext, Object aPreparsedExpression) {
+    try {
+      Object list = ParameterExpander.evaluateExpression(aContext, (String) aPreparsedExpression);
+
+      if (list instanceof List)
+        return ((List) list).iterator();
+
+      if (list instanceof RewindableIterator) {
+        ((RewindableIterator) list).rewind();
+        return (RewindableIterator) list;
+      }
+
+      if (list instanceof Iterator) {
+        return (Iterator) list;
+      }
+
+      throw new TALExc("Not a list: " + list);
+    }
+    catch (Throwable t) {
+      throw new TALFailure(t);
+    }
+  }
+
+  public void processAssignment(Object aContext, Object aPreparsedReferenceExpression, Object aPreparsedExpression) {
+    try {
+      ParameterExpander.setValueForKey( (Map) aContext, (String) aPreparsedReferenceExpression, ParameterExpander.evaluateExpression(aContext, (String) aPreparsedExpression));
+    }
+    catch (Throwable t) {
+      throw new TALFailure(t);
+    }
+  }
+
+  public void processDirectAssignment(Object aContext, Object aPreparsedReferenceExpression, Object aValue) {
+    try {
+      ParameterExpander.setValueForKey( (Map) aContext, (String) aPreparsedReferenceExpression, aValue);
+    }
+    catch (Throwable t) {
+      throw new TALFailure(t);
+    }
+  }
+
+  public void processPseudoAssignment(Object aContext, String aName, Object aValue) {
+    try {
+      ParameterExpander.setValueForKey( (Map) aContext, aName, aValue);
+    }
+    catch (Throwable t) {
+      throw new TALFailure(t);
+    }
+  }
+
+  public Object evaluatePseudoVariable(Object aContext, String aName) {
+    try {
+      return ParameterExpander.getObjectField(aContext, aName);
+    }
+    catch (Throwable t) {
+      throw new TALFailure(t);
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/SimpleTemplateNodeLibraryRegistry.java b/source/mir/generator/tal/SimpleTemplateNodeLibraryRegistry.java
new file mode 100755 (executable)
index 0000000..561f50a
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import mir.generator.tal.template.TemplateNodeLibraryRegistry;
+import mir.generator.tal.template.TemplateNodeLibrary;
+
+public class SimpleTemplateNodeLibraryRegistry implements TemplateNodeLibraryRegistry {
+  private Map urlToLibrary;
+  private Map prefixToLibrary;
+
+  public SimpleTemplateNodeLibraryRegistry() {
+    urlToLibrary = new HashMap();
+    prefixToLibrary = new HashMap();
+  }
+
+  public void registerTemplateNodeLibrary(String aPrefix, String aUrl, TemplateNodeLibrary aLibrary) {
+    urlToLibrary.put(aUrl, aLibrary);
+    prefixToLibrary.put(aPrefix, aLibrary);
+  }
+
+  public TemplateNodeLibrary findLibraryForUrl(String aUrl) {
+    return (TemplateNodeLibrary) urlToLibrary.get(aUrl);
+  }
+
+  public TemplateNodeLibrary findLibraryForPrefix(String aPrefix) {
+    return (TemplateNodeLibrary) prefixToLibrary.get(aPrefix);
+  }
+}
diff --git a/source/mir/generator/tal/TALExc.java b/source/mir/generator/tal/TALExc.java
new file mode 100755 (executable)
index 0000000..f722d2c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal;
+
+import multex.Exc;
+
+public class TALExc extends Exc {
+  public TALExc(String aMessage) {
+    super(aMessage);
+  }
+}
diff --git a/source/mir/generator/tal/TALFailure.java b/source/mir/generator/tal/TALFailure.java
new file mode 100755 (executable)
index 0000000..d15ebf5
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal;
+
+import multex.Failure;
+
+public class TALFailure extends Failure {
+  public TALFailure(String msg,Throwable cause) {
+    super(msg,cause);
+  }
+
+  public TALFailure(Throwable aCause) {
+    this (aCause.getMessage(), aCause);
+  }
+}
diff --git a/source/mir/generator/tal/TALTemplateEngine.java b/source/mir/generator/tal/TALTemplateEngine.java
new file mode 100755 (executable)
index 0000000..aa3fb76
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+import java.util.List;
+
+import mir.generator.tal.interfaces.TALExpressionParser;
+import mir.generator.tal.template.*;
+import mir.util.StringRoutines;
+
+public class TALTemplateEngine implements TemplateLibrary {
+  private TALExpressionParser expressionParser;
+  private File basePath;
+  private CachingFileLoader loader;
+
+  private SimpleTemplateNodeLibraryRegistry registry;
+
+  public TALTemplateEngine(TALExpressionParser anExpressionParser, File aBasePath) {
+    expressionParser = anExpressionParser;
+    basePath = aBasePath;
+    loader = new CachingFileLoader(100, new TemplateFactory());
+
+    registry = new SimpleTemplateNodeLibraryRegistry();
+
+    registerTemplateNodeLibrary("tal", "http://xml.zope.org/namespaces/tal",
+        new CoreTemplateNodeLibrary("tal", "http://xml.zope.org/namespaces/tal"));
+    registerTemplateNodeLibrary("metal", "http://xml.zope.org/namespaces/metal",
+        new MacroTemplateNodeLibrary("metal", "http://xml.zope.org/namespaces/metal"));
+  }
+
+  public void registerTemplateNodeLibrary(String aPrefix, String aUrl, TemplateNodeLibrary aLibrary) {
+    registry.registerTemplateNodeLibrary(aPrefix, aUrl, aLibrary);
+  }
+
+  public Template loadTemplate(String aName) throws IOException, TemplateProcessingException {
+    List parts = StringRoutines.splitString(aName, "#");
+
+    if (parts.size()!=1 && parts.size()!=2) {
+      throw new TemplateProcessingException("Invalid template name: " + aName);
+    }
+
+    File location = new File(basePath, (String) parts.get(0));
+
+    Template baseTemplate = (Template) loader.retrieveFile(location.getCanonicalPath());
+
+    if (baseTemplate!=null && parts.size()>1) {
+      Map definitions = (Map) baseTemplate.getContext().get(MacroTemplateNodeLibrary.MACRO_DEFINITIONS_KEY);
+      if (definitions==null || !definitions.containsKey(parts.get(1))) {
+        throw new TemplateProcessingException("No macro '"+(String) parts.get(1)+"' found in template '" + (String) parts.get(0) + "'");
+      }
+
+      return new Template(expressionParser, (TemplateNode) definitions.get(parts.get(1)), baseTemplate.getContext());
+    }
+    else {
+      return baseTemplate;
+    }
+
+
+
+//      public Template(TALExpressionParser aParser, TemplateNode aRootNode, Map aTemplateContext) {
+  }
+
+  public Template lookupTemplate(String aName) throws TemplateProcessingException {
+    try {
+      return loadTemplate(aName);
+    }
+    catch (IOException e) {
+      throw new TemplateProcessingException("Can't load template " + aName + ": " + e.toString(), e);
+    }
+  }
+
+  private class TemplateFactory implements CachingFileLoader.CachedFileObjectFactory {
+    public Object constructObject(InputStream aStream) {
+      try {
+        TALTemplateParser parser = new TALTemplateParser(registry);
+
+        return parser.parse(aStream, expressionParser);
+      }
+      catch (Throwable t) {
+        throw new TALFailure(t);
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/TALTemplateParser.java b/source/mir/generator/tal/TALTemplateParser.java
new file mode 100755 (executable)
index 0000000..ff1596f
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.HashMap;
+
+import mir.generator.tal.interfaces.TALExpressionParser;
+import mir.generator.tal.template.CompositeTemplateNode;
+import mir.generator.tal.template.PlainTextTemplateNode;
+import mir.generator.tal.template.Template;
+import mir.generator.tal.template.TemplateNodeLibrary;
+import mir.generator.tal.template.TemplateNode;
+import mir.generator.tal.template.TemplateNodeLibraryRegistry;
+import mir.util.HTMLRoutines;
+import mir.util.xml.SectionHandler;
+import mir.util.xml.XMLName;
+import mir.util.xml.XMLParserEngine;
+import mir.util.xml.XMLParserExc;
+import mir.util.xml.XMLParserFailure;
+import mir.util.xml.XMLReaderTool;
+
+public class TALTemplateParser {
+  private TemplateNodeLibraryRegistry registry;
+
+  public TALTemplateParser(TemplateNodeLibraryRegistry aRegistry) {
+    registry = aRegistry;
+  }
+
+  public Template parse(String aData, TALExpressionParser aParser) throws TALExc, TALFailure {
+    return parse(new StringReader(aData), aParser);
+  }
+
+  public Template parse(File aFile, TALExpressionParser aParser) throws TALExc, TALFailure {
+    try {
+      return parse(new BufferedInputStream(new FileInputStream(aFile), 1024*128), aParser);
+    }
+    catch (FileNotFoundException e) {
+      throw new TALFailure(e);
+    }
+  }
+  public Template parse(InputStream anInputStream, TALExpressionParser aParser) throws TALExc, TALFailure {
+    return parse(new InputStreamReader(anInputStream), aParser);
+  }
+
+  public Template parse(Reader aReader, TALExpressionParser aParser) throws TALExc, TALFailure {
+    Map templateContext = new HashMap();
+    TALHandler handler = new TALHandler(aParser, templateContext);
+
+    try {
+      XMLParserEngine.getInstance().parse("html", aReader, handler);
+    }
+    catch (XMLParserExc e) {
+      throw new TALFailure(e);
+    }
+
+    return new Template(aParser, handler.getNode(), templateContext);
+  }
+
+  protected class TALHandler implements SectionHandler {
+    private CompositeTemplateNode compositeNode;
+    private StringBuffer data;
+    private StringBuffer plainData;
+    private TALExpressionParser parser;
+    private String currentTag;
+    private TemplateNodeLibrary library;
+    private XMLName tag;
+    private Map attributes;
+    private Map templateContext;
+
+    public TALHandler(TALExpressionParser aParser, Map aTemplateContext) {
+      parser = aParser;
+      data = new StringBuffer();
+      plainData = new StringBuffer();
+      compositeNode = new CompositeTemplateNode();
+      templateContext = aTemplateContext;
+    }
+
+    private void flushData() {
+      if (data.length()!=0) {
+        compositeNode.appendSubNode(new PlainTextTemplateNode(data.toString(), plainData.toString()));
+        data.delete(0, data.length());
+        plainData.delete(0, plainData.length());
+      }
+    }
+
+    public void extra(String anExtraData) throws XMLParserExc, XMLParserFailure {
+      appendCode(anExtraData);
+    }
+
+    public TemplateNodeLibrary findLibrary(XMLName aName) {
+      TemplateNodeLibrary result = null;
+
+      if (aName.getNamespaceURI()!=null) {
+        result = registry.findLibraryForUrl(aName.getNamespaceURI());
+      }
+
+      if ((result == null) && (aName.getPrefix()!=null) && (aName.getPrefix().length()>0)) {
+        result = registry.findLibraryForPrefix(aName.getPrefix());
+      }
+
+      return result;
+    }
+
+    public SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
+      library = findLibrary(aTag);
+
+      Iterator i = anAttributes.keySet().iterator();
+      while (library==null && i.hasNext()) {
+        library=findLibrary((XMLName) i.next());
+      }
+
+      currentTag = XMLReaderTool.normalizeXMLName(aTag);
+
+      if (library == null) {
+        appendCode("<"+currentTag);
+        i = anAttributes.entrySet().iterator();
+
+        while (i.hasNext()) {
+          Map.Entry entry = (Map.Entry) i.next();
+
+          appendCode(" "+ XMLReaderTool.normalizeXMLName((XMLName) entry.getKey()));
+          appendCode("=\"");
+          appendText((String) entry.getValue());
+          appendCode("\"");
+        }
+      }
+      else {
+        tag = aTag;
+        attributes = anAttributes;
+      }
+
+      return new TALHandler(parser, templateContext);
+    };
+
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
+      if (library == null) {
+        TemplateNode subNode = ((TALHandler) aHandler).getNode();
+        if (subNode instanceof CompositeTemplateNode &&
+            ((CompositeTemplateNode) subNode).isEmpty()) {
+          appendCode(" />");
+        }
+        else {
+          appendCode(">");
+          appendSubNode(subNode);
+          appendCode("</"+currentTag+">");
+        }
+      }
+      else {
+        appendSubNode(
+            library.constructTemplateNode(parser, tag, attributes, ((TALHandler) aHandler).getNode(), templateContext));
+        tag = null;
+        attributes = null;
+      }
+    };
+
+    protected void appendSubNode(TemplateNode aNode) {
+      flushData();
+
+      compositeNode.appendSubNode(aNode);
+    }
+
+    protected void appendCode(String aCode) {
+      data.append(aCode);
+    }
+
+    protected void appendText(String aText) {
+      data.append(HTMLRoutines.encodeHTML(aText));
+      plainData.append(aText);
+    }
+
+    public void finishSection() throws XMLParserExc {
+      flushData();
+    }
+
+    public TemplateNode getNode() {
+      return compositeNode;
+    }
+
+    public void characters(String aCharacters) throws XMLParserExc {
+      appendText(aCharacters);
+    }
+
+    public void startSection() throws XMLParserExc, XMLParserFailure {
+    }
+  }
+}
diff --git a/source/mir/generator/tal/TALTest.java b/source/mir/generator/tal/TALTest.java
new file mode 100755 (executable)
index 0000000..1eb475d
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal;
+
+import java.io.PrintWriter;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import mir.generator.tal.interfaces.TALLogger;
+import mir.generator.tal.template.Template;
+import mir.generator.tal.template.TemplateLibrary;
+import mir.generator.tal.template.TemplateProcessingException;
+import mir.generator.tal.template.CoreTemplateNodeLibrary;
+import mir.generator.tal.template.MacroTemplateNodeLibrary;
+
+public class TALTest {
+  public static void main(String args[]) {
+    try {
+      final SimpleTemplateNodeLibraryRegistry registry = new SimpleTemplateNodeLibraryRegistry();
+
+      registry.registerTemplateNodeLibrary("tal", "http://xml.zope.org/namespaces/tal",
+          new CoreTemplateNodeLibrary("tal", "http://xml.zope.org/namespaces/tal"));
+      registry.registerTemplateNodeLibrary("metal", "http://xml.zope.org/namespaces/metal",
+          new MacroTemplateNodeLibrary("metal", "http://xml.zope.org/namespaces/metal"));
+
+      TemplateLibrary library = new TemplateLibrary() {
+        public Template lookupTemplate(String aTemplateName) throws TemplateProcessingException {
+          try {
+            TALTemplateParser parser = new TALTemplateParser(registry);
+
+            if (aTemplateName.equals("a")) {
+              return parser.parse("<test tal:on-error='${exception.message}'><bkla><font tal:content='${sdf'></bkla><td><b><font>bla</font></b></td></font>" +
+                  "<test2 metal:use-macro=\"b#testmacro\"></test2><test3 a='b' tal:attributes='c a:${tagattributes.a}'> </test3> " +
+                  "<test4 tal:content='the content was ${tagcontent}'>bla <b>die</b> bla ></test4><a width='100%'/>" +
+                  "<test5 tal:bla=a><tal:bla/></test5>   </test>", new MirExpressionParser());
+            }
+            else {
+              return parser.parse("<test3><test4 metal:define-macro=\"testmacro\">hoi</test4><test3>", new MirExpressionParser());
+            }
+          }
+          catch (Throwable t) {
+            t.printStackTrace();
+            System.out.println(t.toString());
+            return null;
+          }
+        }
+      };
+
+      Map test = new HashMap();
+
+      Template template = library.lookupTemplate("a");
+
+      PrintWriter p = new PrintWriter(System.out);
+
+      template.process(new HashMap(), p, new TALLogger.TALSystemOutLogger(), library);
+
+      p.close();
+
+    }
+    catch (Throwable t) {
+      System.out.println("Exception: " + t.toString());
+      t.printStackTrace(System.out);
+    }
+  }
+  public static void main2(String args[]) {
+    try {
+      TALTemplateEngine engine = new TALTemplateEngine(
+          new MirExpressionParser(), new File("m:/romania/mir/etc/producer/"));
+
+      Map test = new HashMap();
+      test.put("name", "zapata");
+
+      Template template = engine.loadTemplate("indy-ro-txt.html");
+
+      PrintWriter p = new PrintWriter(System.out);
+
+      template.process(new Object(), p, new TALLogger.TALSystemOutLogger(), engine);
+
+      p.close();
+
+    }
+    catch (Throwable t) {
+      System.out.println("Exception: " + t.toString());
+      t.printStackTrace(System.out);
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/interfaces/TALExpressionParser.java b/source/mir/generator/tal/interfaces/TALExpressionParser.java
new file mode 100755 (executable)
index 0000000..bc3106e
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal.interfaces;
+
+import java.util.Iterator;
+
+public interface TALExpressionParser {
+  public Object preparseExpression(String anExpression);
+  public Object preparseStringExpression(String anExpression);
+  public Object preparseBooleanExpression(String anExpression);
+  public Object preparseReferenceExpression(String anExpression);
+  public Object preparseListExpression(String anExpression);
+  public Object preparseTRUE();
+  public Object preparseFALSE();
+
+  public Object evaluateExpression(Object aContext, Object aPreparsedExpression);
+  public String evaluateStringExpression(Object aContext, Object aPreparsedExpression);
+  public boolean evaluateBooleanExpression(Object aContext, Object aPreparsedExpression);
+  public Iterator evaluateListExpression(Object aContext, Object aPreparsedExpression);
+  public void processAssignment(Object aContext, Object aPreparsedReferenceExpression, Object aPreparsedExpression);
+
+  /**
+   * process a direct assignment of an object to a preparsed reference expression
+   *
+   */
+  public void processDirectAssignment(Object aContext, Object aPreparsedReferenceExpression, Object aValue);
+
+  /**
+   * process an assigment to a pseudo variable. The pseudo variable will have a java
+   *   identifier-like name.
+   *
+   */
+  public void processPseudoAssignment(Object aContext, String aName, Object aValue);
+
+  /**
+   * Retrieve the value of a pseudo variable
+   *
+   */
+  public Object evaluatePseudoVariable(Object aContext, String aName);
+
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/interfaces/TALLogger.java b/source/mir/generator/tal/interfaces/TALLogger.java
new file mode 100755 (executable)
index 0000000..2f36c83
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal.interfaces;
+
+public interface TALLogger {
+  public void debug(String anObject, String aMessage);
+  public void info(String anObject, String aMessage);
+  public void warning(String anObject, String aMessage);
+  public void error(String anObject, String aMessage);
+  public void fatal(String anObject, String aMessage);
+
+  /**
+   * Simple logging class that logs everything to System.out
+   */
+  public class TALSystemOutLogger implements TALLogger {
+    public TALSystemOutLogger() {
+    }
+
+    public void debug(String anObject, String aMessage) {
+      System.out.println("DEBUG: " + anObject + "  " + aMessage);
+    }
+
+    public void info(String anObject, String aMessage) {
+      System.out.println("INFO: " + anObject + "  " + aMessage);
+    }
+
+    public void warning(String anObject, String aMessage) {
+      System.out.println("WARNING: " + anObject + "  " + aMessage);
+    }
+
+    public void error(String anObject, String aMessage) {
+      System.out.println("ERROR: " + anObject + "  " + aMessage);
+    }
+
+    public void fatal(String anObject, String aMessage) {
+      System.out.println("FATAL: " + anObject + "  " + aMessage);
+    }
+  }
+
+  /**
+   * Simple logging class that discards all logging information.
+   */
+  public class TALVoidLogger implements TALLogger {
+    public void debug(String anObject, String aMessage) {
+    }
+
+    public void info(String anObject, String aMessage) {
+    }
+
+    public void warning(String anObject, String aMessage) {
+    }
+
+    public void error(String anObject, String aMessage) {
+    }
+
+    public void fatal(String anObject, String aMessage) {
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/template/CompositeTemplateNode.java b/source/mir/generator/tal/template/CompositeTemplateNode.java
new file mode 100755 (executable)
index 0000000..55a6cb0
--- /dev/null
@@ -0,0 +1,98 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator.tal.template;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import mir.generator.tal.interfaces.TALExpressionParser;\r
+import mir.generator.tal.interfaces.TALLogger;\r
+\r
+/**\r
+ * Template node that is composed of a list of template nodes.\r
+ *\r
+ */\r
+public class CompositeTemplateNode implements TemplateNode {\r
+  private List parts;\r
+\r
+  public CompositeTemplateNode() {\r
+    parts = new ArrayList();\r
+  }\r
+\r
+  /** {@inheritDoc} */\r
+  public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination,\r
+      TALLogger aLogger, Map aTemplateContext, TemplateLibrary aLibrary) throws TemplateProcessingException {\r
+    Iterator i = parts.iterator();\r
+\r
+    while (i.hasNext()) {\r
+      ((TemplateNode) i.next()).process(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);\r
+    }\r
+  }\r
+\r
+  public String getPlainText() {\r
+    StringBuffer result = new StringBuffer();\r
+\r
+    Iterator i = parts.iterator();\r
+    while (i.hasNext()) {\r
+      result.append(((TemplateNode) i.next()).getPlainText());\r
+    }\r
+\r
+    return result.toString();\r
+  }\r
+\r
+  public boolean isEmpty() {\r
+    return parts.isEmpty();\r
+  }\r
+\r
+  /**\r
+   * Adds a <code>TemplateNode</code> at the end of the chain.\r
+   */\r
+  public void appendSubNode(TemplateNode aNode) {\r
+    if (aNode instanceof CompositeTemplateNode) {\r
+      Iterator i = ((CompositeTemplateNode) aNode).parts.iterator();\r
+      while (i.hasNext()) {\r
+        appendSubNode((TemplateNode) i.next());\r
+      }\r
+    }\r
+    else if (aNode instanceof PlainTextTemplateNode &&\r
+             parts.size()>0 &&\r
+             (parts.get(parts.size()-1) instanceof PlainTextTemplateNode)) {\r
+\r
+      ((PlainTextTemplateNode) parts.get(parts.size()-1)).appendText(((PlainTextTemplateNode) aNode).getText());\r
+      ((PlainTextTemplateNode) parts.get(parts.size()-1)).appendPlainText(((PlainTextTemplateNode) aNode).getPlainText());\r
+    }\r
+    else {\r
+      parts.add(aNode);\r
+    }\r
+  }\r
+\r
+}\r
diff --git a/source/mir/generator/tal/template/CoreTemplateNodeLibrary.java b/source/mir/generator/tal/template/CoreTemplateNodeLibrary.java
new file mode 100755 (executable)
index 0000000..e806deb
--- /dev/null
@@ -0,0 +1,380 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+\r
+package mir.generator.tal.template;\r
+\r
+import java.util.*;\r
+\r
+import mir.generator.tal.interfaces.TALExpressionParser;\r
+import mir.generator.tal.interfaces.TALLogger;\r
+import mir.util.HTMLRoutines;\r
+import mir.util.StringRoutines;\r
+import mir.util.xml.XMLName;\r
+import mir.util.xml.XMLParserExc;\r
+import mir.util.xml.XMLReaderTool;\r
+\r
+public class CoreTemplateNodeLibrary implements TemplateNodeLibrary {\r
+  private String prefix;\r
+  private String uri;\r
+\r
+  private boolean isOurTag(XMLName aName) {\r
+    return prefix.equals(aName.getPrefix()) || uri.equals(aName.getNamespaceURI());\r
+  }\r
+\r
+  public CoreTemplateNodeLibrary(String aPrefix, String aUri) {\r
+    prefix = aPrefix;\r
+    uri = aUri;\r
+  }\r
+\r
+  private static final String CONDITION_ATTRIBUTE = "condition";\r
+  private static final String REPEAT_ATTRIBUTE = "repeat";\r
+  private static final String CONTENT_ATTRIBUTE = "content";\r
+  private static final String ERROR_ATTRIBUTE = "on-error";\r
+  private static final String REPLACE_ATTRIBUTE = "replace";\r
+  private static final String DEFINITION_ATTRIBUTE = "define";\r
+  private static final String OMITTAG_ATTRIBUTE = "omit-tag";\r
+  private static final String ATTRIBUTE_ATTRIBUTE = "attributes";\r
+\r
+  public TemplateNode constructTemplateNode(TALExpressionParser aParser, XMLName aTag, Map anAttributes,\r
+      TemplateNode aChildTemplateNode, Map aTemplateContext) throws XMLParserExc {\r
+    TALBasicTemplateNode result = new TALBasicTemplateNode(XMLReaderTool.normalizeXMLName(aTag));\r
+    result.setBody(aChildTemplateNode);\r
+\r
+    if (isOurTag(aTag))\r
+      result.setOmitTag(aParser.preparseTRUE());\r
+\r
+    Iterator i = anAttributes.entrySet().iterator();\r
+    while (i.hasNext()) {\r
+      Map.Entry entry = (Map.Entry) i.next();\r
+      XMLName name = (XMLName) entry.getKey();\r
+\r
+      if (!isOurTag(name)) {\r
+        result.addFixedAttribute(XMLReaderTool.normalizeXMLName(name), (String) entry.getValue());\r
+      }\r
+      else {\r
+        if (name.getLocalName().equalsIgnoreCase(DEFINITION_ATTRIBUTE)) {\r
+          List definitions = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');\r
+\r
+          Iterator j = definitions.iterator();\r
+          while (j.hasNext())\r
+          {\r
+            List parts = StringRoutines.separateString((String) j.next(), " ");\r
+\r
+            if (parts.size()==2) {\r
+              result.addDefinition(aParser.preparseReferenceExpression((String) parts.get(0)), aParser.preparseExpression((String) parts.get(1)));\r
+            }\r
+          }\r
+        }\r
+        else if (name.getLocalName().equalsIgnoreCase(CONDITION_ATTRIBUTE)) {\r
+          result.setCondition(aParser.preparseBooleanExpression((String) entry.getValue()));\r
+        }\r
+        else if (name.getLocalName().equalsIgnoreCase(CONTENT_ATTRIBUTE)) {\r
+          result.setContent(aParser.preparseStringExpression((String) entry.getValue()));\r
+        }\r
+        else if (name.getLocalName().equalsIgnoreCase(ERROR_ATTRIBUTE)) {\r
+          result.setError(aParser.preparseStringExpression((String) entry.getValue()));\r
+        }\r
+        else if (name.getLocalName().equalsIgnoreCase(OMITTAG_ATTRIBUTE)) {\r
+          if (((String) entry.getValue()).trim().length()==0)\r
+            result.setOmitTag(aParser.preparseTRUE());\r
+          else\r
+            result.setOmitTag(aParser.preparseBooleanExpression((String) entry.getValue()));\r
+        }\r
+        else if (name.getLocalName().equalsIgnoreCase(REPLACE_ATTRIBUTE)) {\r
+          result.setOmitTag(aParser.preparseTRUE());\r
+          result.setContent(aParser.preparseStringExpression((String) entry.getValue()));\r
+        }\r
+        else if (name.getLocalName().equalsIgnoreCase(REPEAT_ATTRIBUTE)) {\r
+          List parts = StringRoutines.separateString((String) entry.getValue(), " ");\r
+\r
+          if (parts.size()==2) {\r
+            result.setRepeat(aParser.preparseReferenceExpression((String) parts.get(0)), aParser.preparseExpression((String) parts.get(1)));\r
+          }\r
+        }\r
+        else if (name.getLocalName().equalsIgnoreCase(ATTRIBUTE_ATTRIBUTE)) {\r
+          List attributes = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');\r
+\r
+          Iterator j = attributes.iterator();\r
+          while (j.hasNext()) {\r
+            String value = (String) j.next();\r
+            List parts = StringRoutines.separateString(value.trim(), " ");\r
+\r
+            if (parts.size()==2) {\r
+              result.addModifiedAttribute((String) parts.get(0), aParser.preparseExpression((String) parts.get(1)));\r
+            }\r
+            else {\r
+              throw new XMLParserExc(ATTRIBUTE_ATTRIBUTE + " tag should have exactly 2 parts ("+value+")");\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    return result;\r
+  }\r
+\r
+  public static class TALBasicTemplateNode implements TemplateNode {\r
+    private String tag;\r
+    private Map fixedAttributes;\r
+    private Map attributeModifiers;\r
+\r
+    private List definitions;\r
+    private Object condition;\r
+\r
+    private Object repeatVariable;\r
+    private Object repeatExpression;\r
+    private Object contentExpression;\r
+    private Object omitTagExpression;\r
+    private Object errorExpression;\r
+\r
+    private TemplateNode body;\r
+\r
+    public TALBasicTemplateNode(String aTag) {\r
+      tag = aTag;\r
+\r
+      fixedAttributes = new HashMap();\r
+      attributeModifiers = new HashMap();\r
+\r
+      definitions = new ArrayList();\r
+      condition = null;\r
+\r
+      repeatVariable = null;\r
+      repeatExpression = null;\r
+      contentExpression = null;\r
+      omitTagExpression = null;\r
+\r
+      body = null;\r
+    }\r
+\r
+    public void setBody(TemplateNode aBody) {\r
+      body = aBody;\r
+    }\r
+\r
+    public void addFixedAttribute(String aKey, String aValue) {\r
+      fixedAttributes.put(aKey, aValue);\r
+    }\r
+\r
+    public void addModifiedAttribute(String aKey, Object aValue) {\r
+      attributeModifiers.put(aKey, aValue);\r
+    }\r
+\r
+    public void addDefinition(Object aKey, Object aValue) {\r
+      definitions.add(new Definition(aKey, aValue));\r
+    }\r
+\r
+    public void setCondition(Object aCondition) {\r
+      condition = aCondition;\r
+    }\r
+\r
+    public void setRepeat(Object aRepeatVariable, Object aRepeatExpression) {\r
+      repeatVariable = aRepeatVariable;\r
+      repeatExpression = aRepeatExpression;\r
+    }\r
+\r
+    public void setContent(Object aContentExpression) {\r
+      contentExpression = aContentExpression;\r
+    }\r
+\r
+    public void setOmitTag(Object anOmitTagExpression) {\r
+      omitTagExpression = anOmitTagExpression;\r
+    }\r
+\r
+    public void setError(Object anErrorExpression) {\r
+      errorExpression = anErrorExpression;\r
+    }\r
+\r
+    public static class Definition {\r
+      private Object variable;\r
+      private Object expression;\r
+\r
+      public Definition(Object aVariable, Object anExpression) {\r
+        variable = aVariable;\r
+        expression = anExpression;\r
+      }\r
+\r
+      public Object getVariable() {\r
+        return variable;\r
+      }\r
+\r
+      public Object getExpression() {\r
+        return expression;\r
+      }\r
+    }\r
+\r
+    public void process(TALExpressionParser aParser, Object aContext,\r
+        StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext,\r
+        TemplateLibrary aLibrary) throws TemplateProcessingException {\r
+      if (errorExpression != null) {\r
+        StringBuffer destination = new StringBuffer();\r
+\r
+        try {\r
+          outerProcess(aParser, aContext, destination, aLogger, aTemplateContext, aLibrary);\r
+        }\r
+        catch (Throwable t) {\r
+          try {\r
+//            destination.delete(0, destination.length());\r
+            aParser.processPseudoAssignment(aContext, "exception", t);\r
+            destination.insert(0, aParser.evaluateStringExpression(aContext, errorExpression));\r
+            destination.append(" >>>ERROR POSITION<<< ");\r
+          }\r
+          catch (Throwable s) {\r
+            throw new TemplateProcessingException(s);\r
+          }\r
+        }\r
+        finally {\r
+          aDestination.append(destination);\r
+        }\r
+      }\r
+      else {\r
+        outerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);\r
+      }\r
+    }\r
+\r
+    public String getPlainText() {\r
+      return body.getPlainText();\r
+    }\r
+\r
+    public void outerProcess(TALExpressionParser aParser, Object aContext,\r
+        StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext,\r
+        TemplateLibrary aLibrary) throws TemplateProcessingException {\r
+\r
+      Object oldAttributes = aParser.evaluatePseudoVariable(aContext, "tagattributes");\r
+      aParser.processPseudoAssignment(aContext, "tagattributes", Collections.unmodifiableMap(fixedAttributes));\r
+\r
+      Object oldContent = aParser.evaluatePseudoVariable(aContext, "tagcontent");\r
+      aParser.processPseudoAssignment(aContext, "tagcontent", body.getPlainText());\r
+\r
+      try {\r
+        Iterator i;\r
+\r
+        i = definitions.iterator();\r
+        while (i.hasNext()) {\r
+          Definition d = (Definition) i.next();\r
+          aParser.processAssignment(aContext, d.getVariable(), d.getExpression());\r
+        }\r
+\r
+        if (condition == null || aParser.evaluateBooleanExpression(aContext, condition)) {\r
+          if (repeatExpression != null) {\r
+            i = aParser.evaluateListExpression(aContext, repeatExpression);\r
+\r
+            while (i.hasNext()) {\r
+              aParser.processDirectAssignment(aContext, repeatVariable, i.next());\r
+              innerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);\r
+            }\r
+          }\r
+          else {\r
+            innerProcess(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);\r
+          }\r
+        }\r
+      }\r
+      finally {\r
+        try {\r
+          aParser.processPseudoAssignment(aContext, "tagattributes", oldAttributes);\r
+          aParser.processPseudoAssignment(aContext, "tagcontent", oldContent);\r
+        }\r
+        catch (Throwable t) {\r
+        }\r
+      }\r
+    };\r
+\r
+    private void innerProcess(TALExpressionParser aParser, Object aContext,\r
+        StringBuffer aDestination, TALLogger aLogger, Map aTemplateContext, TemplateLibrary aLibrary)\r
+        throws TemplateProcessingException {\r
+\r
+      boolean omitTag = false;\r
+      StringBuffer content = aDestination;\r
+\r
+      if (omitTagExpression != null)\r
+        omitTag = aParser.evaluateBooleanExpression(aContext, omitTagExpression);\r
+\r
+      if (!omitTag) {\r
+        content = new StringBuffer();\r
+        Map generatedAttributes = new HashMap(fixedAttributes);\r
+\r
+        Iterator i = attributeModifiers.entrySet().iterator();\r
+        while (i.hasNext()) {\r
+          Map.Entry entry = (Map.Entry) i.next();\r
+\r
+          generatedAttributes.put(entry.getKey(), aParser.evaluateStringExpression(aContext, entry.getValue()));\r
+        }\r
+\r
+        aDestination.append("<");\r
+        aDestination.append(tag);\r
+\r
+        i = generatedAttributes.entrySet().iterator();\r
+        while (i.hasNext()) {\r
+          Map.Entry entry = (Map.Entry) i.next();\r
+          aDestination.append(" ");\r
+          aDestination.append(entry.getKey());\r
+          aDestination.append("=");\r
+          aDestination.append("\"");\r
+          aDestination.append(HTMLRoutines.encodeHTML( (String) entry.getValue()));\r
+          aDestination.append("\"");\r
+        }\r
+      }\r
+\r
+      try{\r
+        if (contentExpression != null) {\r
+          content.append(aParser.evaluateStringExpression(aContext, contentExpression));\r
+        }\r
+        else {\r
+          if (body != null) {\r
+            body.process(aParser, aContext, content, aLogger, aTemplateContext, aLibrary);\r
+          }\r
+        }\r
+        if (!omitTag) {\r
+          if (content.length()==0) {\r
+            aDestination.append(" />");\r
+          }\r
+          else {\r
+            aDestination.append(">");\r
+            aDestination.append(content);\r
+            aDestination.append("</");\r
+            aDestination.append(tag);\r
+            aDestination.append(">");\r
+          }\r
+        }\r
+      }\r
+      catch (Throwable t) {\r
+        if (!omitTag) {\r
+          aDestination.append(content);\r
+        }\r
+\r
+        if (t instanceof TemplateProcessingException) {\r
+          throw (TemplateProcessingException) t;\r
+        }\r
+        else if (t instanceof RuntimeException) {\r
+          throw (RuntimeException) t;\r
+        }\r
+        else throw new TemplateProcessingException(t.toString());\r
+      }\r
+    }\r
+  }\r
+}\r
diff --git a/source/mir/generator/tal/template/MacroTemplateNodeLibrary.java b/source/mir/generator/tal/template/MacroTemplateNodeLibrary.java
new file mode 100755 (executable)
index 0000000..1310c7b
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal.template;
+
+import java.util.Map;
+import java.util.Iterator;
+import java.util.List;
+import java.util.HashMap;
+
+import mir.generator.tal.interfaces.TALExpressionParser;
+import mir.generator.tal.interfaces.TALLogger;
+import mir.util.xml.XMLName;
+import mir.util.xml.XMLParserExc;
+import mir.util.xml.XMLReaderTool;
+import mir.util.StringRoutines;
+import mir.util.HTMLRoutines;
+
+public class MacroTemplateNodeLibrary implements TemplateNodeLibrary {
+  /** {@inheritDoc} */
+  private static final String DEFINE_MACRO_ATTRIBUTE = "define-macro";
+  private static final String USE_MACRO_ATTRIBUTE = "use-macro";
+  private static final String DEFINE_SLOT_ATTRIBUTE = "define-slot";
+  private static final String FILL_SLOT_ATTRIBUTE = "fill-macro";
+
+  public static final String MACRO_DEFINITIONS_KEY = "$" + MacroTemplateNodeLibrary.class.getName() + "$macro_definitions";
+  public static final String ORPHANED_SLOTS_KEY = "$" + MacroTemplateNodeLibrary.class.getName() + "$macro_definitions";
+
+  private String prefix;
+  private String uri;
+
+
+  private boolean isOurTag(XMLName aName) {
+    return prefix.equals(aName.getPrefix()) || uri.equals(aName.getNamespaceURI());
+  }
+
+  public MacroTemplateNodeLibrary(String aPrefix, String aUri) {
+    prefix = aPrefix;
+    uri = aUri;
+  }
+
+  public TemplateNode constructTemplateNode(TALExpressionParser anExpressionParser, XMLName aTag, Map anAttributes,
+      TemplateNode aChildTemplateNode, Map aTemplateContext) throws XMLParserExc {
+
+    StringBuffer prefix = new StringBuffer();
+    boolean useSurroundingTag = !(isOurTag(aTag));
+
+    prefix.append("<").append(XMLReaderTool.normalizeXMLName(aTag));
+    String suffix = "</"+XMLReaderTool.normalizeXMLName(aTag)+">";
+
+    String macroDefinition = null;
+    String slotDefinition = null;
+    String slotFill = null;
+    Object macroCallExpression = null;
+
+    Iterator i = anAttributes.entrySet().iterator();
+
+    while (i.hasNext()) {
+      Map.Entry entry = (Map.Entry) i.next();
+      XMLName name = (XMLName) entry.getKey();
+
+      if (!isOurTag(name)) {
+        prefix.append(" ").append(XMLReaderTool.normalizeXMLName(name));
+        prefix.append("=\"").append(HTMLRoutines.encodeHTML( (String) entry.getValue())).append('"');
+      }
+      else {
+        if (name.getLocalName().equalsIgnoreCase(DEFINE_MACRO_ATTRIBUTE)) {
+          macroDefinition = (String) entry.getValue();
+        }
+        else if (name.getLocalName().equalsIgnoreCase(USE_MACRO_ATTRIBUTE)) {
+          macroCallExpression = anExpressionParser.preparseStringExpression((String) entry.getValue());
+        }
+        else if (name.getLocalName().equalsIgnoreCase(DEFINE_SLOT_ATTRIBUTE)) {
+          slotDefinition = (String) entry.getValue();
+        }
+        else if (name.getLocalName().equalsIgnoreCase(FILL_SLOT_ATTRIBUTE)) {
+          slotFill = (String) entry.getValue();
+        }
+      }
+    }
+    prefix.append(">");
+
+    MacroTemplateNode result;
+    if (useSurroundingTag) {
+      result = new MacroTemplateNode(aChildTemplateNode, prefix.toString(), suffix, slotDefinition, slotFill);
+    }
+    else {
+      result = new MacroTemplateNode(aChildTemplateNode, "", "", slotDefinition, slotFill);
+    }
+
+    if (macroCallExpression!=null) {
+      result.setMacroCall(macroCallExpression);
+    }
+
+    if (macroDefinition!=null) {
+      macroDefinition = macroDefinition.trim();
+      if (macroDefinition.length()==0) {
+        throw new XMLParserExc("Empty macro name");
+      }
+
+      Map definitions = (Map) aTemplateContext.get(MACRO_DEFINITIONS_KEY);
+      if (definitions==null) {
+        definitions=new HashMap();
+        aTemplateContext.put(MACRO_DEFINITIONS_KEY, definitions);
+      }
+
+      if (definitions.containsKey(macroDefinition)) {
+        throw new XMLParserExc("Duplicate macro name: " + macroDefinition);
+      }
+
+      definitions.put(macroDefinition, result);
+
+      Map slots = (Map) aTemplateContext.get(ORPHANED_SLOTS_KEY);
+      if (slots!=null) {
+      }
+    }
+
+    return result;
+  }
+
+  private class MacroTemplateNode implements TemplateNode {
+    private TemplateNode childNode;
+    private String prefix;
+    private String suffix;
+
+    private Object macroCallTemplateExpression = null;
+
+    private String slotDefinition;
+    private String slotFill;
+
+    public MacroTemplateNode(TemplateNode aChildNode, String aPrefix, String aSuffix,
+        String aSlotDefinition, String aSlotFill) {
+      childNode = aChildNode;
+      prefix = aPrefix;
+      suffix = aSuffix;
+
+      slotDefinition = aSlotDefinition;
+      slotFill = aSlotFill;
+    }
+
+    public void setMacroCall(Object anExpression) {
+      macroCallTemplateExpression = anExpression;
+    }
+
+    /** {@inheritDoc} */
+    public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination,
+        TALLogger aLogger, Map aTemplateContext, TemplateLibrary aLibrary) throws TemplateProcessingException {
+
+      if (macroCallTemplateExpression!=null) {
+        String macroPath = aParser.evaluateStringExpression(aContext, macroCallTemplateExpression);
+        List parts = StringRoutines.separateString(macroPath, "#");
+        if (parts.size()!=2) {
+          throw new TemplateProcessingException("Invalid macro path '" + macroPath + "'");
+        }
+
+        Template template = aLibrary.lookupTemplate((String) parts.get(0));
+        Map definitions = (Map) template.getContext().get(MACRO_DEFINITIONS_KEY);
+        if (template==null) {
+          throw new TemplateProcessingException("Cannot find template '" + (String) parts.get(0) + "'");
+        }
+        if (definitions==null || !definitions.containsKey(parts.get(1))) {
+          throw new TemplateProcessingException("No macro '"+(String) parts.get(1)+"' found in template '" + (String) parts.get(0) + "'");
+        }
+
+        MacroTemplateNode macro = (MacroTemplateNode) definitions.get(parts.get(1));
+
+        macro.process(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
+      }
+      else {
+        aDestination.append(prefix);
+
+        childNode.process(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
+        aDestination.append(suffix);
+      }
+    }
+
+    public String getPlainText() {
+      return childNode.getPlainText();
+    }
+  }
+}
diff --git a/source/mir/generator/tal/template/PlainTextTemplateNode.java b/source/mir/generator/tal/template/PlainTextTemplateNode.java
new file mode 100755 (executable)
index 0000000..617d45d
--- /dev/null
@@ -0,0 +1,77 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator.tal.template;\r
+\r
+import java.util.Map;\r
+\r
+import mir.generator.tal.interfaces.TALExpressionParser;\r
+import mir.generator.tal.interfaces.TALLogger;\r
+\r
+/**\r
+ * Simple <code>TemplateNode</code> that just outputs a fixed\r
+ * piece of allText.\r
+ */\r
+public class PlainTextTemplateNode implements TemplateNode {\r
+  private String allText;\r
+  private String plainText;\r
+\r
+  public PlainTextTemplateNode() {\r
+    this("", "");\r
+  }\r
+\r
+  public PlainTextTemplateNode(String aText, String aPlainText) {\r
+    allText = aText;\r
+    plainText = aPlainText;\r
+  }\r
+\r
+  /** Appends text at the end */\r
+  public void appendText(String aText) {\r
+    allText = allText + aText;\r
+  }\r
+\r
+  /** Appends allText at the end */\r
+  public void appendPlainText(String aText) {\r
+    plainText = plainText + aText;\r
+  }\r
+\r
+  public String getText() {\r
+    return allText;\r
+  }\r
+\r
+  public String getPlainText() {\r
+    return plainText;\r
+  }\r
+\r
+  public void process(TALExpressionParser aParser, Object aContext,\r
+      StringBuffer aDestination, TALLogger aLogger,\r
+      Map aTemplateContext, TemplateLibrary aLibrary) throws TemplateProcessingException {\r
+    aDestination.append(allText);\r
+  }\r
+}\r
diff --git a/source/mir/generator/tal/template/Template.java b/source/mir/generator/tal/template/Template.java
new file mode 100755 (executable)
index 0000000..e890c05
--- /dev/null
@@ -0,0 +1,68 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator.tal.template;\r
+\r
+import java.io.PrintWriter;\r
+import java.util.Map;\r
+\r
+import mir.generator.tal.interfaces.TALExpressionParser;\r
+import mir.generator.tal.interfaces.TALLogger;\r
+\r
+/**\r
+ * @see <a href="http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TAL%20Specification%201.4">TAL Spec</a>\r
+ */\r
+\r
+public class Template {\r
+  private TemplateNode rootNode;\r
+  private TALExpressionParser parser;\r
+  private Map context;\r
+\r
+  public Template(TALExpressionParser aParser, TemplateNode aRootNode, Map aTemplateContext) {\r
+    rootNode = aRootNode;\r
+    parser = aParser;\r
+    context = aTemplateContext;\r
+  }\r
+\r
+  /** get this template's context */\r
+  public Map getContext() {\r
+    return context;\r
+  }\r
+\r
+  public void process(Object aContext, PrintWriter aDestination,\r
+      TALLogger aLogger, TemplateLibrary aLibrary) throws TemplateProcessingException {\r
+    StringBuffer output = new StringBuffer();\r
+\r
+    aLogger.debug("Template", "processing rootnode");\r
+    rootNode.process(parser, aContext, output, aLogger, context, aLibrary);\r
+    aLogger.debug("Template", "done processing rootnode");\r
+    aDestination.print(output);\r
+  }\r
+\r
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/template/TemplateLibrary.java b/source/mir/generator/tal/template/TemplateLibrary.java
new file mode 100755 (executable)
index 0000000..e558c89
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal.template;
+
+/**
+ * A <code>TemplateLibrary</code> offers access to a set of {@link Template}s.
+ * Templates can be looked up by name.
+ */
+public interface TemplateLibrary {
+  /**
+   * Looks up a Template based on a name
+   */
+  public Template lookupTemplate(String aTemplateName) throws TemplateProcessingException;
+}
diff --git a/source/mir/generator/tal/template/TemplateNode.java b/source/mir/generator/tal/template/TemplateNode.java
new file mode 100755 (executable)
index 0000000..824552d
--- /dev/null
@@ -0,0 +1,52 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator.tal.template;\r
+\r
+import java.util.Map;\r
+\r
+import mir.generator.tal.interfaces.TALExpressionParser;\r
+import mir.generator.tal.interfaces.TALLogger;\r
+\r
+/**\r
+ * A {@link Template} consists of a chain of <code>TemplateNodes</code>.\r
+ */\r
+public interface TemplateNode {\r
+  /**\r
+   */\r
+  public void process(\r
+      TALExpressionParser aParser,\r
+      Object aContext,\r
+      StringBuffer aDestination,\r
+      TALLogger aLogger,\r
+      Map aTemplateContext,\r
+      TemplateLibrary aTemplateLibrary) throws TemplateProcessingException;\r
+\r
+  public String getPlainText();\r
+}\r
diff --git a/source/mir/generator/tal/template/TemplateNodeLibrary.java b/source/mir/generator/tal/template/TemplateNodeLibrary.java
new file mode 100755 (executable)
index 0000000..bdb8545
--- /dev/null
@@ -0,0 +1,49 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator.tal.template;\r
+\r
+import java.util.Map;\r
+\r
+import mir.util.xml.XMLName;\r
+import mir.util.xml.XMLParserExc;\r
+import mir.generator.tal.interfaces.TALExpressionParser;\r
+\r
+public interface TemplateNodeLibrary {\r
+  /**\r
+   * Construct a {@link TemplateNode} based on the tag and attributes given.\r
+   *\r
+   * @param anExpressionParser\r
+   * @param aTag\r
+   * @param anAttributes\r
+   * @param aChildTemplateNode\r
+   */\r
+  public TemplateNode constructTemplateNode(TALExpressionParser anExpressionParser,\r
+      XMLName aTag, Map anAttributes, TemplateNode aChildTemplateNode, Map aTemplateContext) throws XMLParserExc;\r
+}\r
diff --git a/source/mir/generator/tal/template/TemplateNodeLibraryRegistry.java b/source/mir/generator/tal/template/TemplateNodeLibraryRegistry.java
new file mode 100755 (executable)
index 0000000..a67e371
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.generator.tal.template;
+
+public interface TemplateNodeLibraryRegistry {
+  public TemplateNodeLibrary findLibraryForUrl(String aUrl);
+  public TemplateNodeLibrary findLibraryForPrefix(String aPrefix);
+}
diff --git a/source/mir/generator/tal/template/TemplateProcessingException.java b/source/mir/generator/tal/template/TemplateProcessingException.java
new file mode 100755 (executable)
index 0000000..19a70b4
--- /dev/null
@@ -0,0 +1,52 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator.tal.template;\r
+\r
+public class TemplateProcessingException extends Exception {\r
+  private Throwable cause;\r
+\r
+  public TemplateProcessingException(Throwable aCause) {\r
+    this (aCause.getMessage(), aCause);\r
+  }\r
+\r
+  public TemplateProcessingException(String aMessage, Throwable aCause) {\r
+    super(aMessage);\r
+\r
+    cause = aCause;\r
+  }\r
+\r
+  public TemplateProcessingException(String aMessage) {\r
+    this(aMessage, null);\r
+  }\r
+\r
+  public Throwable getCause() {\r
+    return cause;\r
+  }\r
+}\r
diff --git a/source/mir/log/Log.java b/source/mir/log/Log.java
deleted file mode 100755 (executable)
index 17fec30..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.log;
-
-import mir.config.MirPropertiesConfiguration;
-import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;
-
-public class Log {
-
-  private static Logger myLogger;
-
-  static {
-    try {
-      String loggerClass = MirPropertiesConfiguration.instance().getString("Log.LogClass");
-      myLogger = (Logger) Class.forName(loggerClass).newInstance();
-    }
-    catch (java.lang.ClassNotFoundException cnfe) {
-      System.err.println("Log was not able to initialize: class not found");
-      cnfe.printStackTrace(System.err);
-    }
-    catch (java.lang.InstantiationException ie) {
-      System.err.println(
-          "Log was not able to initialize: could not initialize class");
-      ie.printStackTrace(System.err);
-    }
-    catch (java.lang.IllegalAccessException iae) {
-      System.err.println("Log was not able to initialize: illegal access");
-      iae.printStackTrace(System.err);
-    }
-    catch (PropertiesConfigExc e) {
-      e.printStackTrace(System.err);
-    }
-  }
-
-  public static void debug(Object o, String s) {
-    myLogger.debug(o, s);
-  }
-
-  public static void info(Object o, String s) {
-    myLogger.info(o, s);
-  }
-
-  public static void warn(Object o, String s) {
-    myLogger.warn(o, s);
-  }
-
-  public static void error(Object o, String s) {
-    myLogger.error(o, s);
-  }
-
-  public static void fatal(Object o, String s) {
-    myLogger.fatal(o, s);
-  }
-}
index 47dc7db..46d052a 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.
  */
 
@@ -38,4 +38,6 @@ public interface Logger {
   public void warn( Object o, String s);
   public void error( Object o, String s);
   public void fatal( Object o, String s);
+
+  public void reload() throws LoggerExc, LoggerFailure;
 }
diff --git a/source/mir/log/LoggerEngine.java b/source/mir/log/LoggerEngine.java
new file mode 100755 (executable)
index 0000000..9073595
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.log;
+
+import mir.config.MirPropertiesConfiguration;
+
+public class LoggerEngine {
+  private static Logger loggerInstance;
+
+  static {
+    try {
+      String loggerClass = MirPropertiesConfiguration.instance().getString("Log.LogClass");
+      loggerInstance = (Logger) Class.forName(loggerClass).newInstance();
+    }
+    catch (java.lang.ClassNotFoundException cnfe) {
+      System.err.println("LoggerEngine was not able to initialize: class not found");
+      cnfe.printStackTrace(System.err);
+    }
+    catch (java.lang.InstantiationException ie) {
+      System.err.println(
+          "LoggerEngine was not able to initialize: could not initialize class");
+      ie.printStackTrace(System.err);
+    }
+    catch (java.lang.IllegalAccessException iae) {
+      System.err.println("LoggerEngine was not able to initialize: illegal access");
+      iae.printStackTrace(System.err);
+    }
+  }
+
+  public static void debug(Object o, String s) {
+    loggerInstance.debug(o, s);
+  }
+
+  public static void info(Object o, String s) {
+    loggerInstance.info(o, s);
+  }
+
+  public static void warn(Object o, String s) {
+    loggerInstance.warn(o, s);
+  }
+
+  public static void error(Object o, String s) {
+    loggerInstance.error(o, s);
+  }
+
+  public static void fatal(Object o, String s) {
+    loggerInstance.fatal(o, s);
+  }
+
+  public static void reload() throws LoggerExc, LoggerFailure {
+    loggerInstance.reload();
+  }
+}
diff --git a/source/mir/log/LoggerExc.java b/source/mir/log/LoggerExc.java
new file mode 100755 (executable)
index 0000000..10bfd70
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.log;
+
+import multex.Exc;
+
+public class LoggerExc extends Exc {
+  public LoggerExc(String aMessage) {
+    super(aMessage);
+  }
+}
diff --git a/source/mir/log/LoggerFailure.java b/source/mir/log/LoggerFailure.java
new file mode 100755 (executable)
index 0000000..f8d1b16
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.log;
+
+import multex.Failure;
+
+public class LoggerFailure extends Failure {
+
+  public LoggerFailure(String aMessage,Throwable aCause) {
+    super(aMessage, aCause);
+  }
+
+  public LoggerFailure(Throwable aCause) {
+    this (aCause.getMessage(), aCause);
+  }
+}
index 7853ef9..eb8db65 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.
  */
 
@@ -45,23 +45,23 @@ public class LoggerWrapper {
   }
 
   public void debug( String aMessage ) {
-    Log.debug(object, aMessage);
+    LoggerEngine.debug(object, aMessage);
   };
 
   public void info( String aMessage ) {
-    Log.info(object, aMessage);
+    LoggerEngine.info(object, aMessage);
   };
 
   public void warn( String aMessage ) {
-    Log.warn(object, aMessage);
+    LoggerEngine.warn(object, aMessage);
   };
 
   public void error( String aMessage ) {
-    Log.error(object, aMessage);
+    LoggerEngine.error(object, aMessage);
   };
 
   public void fatal( String aMessage ) {
-    Log.fatal(object, aMessage);
+    LoggerEngine.fatal(object, aMessage);
   };
 
   public void message( int aType, String aMessage) {
diff --git a/source/mir/log/TestFramework.java b/source/mir/log/TestFramework.java
deleted file mode 100755 (executable)
index 48a7891..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.log;
-
-
-public class TestFramework {
-
-  public static void main(String[] args) {
-    TestFramework t = new TestFramework();
-
-    Log.info( TestFramework.class, "class");
-    Log.info( t, "object" );
-    Log.info( null, "lalala" );
-  }
-}
index 99ebed4..cd80fd8 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.log.log4j;
@@ -33,8 +33,8 @@ import java.util.HashMap;
 import java.util.Map;
 
 import mir.config.MirPropertiesConfiguration;
-import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;
-
+import mir.log.LoggerExc;
+import mir.log.LoggerFailure;
 import org.apache.log4j.Logger;
 import org.apache.log4j.PropertyConfigurator;
 
@@ -42,33 +42,53 @@ import org.apache.log4j.PropertyConfigurator;
 public class LoggerImpl implements mir.log.Logger {
   private static Map loggers = new HashMap();
 
-  public LoggerImpl() throws PropertiesConfigExc {
-    System.setProperty("log.home",
-        MirPropertiesConfiguration.instance().getStringWithHome("Log.Home"));
-    PropertyConfigurator.configure(
-        MirPropertiesConfiguration.instance().getStringWithHome("Log.log4j.ConfigurationFile").trim());
+  public LoggerImpl() throws LoggerExc {
+    reload();
   }
 
+  /** {@inheritDoc} */
   public void debug(Object o, String s) {
     this.getLogger(o).debug(s);
   }
 
+  /** {@inheritDoc} */
   public void info(Object o, String s) {
     this.getLogger(o).info(s);
   }
 
+  /** {@inheritDoc} */
   public void warn(Object o, String s) {
     this.getLogger(o).warn(s);
   }
 
+  /** {@inheritDoc} */
   public void error(Object o, String s) {
     this.getLogger(o).error(s);
   }
 
+  /** {@inheritDoc} */
   public void fatal(Object o, String s) {
     this.getLogger(o).fatal(s);
   }
 
+  /** {@inheritDoc} */
+  public void reload() throws LoggerExc, LoggerFailure {
+    try {
+      synchronized (loggers) {
+        System.setProperty("log.home",
+            MirPropertiesConfiguration.instance().getFile("Log.Home").getAbsolutePath());
+
+        PropertyConfigurator.configure(
+            MirPropertiesConfiguration.instance().getFile("Log.log4j.ConfigurationFile").getAbsolutePath());
+
+        loggers.clear();
+      }
+    }
+    catch (Throwable t) {
+      throw new LoggerFailure(t);
+    }
+  }
+
   private Logger getLogger(Object o) {
     String name;
     Logger l;
diff --git a/source/mir/media/MediaHandler.java b/source/mir/media/MediaHandler.java
new file mode 100755 (executable)
index 0000000..0283649
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.media;
+
+import java.io.InputStream;
+import java.io.File;
+import java.util.List;
+
+import mir.entity.Entity;
+import mir.session.UploadedFile;
+
+/**
+ * Interface for Media handling in Mir. All media handlers
+ * must implement this interface. Each specific media type,
+ * be it Gif, Jpeg, Mp3 audio, Real Audio or quicktime video
+ * has special needs when it comes to representation on the various
+ * pages (article, list, summary), must be stored differently and has a
+ * different URL, etc... This interface allows Mir to support
+ * an infinite (I hope) number of media types. Once this is done,
+ * no code at any other level in Mir needs to be changed other than
+ * adding the content-type <-> media handler name mapping in the
+ * media_type table. The following is an example of the media_type
+ * table:
+ * <p>
+ * id |  name   |        mime_type         | classname |   tablename   | dcname<br>
+ *---+---------+--------------------------+-----------+---------------+-------<br>
+ *  2 | unknown | application/octet-stream | --        | UploadedMedia | <br>
+ *  3 | jpg     | image/gif                | ImagesGif | Images        | <br>
+ *  4 | mp3     | audio/mp3                | Audio     | UploadedMedia | <br>
+ * <p>
+ * The "id" field is used as a mapping in the table that contains the media type
+ * to the media_type table. For example, the images table has a to_media_type
+ * field that contains the id in the media_type table.
+ * <p>
+ * The "name" field is used for various display/filenaming purposes. it should
+ * match a valid file extension name for a media_type (we could have used the
+ * content-type map for this....).
+ * <p>
+ * The "mime_type" field is the most important as it does maps the type to Java
+ * classes (the storage and media_handler name). We call those classes using
+ * reflection. This way, once a Handler for a specific media type is implemented
+ * and entered into the media_type table, no other Mir code needs to be modified.
+ * <p>
+ * The "classname" field is the name of the media handler (e.g MediaHandlerAudio)
+ * we use it to call the MediaHandler methods via reflection.
+ * <p>
+ * The "tablename" is the name of the database storage classes (e.g DatabaseImages
+ * and EntityImages). We use this to fetch/storage the media (meta)data in the db.
+ * <p?
+ * The "dcname" field is as of yet unused. Do search for "Dublin Core" on google
+ * to learn more.
+ * <p>
+ * Most media handlers should just extend MediaHandlerGeneric (i.e inherit from
+ * ) and just override the things that need to be specific. see MediaHandlerAudio
+ *
+ * @author <mh@nadir.org>, the Mir-coders group
+ */
+
+public interface MediaHandler {
+  /**
+   * Store the media content from an {@link UploadedFile}
+   */
+  public void store(UploadedFile anUploadedFile, Entity aMedia, Entity aMediaType) throws MediaExc, MediaFailure;
+
+  /**
+   * Store the media content from an input stream.
+   */
+  public void store(InputStream anInputStream, Entity aMedia, Entity aMediaType) throws MediaExc, MediaFailure;
+
+  /**
+   * Store the media content from a file.
+   */
+  public void store(File aFile, Entity aMedia, Entity aMediaType) throws MediaExc, MediaFailure;
+
+  /**
+   * Perform production related tasks for this media.  
+   */
+  public void produce(Entity aMedia, Entity aMediaType ) throws MediaExc, MediaFailure;
+
+  /**
+   * Get's the media data from storage and returns it as an InputStream
+   * Not very useful for most media types as they are stored in a file,
+   * but very usefull for ones stored in the DB as it is necessary to get
+   * it first before making a file out of it (in Producer*).
+   */
+  public InputStream getMedia (Entity aMedia, Entity aMediaType) throws MediaExc, MediaFailure;
+
+  /**
+   * Pretty much like get() above. But get's the specific Icon
+   * representation. useful for media stored in the DB.
+   */
+  public InputStream getThumbnail(Entity aMedia) throws MediaExc, MediaFailure;
+
+
+  /**
+   * Returns the mime-type of the media's thumbnail
+   */
+  public String getThumbnailMimeType(Entity aMediaEntity, Entity aMediaType) throws MediaExc, MediaFailure;
+
+  /**
+   * gets the final content representation for the media
+   * in the form of a URL (String) that allows someone to
+   * download, look at or listen to the media. (HREF, img src
+   * streaming link, etc..)
+   * It should use the helper functions in the StringUtil class to
+   * build URL's safely, eliminating any *illegal* user input.
+   */
+  public List getURL (Entity aMedia, Entity aMediaType) throws MediaExc, MediaFailure;
+
+        /**
+   * Returns the absolute filesystem path to where the media
+   * content should be stored. This path is usually defined
+   * in the configuration wich is accessible through the MirConfig
+   * class.
+   */
+  public String getStoragePath () throws MediaExc, MediaFailure;
+
+        /**
+   * Returns the *relative* filesystem path to where the media
+   * icon content should be stored. It is relative to the path
+   * returned by getStoragePath()
+   * This path is usually defined
+   * in the configuration wich is accessible through the MirConfig
+   * class.
+   */
+  public String getIconStoragePath () throws MediaExc, MediaFailure;
+
+        /**
+   * Returns the base URL to that the media is accessible from
+   * to the end user. This could be a URL to another host.
+   * This is used in the Metadata stored in the DB and later on
+   * ,the templates use it.
+   * It is usually defined
+   * in the configuration witch is accessible through the MirConfig
+   * class.
+   */
+  public String getPublishHost () throws MediaExc, MediaFailure;
+
+        /**
+   * Returns the file name of the Icon representing the media type.
+   * It is used in the summary view.
+   * It is usually defined
+   * in the configuration wich is accessible through the MirConfig
+   * class.
+   */
+  public String getBigIconName ();
+
+        /**
+   * Returns the file name of the small Icon representing
+   * the media type.
+   * It is used in the right hand newswire list of the startpage.
+   * It is usually defined
+   * in the configuration wich is accessible through the MirConfig
+   * class.
+   */
+  public String getTinyIconName ();
+
+  /**
+   * Returns the IMG SRC "ALT" text to be used
+   * for the Icon representations
+   * @return String, the ALT text.
+   */
+  public String getIconAltName ();
+
+  /**
+   * returns a brief text dscription of what this
+   * media type is.
+   * @return String
+   */
+  public String getDescr (Entity aMediaType);
+
+}
+
+
diff --git a/source/mir/media/MediaHelper.java b/source/mir/media/MediaHelper.java
deleted file mode 100755 (executable)
index a4d4377..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.media;
-
-import java.lang.reflect.Method;
-
-import mir.entity.Entity;
-import mir.storage.Database;
-
-
-/**
- * helper class to resolve media handlers using reflection
- *
- * @author mh
- * @version 2002
- */
-
-public final class MediaHelper {
-
-  static String _classPrefix = "mircoders.media.MediaHandler";
-
-  public static MirMedia getHandler( Entity mediaType ) throws MediaExc, MediaFailure {
-
-    MirMedia mediaHandler;
-    String handlerName = mediaType.getValue("classname");
-    try {
-      Class handlerClass = Class.forName(_classPrefix+handlerName);
-      return mediaHandler = (MirMedia)handlerClass.newInstance();
-    }
-    catch (Throwable e) {
-      throw new MediaFailure("getHandler -- error in reflection " + e.toString(), e);
-    }
-  }
-
-  public static Database getStorage(Entity mediaType, String classPrefix) throws MediaExc, MediaFailure {
-
-    Database mediaStorage;
-    String storageName =  mediaType.getValue("tablename");
-    try {
-      Class storageClass = Class.forName(classPrefix+storageName);
-      Method m = storageClass.getMethod("getInstance", null);
-      return mediaStorage = (Database)m.invoke(null, null);
-    }
-    catch (Throwable e) {
-      throw new MediaFailure("getStorage -- error in reflection " + e.toString(), e);
-    }
-  }
-
-}
-
-
-
diff --git a/source/mir/media/MirMedia.java b/source/mir/media/MirMedia.java
deleted file mode 100755 (executable)
index 40f21a1..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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,
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
- * (or with modified versions of the above that use the same license as the above),
- * 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.media;
-
-import java.io.InputStream;\r
-import java.util.List;\r
-\r
-import mir.entity.Entity;
-
-/**
- * Interface for Media handling in Mir. All media handlers
- * must implement this interface. Each specific media type,
- * be it Gif, Jpeg, Mp3 audio, Real Audio or quicktime video
- * has special needs when it comes to representation on the various
- * pages (article, list, summary), must be stored differently and has a
- * different URL, etc... This interface allows Mir to support
- * an infinite (I hope) number of media types. Once this is done,
- * no code at any other level in Mir needs to be changed other than
- * adding the content-type <-> media handler name mapping in the
- * media_type table. The following is an example of the media_type
- * table:
- * <p>
- * id |  name   |        mime_type         | classname |   tablename   | dcname<br>
- *---+---------+--------------------------+-----------+---------------+-------<br>
- *  2 | unknown | application/octet-stream | --        | UploadedMedia | <br>
- *  3 | jpg     | image/gif                | ImagesGif | Images        | <br>
- *  4 | mp3     | audio/mp3                | Audio     | UploadedMedia | <br>
- * <p>
- * The "id" field is used as a mapping in the table that contains the media type
- * to the media_type table. For example, the images table has a to_media_type
- * field that contains the id in the media_type table.
- * <p>
- * The "name" field is used for various display/filenaming purposes. it should
- * match a valid file extension name for a media_type (we could have used the
- * content-type map for this....).
- * <p>
- * The "mime_type" field is the most important as it does maps the type to Java
- * classes (the storage and media_handler name). We call those classes using
- * reflection. This way, once a Handler for a specific media type is implemented
- * and entered into the media_type table, no other Mir code needs to be modified.
- * <p>
- * The "classname" field is the name of the media handler (e.g MediaHandlerAudio)
- * we use it to call the MediaHandler methods via reflection.
- * <p>
- * The "tablename" is the name of the database storage classes (e.g DatabaseImages
- * and EntityImages). We use this to fetch/storage the media (meta)data in the db.
- * <p?
- * The "dcname" field is as of yet unused. Do search for "Dublin Core" on google
- * to learn more.
- * <p>
- * Most media handlers should just extend MediaHandlerGeneric (i.e inherit from
- * ) and just override the things that need to be specific. see MediaHandlerAudio
- *
- * @author <mh@nadir.org>, the Mir-coders group
- * @version $Id: MirMedia.java,v 1.19 2003/09/03 18:29:01 zapata Exp $
- */
-
-public interface  MirMedia{
-
-  /**
-   * Takes the uploaded media data itself, along with the media Entity
-   * which contains the Media metadata plus the MediaType entity containing
-   * all the info for the specific media type itself. It's job is store the
-   * Media data (content) itself, this could be on the local filesystem, in the
-   * DB or even on a remote host. It then inserts the MetaData in the DB.
-   * @param InputStream, a stream of the uploaded data.
-   * @param ent, an Entity holding the media MetaData
-   * @param mediaType, an Entity holding the media_table entry
-   * @return boolean, success/fail
-   * @see mir.entity.Entity
-   */
-  public abstract void set (InputStream in, Entity ent, Entity mediaTypeEnt ) throws MediaExc, MediaFailure;
-
-  public abstract void produce (Entity ent, Entity mediaTypeEnt ) throws MediaExc, MediaFailure;
-
-  /**
-   * Get's the media data from storage and returns it as an InputStream
-   * Not very useful for most media types as they are stored in a file,
-   * but very usefull for ones stored in the DB as it is necessary to get
-   * it first before making a file out of it (in Producer*).
-   * @param ent, an Entity holding the media MetaData
-   * @param mediaType, an Entity holding the media_table entry
-   * @return java.io.InputStream
-   * @see mir.entity.Entity
-   */
-  public abstract InputStream getMedia (Entity ent, Entity mediaTypeEnt) throws MediaExc, MediaFailure;
-
-  /**
-   * Pretty much like get() above. But get's the specific Icon
-   * representation. useful for media stored in the DB.
-   * @param ent, an Entity holding the media MetaData
-   * @return java.io.InputStream
-   * @see mir.entity.Entity
-   */
-  public abstract InputStream getIcon (Entity ent) throws MediaExc, MediaFailure;
-
-
-  /**
-   *
-   * @param ent
-   * @return
-   * @throws MediaExc
-   * @throws MediaFailure
-   */
-  public abstract String getIconMimeType (Entity aMediaEntity, Entity aMediaType) throws MediaExc, MediaFailure;
-
-  /**
-   * gets the final content representation for the media
-   * in the form of a URL (String) that allows someone to
-   * download, look at or listen to the media. (HREF, img src
-   * streaming link, etc..)
-   * It should use the helper functions in the StringUtil class to
-   * build URL's safely, eliminating any *illegal* user input.
-   * @param ent, an Entity holding the media MetaData
-   * @param mediaTypeEnt, an Entity holding the media_table entry
-   * @return String, the url.
-   * @see mir.entity.Entity
-   * @see mir.misc.StringUtil
-   */
-  public abstract List getURL (Entity ent, Entity mediaTypeEnt) throws MediaExc, MediaFailure;
-
-        /**
-   * Returns the absolute filesystem path to where the media
-   * content should be stored. This path is usually defined
-   * in the configuration wich is accessible through the MirConfig
-   * class.
-   * @return String, the path.
-   * @see mir.misc.MirConfig
-   */
-  public abstract String getStoragePath () throws MediaExc, MediaFailure;
-
-        /**
-   * Returns the *relative* filesystem path to where the media
-   * icon content should be stored. It is relative to the path
-   * returned by getStoragePath()
-   * This path is usually defined
-   * in the configuration wich is accessible through the MirConfig
-   * class.
-   * @return String, the path.
-   * @see mir.misc.MirConfig
-   */
-  public abstract String getIconStoragePath () throws MediaExc, MediaFailure;
-
-        /**
-   * Returns the base URL to that the media is accessible from
-   * to the end user. This could be a URL to another host.
-   * This is used in the Metadata stored in the DB and later on
-   * ,the templates use it.
-   * It is usually defined
-   * in the configuration witch is accessible through the MirConfig
-   * class.
-   * @return String, the base URL to the host.
-   * @see mir.misc.MirConfig
-   */
-  public abstract String getPublishHost () throws MediaExc, MediaFailure;
-
-        /**
-   * Returns the file name of the Icon representing the media type.
-   * It is used in the summary view.
-   * It is usually defined
-   * in the configuration wich is accessible through the MirConfig
-   * class.
-   * @return String, the icon filename.
-   * @see mir.misc.MirConfig
-   */
-  public abstract String getBigIconName ();
-
-        /**
-   * Returns the file name of the small Icon representing
-   * the media type.
-   * It is used in the right hand newswire list of the startpage.
-   * It is usually defined
-   * in the configuration wich is accessible through the MirConfig
-   * class.
-   * @return String, the icon filename.
-   * @see mir.misc.MirConfig
-   */
-  public abstract String getTinyIconName ();
-
-        /**
-   * Returns the IMG SRC "ALT" text to be used
-   * for the Icon representations
-   * @return String, the ALT text.
-   */
-  public abstract String getIconAltName ();
-
-        /**
-   * your can all figure it out.
-   * @return boolean.
-   */
-  public abstract boolean isVideo ();
-
-        /**
-   * you can all figure it out.
-   * @return boolean.
-   */
-  public abstract boolean isAudio ();
-
-        /**
-   * you can all figure it out.
-   * @return boolean.
-   */
-  public abstract boolean isImage ();
-
-  /**
-   * returns a brief text dscription of what this
-   * media type is.
-   * @return String
-   */
-  public abstract String getDescr (Entity mediaTypeEnt);
-
-}
-
-
index 3f08a57..688d951 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.misc;
 
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -36,32 +39,12 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStreamWriter;
 import java.io.Reader;
-
-import mir.config.MirPropertiesConfiguration;
-import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;
-
 /**
  * Hilfsklasse zum Mergen von Template und Daten
  */
 public final class FileUtil {
-
-  private static String producerStorageRoot;
-
-  //
-  // Initialisierung
-
-  static {
-    try {
-      producerStorageRoot =
-          MirPropertiesConfiguration.instance().getString("Producer.StorageRoot");
-    }
-    catch (PropertiesConfigExc e) {
-      e.printStackTrace();
-    }
-  }
-
   /**
-   * Privater Konstruktor, um versehentliche Instantiierung zu verhindern
+   * Privater Construktor to avoid accidental instantiation
    */
   private FileUtil() {
   }
@@ -88,8 +71,9 @@ public final class FileUtil {
 
     if (in != null) {
       try {
-        FileOutputStream out = new FileOutputStream(f);
+        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(f),8192);
 
+        // TODO get size with in.available()
         int read;
         byte[] buf = new byte[8 * 1024];
         while ( (read = in.read(buf)) != -1) {
@@ -131,7 +115,7 @@ public final class FileUtil {
       try {
         File f = getFile(filename);
         FileOutputStream fOut = new FileOutputStream(f);
-        OutputStreamWriter out = new OutputStreamWriter(fOut, encoding);
+        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(fOut, encoding),8192);
         int read;
         char[] cbuf = new char[8 * 1024];
         while ( (read = in.read(cbuf)) != -1) {
@@ -158,8 +142,8 @@ public final class FileUtil {
       try {
         if (out.length != f.length())
           return false;
-        FileInputStream inStream;
-        inStream = new FileInputStream(f);
+        BufferedInputStream inStream;
+        inStream = new BufferedInputStream(new FileInputStream(f),8192);
         inStream.read(out);
         inStream.close();
       }
diff --git a/source/mir/misc/HTMLParseException.java b/source/mir/misc/HTMLParseException.java
deleted file mode 100755 (executable)
index 3e13956..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.misc;
-
-
-/*
- *  HTMLParseException -
- *  wird vom HTMLProcessor geschmissen</b>
- *
- *
- * @version 30.6.199
- * @author RK
- */
-
-public class HTMLParseException extends Exception
-{
-       HTMLParseException(String msg) {
-               super(msg);
-       }
-}
-
diff --git a/source/mir/misc/LineFilterWriter.java b/source/mir/misc/LineFilterWriter.java
deleted file mode 100755 (executable)
index 240a14e..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.misc;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.Writer;
-
-/**
- *  LineFilterWriter eliminates superfluous \t \r \n and spaces
- *  and thus compresses the output of html
- *
- **/
-public final class LineFilterWriter extends PrintWriter{
-
-  protected Writer out;
-
-  public LineFilterWriter(Writer out) {
-    super(out);
-    this.out=out;
-  }
-
-  public final void write(String str){
-    int i,j,len;
-    boolean state=true;
-    char c;
-    len=str.length();
-    if (len==1) {try{out.write(str);}catch(IOException e){}return;}
-    StringBuffer sbuf = new StringBuffer();
-
-    for(i=0;i<len;i++) {
-      c=str.charAt(i);
-      if(state) {
-        j = str.indexOf('\n',i);
-        if (j==-1) j=len-1;
-                               sbuf.append(str.substring(i,j+1));
-        i=j;
-        state=false;
-      }
-      else
-         if (!Character.isWhitespace(c)) {
-                                               sbuf.append(c);
-            state=true;
-         }
-    }
-    try{out.write(sbuf.toString());}catch(IOException e){;}
-  }
-
-  public final void write(char[] cbuf, int off,int len){
-    int i,j=off;
-    boolean state=true;
-    char c;
-
-    for(i=off;i<len;i++) {
-      c=cbuf[i];
-      if(state) {
-        if (c=='\n') state=false;
-        cbuf[j++]=c;
-      }
-      else
-         if (!Character.isWhitespace(c)) {
-                                               cbuf[j++]=c;
-            state=true;
-         }
-    }
-    try{out.write(cbuf,off,j);}catch(IOException e){;}
-  }
-
-
-}
index 48966e7..2e88252 100755 (executable)
@@ -29,6 +29,7 @@
  */
 package mir.misc;
 
+import java.io.BufferedOutputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -71,7 +72,7 @@ public class PDFUtil {
 
       if (pdfDestination instanceof String) {
         String filePath = (String) pdfDestination;
-        driver.setOutputStream(new FileOutputStream(filePath));
+        driver.setOutputStream(new BufferedOutputStream(new FileOutputStream(filePath)));
         driver.render(parser, inputHandler.getInputSource());
       }
       else if (pdfDestination instanceof HttpServletResponse){
index 5588286..967ffec 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  any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two.  You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries.  If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-package  mir.misc;\r
-\r
-import java.text.NumberFormat;\r
-import java.util.Calendar;\r
-import java.util.Date;\r
-import java.util.GregorianCalendar;\r
-import java.util.TimeZone;\r
-\r
-import gnu.regexp.RE;\r
-import gnu.regexp.REException;\r
-\r
-/**\r
- * Statische Hilfsmethoden zur Stringbehandlung\r
- *\r
- * @version $Id: StringUtil.java,v 1.34 2003/09/03 18:29:02 zapata Exp $\r
- * @author mir-coders group\r
- *\r
- */\r
-public final class StringUtil {\r
-\r
-  private static RE   re_newline2br, re_brbr2p, re_mail, re_url, re_tags,\r
-                      re_tables, re_forbiddenTags;\r
-\r
-  private StringUtil() { }  // this avoids contruction\r
-\r
-  static {\r
-    try {\r
-      //precompile regex\r
-      re_newline2br = new RE("(\r?\n){1}");\r
-      re_brbr2p     = new RE("(<br>\r?\n<br>){1,}");\r
-      re_mail       = new RE("\\b([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_-]+)\\.([a-zA-Z0-9_.-]+)\\b");\r
-      re_url        = new RE("((https://)|(http://)|(ftp://)){1}([a-zA-Z0-9_-]+).([a-zA-Z0-9_.:-]+)/?([^ \t\r\n<>\\)\\]]+[^ \t\r\n.,<>\\)\\]])");\r
-      re_tags       = new RE("<[^>]*>",RE.REG_ICASE);\r
-      re_tables = new RE("<[ \t\r\n/]*(table|td|tr)[ \t\r\n]*>",RE.REG_ICASE);\r
-      re_forbiddenTags = new RE("<[ \t\r\n/]*(html|meta|body|head|script)[ \t\r\n]*>",RE.REG_ICASE);\r
-    }\r
-    catch (REException e){\r
-      System.err.println("FATAL: StringUtil: could not precompile REGEX: "+e.toString());\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Formats a number with the specified minimum and maximum number of digits.\r
-   **/\r
-  public static synchronized String zeroPaddingNumber(long value, int minDigits,\r
-      int maxDigits)\r
-  {\r
-    NumberFormat numberFormat = NumberFormat.getInstance();\r
-    numberFormat.setMinimumIntegerDigits(minDigits);\r
-    numberFormat.setMaximumIntegerDigits(maxDigits);\r
-    return numberFormat.format(value);\r
-  }\r
-\r
-  /**\r
-   * Wandelt Datum in einen 8-ziffrigen String um (yyyymmdd)\r
-   * @param theDate\r
-   * @return 8-ziffriger String (yyyymmdd)\r
-   */\r
-\r
-  public static final String date2webdbDate (GregorianCalendar theDate) {\r
-    StringBuffer webdbDate = new StringBuffer();\r
-    webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));\r
-    webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));\r
-    webdbDate.append(pad2(theDate.get(Calendar.DATE)));\r
-    return  webdbDate.toString();\r
-  }\r
-\r
-  /**\r
-   * Wandelt Calendar in einen 12-ziffrigen String um (yyyymmddhhmm)\r
-   * @param theDate\r
-   * @return 12-ziffriger String (yyyymmdd)\r
-   */\r
-\r
-  public static final String date2webdbDateTime (GregorianCalendar theDate) {\r
-    StringBuffer webdbDate = new StringBuffer();\r
-    webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));\r
-    webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));\r
-    webdbDate.append(pad2(theDate.get(Calendar.DATE)));\r
-    webdbDate.append(pad2(theDate.get(Calendar.HOUR)));\r
-    webdbDate.append(pad2(theDate.get(Calendar.MINUTE)));\r
-    return  webdbDate.toString();\r
-  }\r
-\r
-  /**\r
-   * Return a http://www.w3.org/TR/NOTE-datetime formatted date (yyyy-mm-ddThh:mm:ssTZ)\r
-   * @param theDate\r
-   * @return w3approved datetime\r
-   */\r
-\r
-  public static final String date2w3DateTime (GregorianCalendar theDate) {\r
-    StringBuffer webdbDate = new StringBuffer();\r
-    webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));\r
-    webdbDate.append("-");\r
-    webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));\r
-    webdbDate.append("-");\r
-    webdbDate.append(pad2(theDate.get(Calendar.DATE)));\r
-    webdbDate.append("T");\r
-    webdbDate.append(pad2(theDate.get(Calendar.HOUR_OF_DAY)));\r
-    webdbDate.append(":");\r
-    webdbDate.append(pad2(theDate.get(Calendar.MINUTE)));\r
-    webdbDate.append(":");\r
-    webdbDate.append(pad2(theDate.get(Calendar.SECOND)));\r
-    //assumes you are an hour-multiple away from UTC....\r
-    int offset=(theDate.get(Calendar.ZONE_OFFSET)/(60*60*1000));\r
-    if (offset < 0){\r
-      webdbDate.append("-");\r
-    }\r
-    else{\r
-      webdbDate.append("+");\r
-    }\r
-    webdbDate.append(pad2(Math.abs(offset)));\r
-    webdbDate.append(":00");\r
-    return  webdbDate.toString();\r
-  }\r
-\r
-  /**\r
-   * wandelt Calendar in dd.mm.yyyy / hh.mm um\r
-   * @param theDate\r
-   * @return String mit (dd.mm.yyyy / hh.mm um)\r
-   */\r
-  public static String date2readableDateTime (GregorianCalendar theDate) {\r
-    String readable = "";\r
-    int hour;\r
-    readable += pad2(theDate.get(Calendar.DATE));\r
-    readable += "." + pad2(theDate.get(Calendar.MONTH) + 1);\r
-    readable += "." + String.valueOf(theDate.get(Calendar.YEAR));\r
-    hour = theDate.get(Calendar.HOUR);\r
-    if (theDate.get(Calendar.AM_PM) == Calendar.PM)\r
-      hour += 12;\r
-    readable += " / " + pad2(hour);\r
-    readable += ":" + pad2(theDate.get(Calendar.MINUTE));\r
-    return  readable;\r
-  }\r
-\r
-  /**\r
-  *  deleteForbiddenTags\r
-  *  this method deletes all <script>, <body> and <head>-tags\r
-  */\r
-  public static final String deleteForbiddenTags(String haystack) {\r
-    return re_forbiddenTags.substituteAll(haystack,"");\r
-  }\r
-\r
-  /**\r
-   *  deleteHTMLTableTags\r
-   *  this method deletes all <table>, <tr> and <td>-tags\r
-   */\r
-  public static final String deleteHTMLTableTags(String haystack) {\r
-    return re_tables.substituteAll(haystack,"");\r
-  }\r
-\r
-  /**\r
-   * wandelt eine Datum in einen 8-buchstabigen String, der durch <code>/</code>\r
-   * getrennt ist.\r
-   *\r
-   * @param webdbDate\r
-   * @return String mit <code>/yyyy/mm/dd</code>\r
-   */\r
-  public static final String webdbDate2path (String webdbDate) {\r
-    StringBuffer path = new StringBuffer();\r
-    path.append("/").append(webdbDate.substring(0, 4));\r
-    path.append("/").append(webdbDate.substring(4, 6));\r
-    path.append("/");\r
-    //who did this?\r
-    //path.append("/").append(webdbDate.substring(6, 8));\r
-    return  path.toString();\r
-  }\r
-\r
-  /**\r
-   * Ersetzt in String <code>s</code> das Regexp <code>pattern</code> durch <code>substitute</code>\r
-   * @param s\r
-   * @param pattern\r
-   * @param substitute\r
-   * @return String mit den Ersetzungen\r
-   */\r
-  public static String regexpReplace(String haystack, String pattern, String substitute) {\r
-    try {\r
-      RE regex = new RE(pattern);\r
-      return regex.substituteAll(haystack,substitute);\r
-    } catch(REException ex){\r
-      return null;\r
-    }\r
-  }\r
-\r
-  /**\r
-   * L?scht <code>/</code> am Ende des Strings, falls vorhanden\r
-   * @param path\r
-   * @return String ohne <code>/</code> am Ende\r
-   */\r
-  public static final String removeSlash (String path) {\r
-    return  path.length() > 1 && path.endsWith("/") ? path.substring(0, path.length()\r
-        - 1) : path;\r
-  }\r
-\r
-  /**\r
-   * formatiert eine Zahl (0-99) zweistellig (z.B. 5 -> 05)\r
-   * @return zwistellige Zahl\r
-   */\r
-  public static String pad2 (int number) {\r
-    return  number < 10 ? "0" + number : String.valueOf(number);\r
-  }\r
-\r
-  /**\r
-   * formatiert eine Zahl (0-999) dreistellig (z.B. 7 -> 007)\r
-   *\r
-   * @return 3-stellige Zahl\r
-   */\r
-  public static String pad3 (int number) {\r
-    return  number < 10 ? "00" + number : number < 100 ? "0" + number : String.valueOf(number);\r
-  }\r
-\r
-  /**\r
-   * Liefert Default-Wert def zur?ck, wenn String <code>s</code>\r
-   * kein Integer ist.\r
-   *\r
-   * @param s\r
-   * @param def\r
-   * @return geparster int aus s oder def\r
-   */\r
-  public static int parseInt(String s, int def) {\r
-    if (s == null) return def;\r
-    try {\r
-      return Integer.parseInt(s);\r
-    } catch (NumberFormatException e) {\r
-      return def;\r
-    }\r
-  }\r
-\r
-\r
-  /**\r
-   *  convertNewline2P ist eine regex-routine zum umwandeln von 2 oder mehr newlines (\n)\r
-   *  in den html-tag <p>\r
-   *  nur sinnvoll, wenn text nicht im html-format eingegeben\r
-   */\r
-  public static String convertNewline2P(String haystack) {\r
-    return re_brbr2p.substituteAll(haystack,"\n</p><p>");\r
-  }\r
-\r
-  /**\r
-   *  convertNewline2Break ist eine regex-routine zum umwandeln von 1 newline (\n)\r
-   *  in den html-tag <br>\r
-   *  nur sinnvoll, wenn text nicht im html-format eingegeben\r
-   */\r
-  public static String convertNewline2Break(String haystack) {\r
-    return re_newline2br.substituteAll(haystack,"$0<br />");\r
-  }\r
-\r
-  /**\r
-   *  createMailLinks wandelt text im email-adressenformat\r
-   *  in einen klickbaren link um\r
-   *  nur sinnvoll, wenn text nicht im html-format eingegeben\r
-   */\r
-  public static String createMailLinks(String haystack) {\r
-    return re_mail.substituteAll(haystack,"<a href=\"mailto:$0\">$0</a>");\r
-  }\r
-\r
-\r
-  /**\r
-   *  createMailLinks wandelt text im email-adressenformat\r
-   *  in einen klickbaren link um\r
-   *  nur sinnvoll, wenn text nicht im html-format eingegeben\r
-   */\r
-  public static String createMailLinks(String haystack, String imageRoot, String mailImage) {\r
-    return re_mail.substituteAll(haystack,"<img src=\""+imageRoot+"/"+mailImage+"\" border=\"0\"/>&#160;<a href=\"mailto:$0\">$0</a>");\r
-  }\r
-\r
-\r
-  /**\r
-   *  createURLLinks wandelt text im url-format\r
-   *  in einen klickbaren link um\r
-   *  nur sinnvoll, wenn text nicht im html-format eingegeben\r
-   */\r
-  public static String createURLLinks(String haystack) {\r
-    return re_url.substituteAll(haystack,"<a href=\"$0\">$0</a>");\r
-  }\r
-\r
-  /**\r
-   * this routine takes text in url format and makes\r
-   * a clickaeble "<href>" link removing any "illegal" html tags\r
-   * @param haystack, the url\r
-   * @param title, the href link text\r
-   * @param imagRoot, the place to find icons\r
-   * @param extImage, the url of the icon to show next to the link\r
-   * @return a String containing the url\r
-   */\r
-  public static String createURLLinks(String haystack, String title, String imageRoot,String extImage) {\r
-    if (title == null) {\r
-      return re_url.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">$0</a>");\r
-    } else {\r
-      title = removeHTMLTags(title);\r
-      return re_url.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">"+title+"</a>");\r
-    }\r
-  }\r
-\r
-  /**\r
-   * this routine takes text in url format and makes\r
-   * a clickaeble "<href>" link removing any "illegal" html tags\r
-   * @param haystack, the url\r
-   * @param imageRoot, the place to find icons\r
-   * @param extImage, the url of the icon to show next to the link\r
-   * @param intImage, unused\r
-   * @return a String containing the url\r
-   */\r
-  public static String createURLLinks(String haystack, String title, String imageRoot,String extImage,String intImage) {\r
-    return createURLLinks(haystack, title, imageRoot, extImage);\r
-  }\r
-\r
-  /**\r
-   * this method deletes all html tags\r
-   */\r
-  public static final String removeHTMLTags(String haystack){\r
-    return re_tags.substituteAll(haystack,"");\r
-  }\r
-\r
-  /**\r
-   * this method deletes all but the approved tags html tags\r
-   * it also deletes approved tags which contain malicious-looking attributes and doesn't work at all\r
-   */\r
-  public static String approveHTMLTags(String haystack){\r
-    try {\r
-      String approvedTags="a|img|h1|h2|h3|h4|h5|h6|br|b|i|strong|p";\r
-      String badAttributes="onAbort|onBlur|onChange|onClick|onDblClick|onDragDrop|onError|onFocus|onKeyDown|onKeyPress|onKeyUp|onLoad|onMouseDown|onMouseMove|onMouseOut|onMouseOver|onMouseUp|onMove|onReset|onResize|onSelect|onSubmit|onUnload";\r
-      String approvedProtocols="rtsp|http|ftp|https|freenet|mailto";\r
-\r
-      // kill all the bad tags that have attributes\r
-      String s = "<\\s*/?\\s*(?!(("+approvedTags+")\\s))\\w+\\s[^>]*>";\r
-      RE regex = new RE(s,RE.REG_ICASE);\r
-      haystack = regex.substituteAll(haystack,"");\r
-\r
-      // kill all the bad tags that are attributeless\r
-      regex = new RE("<\\s*/?\\s*(?!(("+approvedTags+")\\s*>))\\w+\\s*>",RE.REG_ICASE);\r
-      haystack = regex.substituteAll(haystack,"");\r
-\r
-      // kill all the tags which have a javascript attribute like onLoad\r
-      regex = new RE("<[^>]*("+badAttributes+")[^>]*>",RE.REG_ICASE);\r
-      haystack = regex.substituteAll(haystack,"");\r
-\r
-      // kill all the tags which include a url to an unacceptable protocol\r
-      regex = new RE("<\\s*a\\s+[^>]*href=(?!(\'|\")?("+approvedProtocols+"))[^>]*>",RE.REG_ICASE);\r
-      haystack = regex.substituteAll(haystack,"");\r
-\r
-      return haystack;\r
-    } catch(REException ex){\r
-      ex.printStackTrace();\r
-      return null;\r
-    }\r
-  }\r
-\r
-\r
-  /**\r
-   *  createHTML ruft alle regex-methoden zum unwandeln eines nicht\r
-   *  htmlcodierten string auf und returnt einen htmlcodierten String\r
-   */\r
-  public static String createHTML(String content){\r
-    content=convertNewline2Break(content);\r
-    content=convertNewline2P(content);\r
-    content=createMailLinks(content);\r
-    content=createURLLinks(content);\r
-    return content;\r
-  }\r
-\r
-\r
-  /**\r
-   *  createHTML ruft alle regex-methoden zum unwandeln eines nicht\r
-   *  htmlcodierten string auf und returnt einen htmlcodierten String\r
-   */\r
-  public static String createHTML(String content,String producerDocRoot,String mailImage,String extImage,String intImage){\r
-    content=convertNewline2Break(content);\r
-    content=convertNewline2P(content);\r
-    content=createMailLinks(content,producerDocRoot,mailImage);\r
-    content=createURLLinks(content,null,producerDocRoot,extImage,intImage);\r
-    return content;\r
-  }\r
-\r
-  /**\r
-   * Converts mir's horrible internal date format (yyyy-MM-dd HH:mm:ss+zz) into a java Date\r
-   *\r
-   * @param anInternalDate\r
-   * @return\r
-   */\r
-  public static Date convertMirInternalDateToDate(String anInternalDate) {\r
-    Calendar calendar = new GregorianCalendar();\r
-\r
-    int year;\r
-    int month;\r
-    int day;\r
-    int hours;\r
-    int minutes;\r
-    int seconds;\r
-    int timezoneOffset;\r
-\r
-    year = Integer.parseInt(anInternalDate.substring(0,4));\r
-    month = Integer.parseInt(anInternalDate.substring(5,7));\r
-    day = Integer.parseInt(anInternalDate.substring(8,10));\r
-    hours = Integer.parseInt(anInternalDate.substring(11,13));\r
-    minutes = Integer.parseInt(anInternalDate.substring(14,16));\r
-    seconds = Integer.parseInt(anInternalDate.substring(17,19));\r
-\r
-    timezoneOffset = Integer.parseInt(anInternalDate.substring(20,22));\r
-    if (anInternalDate.charAt(19) == '-')\r
-      timezoneOffset = -timezoneOffset;\r
-\r
-    calendar.setTimeZone(TimeZone.getTimeZone("UTC"));\r
-    calendar.set(year, month-1, day, hours, minutes, seconds);\r
-    calendar.add(Calendar.HOUR, -timezoneOffset);\r
-\r
-    return calendar.getTime();\r
-  }\r
-\r
-}\r
-\r
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.misc;
+
+import gnu.regexp.RE;
+import gnu.regexp.REException;
+
+import java.text.NumberFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+/**
+ * Statische Hilfsmethoden zur Stringbehandlung
+ *
+ * @version $Id: StringUtil.java,v 1.35 2004/11/06 19:27:33 idfx Exp $
+ * @author mir-coders group
+ *
+ */
+public final class StringUtil {
+
+  private static RE   re_newline2br, re_brbr2p, re_mail, re_url, re_tags,
+                      re_tables, re_forbiddenTags;
+
+  private StringUtil() { }  // this avoids contruction
+
+  static {
+    try {
+      //precompile regex
+      re_newline2br = new RE("(\r?\n){1}");
+      re_brbr2p     = new RE("(<br>\r?\n<br>){1,}");
+      re_mail       = new RE("\\b([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_-]+)\\.([a-zA-Z0-9_.-]+)\\b");
+      re_url        = new RE("((https://)|(http://)|(ftp://)){1}([a-zA-Z0-9_-]+).([a-zA-Z0-9_.:-]+)/?([^ \t\r\n<>\\)\\]]+[^ \t\r\n.,<>\\)\\]])");
+      re_tags       = new RE("<[^>]*>",RE.REG_ICASE);
+      re_tables = new RE("<[ \t\r\n/]*(table|td|tr)[ \t\r\n]*>",RE.REG_ICASE);
+      re_forbiddenTags = new RE("<[ \t\r\n/]*(html|meta|body|head|script)[ \t\r\n]*>",RE.REG_ICASE);
+    }
+    catch (REException e){
+      System.err.println("FATAL: StringUtil: could not precompile REGEX: "+e.toString());
+    }
+  }
+
+  /**
+   * Formats a number with the specified minimum and maximum number of digits.
+   **/
+  public static synchronized String zeroPaddingNumber(long value, int minDigits,
+      int maxDigits)
+  {
+    NumberFormat numberFormat = NumberFormat.getInstance();
+    numberFormat.setMinimumIntegerDigits(minDigits);
+    numberFormat.setMaximumIntegerDigits(maxDigits);
+    return numberFormat.format(value);
+  }
+
+  /**
+   * Wandelt Datum in einen 8-ziffrigen String um (yyyymmdd)
+   * @param theDate
+   * @return 8-ziffriger String (yyyymmdd)
+   */
+
+  public static final String date2webdbDate (GregorianCalendar theDate) {
+    StringBuffer webdbDate = new StringBuffer();
+    webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
+    webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
+    webdbDate.append(pad2(theDate.get(Calendar.DATE)));
+    return  webdbDate.toString();
+  }
+
+  /**
+   * Wandelt Calendar in einen 12-ziffrigen String um (yyyymmddhhmm)
+   * @param theDate
+   * @return 12-ziffriger String (yyyymmdd)
+   */
+
+  public static final String date2webdbDateTime (GregorianCalendar theDate) {
+    StringBuffer webdbDate = new StringBuffer();
+    webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
+    webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
+    webdbDate.append(pad2(theDate.get(Calendar.DATE)));
+    webdbDate.append(pad2(theDate.get(Calendar.HOUR)));
+    webdbDate.append(pad2(theDate.get(Calendar.MINUTE)));
+    return  webdbDate.toString();
+  }
+
+  /**
+   * Return a http://www.w3.org/TR/NOTE-datetime formatted date (yyyy-mm-ddThh:mm:ssTZ)
+   * @param theDate
+   * @return w3approved datetime
+   */
+
+  public static final String date2w3DateTime (GregorianCalendar theDate) {
+    StringBuffer webdbDate = new StringBuffer();
+    webdbDate.append(String.valueOf(theDate.get(Calendar.YEAR)));
+    webdbDate.append("-");
+    webdbDate.append(pad2(theDate.get(Calendar.MONTH) + 1));
+    webdbDate.append("-");
+    webdbDate.append(pad2(theDate.get(Calendar.DATE)));
+    webdbDate.append("T");
+    webdbDate.append(pad2(theDate.get(Calendar.HOUR_OF_DAY)));
+    webdbDate.append(":");
+    webdbDate.append(pad2(theDate.get(Calendar.MINUTE)));
+    webdbDate.append(":");
+    webdbDate.append(pad2(theDate.get(Calendar.SECOND)));
+    //assumes you are an hour-multiple away from UTC....
+    int offset=(theDate.get(Calendar.ZONE_OFFSET)/(60*60*1000));
+    if (offset < 0){
+      webdbDate.append("-");
+    }
+    else{
+      webdbDate.append("+");
+    }
+    webdbDate.append(pad2(Math.abs(offset)));
+    webdbDate.append(":00");
+    return  webdbDate.toString();
+  }
+
+  /**
+   * wandelt Calendar in dd.mm.yyyy / hh.mm um
+   * @param theDate
+   * @return String mit (dd.mm.yyyy / hh.mm um)
+   */
+  public static String date2readableDateTime (GregorianCalendar theDate) {
+    String readable = "";
+    int hour;
+    readable += pad2(theDate.get(Calendar.DATE));
+    readable += "." + pad2(theDate.get(Calendar.MONTH) + 1);
+    readable += "." + String.valueOf(theDate.get(Calendar.YEAR));
+    hour = theDate.get(Calendar.HOUR);
+    if (theDate.get(Calendar.AM_PM) == Calendar.PM)
+      hour += 12;
+    readable += " / " + pad2(hour);
+    readable += ":" + pad2(theDate.get(Calendar.MINUTE));
+    return  readable;
+  }
+
+  /**
+  *  deleteForbiddenTags
+  *  this method deletes all <script>, <body> and <head>-tags
+  */
+  public static final String deleteForbiddenTags(String haystack) {
+    return re_forbiddenTags.substituteAll(haystack,"");
+  }
+
+  /**
+   *  deleteHTMLTableTags
+   *  this method deletes all <table>, <tr> and <td>-tags
+   */
+  public static final String deleteHTMLTableTags(String haystack) {
+    return re_tables.substituteAll(haystack,"");
+  }
+
+  /**
+   * wandelt eine Datum in einen 8-buchstabigen String, der durch <code>/</code>
+   * getrennt ist.
+   *
+   * @param webdbDate
+   * @return String mit <code>/yyyy/mm/dd</code>
+   */
+  public static final String webdbDate2path (String webdbDate) {
+    StringBuffer path = new StringBuffer();
+    path.append("/").append(webdbDate.substring(0, 4));
+    path.append("/").append(webdbDate.substring(4, 6));
+    path.append("/");
+    //who did this?
+    //path.append("/").append(webdbDate.substring(6, 8));
+    return  path.toString();
+  }
+
+  /**
+   * Ersetzt in String <code>s</code> das Regexp <code>pattern</code> durch <code>substitute</code>
+   * @param s
+   * @param pattern
+   * @param substitute
+   * @return String mit den Ersetzungen
+   */
+  public static String regexpReplace(String haystack, String pattern, String substitute) {
+    try {
+      RE regex = new RE(pattern);
+      return regex.substituteAll(haystack,substitute);
+    } catch(REException ex){
+      return null;
+    }
+  }
+
+  /**
+   * L?scht <code>/</code> am Ende des Strings, falls vorhanden
+   * @param path
+   * @return String ohne <code>/</code> am Ende
+   */
+  public static final String removeSlash (String path) {
+    return  path.length() > 1 && path.endsWith("/") ? path.substring(0, path.length()
+        - 1) : path;
+  }
+
+  /**
+   * formatiert eine Zahl (0-99) zweistellig (z.B. 5 -> 05)
+   * @return zwistellige Zahl
+   */
+  public static String pad2 (int number) {
+    return  number < 10 ? "0" + number : String.valueOf(number);
+  }
+
+  /**
+   * formatiert eine Zahl (0-999) dreistellig (z.B. 7 -> 007)
+   *
+   * @return 3-stellige Zahl
+   */
+  public static String pad3 (int number) {
+    return  number < 10 ? "00" + number : number < 100 ? "0" + number : String.valueOf(number);
+  }
+
+  /**
+   * Liefert Default-Wert def zur?ck, wenn String <code>s</code>
+   * kein Integer ist.
+   *
+   * @param s
+   * @param def
+   * @return geparster int aus s oder def
+   */
+  public static int parseInt(String s, int def) {
+    if (s == null) return def;
+    try {
+      return Integer.parseInt(s);
+    } catch (NumberFormatException e) {
+      return def;
+    }
+  }
+
+
+  /**
+   *  convertNewline2P ist eine regex-routine zum umwandeln von 2 oder mehr newlines (\n)
+   *  in den html-tag <p>
+   *  nur sinnvoll, wenn text nicht im html-format eingegeben
+   */
+  public static String convertNewline2P(String haystack) {
+    return re_brbr2p.substituteAll(haystack,"\n</p><p>");
+  }
+
+  /**
+   *  convertNewline2Break ist eine regex-routine zum umwandeln von 1 newline (\n)
+   *  in den html-tag <br>
+   *  nur sinnvoll, wenn text nicht im html-format eingegeben
+   */
+  public static String convertNewline2Break(String haystack) {
+    return re_newline2br.substituteAll(haystack,"$0<br />");
+  }
+
+  /**
+   *  createMailLinks wandelt text im email-adressenformat
+   *  in einen klickbaren link um
+   *  nur sinnvoll, wenn text nicht im html-format eingegeben
+   */
+  public static String createMailLinks(String haystack) {
+    return re_mail.substituteAll(haystack,"<a href=\"mailto:$0\">$0</a>");
+  }
+
+
+  /**
+   *  createMailLinks wandelt text im email-adressenformat
+   *  in einen klickbaren link um
+   *  nur sinnvoll, wenn text nicht im html-format eingegeben
+   */
+  public static String createMailLinks(String haystack, String imageRoot, String mailImage) {
+    return re_mail.substituteAll(haystack,"<img src=\""+imageRoot+"/"+mailImage+"\" border=\"0\"/>&#160;<a href=\"mailto:$0\">$0</a>");
+  }
+
+
+  /**
+   *  createURLLinks wandelt text im url-format
+   *  in einen klickbaren link um
+   *  nur sinnvoll, wenn text nicht im html-format eingegeben
+   */
+  public static String createURLLinks(String haystack) {
+    return re_url.substituteAll(haystack,"<a href=\"$0\">$0</a>");
+  }
+
+  /**
+   * this routine takes text in url format and makes
+   * a clickaeble "<href>" link removing any "illegal" html tags
+   * @param haystack, the url
+   * @param title, the href link text
+   * @param imagRoot, the place to find icons
+   * @param extImage, the url of the icon to show next to the link
+   * @return a String containing the url
+   */
+  public static String createURLLinks(String haystack, String title, String imageRoot,String extImage) {
+    if (title == null) {
+      return re_url.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">$0</a>");
+    } else {
+      title = removeHTMLTags(title);
+      return re_url.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">"+title+"</a>");
+    }
+  }
+
+  /**
+   * this routine takes text in url format and makes
+   * a clickaeble "<href>" link removing any "illegal" html tags
+   * @param haystack, the url
+   * @param imageRoot, the place to find icons
+   * @param extImage, the url of the icon to show next to the link
+   * @param intImage, unused
+   * @return a String containing the url
+   */
+  public static String createURLLinks(String haystack, String title, String imageRoot,String extImage,String intImage) {
+    return createURLLinks(haystack, title, imageRoot, extImage);
+  }
+
+  /**
+   * this method deletes all html tags
+   */
+  public static final String removeHTMLTags(String haystack){
+    return re_tags.substituteAll(haystack,"");
+  }
+
+  /**
+   * this method deletes all but the approved tags html tags
+   * it also deletes approved tags which contain malicious-looking attributes and doesn't work at all
+   */
+  public static String approveHTMLTags(String haystack){
+    try {
+      String approvedTags="a|img|h1|h2|h3|h4|h5|h6|br|b|i|strong|p";
+      String badAttributes="onAbort|onBlur|onChange|onClick|onDblClick|onDragDrop|onError|onFocus|onKeyDown|onKeyPress|onKeyUp|onLoad|onMouseDown|onMouseMove|onMouseOut|onMouseOver|onMouseUp|onMove|onReset|onResize|onSelect|onSubmit|onUnload";
+      String approvedProtocols="rtsp|http|ftp|https|freenet|mailto";
+
+      // kill all the bad tags that have attributes
+      String s = "<\\s*/?\\s*(?!(("+approvedTags+")\\s))\\w+\\s[^>]*>";
+      RE regex = new RE(s,RE.REG_ICASE);
+      haystack = regex.substituteAll(haystack,"");
+
+      // kill all the bad tags that are attributeless
+      regex = new RE("<\\s*/?\\s*(?!(("+approvedTags+")\\s*>))\\w+\\s*>",RE.REG_ICASE);
+      haystack = regex.substituteAll(haystack,"");
+
+      // kill all the tags which have a javascript attribute like onLoad
+      regex = new RE("<[^>]*("+badAttributes+")[^>]*>",RE.REG_ICASE);
+      haystack = regex.substituteAll(haystack,"");
+
+      // kill all the tags which include a url to an unacceptable protocol
+      regex = new RE("<\\s*a\\s+[^>]*href=(?!(\'|\")?("+approvedProtocols+"))[^>]*>",RE.REG_ICASE);
+      haystack = regex.substituteAll(haystack,"");
+
+      return haystack;
+    } catch(REException ex){
+      ex.printStackTrace();
+      return null;
+    }
+  }
+
+
+  /**
+   *  createHTML ruft alle regex-methoden zum unwandeln eines nicht
+   *  htmlcodierten string auf und returnt einen htmlcodierten String
+   */
+  public static String createHTML(String content){
+    content=convertNewline2Break(content);
+    content=convertNewline2P(content);
+    content=createMailLinks(content);
+    content=createURLLinks(content);
+    return content;
+  }
+
+
+  /**
+   *  createHTML ruft alle regex-methoden zum unwandeln eines nicht
+   *  htmlcodierten string auf und returnt einen htmlcodierten String
+   */
+  public static String createHTML(String content,String producerDocRoot,String mailImage,String extImage,String intImage){
+    content=convertNewline2Break(content);
+    content=convertNewline2P(content);
+    content=createMailLinks(content,producerDocRoot,mailImage);
+    content=createURLLinks(content,null,producerDocRoot,extImage,intImage);
+    return content;
+  }
+
+  /**
+   * Converts mir's horrible internal date format (yyyy-MM-dd HH:mm:ss+zz) into a java Date
+   *
+   * @param anInternalDate
+   * @return
+   */
+  public static Date convertMirInternalDateToDate(String anInternalDate) {
+    Calendar calendar = new GregorianCalendar();
+
+    int year;
+    int month;
+    int day;
+    int hours;
+    int minutes;
+    int seconds;
+    int timezoneOffset;
+
+    year = Integer.parseInt(anInternalDate.substring(0,4));
+    month = Integer.parseInt(anInternalDate.substring(5,7));
+    day = Integer.parseInt(anInternalDate.substring(8,10));
+    hours = Integer.parseInt(anInternalDate.substring(11,13));
+    minutes = Integer.parseInt(anInternalDate.substring(14,16));
+    seconds = Integer.parseInt(anInternalDate.substring(17,19));
+
+    timezoneOffset = Integer.parseInt(anInternalDate.substring(20,22));
+    if (anInternalDate.charAt(19) == '-')
+      timezoneOffset = -timezoneOffset;
+
+    calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
+    calendar.set(year, month-1, day, hours, minutes, seconds);
+    calendar.add(Calendar.HOUR, -timezoneOffset);
+
+    return calendar.getTime();
+  }
+
+}
+
index 7d0c5c5..aea424b 100755 (executable)
  */
 package  mir.module;
 
-import java.util.Map;\r
-\r
-import mir.entity.Entity;\r
-import mir.entity.EntityList;\r
+import java.util.Map;
+import java.sql.SQLException;
+
+import mir.entity.Entity;
+import mir.entity.EntityList;
 import mir.storage.StorageObject;
 
 
@@ -49,30 +50,24 @@ import mir.storage.StorageObject;
  */
 
 public class AbstractModule {
-  protected StorageObject theStorage;
+  protected StorageObject storage;
 
-  public void setStorage(StorageObject storage) {
-    this.theStorage = storage;
+  public AbstractModule(StorageObject aStorageObject) {
+    storage = aStorageObject;
   }
 
   /**
-   * Liefert das Standard-StorageObject zur?ck, mit dem das Module assoziiert ist.
-   * @return Standard-StorageObject
+   * Returns the storage object associated with this module
    */
   public StorageObject getStorageObject () {
-    return theStorage;
+    return storage;
   }
 
-  /**
-   *   Holt eine Entity anhand der Id via StorageObject
-   *   @param String der Entity
-   *   @return Entity
-   */
   public Entity getById (String id) throws ModuleExc, ModuleFailure {
     try {
-      if (theStorage == null)
+      if (storage == null)
         throw  new ModuleExc("AbstractModule.getById: No StorageObject set!");
-      Entity entity = (Entity)theStorage.selectById(id);
+      Entity entity = storage.selectById(id);
 
       if (entity == null)
         throw new ModuleExc("AbstractModule.getById: No object for id = " + id);
@@ -84,18 +79,12 @@ public class AbstractModule {
     }
   }
 
-  /**
-   *   Holt eine EntityListe anhand des WhereClause via StorageObject
-   *   @param String whereclause
-   *   @param offset - ab welchem Datensatz die gematchten Entities zurueckgeliefert werden
-   *   @return EntityList Liste der gematchten Datens?tze
-   */
   public EntityList getByWhereClause (String whereClause, int offset) throws ModuleExc, ModuleFailure {
     try {
-      if (theStorage == null)
+      if (storage == null)
         throw  new ModuleExc("AbstractModule.getByWhereClause: No StorageObject set!");
 
-      return theStorage.selectByWhereClause(whereClause, offset);
+      return storage.selectByWhereClause(whereClause, offset);
     }
     catch (Throwable e) {
       throw new ModuleFailure(e);
@@ -103,60 +92,6 @@ public class AbstractModule {
   }
 
   /**
-   *   Holt eine EntityListe anhand des WhereClause aus dem StorageObject
-   *   @param String where WhereClause
-   *   @param String order Sortierreihenfolge
-   *   @param offset - ab welchem Datensatz die gematchten Entities zurueckgeliefert werden
-   *   @return EntityList Liste der gematchten Datens?tze
-   */
-  public EntityList getByWhereClause (String where, String order, int offset) throws ModuleExc, ModuleFailure {
-    try {
-      if (theStorage==null)
-        throw new ModuleExc("AbstractModule.getByWhereClause: No StorageObject set!");
-
-      return theStorage.selectByWhereClause(where, order, offset);
-    }
-    catch (Throwable e) {
-      throw new ModuleFailure(e);
-    }
-  }
-  /**
-   *   Executes a where clause on the StorageObject with order criteria
-   *   fetching from offset the number of limit objects
-   *
-   *   @param String where
-   *   @param String order
-   *   @param int offset
-   *   @param int limit
-   *   @return EntityList
-   */
-
-  public EntityList getByWhereClause(String where, String order, int offset, int limit) throws ModuleExc, ModuleFailure   {
-    try {
-      if (theStorage==null)
-        throw new ModuleExc("AbstractModule.getByWhereClause: StorageObject not set!");
-
-      return theStorage.selectByWhereClause(where, order, offset, limit);
-    }
-    catch (Throwable e) {
-      throw new ModuleFailure(e);
-    }
-  }
-
-  /**
-   *   Holt eine EntityListe anhand des Wertes aValue von Feld aField aus dem StorageObject
-   *   @param String aField - Feldname im StorageObject
-   *   @param String aValue - Wert in Feld im StorageObject
-   *   @param offset - ab welchem Datensatz die gematchten Entities zurueckgeliefert werden
-   *   @return EntityList Liste der gematchten Datens?tze
-   */
-  public EntityList getByFieldValue (String aField, String aValue, int offset) throws ModuleExc, ModuleFailure {
-    String whereClause;
-    whereClause = aField + " like '%" + aValue + "%'";
-    return getByWhereClause(whereClause, offset);
-  }
-
-  /**
    *    * Standardfunktion, um einen Datensatz via StorageObject einzuf?gen
    * @param theValues Hash mit Spalte/Wert-Paaren
    * @return Id des eingef?gten Objekts
@@ -165,9 +100,9 @@ public class AbstractModule {
    */
   public String add (Map theValues) throws ModuleExc, ModuleFailure {
     try {
-      Entity theEntity = (Entity)theStorage.getEntityClass().newInstance();
-      theEntity.setStorage(theStorage);
-      theEntity.setValues(theValues);
+      Entity theEntity = (Entity)storage.getEntityClass().newInstance();
+      theEntity.setStorage(storage);
+      theEntity.setFieldValues(theValues);
       return theEntity.insert();
     }
     catch (Throwable e) {
@@ -177,16 +112,11 @@ public class AbstractModule {
 
   /**
    * This function creates an Entity without yet storing it in the database
-   *
-   * @param theValues
-   * @return
-   * @throws ModuleExc
-   * @throws ModuleFailure
    */
   public Entity createNew() throws ModuleExc, ModuleFailure {
     try {
-      Entity result = (Entity)theStorage.getEntityClass().newInstance();
-      result.setStorage(theStorage);
+      Entity result = (Entity)storage.getEntityClass().newInstance();
+      result.setStorage(storage);
 
       return result;
     }
@@ -204,10 +134,10 @@ public class AbstractModule {
    */
   public String set (Map theValues) throws ModuleExc, ModuleFailure {
     try {
-      Entity theEntity = theStorage.selectById((String)theValues.get("id"));
+      Entity theEntity = storage.selectById((String)theValues.get("id"));
       if (theEntity == null)
         throw new ModuleExc("No object found with id " + theValues.get("id"));
-      theEntity.setValues(theValues);
+      theEntity.setFieldValues(theValues);
       theEntity.update();
       return theEntity.getId();
     }
@@ -224,7 +154,7 @@ public class AbstractModule {
    */
   public void deleteById (String idParam) throws ModuleExc, ModuleFailure {
     try {
-      theStorage.delete(idParam);
+      storage.delete(idParam);
     }
     catch (Throwable e) {
       throw new ModuleFailure(e);
@@ -236,10 +166,10 @@ public class AbstractModule {
    */
   public int getSize(String where) throws ModuleExc, ModuleFailure {
     try {
-      return theStorage.getSize(where);
+      return storage.getSize(where);
     }
-    catch (Throwable e) {
-      throw new ModuleFailure(e);
+    catch (SQLException e) {
+      throw new ModuleFailure("Can't retrieve number of entities: " + e.toString(), e);
     }
   }
 
diff --git a/source/mir/producer/BundleProducerNode.java b/source/mir/producer/BundleProducerNode.java
new file mode 100755 (executable)
index 0000000..f7f8cdb
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
+
+import java.util.Map;
+
+import mir.bundle.Bundle;
+import mir.log.LoggerWrapper;
+import mir.util.ParameterExpander;
+import mir.util.generator.BundleGeneratorFunction;
+import mircoders.global.MirGlobal;
+
+/**
+ * This producer node loads a bundle
+ */
+public class BundleProducerNode implements ProducerNode {
+  private String key;
+  private String bundleExpression;
+  private String languageExpression;
+
+  public BundleProducerNode(String aKey, String aBundleExpression) {
+    this (aKey, aBundleExpression, null);
+  }
+
+  public BundleProducerNode(String aKey, String aBundleExpression, String aLanguageExpression) {
+    bundleExpression = aBundleExpression;
+    languageExpression = aLanguageExpression;
+    key = aKey;
+  }
+
+  /** {@inheritDoc} */
+  public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure {
+    try {
+      String bundle = ParameterExpander.expandExpression( aValueMap, bundleExpression );
+      String[] languages = new String[0];
+      if (languageExpression!=null)
+        languages = new String[] { ParameterExpander.expandExpression( aValueMap, languageExpression ) };
+
+      if (MirGlobal.config().getString("Producer.BundleCompatibility", "0").equals("1") &&
+          bundle.startsWith("bundles.")) {
+        bundle = "etc/bundles/" + bundle.substring("bundles.".length());
+      }
+
+      ParameterExpander.setValueForKey(
+          aValueMap, key, new BundleGeneratorFunction(
+              new Bundle[] { MirGlobal.getBundleFactory().getBundle( bundle, languages ) }
+          )
+      );
+    }
+    catch (Throwable t) {
+      aLogger.error("Failed to load bundle " + bundleExpression + " for language " +
+          languageExpression +  " into key " + key + ": " + t.getMessage());
+    }
+  };
+
+}
\ No newline at end of file
index 9f4db9e..63fe79e 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
 
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Vector;
 
 import mir.log.LoggerWrapper;
 
@@ -40,7 +40,7 @@ public class CompositeProducerNode implements ProducerNode {
   private List subNodes;
 
   public CompositeProducerNode() {
-    subNodes = new Vector();
+    subNodes = new ArrayList();
   }
 
   public CompositeProducerNode(ProducerNode[] aSubNodes) {
index d4e823c..2eb3b08 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
@@ -39,10 +39,10 @@ import mir.util.ParameterExpander;
 public class DirCopyingProducerNode implements ProducerNode  {
   private String sourceExpression;
   private String destinationExpression;
-  private String sourceBasePath;
-  private String destinationBasePath;
+  private File sourceBasePath;
+  private File destinationBasePath;
 
-  public DirCopyingProducerNode(String aSourceBasePath, String aDestinationBasePath, String aSource, String aDestination) {
+  public DirCopyingProducerNode(File aSourceBasePath, File aDestinationBasePath, String aSource, String aDestination) {
     sourceBasePath = aSourceBasePath;
     destinationBasePath = aDestinationBasePath;
     sourceExpression = aSource;
@@ -52,8 +52,6 @@ public class DirCopyingProducerNode implements ProducerNode  {
   public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure {
     String source = "";
     String destination = "";
-    File sourceFile;
-    File destinationFile;
 
     try {
       source = ParameterExpander.expandExpression( aValueMap, sourceExpression );
index 1aa17cd..aa0bf41 100755 (executable)
@@ -33,12 +33,13 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Vector;
+import java.util.ArrayList;
 
 import mir.entity.adapter.EntityAdapterModel;
 import mir.entity.adapter.EntityIteratorAdapter;
 import mir.log.LoggerWrapper;
 import mir.util.ParameterExpander;
+import mir.util.StringRoutines;
 
 /**
  * <p>Title: EntityBatchingProducerNode</p>
@@ -59,6 +60,8 @@ public class EntityBatchingProducerNode implements ProducerNode {
   private String batchInfoKey;
   private String batchDataKey;
   private EntityAdapterModel model;
+  private String mainTablePrefix;
+  private String extraTables;
   private String definition;
   private String whereClause;
   private String orderByClause;
@@ -73,6 +76,8 @@ public class EntityBatchingProducerNode implements ProducerNode {
         String aBatchDataKey,
         String aBatchInfoKey,
         EntityAdapterModel aModel,
+        String aMainTablePrefix,
+        String someExtraTables,
         String aDefinition,
         String aWhereClause,
         String anOrderByClause,
@@ -89,6 +94,8 @@ public class EntityBatchingProducerNode implements ProducerNode {
     batchDataKey = aBatchDataKey;
     batchInfoKey = aBatchInfoKey;
     model = aModel;
+    mainTablePrefix = aMainTablePrefix;
+    extraTables = someExtraTables;
     definition = aDefinition;
     whereClause = aWhereClause;
     orderByClause = anOrderByClause;
@@ -106,14 +113,12 @@ public class EntityBatchingProducerNode implements ProducerNode {
   }
 
   public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure {
-    Iterator browser;
     int nrEntities;
     int nrBatchesAfterFirst;
     int nrEntitiesInFirstBatch;
     int nrBatchesToProcess;
     List batchesData;
     int i;
-    int position;
     Map batchData;
     String expandedWhereClause;
     String expandedOrderByClause;
@@ -134,11 +139,13 @@ public class EntityBatchingProducerNode implements ProducerNode {
       nrEntitiesToSkip = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesToSkipExpression);
       nrEntitiesPerBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, nrEntitiesPerBatchExpression);
       minNrEntitiesInFirstBatch = ParameterExpander.evaluateIntegerExpression( aValueMap, minNrEntitiesInFirstBatchExpression);
+      List extraTableList = StringRoutines.splitString(ParameterExpander.expandExpression( aValueMap, extraTables).trim(), ",");
 
-      batchesData = new Vector();
-      batchLocations = new Vector();
+      batchesData = new ArrayList();
+      batchLocations = new ArrayList();
 
-      nrEntities = model.getMappingForName(definition).getStorage().getSize(expandedWhereClause)-nrEntitiesToSkip;
+      nrEntities = model.getMappingForName(definition).getStorage().getSize(
+          mainTablePrefix, extraTableList, expandedWhereClause)-nrEntitiesToSkip;
       nrEntitiesInFirstBatch = nrEntities % nrEntitiesPerBatch;
       while (nrEntitiesInFirstBatch<minNrEntitiesInFirstBatch && nrEntities-nrEntitiesInFirstBatch>=nrEntitiesPerBatch)
         nrEntitiesInFirstBatch = nrEntitiesInFirstBatch + nrEntitiesPerBatch;
@@ -190,9 +197,9 @@ public class EntityBatchingProducerNode implements ProducerNode {
           else
             batchData.put("next", null);
 
-          Iterator j = new EntityIteratorAdapter(expandedWhereClause, expandedOrderByClause,
+          Iterator j = new EntityIteratorAdapter(mainTablePrefix, extraTableList, expandedWhereClause, expandedOrderByClause,
                     location.nrEntities, model, definition, location.nrEntities, location.firstEntity);
-          List entities = new Vector();
+          List entities = new ArrayList();
 
           while (j.hasNext())
             entities.add(0, j.next());
index 055e182..0a09c02 100755 (executable)
 package mir.producer;
 
 import java.util.Map;
-import java.util.Vector;
 
 import mir.entity.adapter.EntityAdapterModel;
-import mir.entity.adapter.EntityIteratorAdapter;
 import mir.log.LoggerWrapper;
-import mir.util.CachingRewindableIterator;
 import mir.util.ParameterExpander;
 
 public class EntityDeletingProducerNode implements ProducerNode {
index 5986d14..ca4fef8 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
@@ -36,11 +36,14 @@ import mir.entity.adapter.EntityAdapterModel;
 import mir.entity.adapter.EntityIteratorAdapter;
 import mir.log.LoggerWrapper;
 import mir.util.ParameterExpander;
+import mir.util.StringRoutines;
 
 public class EntityEnumeratingProducerNode extends ProducerNodeDecorator {
   private String key;
   private EntityAdapterModel model;
   private String definition;
+  private String mainTablePrefix;
+  private String extraTables;
   private String skip;
   private String limit;
   private String whereClause;
@@ -48,7 +51,8 @@ public class EntityEnumeratingProducerNode extends ProducerNodeDecorator {
 
   public EntityEnumeratingProducerNode(
               String aKey,
-              EntityAdapterModel aModel, String aDefinition,
+              EntityAdapterModel aModel, String aMainTablePrefix,
+              String anExtraTables, String aDefinition,
               String aWhereClause, String anOrderByClause,
               String aLimit, String aSkip,
               ProducerNode aSubNode) {
@@ -57,7 +61,8 @@ public class EntityEnumeratingProducerNode extends ProducerNodeDecorator {
     model = aModel;
     definition = aDefinition;
     key = aKey;
-
+    mainTablePrefix=aMainTablePrefix;
+    extraTables = anExtraTables;
     whereClause = aWhereClause;
     orderByClause = anOrderByClause;
 
@@ -70,6 +75,8 @@ public class EntityEnumeratingProducerNode extends ProducerNodeDecorator {
 
     try {
       browser = new EntityIteratorAdapter(
+          mainTablePrefix,
+          StringRoutines.splitString(ParameterExpander.expandExpression( aValueMap, extraTables).trim(), ","),
           ParameterExpander.expandExpression( aValueMap, whereClause ),
           ParameterExpander.expandExpression( aValueMap, orderByClause ),
           100,
index 123c15b..32e0d3a 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
 
+import java.util.Collections;
 import java.util.Map;
-import java.util.Vector;
 
 import mir.entity.adapter.EntityAdapterModel;
 import mir.entity.adapter.EntityIteratorAdapter;
 import mir.log.LoggerWrapper;
 import mir.util.CachingRewindableIterator;
 import mir.util.ParameterExpander;
+import mir.util.StringRoutines;
 
 public class EntityListProducerNode extends ProducerNodeDecorator {
-  private String key;
+  private String keyExpression;
   private String whereClause;
   private String orderByClause;
-  private int batchSize;
+  private String mainTablePrefix;
+  private String extraTables;
   private EntityAdapterModel model;
   private String definition;
   private String limitExpression;
   private String skipExpression;
 
   public EntityListProducerNode(String aKey,
-      EntityAdapterModel aModel, String aDefinition,
-      String aWhereClause, String anOrderByClause,
+      EntityAdapterModel aModel, String aMainTablePrefix, String anExtraTables,
+      String aDefinition, String aWhereClause, String anOrderByClause,
       String aLimitExpression, String aSkipExpression, ProducerNode aSubNode) {
     super(aSubNode);
 
     model = aModel;
+    mainTablePrefix = aMainTablePrefix;
+    extraTables = anExtraTables;
     definition = aDefinition;
-    key = aKey;
+    keyExpression = aKey;
     whereClause = aWhereClause;
     orderByClause = anOrderByClause;
     limitExpression = aLimitExpression;
     skipExpression = aSkipExpression;
   }
 
-  public EntityListProducerNode(String aKey,
-      EntityAdapterModel aModel, String aDefinition,
-      String aWhereClause, String anOrderByClause,
-      int aLimit, int aSkip, ProducerNode aSubNode) {
-    this(aKey,  aModel, aDefinition, aWhereClause, anOrderByClause,
-         Integer.toString(aLimit), Integer.toString(aSkip), aSubNode);
-  }
-
   public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure, ProducerExc {
     try {
       int limit = ParameterExpander.evaluateIntegerExpressionWithDefault(aValueMap, limitExpression, -1);
@@ -78,36 +74,42 @@ public class EntityListProducerNode extends ProducerNodeDecorator {
 
       if (skipExpression != null && !skipExpression.trim().equals(""))
         skip = ParameterExpander.evaluateIntegerExpression(aValueMap, skipExpression);
+      String key = ParameterExpander.expandExpression(aValueMap, keyExpression);
 
-      ParameterExpander.setValueForKey(
-        aValueMap,
-        key,
-        new CachingRewindableIterator(
-          new EntityIteratorAdapter(
-            ParameterExpander.expandExpression( aValueMap, whereClause ),
-            ParameterExpander.expandExpression( aValueMap, orderByClause ),
-            Math.min(50, limit),
-            model,
-            definition,
-            limit,
-            skip )
-        )
-      );
-    }
-    catch (Throwable t) {
-      aLogger.error("cannot retrieve list into key " + key + ": " + t.getMessage());
       try {
         ParameterExpander.setValueForKey(
           aValueMap,
           key,
-          new CachingRewindableIterator(new Vector().iterator())
+          new CachingRewindableIterator(
+            new EntityIteratorAdapter( mainTablePrefix,
+              StringRoutines.splitString(ParameterExpander.expandExpression( aValueMap, extraTables).trim(), ","),
+              ParameterExpander.expandExpression( aValueMap, whereClause ),
+              ParameterExpander.expandExpression( aValueMap, orderByClause ),
+              Math.min(50, limit),
+              model,
+              definition,
+              limit,
+              skip )
+          )
         );
       }
-      catch (Throwable s) {
+      catch (Throwable t) {
+        aLogger.error("cannot retrieve list into keyExpression " + key + ": " + t.getMessage());
+        try {
+          ParameterExpander.setValueForKey(
+            aValueMap,
+            key,
+            new CachingRewindableIterator(Collections.EMPTY_LIST.iterator())
+          );
+        }
+        catch (Throwable s) {
+        }
       }
     }
+    catch (Throwable t) {
+      aLogger.error("cannot process entity list producer node: : " + t.getMessage());
+    }
 
     super.produce(aValueMap, aVerb, aLogger);
-  };
-
+  }
 }
\ No newline at end of file
index 295a63a..ec3e0c7 100755 (executable)
 
 package mir.producer;
 
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.*;
+import java.util.Map;
 
 import mir.entity.Entity;
 import mir.entity.adapter.EntityAdapter;
 import mir.entity.adapter.EntityAdapterModel;
 import mir.log.LoggerWrapper;
+import mir.util.JDBCStringRoutines;
 import mir.util.ParameterExpander;
-import mir.util.*;
 
 
 public class EntityModifyingProducerNode implements ProducerNode {
@@ -85,11 +86,11 @@ public class EntityModifyingProducerNode implements ProducerNode {
           Object value = ParameterExpander.evaluateExpression(aValueMap, valueExpression);
 
           if (value instanceof String)
-            entity.setValueForProperty(entityField, (String) value);
+            entity.setFieldValue(entityField, (String) value);
           else if (value instanceof EntityAdapter)
-            entity.setValueForProperty(entityField, ((EntityAdapter) value).getEntity().getId());
+            entity.setFieldValue(entityField, ((EntityAdapter) value).getEntity().getId());
           else if (value instanceof Date) {
-            entity.setValueForProperty(entityField, JDBCStringRoutines.formatDate((Date) value));
+            entity.setFieldValue(entityField, JDBCStringRoutines.formatDate((Date) value));
           }
           else
             aLogger.warn("Can't set value " + value + " for field " + entityField);
@@ -105,7 +106,7 @@ public class EntityModifyingProducerNode implements ProducerNode {
     }
     catch (Throwable t) {
       aLogger.error("Error while performing entity modification operation: " + t.getMessage());
-      t.printStackTrace(aLogger.asPrintWriter(aLogger.DEBUG_MESSAGE));
+      t.printStackTrace(aLogger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
 
       throw new ProducerFailure(t.getMessage(), t);
     }
diff --git a/source/mir/producer/ExecuteProgramProducerNode.java b/source/mir/producer/ExecuteProgramProducerNode.java
new file mode 100755 (executable)
index 0000000..0c57a15
--- /dev/null
@@ -0,0 +1,128 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.producer;\r
+\r
+import java.util.Map;\r
+\r
+import mir.log.LoggerWrapper;\r
+import mir.util.ParameterExpander;\r
+\r
+public class ExecuteProgramProducerNode implements ProducerNode  {\r
+  private String scriptExpression;\r
+  private String maxDurationExpression;\r
+  private String outputVariableExpression;\r
+  private String returnValueVariableExpression;\r
+\r
+  public ExecuteProgramProducerNode(String aScriptExpression, String aMaxDurationExpression, String anOutputVariableExpression,\r
+                                    String aReturnValueVariableExpression) {\r
+    scriptExpression = aScriptExpression;\r
+    maxDurationExpression = aMaxDurationExpression;\r
+    outputVariableExpression = anOutputVariableExpression;\r
+    returnValueVariableExpression = aReturnValueVariableExpression;\r
+  }\r
+\r
+  public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure {\r
+    String script;\r
+    long maxDuration;\r
+\r
+    try {\r
+      script = ParameterExpander.expandExpression(aValueMap, scriptExpression);\r
+      maxDuration = ParameterExpander.evaluateIntegerExpressionWithDefault(aValueMap, maxDurationExpression, 0);\r
+\r
+      ProcessRunner runner = new ProcessRunner(aLogger, script);\r
+      runner.start();\r
+\r
+      synchronized (runner) {\r
+        runner.wait(maxDuration);\r
+      }\r
+      runner.interrupt();\r
+\r
+      if (runner.getFinished()) {\r
+        aLogger.info(script + " terminated successfully, return value = " + runner.getReturnValue() + ".");\r
+\r
+        if (returnValueVariableExpression != null) {\r
+          ParameterExpander.setValueForKey(aValueMap,\r
+              ParameterExpander.expandExpression(aValueMap, returnValueVariableExpression),\r
+              new Integer(runner.getReturnValue()));\r
+        }\r
+\r
+      }\r
+      else {\r
+        aLogger.info(script + " interrupted prematurely after " + maxDuration + "ms.");\r
+      }\r
+    }\r
+    catch (Throwable e) {\r
+      aLogger.error("Error while executing " + scriptExpression + " : " + e.toString());\r
+    }\r
+  }\r
+\r
+  private static class ProcessRunner extends Thread {\r
+    private String script;\r
+    private boolean finished = false;\r
+    private int returnValue = 0;\r
+    private LoggerWrapper logger;\r
+\r
+    public ProcessRunner(LoggerWrapper aLogger, String aScript) {\r
+      script = aScript;\r
+      logger = aLogger;\r
+    }\r
+\r
+    public boolean getFinished() {\r
+      return finished;\r
+    }\r
+\r
+    public int getReturnValue() {\r
+      return returnValue;\r
+    }\r
+\r
+    public void run() {\r
+      Process process = null;\r
+      try {\r
+        process = Runtime.getRuntime().exec(script);\r
+        returnValue = process.waitFor();\r
+\r
+        finished = true;\r
+\r
+        synchronized (this) {\r
+          this.notify();\r
+        }\r
+      }\r
+      catch (InterruptedException e) {\r
+        if (process!=null) {\r
+          process.destroy();\r
+        }\r
+      }\r
+      catch (Exception e) {\r
+        logger.error(script + " failed to execute: " + e.getMessage());\r
+      }\r
+    }\r
+  }\r
+\r
+}\r
diff --git a/source/mir/producer/ExternalDbProducerNode.java b/source/mir/producer/ExternalDbProducerNode.java
new file mode 100755 (executable)
index 0000000..cfc1e51
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.sql.*;
+
+
+import mir.log.LoggerWrapper;
+import mir.util.ExceptionFunctions;
+import mir.util.ParameterExpander;
+
+public class ExternalDbProducerNode extends ProducerNodeDecorator {
+  private String key;
+  private String driver;
+  private String host;
+  private String port;
+  private String database;
+  private String username;
+  private String password;
+  private String query;   
+
+  public ExternalDbProducerNode(String aKey, String aDriver, String aHost, String aPort, String aDatabase, String aUsername, String aPassword,String aQuery,ProducerNode aSubNode) {
+    super(aSubNode);
+    key = aKey;
+    driver = aDriver;
+    host = aHost;
+    port = aPort;
+    database = aDatabase;
+    username = aUsername;
+    password = aPassword;
+    query =aQuery;
+    
+  }
+
+  public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure {
+    try {
+      String expandedKey = ParameterExpander.expandExpression( aValueMap, key );
+      String expandedDriver = ParameterExpander.expandExpression( aValueMap, driver);
+      String expandedHost = ParameterExpander.expandExpression( aValueMap, host);
+      String expandedPort = ParameterExpander.expandExpression( aValueMap, port);
+      String expandedDatabase = ParameterExpander.expandExpression( aValueMap, database);
+      String expandedUsername = ParameterExpander.expandExpression( aValueMap, username);
+      String expandedPassword = ParameterExpander.expandExpression( aValueMap, password);
+      String expandedQuery = ParameterExpander.expandExpression( aValueMap, query);
+
+      if (expandedDriver.equals("postgresql")){
+       Class.forName("org.postgresql.Driver");
+      }
+      if (expandedDriver.equals("mysql")){
+       Class.forName("com.mysql.jdbc.Driver");
+      }
+      else {
+         throw new Exception("Unsupported DB Driver:"+expandedDriver);
+      }
+      
+      Connection db = DriverManager.getConnection("jdbc:"+expandedDriver+"://"+expandedHost
+                                                 +":"+expandedPort+"/"+expandedDatabase
+                                                 , expandedUsername, expandedPassword);
+      
+      Statement st = db.createStatement();
+      ResultSet rs = st.executeQuery(expandedQuery);
+      ResultSetMetaData rsmd = rs.getMetaData();
+      int numberOfColumns= rsmd.getColumnCount();
+      ArrayList fieldNames = new ArrayList(numberOfColumns);     
+      for (int i=0;i<numberOfColumns;i++){
+         fieldNames.add(rsmd.getColumnName(i+1));
+      }
+
+      while(rs.next()  && !isAborted(aValueMap)) {
+       HashMap result=new HashMap();
+       Iterator fields = fieldNames.iterator();
+       while (fields.hasNext()) {
+         String field=(String) fields.next();
+         result.put(field,rs.getString(field));
+       }    
+       ParameterExpander.setValueForKey(aValueMap,expandedKey,result);
+       super.produce(aValueMap, aVerb, aLogger);
+      }
+      rs.close();
+      st.close();
+      db.close();
+    }
+    catch (Throwable t) {
+      Throwable s = ExceptionFunctions.traceCauseException(t);
+      aLogger.error("Error while accessing external database: " + s.getClass().getName()+","+ s.getMessage());
+    }
+  };
+}
index 1ea6d17..50f5b58 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
@@ -50,7 +50,8 @@ public class FileDateSettingProducerNode extends FileOperationProducerNode {
       Object date = ParameterExpander.findValueForKey( aValueMap, dateExpression );
 
       if (!(date instanceof Date))
-        aLogger.error( "FileDateSettingProducerNode: expression " + dateExpression + " does not evaluate to a Date!") ;
+        aLogger.error( "FileDateSettingProducerNode: expression " +
+            dateExpression + " does not evaluate to a Date!") ;
 
       if (!aFile.setLastModified(((Date) date).getTime())) {
         aLogger.error("Can't set date for " + aFile.getName());
index 2ecb203..9841903 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
 
+import java.util.HashMap;
 import java.util.Map;
 
 import mir.generator.Generator;
@@ -40,10 +41,10 @@ public class GeneratingProducerNode implements ProducerNode {
   private String generatorExpression;
   private String destinationExpression;
   private String parametersExpression;
-  private Generator.GeneratorLibrary generatorLibrary;
+  private Generator.Library generatorLibrary;
   private WriterEngine writerEngine;
 
-  public GeneratingProducerNode(Generator.GeneratorLibrary aGeneratorLibrary, WriterEngine aWriterEngine, String aGenerator, String aDestination, String aParameters) {
+  public GeneratingProducerNode(Generator.Library aGeneratorLibrary, WriterEngine aWriterEngine, String aGenerator, String aDestination, String aParameters) {
     generatorExpression=aGenerator;
     destinationExpression=aDestination;
     parametersExpression=aParameters;
@@ -51,7 +52,7 @@ public class GeneratingProducerNode implements ProducerNode {
     writerEngine = aWriterEngine;
   }
 
-  public GeneratingProducerNode(Generator.GeneratorLibrary aGeneratorLibrary, WriterEngine aWriterEngine, String aGenerator, String aDestination) {
+  public GeneratingProducerNode(Generator.Library aGeneratorLibrary, WriterEngine aWriterEngine, String aGenerator, String aDestination) {
     this(aGeneratorLibrary, aWriterEngine, aGenerator, aDestination, "");
   }
 
@@ -67,20 +68,41 @@ public class GeneratingProducerNode implements ProducerNode {
 
     startTime = System.currentTimeMillis();
     try {
-      destinationIdentifier = ParameterExpander.expandExpression( aValueMap, destinationExpression );
-      generatorIdentifier = ParameterExpander.expandExpression( aValueMap, generatorExpression );
-      parameters = ParameterExpander.expandExpression( aValueMap, parametersExpression );
+      Map mirMap = (Map) aValueMap.get("Mir");
+      if (mirMap==null) {
+        mirMap = new HashMap();
+        aValueMap.put("Mir", mirMap);
+      }
 
-      writer = writerEngine.openWriter( destinationIdentifier, parameters );
-      generator = generatorLibrary.makeGenerator( generatorIdentifier );
-      generator.generate(writer, aValueMap, aLogger);
-      writerEngine.closeWriter( writer );
+      Object oldGenerator = mirMap.get("generator");
+      Object oldDestination = mirMap.get("destination");
+      Object oldParameters = mirMap.get("parameters");
+      try {
+        destinationIdentifier = ParameterExpander.expandExpression(aValueMap, destinationExpression);
+        generatorIdentifier = ParameterExpander.expandExpression(aValueMap, generatorExpression);
+        parameters = ParameterExpander.expandExpression(aValueMap, parametersExpression);
 
-      endTime = System.currentTimeMillis();
-      aLogger.info("Generated " + generatorIdentifier + " into " + destinationIdentifier + " [" + parameters + "] in " + (endTime-startTime) + " ms");
+        mirMap.put("generator", generatorIdentifier);
+        mirMap.put("destination", destinationIdentifier);
+        mirMap.put("parameters", parameters);
+
+        writer = writerEngine.openWriter(destinationIdentifier, parameters);
+        generator = generatorLibrary.makeGenerator(generatorIdentifier);
+        generator.generate(writer, aValueMap, aLogger);
+        writerEngine.closeWriter(writer);
+
+        endTime = System.currentTimeMillis();
+        aLogger.info("Generated " + generatorIdentifier + " into " + destinationIdentifier + " [" + parameters + "] in " + (endTime - startTime) + " ms");
+      }
+      finally {
+        mirMap.put("generator", oldGenerator);
+        mirMap.put("destination", oldDestination);
+        mirMap.put("parameters", oldParameters);
+      }
     }
     catch (Throwable t) {
       aLogger.error("  error while generating: " + t.getClass().getName() + ": " + t.getMessage());
+      t.printStackTrace(aLogger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
     }
   }
 }
\ No newline at end of file
index 6dc6d01..e9a68fc 100755 (executable)
  */
 package mir.producer;
 
-import java.util.*;
+import java.util.Collection;
+import java.util.Iterator;
 import java.util.Map;
 
-import mir.entity.adapter.EntityAdapterModel;
-import mir.entity.adapter.EntityIteratorAdapter;
 import mir.log.LoggerWrapper;
-import mir.util.*;
+import mir.util.ParameterExpander;
+import mir.util.RewindableIterator;
 
 public class ListEnumeratingProducerNode extends ProducerNodeDecorator {
   private String key;
diff --git a/source/mir/producer/NodedProducerFactory.java b/source/mir/producer/NodedProducerFactory.java
deleted file mode 100755 (executable)
index 6df430b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Vector;
-
-public class NodedProducerFactory implements ProducerFactory {
-  private ProducerNode rootNode;
-  private List verbs;
-  private String name;
-
-  public NodedProducerFactory(String aName, ProducerNode aRootNode) {
-    rootNode = aRootNode;
-    verbs = new Vector();
-    name = aName;
-  }
-
-  public void addVerb(String aName, String aDescription) {
-    verbs.add(new SimpleProducerVerb(aName, aDescription));
-  }
-
-  public String getName() {
-    return name;
-  }
-
-  public mir.producer.Producer makeProducer(String aVerb, Map aBasicValueSet) throws ProducerFailure {
-    Map baseValues;
-
-    try {
-      baseValues = new HashMap();
-      baseValues.putAll(aBasicValueSet);
-
-      return new NodedProducer(rootNode, aVerb, baseValues);
-    }
-    catch (Throwable t) {
-      throw new ProducerFailure(t.getMessage(), t);
-    }
-  };
-
-  public Iterator verbs() {
-    return verbs.iterator();
-  };
-}
-
index df164dc..d3ca018 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
 
-import java.util.Iterator;
 import java.util.Map;
+import java.util.List;
 
 public interface ProducerFactory {
   public interface ProducerVerb {
@@ -38,8 +38,24 @@ public interface ProducerFactory {
     String getDescription();
   }
 
+  /**
+   * The identifying name of the factory
+   */
   public String getName();
+
+  /**
+   * Returns <code>true</code> if <code>aVerb</code> is a valid verb for this factory
+   */
+  public boolean allowVerb(String aVerb);
+
+  /**
+   * Instantiates a producer based on the supplied verb
+   */
   public Producer makeProducer(String aVerb, Map aStartingValues) throws ProducerFailure, ProducerExc;
-  public Iterator verbs(); /* returns ProducerVerbs */
+
+  /**
+   * The set of pre-defined verbs. Returns a list of {@link ProducerVerb}s
+   */
+  public List verbs();
 }
 
index 084e58e..2e0f7c8 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
@@ -33,6 +33,14 @@ import java.util.Map;
 
 import mir.log.LoggerWrapper;
 
+/**
+ * A <code>ProducerNode</code> is an atom of a noded producer factory.
+ *
+ */
 public interface ProducerNode {
+  /**
+   * Perform the operations of the producer node, based on a verb and a value set.
+   * The supplied logger object should be used for any logging.
+   */
   public void produce(Map aValueSet, String aVerb, LoggerWrapper aLogger) throws ProducerExc, ProducerFailure;
 }
\ No newline at end of file
index 209f51f..fe99ff6 100755 (executable)
  */
 package mir.producer;
 
-import java.util.*;
+import java.util.List;
+import java.util.Map;
 
 import mir.log.LoggerWrapper;
-import mir.rss.*;
+import mir.rss.RSSAggregator;
 import mir.util.ExceptionFunctions;
 import mir.util.ParameterExpander;
 
index 6dae7c6..9d62022 100755 (executable)
@@ -32,8 +32,9 @@ package mir.producer;
 import java.util.Map;
 
 import mir.log.LoggerWrapper;
+import mir.rss.RSS091Reader;
 import mir.rss.RSSData;
-import mir.rss.*;
+import mir.rss.RSSReader;
 import mir.util.ExceptionFunctions;
 import mir.util.ParameterExpander;
 
@@ -41,11 +42,17 @@ public class RSSProducerNode implements ProducerNode {
   private String key;
   private String url;
   private String version;
+  private String encoding;
 
-  public RSSProducerNode(String aKey, String anURL, String aVersion) {
+  public RSSProducerNode(String aKey, String aURL, String aVersion) {
+    this (aKey, aURL, aVersion, null);
+  }
+
+  public RSSProducerNode(String aKey, String aURL, String aVersion, String anEncoding) {
     key = aKey;
-    url = anURL;
+    url = aURL;
     version = aVersion;
+    encoding = anEncoding;
   }
 
   public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure {
@@ -54,16 +61,30 @@ public class RSSProducerNode implements ProducerNode {
       String expandedKey = ParameterExpander.expandExpression( aValueMap, key );
       String expandedUrl = ParameterExpander.expandExpression( aValueMap, url );
       String expandedVersion = ParameterExpander.expandExpression( aValueMap, version );
+      String expandedEncoding = null;
+      if (encoding!=null) {
+        expandedEncoding = ParameterExpander.expandExpression( aValueMap, encoding );
+      }
 
       ParameterExpander.setValueForKey(aValueMap, expandedKey, null);
 
-      if (version.equals("1.0")) {
+      if (expandedVersion.equals("1.0")) {
         RSSReader reader = new RSSReader();
-        rssData = reader.parseUrl(expandedUrl);
+        if (expandedEncoding!=null) {
+          rssData = reader.parseUrl(expandedUrl, expandedEncoding);
+        }
+        else {
+          rssData = reader.parseUrl(expandedUrl);
+        }
       }
-      else if (version.equals("0.91")) {
+      else if (expandedVersion.equals("0.91")) {
         RSS091Reader reader = new RSS091Reader();
-        rssData = reader.parseUrl(expandedUrl);
+        if (expandedEncoding!=null) {
+          rssData = reader.parseUrl(expandedUrl, expandedEncoding);
+        }
+        else {
+          rssData = reader.parseUrl(expandedUrl);
+        }
       }
       ParameterExpander.setValueForKey(aValueMap, expandedKey, rssData);
     }
diff --git a/source/mir/producer/ResourceBundleProducerNode.java b/source/mir/producer/ResourceBundleProducerNode.java
deleted file mode 100755 (executable)
index 26d1118..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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;
-
-import java.util.Locale;
-import java.util.Map;
-
-import mir.log.LoggerWrapper;
-import mir.util.ParameterExpander;
-import mir.util.ResourceBundleGeneratorFunction;
-
-import org.apache.struts.util.MessageResources;
-
-public class ResourceBundleProducerNode implements ProducerNode {
-  private String key;
-  private String bundleExpression;
-  private String languageExpression;
-
-  public ResourceBundleProducerNode(String aKey, String aBundleExpression) {
-    this (aKey, aBundleExpression, null);
-  }
-
-  public ResourceBundleProducerNode(String aKey, String aBundleExpression, String aLanguageExpression) {
-    bundleExpression = aBundleExpression;
-    languageExpression = aLanguageExpression;
-    key = aKey;
-  }
-
-  public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure {
-    Object messages;
-
-    try {
-      if (languageExpression!=null) {
-        messages =
-            new ResourceBundleGeneratorFunction(
-                new Locale(ParameterExpander.expandExpression( aValueMap, languageExpression ), "" ),
-                MessageResources.getMessageResources( ParameterExpander.expandExpression( aValueMap, bundleExpression ))
-            );
-      }
-      else {
-        messages =
-          MessageResources.getMessageResources(
-              ParameterExpander.expandExpression( aValueMap, bundleExpression ));
-      }
-      ParameterExpander.setValueForKey( aValueMap, key, messages );
-    }
-    catch (Throwable t) {
-      aLogger.error("Failed to load bundle " + bundleExpression + " for language " + languageExpression +  " into key " + key + ": " + t.getMessage());
-    }
-  };
-
-}
\ No newline at end of file
diff --git a/source/mir/producer/ScriptCallingProducerNode.java b/source/mir/producer/ScriptCallingProducerNode.java
deleted file mode 100755 (executable)
index df2ad07..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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;
-
-import java.util.Map;
-
-import mir.log.LoggerWrapper;
-import mir.util.ParameterExpander;
-
-public class ScriptCallingProducerNode implements ProducerNode  {
-  String scriptExpression;
-
-  public ScriptCallingProducerNode(String aScriptExpression) {
-    scriptExpression = aScriptExpression;
-  }
-
-  public void produce(Map aValueMap, String aVerb, LoggerWrapper aLogger) throws ProducerFailure {
-    String script;
-    Process process;
-    int returnValue;
-
-    try {
-      script = ParameterExpander.expandExpression( aValueMap, scriptExpression );
-      process = Runtime.getRuntime().exec(script);
-      returnValue = process.waitFor();
-      aLogger.info(script + " terminated successfully, return value = " + returnValue + ".");
-    }
-    catch (Throwable e) {
-      aLogger.error(scriptExpression + " failed to execute: " + e.getMessage());
-    }
-  }
-}
index 90bef9d..f0295f8 100755 (executable)
@@ -33,8 +33,10 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.io.File;
 
 import mir.entity.adapter.EntityAdapterModel;
 import mir.generator.Generator;
@@ -49,6 +51,7 @@ import mir.producer.EntityListProducerNode;
 import mir.producer.EntityModifyingProducerNode;
 import mir.producer.EvaluatedAssignmentProducerNode;
 import mir.producer.ExpandedAssignmentProducerNode;
+import mir.producer.ExternalDbProducerNode;
 import mir.producer.FileDateSettingProducerNode;
 import mir.producer.FileDeletingProducerNode;
 import mir.producer.FreeQueryProducerNode;
@@ -59,23 +62,25 @@ import mir.producer.LoopProducerNode;
 import mir.producer.ProducerNode;
 import mir.producer.RDFAggregatorProducerNode;
 import mir.producer.RSSProducerNode;
-import mir.producer.ResourceBundleProducerNode;
-import mir.producer.ScriptCallingProducerNode;
-import mir.util.XMLReader;
-import mir.util.XMLReaderTool;
+import mir.producer.BundleProducerNode;
+import mir.producer.ExecuteProgramProducerNode;
+import mir.util.StringRoutines;
+import mir.util.xml.XMLParserExc;
+import mir.util.xml.XMLReaderTool;
 
 public class DefaultProducerNodeBuilders {
 
   public static void registerBuilders(ProducerNodeBuilderLibrary aBuilderLibrary,
-       EntityAdapterModel aModel, Generator.GeneratorLibrary aGeneratorLibrary,
-       WriterEngine aWriterEngine, String aSourceBasePath, String aDestinationBasePath) throws ProducerConfigExc {
+       EntityAdapterModel aModel, Generator.Library aGeneratorLibrary,
+       WriterEngine aWriterEngine, File aSourceBasePath, File aDestinationBasePath) throws ProducerConfigExc {
 
     aBuilderLibrary.registerBuilder("Set", EvaluatedAssignmentProducerNodeBuilder.class);
     aBuilderLibrary.registerBuilder("Define", ExpandedAssignmentProducerNodeBuilder.class);
     aBuilderLibrary.registerBuilder("Log", LoggingProducerNodeBuilder.class);
-    aBuilderLibrary.registerBuilder("Execute", ScriptCallingProducerNodeBuilder.class);
-    aBuilderLibrary.registerBuilder("Resource", ResourceBundleProducerNodeBuilder.class);
-    aBuilderLibrary.registerFactory("CopyDir", new DirCopyProducerNodeBuilder.factory( aSourceBasePath, aDestinationBasePath));
+    aBuilderLibrary.registerBuilder("Execute", ExecuteProgramProducerNodeBuilder.class);
+    aBuilderLibrary.registerBuilder("Resource", BundleProducerNodeBuilder.class);
+    aBuilderLibrary.registerBuilder("Bundle", BundleProducerNodeBuilder.class);
+    aBuilderLibrary.registerFactory("CopyDir", new DirCopyProducerNodeBuilder.factory(aSourceBasePath, aDestinationBasePath));
 
     aBuilderLibrary.registerBuilder("DeleteFile", FileDeletingProducerNodeBuilder.class);
     aBuilderLibrary.registerBuilder("SetFileDate", FileDateSettingProducerNodeBuilder.class);
@@ -86,6 +91,7 @@ public class DefaultProducerNodeBuilders {
     aBuilderLibrary.registerBuilder("RDFAggregate", RDFAggregatorProducerNodeBuilder.class);
 
     aBuilderLibrary.registerBuilder("FreeQuery", FreeQueryProducerNodeBuilder.class);
+    aBuilderLibrary.registerBuilder("ExternalDbQuery", ExternalDbProducerNodeBuilder.class);
 
     aBuilderLibrary.registerFactory("Enumerate", new EnumeratingProducerNodeBuilder.factory(aModel));
     aBuilderLibrary.registerFactory("List", new ListProducerNodeBuilder.factory(aModel));
@@ -95,17 +101,14 @@ public class DefaultProducerNodeBuilders {
     aBuilderLibrary.registerFactory("CreateEntity", new CreateEntityProducerNodeBuilder.factory(aModel));
     aBuilderLibrary.registerFactory("DeleteEntity", new DeleteEntityProducerNodeBuilder.factory(aModel));
 
-    aBuilderLibrary.registerFactory("Generate",
-        new GeneratingProducerNodeBuilder.factory(aGeneratorLibrary, aWriterEngine));
+    aBuilderLibrary.registerFactory("Generate", new GeneratingProducerNodeBuilder.factory(aGeneratorLibrary, aWriterEngine));
   }
 
   public static abstract class AbstractProducerNodeBuilder implements ProducerNodeBuilder {
-    private Map attributes;
     private Map subNodes;
     private Set availableSubnodes;
 
     public AbstractProducerNodeBuilder(String anAvailableSubNodes[]) {
-      attributes = new HashMap();
       subNodes = new HashMap();
       availableSubnodes = new HashSet(Arrays.asList(anAvailableSubNodes));
     }
@@ -128,6 +131,7 @@ public class DefaultProducerNodeBuilders {
   // general attribute names, specifc builders reference these, to keep attribute
   //    names consistent
 
+  public final static String   EXTRA_TABLES_ATTRIBUTE = "extratables";
   public final static String   SELECTION_ATTRIBUTE = "selection";
   public final static String   ORDER_ATTRIBUTE = "order";
   public final static String   DEFINITION_ATTRIBUTE = "table";
@@ -153,7 +157,7 @@ public class DefaultProducerNodeBuilders {
       super(ASSIGNMENT_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, ASSIGNMENT_REQUIRED_ATTRIBUTES, ASSIGNMENT_OPTIONAL_ATTRIBUTES);
 
       key = (String) anAttributes.get(ASSIGNMENT_KEY_ATTRIBUTE);
@@ -176,7 +180,7 @@ public class DefaultProducerNodeBuilders {
       super(ASSIGNMENT_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, ASSIGNMENT_REQUIRED_ATTRIBUTES, ASSIGNMENT_OPTIONAL_ATTRIBUTES);
 
       key = (String) anAttributes.get(ASSIGNMENT_KEY_ATTRIBUTE);
@@ -199,14 +203,17 @@ public class DefaultProducerNodeBuilders {
     private final static String   ENUMERATION_DEFAULT_SUBNODE = "default";
     private final static String   ENUMERATION_LIMIT_ATTRIBUTE = LIMIT_ATTRIBUTE;
     private final static String   ENUMERATION_SKIP_ATTRIBUTE = SKIP_ATTRIBUTE;
+    private final static String   ENUMERATION_EXTRATABLES_ATTRIBUTE = EXTRA_TABLES_ATTRIBUTE;
     private final static String[] ENUMERATION_LIST_REQUIRED_ATTRIBUTES = { ENUMERATION_LIST_ATTRIBUTE, ENUMERATION_KEY_ATTRIBUTE };
     private final static String[] ENUMERATION_LIST_OPTIONAL_ATTRIBUTES = { };
     private final static String[] ENUMERATION_QUERY_REQUIRED_ATTRIBUTES = { ENUMERATION_DEFINITION_ATTRIBUTE, ENUMERATION_KEY_ATTRIBUTE };
-    private final static String[] ENUMERATION_QUERY_OPTIONAL_ATTRIBUTES = { ENUMERATION_SELECTION_ATTRIBUTE, ENUMERATION_ORDER_ATTRIBUTE, ENUMERATION_LIMIT_ATTRIBUTE, ENUMERATION_SKIP_ATTRIBUTE};
+    private final static String[] ENUMERATION_QUERY_OPTIONAL_ATTRIBUTES = { ENUMERATION_SELECTION_ATTRIBUTE, ENUMERATION_ORDER_ATTRIBUTE, ENUMERATION_LIMIT_ATTRIBUTE, ENUMERATION_SKIP_ATTRIBUTE,ENUMERATION_EXTRATABLES_ATTRIBUTE};
     private final static String[] ENUMERATION_SUBNODES = {ENUMERATION_DEFAULT_SUBNODE};
 
     private String key;
     private String definition;
+    private String mainTablePrefix;
+    private String extraTables;
     private String list;
     private String selection;
     private String order;
@@ -220,7 +227,7 @@ public class DefaultProducerNodeBuilders {
       model = aModel;
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc  {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc  {
       definition = (String) anAttributes.get(ENUMERATION_DEFINITION_ATTRIBUTE);
       list = (String) anAttributes.get(ENUMERATION_LIST_ATTRIBUTE);
 
@@ -235,15 +242,23 @@ public class DefaultProducerNodeBuilders {
 
 
       key = (String) anAttributes.get(ENUMERATION_KEY_ATTRIBUTE);
-      selection = (String) XMLReaderTool.getStringAttributeWithDefault(anAttributes, ENUMERATION_SELECTION_ATTRIBUTE, "");
-      order = (String) XMLReaderTool.getStringAttributeWithDefault(anAttributes, ENUMERATION_ORDER_ATTRIBUTE, "");
+      selection = XMLReaderTool.getStringAttributeWithDefault(anAttributes, ENUMERATION_SELECTION_ATTRIBUTE, "");
+      order = XMLReaderTool.getStringAttributeWithDefault(anAttributes, ENUMERATION_ORDER_ATTRIBUTE, "");
       limit = (String) anAttributes.get(ENUMERATION_LIMIT_ATTRIBUTE);
       skip = (String) anAttributes.get(ENUMERATION_SKIP_ATTRIBUTE);
+      extraTables = XMLReaderTool.getStringAttributeWithDefault(anAttributes, ENUMERATION_EXTRATABLES_ATTRIBUTE,"");
+      if (definition!=null) {
+        List parts = StringRoutines.splitString(definition.trim(), " ");
+        if (parts.size() > 0)
+          definition = (String) parts.get(0);
+        if (parts.size() > 1)
+          mainTablePrefix = (String) parts.get(1);
+      }
     };
 
     public ProducerNode constructNode() {
       if (definition!=null)
-        return new EntityEnumeratingProducerNode(key, model, definition, selection, order, limit, skip, getSubNode(ENUMERATION_DEFAULT_SUBNODE ));
+        return new EntityEnumeratingProducerNode(key, model, mainTablePrefix, extraTables, definition, selection, order, limit, skip, getSubNode(ENUMERATION_DEFAULT_SUBNODE ));
       else
         return new ListEnumeratingProducerNode(key, list, getSubNode(ENUMERATION_DEFAULT_SUBNODE ));
     };
@@ -281,11 +296,11 @@ public class DefaultProducerNodeBuilders {
       fieldValues = new HashMap();
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc  {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc  {
       key = (String) anAttributes.get(UPDATE_KEY_ATTRIBUTE);
 
       if (key == null)
-        throw new XMLReader.XMLReaderExc("missing required attribute '" + UPDATE_KEY_ATTRIBUTE + "'" );
+        throw new XMLParserExc("missing required attribute '" + UPDATE_KEY_ATTRIBUTE + "'" );
       definition = (String) anAttributes.get(UPDATE_DEFINITION_ATTRIBUTE);
 
       fieldValues.putAll(anAttributes);
@@ -330,14 +345,14 @@ public class DefaultProducerNodeBuilders {
       fieldValues = new HashMap();
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc  {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc  {
       key = (String) anAttributes.get(CREATEENTITY_KEY_ATTRIBUTE);
       definition = (String) anAttributes.get(CREATEENTITY_DEFINITION_ATTRIBUTE);
 
       if (key == null)
-        throw new XMLReader.XMLReaderExc("missing required attribute '" + CREATEENTITY_KEY_ATTRIBUTE + "'" );
+        throw new XMLParserExc("missing required attribute '" + CREATEENTITY_KEY_ATTRIBUTE + "'" );
       if (definition == null)
-        throw new XMLReader.XMLReaderExc("missing required attribute '" + CREATEENTITY_DEFINITION_ATTRIBUTE + "'" );
+        throw new XMLParserExc("missing required attribute '" + CREATEENTITY_DEFINITION_ATTRIBUTE + "'" );
 
       fieldValues.putAll(anAttributes);
       fieldValues.remove(CREATEENTITY_KEY_ATTRIBUTE);
@@ -378,11 +393,11 @@ public class DefaultProducerNodeBuilders {
       super(LOOP_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc  {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc  {
       XMLReaderTool.checkAttributes(anAttributes, LOOP_REQUIRED_ATTRIBUTES, LOOP_OPTIONAL_ATTRIBUTES);
 
       condition = (String) anAttributes.get(LOOP_CONDITION_ATTRIBUTE);
-      limit = (String) XMLReaderTool.getStringAttributeWithDefault(anAttributes, LOOP_LIMIT_ATTRIBUTE, "");
+      limit = XMLReaderTool.getStringAttributeWithDefault(anAttributes, LOOP_LIMIT_ATTRIBUTE, "");
     };
 
     public ProducerNode constructNode() {
@@ -396,16 +411,18 @@ public class DefaultProducerNodeBuilders {
     private final static String   LIST_KEY_ATTRIBUTE = KEY_ATTRIBUTE;
     private final static String   LIST_DEFINITION_ATTRIBUTE = DEFINITION_ATTRIBUTE;
     private final static String   LIST_SELECTION_ATTRIBUTE = SELECTION_ATTRIBUTE;
+    private final static String   LIST_EXTRATABLES_ATTRIBUTE = EXTRA_TABLES_ATTRIBUTE;
     private final static String   LIST_ORDER_ATTRIBUTE = ORDER_ATTRIBUTE;
-    private final static String   LIST_DEFAULT_SUBNODE = "default";
     private final static String   LIST_LIMIT_ATTRIBUTE = LIMIT_ATTRIBUTE;
     private final static String   LIST_SKIP_ATTRIBUTE = SKIP_ATTRIBUTE;
     private final static String[] LIST_REQUIRED_ATTRIBUTES = { LIST_KEY_ATTRIBUTE, LIST_DEFINITION_ATTRIBUTE };
-    private final static String[] LIST_OPTIONAL_ATTRIBUTES = { LIST_SELECTION_ATTRIBUTE, LIST_ORDER_ATTRIBUTE, LIST_SKIP_ATTRIBUTE, LIST_LIMIT_ATTRIBUTE};
+    private final static String[] LIST_OPTIONAL_ATTRIBUTES = { LIST_SELECTION_ATTRIBUTE, LIST_ORDER_ATTRIBUTE, LIST_SKIP_ATTRIBUTE, LIST_LIMIT_ATTRIBUTE,LIST_EXTRATABLES_ATTRIBUTE};
     private final static String[] LIST_SUBNODES = {};
 
     private String key;
     private String definition;
+    private String mainTablePrefix;
+    private String extraTables;
     private String selection;
     private String order;
     private String limit;
@@ -418,19 +435,24 @@ public class DefaultProducerNodeBuilders {
       model = aModel;
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, LIST_REQUIRED_ATTRIBUTES, LIST_OPTIONAL_ATTRIBUTES);
 
       key = (String) anAttributes.get(LIST_KEY_ATTRIBUTE);
       definition = (String) anAttributes.get(LIST_DEFINITION_ATTRIBUTE);
-      selection = (String) XMLReaderTool.getStringAttributeWithDefault(anAttributes, LIST_SELECTION_ATTRIBUTE, "");
-      order = (String) XMLReaderTool.getStringAttributeWithDefault(anAttributes, LIST_ORDER_ATTRIBUTE, "");
+      selection = XMLReaderTool.getStringAttributeWithDefault(anAttributes, LIST_SELECTION_ATTRIBUTE, "");
+      order = XMLReaderTool.getStringAttributeWithDefault(anAttributes, LIST_ORDER_ATTRIBUTE, "");
       limit = (String) anAttributes.get(LIST_LIMIT_ATTRIBUTE);
       skip = (String) anAttributes.get(LIST_SKIP_ATTRIBUTE);
+      extraTables = XMLReaderTool.getStringAttributeWithDefault(anAttributes, LIST_EXTRATABLES_ATTRIBUTE,"");
+      List parts = StringRoutines.splitString(definition.trim()," ");
+      if (parts.size()>0) definition=(String)parts.get(0);
+      if (parts.size()>1) mainTablePrefix=(String)parts.get(1);
+
     };
 
     public ProducerNode constructNode() {
-      return new EntityListProducerNode(key, model, definition, selection, order, limit, skip, null );
+      return new EntityListProducerNode(key, model, mainTablePrefix, extraTables, definition, selection, order, limit, skip, null );
     };
 
     public static class factory implements ProducerNodeBuilderFactory {
@@ -466,11 +488,11 @@ public class DefaultProducerNodeBuilders {
       model = aModel;
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, DELETEENTITY_REQUIRED_ATTRIBUTES, DELETEENTITY_OPTIONAL_ATTRIBUTES);
 
       definition = (String) anAttributes.get(DELETEENTITY_DEFINITION_ATTRIBUTE);
-      selection = (String) XMLReaderTool.getStringAttributeWithDefault(anAttributes, DELETEENTITY_SELECTION_ATTRIBUTE, "");
+      selection = XMLReaderTool.getStringAttributeWithDefault(anAttributes, DELETEENTITY_SELECTION_ATTRIBUTE, "");
     };
 
     public ProducerNode constructNode() {
@@ -506,7 +528,7 @@ public class DefaultProducerNodeBuilders {
       super(LOG_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       String typeString;
 
       XMLReaderTool.checkAttributes(anAttributes, LOG_REQUIRED_ATTRIBUTES, LOG_OPTIONAL_ATTRIBUTES);
@@ -557,7 +579,7 @@ public class DefaultProducerNodeBuilders {
       super(FREEQUERY_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       String typeString;
 
       XMLReaderTool.checkAttributes(anAttributes, FREEQUERY_REQUIRED_ATTRIBUTES, FREEQUERY_OPTIONAL_ATTRIBUTES);
@@ -588,14 +610,63 @@ public class DefaultProducerNodeBuilders {
       return new FreeQueryProducerNode(key, query, limit, type);
     };
   }
+////////////////////////////////////////////////////////////////////////////////
+
+  public static class ExternalDbProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   EXTDB_KEY_ATTRIBUTE = KEY_ATTRIBUTE;
+    private final static String   EXTDB_DRIVER_ATTRIBUTE = "driver";
+    private final static String   EXTDB_HOST_ATTRIBUTE = "host";
+    private final static String   EXTDB_PORT_ATTRIBUTE = "port";
+    private final static String   EXTDB_DATABASE_ATTRIBUTE = "database";
+    private final static String   EXTDB_USERNAME_ATTRIBUTE = "username";
+    private final static String   EXTDB_PASSWORD_ATTRIBUTE = "password";
+    private final static String   EXTDB_QUERY_ATTRIBUTE = "query";
+    private final static String   EXTDB_DEFAULT_SUBNODE = "default";
+    private final static String[] EXTDB_REQUIRED_ATTRIBUTES = { KEY_ATTRIBUTE, EXTDB_DRIVER_ATTRIBUTE, EXTDB_HOST_ATTRIBUTE, EXTDB_PORT_ATTRIBUTE, EXTDB_DATABASE_ATTRIBUTE, EXTDB_USERNAME_ATTRIBUTE, EXTDB_PASSWORD_ATTRIBUTE, EXTDB_QUERY_ATTRIBUTE };
+    private final static String[] EXTDB_OPTIONAL_ATTRIBUTES = { };
+    private final static String[] EXTDB_SUBNODES = {EXTDB_DEFAULT_SUBNODE};
+
+    private String key;
+    private String driver;
+    private String host;
+    private String port;
+    private String database;
+    private String username;
+    private String password;
+    private String query;   
+
+
+    public ExternalDbProducerNodeBuilder() {
+      super(EXTDB_SUBNODES);
+    }
+
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
+      String typeString;
+
+      XMLReaderTool.checkAttributes(anAttributes, EXTDB_REQUIRED_ATTRIBUTES, EXTDB_OPTIONAL_ATTRIBUTES);
+
+      key = (String) anAttributes.get(EXTDB_KEY_ATTRIBUTE);
+      driver = (String) anAttributes.get(EXTDB_DRIVER_ATTRIBUTE);
+      host = (String) anAttributes.get(EXTDB_HOST_ATTRIBUTE);
+      port = (String) anAttributes.get(EXTDB_PORT_ATTRIBUTE);
+      database = (String) anAttributes.get(EXTDB_DATABASE_ATTRIBUTE);
+      username = (String) anAttributes.get(EXTDB_USERNAME_ATTRIBUTE);
+      password = (String) anAttributes.get(EXTDB_PASSWORD_ATTRIBUTE);
+      query = (String) anAttributes.get(EXTDB_QUERY_ATTRIBUTE);
+
+    };
+
+    public ProducerNode constructNode() {
+      return new ExternalDbProducerNode(key, driver, host, port, database, username, password, query,  getSubNode(EXTDB_DEFAULT_SUBNODE));
+    };
+  }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-  public static class ResourceBundleProducerNodeBuilder extends AbstractProducerNodeBuilder {
+  public static class BundleProducerNodeBuilder extends AbstractProducerNodeBuilder {
     private final static String   RESOURCEBUNDLE_KEY_ATTRIBUTE = KEY_ATTRIBUTE;
     private final static String   RESOURCEBUNDLE_BUNDLE_ATTRIBUTE = "bundle";
     private final static String   RESOURCEBUNDLE_LANGUAGE_ATTRIBUTE = "language";
-    private final static String   RESOURCEBUNDLE_DEFAULT_SUBNODE = "default";
     private final static String[] RESOURCEBUNDLE_REQUIRED_ATTRIBUTES = { RESOURCEBUNDLE_KEY_ATTRIBUTE, RESOURCEBUNDLE_BUNDLE_ATTRIBUTE };
     private final static String[] RESOURCEBUNDLE_OPTIONAL_ATTRIBUTES = { RESOURCEBUNDLE_LANGUAGE_ATTRIBUTE};
     private final static String[] RESOURCEBUNDLE_SUBNODES = {};
@@ -604,11 +675,11 @@ public class DefaultProducerNodeBuilders {
     private String bundle;
     private String language;
 
-    public ResourceBundleProducerNodeBuilder() {
+    public BundleProducerNodeBuilder() {
       super(RESOURCEBUNDLE_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, RESOURCEBUNDLE_REQUIRED_ATTRIBUTES, RESOURCEBUNDLE_OPTIONAL_ATTRIBUTES);
 
       key = (String) anAttributes.get(RESOURCEBUNDLE_KEY_ATTRIBUTE);
@@ -617,7 +688,7 @@ public class DefaultProducerNodeBuilders {
     };
 
     public ProducerNode constructNode() {
-      return new ResourceBundleProducerNode(key, bundle, language);
+      return new BundleProducerNode(key, bundle, language);
     };
   }
 
@@ -637,7 +708,7 @@ public class DefaultProducerNodeBuilders {
       super(FILEDATESETTING_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, FILEDATESETTING_REQUIRED_ATTRIBUTES, FILEDATESETTING_OPTIONAL_ATTRIBUTES);
 
       fileNameKey = (String) anAttributes.get(FILEDATESETTING_FILE_ATTRIBUTE);
@@ -663,7 +734,7 @@ public class DefaultProducerNodeBuilders {
       super(FILEDELETING_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, FILEDELETING_REQUIRED_ATTRIBUTES, FILEDELETING_OPTIONAL_ATTRIBUTES);
 
       fileNameKey = (String) anAttributes.get(FILEDELETING_FILE_ATTRIBUTE);
@@ -676,26 +747,36 @@ public class DefaultProducerNodeBuilders {
 
 ////////////////////////////////////////////////////////////////////////////////
 
-  public static class ScriptCallingProducerNodeBuilder extends AbstractProducerNodeBuilder {
-    private final static String   SCRIPT_COMMAND_ATTRIBUTE = "command";
-    private final static String[] SCRIPT_REQUIRED_ATTRIBUTES = { SCRIPT_COMMAND_ATTRIBUTE };
-    private final static String[] SCRIPT_OPTIONAL_ATTRIBUTES = {};
-    private final static String[] SCRIPT_SUBNODES = {};
+  public static class ExecuteProgramProducerNodeBuilder extends AbstractProducerNodeBuilder {
+    private final static String   EXECUTEPROGRAM_COMMAND_ATTRIBUTE = "command";
+    private final static String   EXECUTEPROGRAM_MAXTIME_ATTRIBUTE = "maxduration";
+    private final static String   EXECUTEPROGRAM_RESULTVAR_ATTRIBUTE = "resultvar";
+    private final static String   EXECUTEPROGRAM_RETURNVALUE_ATTRIBUTE = "returnvaluevar";
+    private final static String[] EXECUTEPROGRAM_REQUIRED_ATTRIBUTES = { EXECUTEPROGRAM_COMMAND_ATTRIBUTE };
+    private final static String[] EXECUTEPROGRAM_OPTIONAL_ATTRIBUTES = { EXECUTEPROGRAM_MAXTIME_ATTRIBUTE, EXECUTEPROGRAM_RESULTVAR_ATTRIBUTE };
+    private final static String[] EXECUTEPROGRAM_SUBNODES = {};
 
     private String command;
+    private String time;
+    private String resultvar;
+    private String returnValueVar;
 
-    public ScriptCallingProducerNodeBuilder() {
-      super(SCRIPT_SUBNODES);
+    public ExecuteProgramProducerNodeBuilder() {
+      super(EXECUTEPROGRAM_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
-      XMLReaderTool.checkAttributes(anAttributes, SCRIPT_REQUIRED_ATTRIBUTES, SCRIPT_OPTIONAL_ATTRIBUTES);
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
+      XMLReaderTool.checkAttributes(anAttributes, EXECUTEPROGRAM_REQUIRED_ATTRIBUTES, EXECUTEPROGRAM_OPTIONAL_ATTRIBUTES);
 
-      command = (String) anAttributes.get(SCRIPT_COMMAND_ATTRIBUTE);
+      command = (String) anAttributes.get(EXECUTEPROGRAM_COMMAND_ATTRIBUTE);
+      time = XMLReaderTool.getStringAttributeWithDefault(anAttributes, EXECUTEPROGRAM_MAXTIME_ATTRIBUTE, null);
+      resultvar = XMLReaderTool.getStringAttributeWithDefault(anAttributes, EXECUTEPROGRAM_RESULTVAR_ATTRIBUTE, null);
+      returnValueVar = XMLReaderTool.getStringAttributeWithDefault(anAttributes, EXECUTEPROGRAM_RETURNVALUE_ATTRIBUTE, null);
     };
 
     public ProducerNode constructNode() {
-      return new ScriptCallingProducerNode(command);
+      return new
+          ExecuteProgramProducerNode(command, time, resultvar, returnValueVar);
     };
   }
 
@@ -710,17 +791,17 @@ public class DefaultProducerNodeBuilders {
   public static class DirCopyProducerNodeBuilder extends AbstractProducerNodeBuilder {
     private String source;
     private String destination;
-    private String sourceBasePath;
-    private String destinationBasePath;
+    private File sourceBasePath;
+    private File destinationBasePath;
 
-    public DirCopyProducerNodeBuilder(String aSourceBasePath, String aDestinationBasePath) {
+    public DirCopyProducerNodeBuilder(File aSourceBasePath, File aDestinationBasePath) {
       super(DIRCOPY_SUBNODES);
 
       sourceBasePath = aSourceBasePath;
       destinationBasePath = aDestinationBasePath;
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, DIRCOPY_REQUIRED_ATTRIBUTES, DIRCOPY_OPTIONAL_ATTRIBUTES);
 
       source = (String) anAttributes.get(DIRCOPY_SOURCE_ATTRIBUTE);
@@ -732,10 +813,10 @@ public class DefaultProducerNodeBuilders {
     };
 
     public static class factory implements ProducerNodeBuilderFactory {
-      private String sourceBasePath;
-      private String destinationBasePath;
+      private File sourceBasePath;
+      private File destinationBasePath;
 
-      public factory(String aSourceBasePath, String aDestinationBasePath) {
+      public factory(File aSourceBasePath, File aDestinationBasePath) {
         sourceBasePath = aSourceBasePath;
         destinationBasePath = aDestinationBasePath;
       }
@@ -759,17 +840,17 @@ public class DefaultProducerNodeBuilders {
     private String generator;
     private String destination;
     private String parameters;
-    private Generator.GeneratorLibrary generatorLibrary;
+    private Generator.Library generatorLibrary;
     private WriterEngine writerEngine;
 
-    public GeneratingProducerNodeBuilder(Generator.GeneratorLibrary aGeneratorLibrary, WriterEngine aWriterEngine) {
+    public GeneratingProducerNodeBuilder(Generator.Library aGeneratorLibrary, WriterEngine aWriterEngine) {
       super(GENERATION_SUBNODES);
 
       writerEngine = aWriterEngine;
       generatorLibrary = aGeneratorLibrary;
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, GENERATION_REQUIRED_ATTRIBUTES, GENERATION_OPTIONAL_ATTRIBUTES);
 
       generator = (String) anAttributes.get(GENERATION_GENERATOR_ATTRIBUTE);
@@ -782,10 +863,10 @@ public class DefaultProducerNodeBuilders {
     };
 
     public static class factory implements ProducerNodeBuilderFactory {
-      private Generator.GeneratorLibrary generatorLibrary;
+      private Generator.Library generatorLibrary;
       private WriterEngine writerEngine;
 
-      public factory(Generator.GeneratorLibrary aGeneratorLibrary, WriterEngine aWriterEngine) {
+      public factory(Generator.Library aGeneratorLibrary, WriterEngine aWriterEngine) {
         writerEngine = aWriterEngine;
         generatorLibrary = aGeneratorLibrary;
       }
@@ -811,16 +892,19 @@ public class DefaultProducerNodeBuilders {
     private final static String   BATCHER_SKIP_ATTRIBUTE = SKIP_ATTRIBUTE;
 
     private final static String   BATCHER_PROCESS_ATTRIBUTE = "process";
+    private final static String   BATCHER_EXTRATABLES_ATTRIBUTE = EXTRA_TABLES_ATTRIBUTE;
 
     private final static String   BATCHER_BATCH_SUBNODE = "batches";
     private final static String   BATCHER_BATCHLIST_SUBNODE = "batchlist";
     private final static String[] BATCHER_REQUIRED_ATTRIBUTES = { BATCHER_DATAKEY_ATTRIBUTE, BATCHER_INFOKEY_ATTRIBUTE, BATCHER_DEFINITION_ATTRIBUTE, BATCHER_BATCHSIZE_ATTRIBUTE };
-    private final static String[] BATCHER_OPTIONAL_ATTRIBUTES = { BATCHER_SELECTION_ATTRIBUTE, BATCHER_ORDER_ATTRIBUTE, BATCHER_MINBATCHSIZE_ATTRIBUTE, BATCHER_SKIP_ATTRIBUTE, BATCHER_PROCESS_ATTRIBUTE };
+    private final static String[] BATCHER_OPTIONAL_ATTRIBUTES = { BATCHER_SELECTION_ATTRIBUTE, BATCHER_ORDER_ATTRIBUTE, BATCHER_MINBATCHSIZE_ATTRIBUTE, BATCHER_SKIP_ATTRIBUTE, BATCHER_PROCESS_ATTRIBUTE, BATCHER_EXTRATABLES_ATTRIBUTE };
     private final static String[] BATCHER_SUBNODES = { BATCHER_BATCH_SUBNODE, BATCHER_BATCHLIST_SUBNODE };
 
     private EntityAdapterModel model;
     private String batchDataKey;
     private String batchInfoKey;
+    private String mainTablePrefix;
+    private String extraTables;
     private String definition;
     private String selection;
     private String order;
@@ -835,7 +919,7 @@ public class DefaultProducerNodeBuilders {
       model = aModel;
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, BATCHER_REQUIRED_ATTRIBUTES, BATCHER_OPTIONAL_ATTRIBUTES);
 
       batchDataKey = XMLReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_DATAKEY_ATTRIBUTE, "data" );
@@ -848,6 +932,12 @@ public class DefaultProducerNodeBuilders {
       minBatchSize = XMLReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_MINBATCHSIZE_ATTRIBUTE, "0" );
       skip = XMLReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_SKIP_ATTRIBUTE, "0" );
       process = XMLReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_PROCESS_ATTRIBUTE, "-1" );
+
+      extraTables = XMLReaderTool.getStringAttributeWithDefault(anAttributes, BATCHER_EXTRATABLES_ATTRIBUTE,"");
+
+      List parts = StringRoutines.splitString(definition.trim()," ");
+      if (parts.size()>0) definition=(String)parts.get(0);
+      if (parts.size()>1) mainTablePrefix=(String)parts.get(1);
     };
 
     public ProducerNode constructNode() {
@@ -855,6 +945,8 @@ public class DefaultProducerNodeBuilders {
           batchDataKey,
           batchInfoKey,
           model,
+          mainTablePrefix,
+          extraTables,
           definition,
           selection,
           order,
@@ -897,7 +989,7 @@ public class DefaultProducerNodeBuilders {
       super(IF_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, IF_REQUIRED_ATTRIBUTES, IF_OPTIONAL_ATTRIBUTES);
 
       condition = (String) anAttributes.get( IF_CONDITION_ATTRIBUTE );
@@ -918,30 +1010,33 @@ public class DefaultProducerNodeBuilders {
   public static class RSSProducerNodeBuilder extends AbstractProducerNodeBuilder {
     private final static String   RSS_KEY_ATTRIBUTE = KEY_ATTRIBUTE;
     private final static String   RSS_URL_ATTRIBUTE = URL_ATTRIBUTE;
+    private final static String   RSS_ENCODING_ATTRIBUTE = "encoding";
     private final static String   RSS_VERSION_ATTRIBUTE = "version";
 
     private final static String[] RSS_REQUIRED_ATTRIBUTES = { RSS_KEY_ATTRIBUTE, RSS_URL_ATTRIBUTE };
-    private final static String[] RSS_OPTIONAL_ATTRIBUTES = { RSS_VERSION_ATTRIBUTE };
+    private final static String[] RSS_OPTIONAL_ATTRIBUTES = { RSS_VERSION_ATTRIBUTE, RSS_ENCODING_ATTRIBUTE };
     private final static String[] RSS_SUBNODES = {  };
 
     private String key;
     private String url;
     private String version;
+    private String encoding;
 
     public RSSProducerNodeBuilder() {
       super(RSS_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, RSS_REQUIRED_ATTRIBUTES, RSS_OPTIONAL_ATTRIBUTES);
 
       key = (String) anAttributes.get( RSS_KEY_ATTRIBUTE );
       url = (String) anAttributes.get( RSS_URL_ATTRIBUTE );
       version = XMLReaderTool.getStringAttributeWithDefault(anAttributes, RSS_VERSION_ATTRIBUTE, "1.0");
+      encoding = XMLReaderTool.getStringAttributeWithDefault(anAttributes, RSS_ENCODING_ATTRIBUTE, null);
     };
 
     public ProducerNode constructNode() {
-      return new RSSProducerNode(key, url, version);
+      return new RSSProducerNode(key, url, version, encoding);
     };
   }
 
@@ -966,7 +1061,7 @@ public class DefaultProducerNodeBuilders {
       super(RDF_AGGREGATOR_SUBNODES);
     }
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributes(anAttributes, RDF_AGGREGATOR_REQUIRED_ATTRIBUTES, RDF_AGGREGATOR_OPTIONAL_ATTRIBUTES);
 
       key = (String) anAttributes.get( RDF_AGGREGATOR_KEY_ATTRIBUTE );
@@ -1036,7 +1131,7 @@ public class DefaultProducerNodeBuilders {
       return definition.getNodeParameters();
     };
 
-    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc {
+    public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc {
       XMLReaderTool.checkAttributeSet(anAttributes.keySet(), definition.getRequiredAttributes(), definition.getOptionalAttributes());
 
       Iterator i = anAttributes.entrySet().iterator();
index dd91805..631573f 100755 (executable)
 package  mir.producer.reader;
 
 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;
-import java.util.Vector;
 
 import mir.producer.CompositeProducerNode;
 import mir.producer.ProducerFactory;
 import mir.producer.ProducerNode;
 import mir.producer.SimpleProducerVerb;
-import mir.util.XMLReader;
-import mir.util.*;
+import mir.util.ExceptionFunctions;
+import mir.util.xml.XMLParserEngine;
+import mir.util.xml.XMLParserExc;
+import mir.util.xml.XMLParserFailure;
 
 public class ProducerConfigReader {
   private ProducerNodeBuilderLibrary builderLibrary;
@@ -53,56 +56,65 @@ public class ProducerConfigReader {
     super();
   };
 
-  public void parseFile(String aFileName, ProducerNodeBuilderLibrary aBuilderLibrary, List aProducerFactories) throws ProducerConfigFailure {
-    parseFile(aFileName, aBuilderLibrary, aProducerFactories, new Vector());
-  }
-
-  public void parseFile(String aFileName, ProducerNodeBuilderLibrary aBuilderLibrary, List aProducerFactories, List aUsedFiles) throws ProducerConfigFailure {
+  public void parse(Reader aReader, ProducerNodeBuilderLibrary aBuilderLibrary, List aProducerFactories) throws ProducerConfigFailure {
     try {
-      XMLReader reader = new XMLReader();
-      aUsedFiles.add(new File(aFileName));
-
       builderLibrary = aBuilderLibrary;
       scriptedNodeBuilderLibrary = new ProducerNodeBuilderLibrary();
 
-      reader.parseFile(aFileName, new RootSectionHandler(aProducerFactories));
+      XMLParserEngine.getInstance().parse("", aReader, new RootSectionHandler(aProducerFactories));
 
     }
     catch (Throwable e) {
       Throwable root = ExceptionFunctions.traceCauseException(e);
 
-      if ((root instanceof XMLReader.XMLReaderExc) && ((XMLReader.XMLReaderExc) root).getHasLocation()) {
-        XMLReader.XMLReaderExc f = (XMLReader.XMLReaderExc) root;
-        throw new ProducerConfigFailure("'" + f.getMessage()+"' in " + f.getFilename()+"(line " + f.getLineNr()+", column " + f.getColumnNr() + ")", 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 = ExceptionFunctions.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 XMLReader.AbstractSectionHandler {
+  public class RootSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private List producers;
 
     public RootSectionHandler(List aProducers) {
       producers = aProducers;
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.equals("producers")) {
         return new ProducersSectionHandler(producers);
       }
       else
-        throw new XMLReader.XMLReaderExc("Tag 'producers' expected, tag '"+aTag+"' found");
+        throw new XMLParserExc("Tag 'producers' expected, tag '"+aTag+"' found");
     }
 
-    public void endElement(XMLReader.SectionHandler aHandler) {
+    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 = { };
@@ -111,7 +123,7 @@ public class ProducerConfigReader {
   private final static String[] NODE_DEFINITION_REQUIRED_ATTRIBUTES = { NODE_DEFINITION_NAME_ATTRIBUTE };
   private final static String[] NODE_DEFINITION_OPTIONAL_ATTRIBUTES = {  };
 
-  public class ProducersSectionHandler extends XMLReader.AbstractSectionHandler {
+  public class ProducersSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private List producers;
     private Set producerNames;
     private String name;
@@ -121,17 +133,17 @@ public class ProducerConfigReader {
       producerNames = new HashSet();
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.equals("producer")) {
-        XMLReaderTool.checkAttributes(anAttributes,
+        mir.util.xml.XMLReaderTool.checkAttributes(anAttributes,
                                       PRODUCER_REQUIRED_ATTRIBUTES,
                                       PRODUCER_OPTIONAL_ATTRIBUTES);
 
         name = (String) anAttributes.get(PRODUCER_NAME_ATTRIBUTE);
-        XMLReaderTool.checkValidIdentifier(name);
+        mir.util.xml.XMLReaderTool.checkValidIdentifier(name);
 
         if (producerNames.contains(name))
-          throw new XMLReader.XMLReaderExc("Duplicate producer name: '" +
+          throw new XMLParserExc("Duplicate producer name: '" +
                                            name + "'");
 
         name = (String) anAttributes.get(PRODUCER_NAME_ATTRIBUTE);
@@ -139,21 +151,21 @@ public class ProducerConfigReader {
         return new ProducerSectionHandler(name);
       }
       else if (aTag.equals("nodedefinition")) {
-        XMLReaderTool.checkAttributes(anAttributes,
+        mir.util.xml.XMLReaderTool.checkAttributes(anAttributes,
                                       NODE_DEFINITION_REQUIRED_ATTRIBUTES,
                                       NODE_DEFINITION_OPTIONAL_ATTRIBUTES);
 
         name = (String) anAttributes.get(NODE_DEFINITION_NAME_ATTRIBUTE);
-        XMLReaderTool.checkValidIdentifier(name);
+        mir.util.xml.XMLReaderTool.checkValidIdentifier(name);
 
         name = (String) anAttributes.get(NODE_DEFINITION_NAME_ATTRIBUTE);
 
         return new NodeDefinitionSectionHandler(name);
       }
-      throw new XMLReader.XMLReaderExc("Unexpected tag: " + aTag);
+      throw new XMLParserExc("Unexpected tag: " + aTag);
     }
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    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());
@@ -163,14 +175,14 @@ public class ProducerConfigReader {
             new DefaultProducerNodeBuilders.ScriptedProducerNodeBuilder.factory(
                 ((NodeDefinitionSectionHandler) aHandler).getDefinition()));
       }
-      else throw new XMLReader.XMLReaderExc("ProducersSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
+      else throw new XMLParserExc("ProducersSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
     }
 
     public void finishSection() {
     }
   }
 
-  public class ProducerSectionHandler extends XMLReader.AbstractSectionHandler {
+  public class ProducerSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private ProducerFactory producerFactory;
     private String factoryName;
 
@@ -183,12 +195,12 @@ public class ProducerConfigReader {
       factoryName = aName;
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.equals("verbs")) {
         if (verbs!=null)
-          throw new XMLReader.XMLReaderExc("Verbs already processed");
+          throw new XMLParserExc("Verbs already processed");
         if (body!=null)
-          throw new XMLReader.XMLReaderExc("Verbs should come before body");
+          throw new XMLParserExc("Verbs should come before body");
         else
           return new ProducerVerbsSectionHandler();
       }
@@ -196,12 +208,12 @@ public class ProducerConfigReader {
         if (body==null)
           return new ProducerNodeSectionHandler();
         else
-          throw new XMLReader.XMLReaderExc("Body already processed");
+          throw new XMLParserExc("Body already processed");
       }
-      throw new XMLReader.XMLReaderExc("Unexpected tag: '"+aTag+"'");
+      throw new XMLParserExc("Unexpected tag: '"+aTag+"'");
     }
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
       if (aHandler instanceof ProducerNodeSectionHandler) {
         body = ((ProducerNodeSectionHandler) aHandler).getProducerNode();
       }
@@ -211,15 +223,15 @@ public class ProducerConfigReader {
         verbNodes = ((ProducerVerbsSectionHandler) aHandler).getVerbNodes();
         defaultVerb = ((ProducerVerbsSectionHandler) aHandler).getDefaultVerb();
       }
-      else throw new XMLReader.XMLReaderExc("ProducerSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
+      else throw new XMLParserExc("ProducerSectionHandler.endElement Internal error: Unexpected handler: " + aHandler.getClass().getName());
     }
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
       if (verbs==null)
-        throw new XMLReader.XMLReaderExc("No verbs defined");
+        throw new XMLParserExc("No verbs defined");
 
       if (body==null)
-        throw new XMLReader.XMLReaderExc("No body defined");
+        throw new XMLParserExc("No body defined");
 
       producerFactory = new ScriptedProducerFactory(factoryName, verbs, verbNodes, body, defaultVerb);
     }
@@ -235,7 +247,7 @@ public class ProducerConfigReader {
   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 XMLReader.AbstractSectionHandler {
+  public class ProducerVerbsSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private Map verbNodes;
     private List verbs;
     private String defaultVerb;
@@ -244,26 +256,26 @@ public class ProducerConfigReader {
 
     public ProducerVerbsSectionHandler() {
       verbNodes = new HashMap();
-      verbs = new Vector();
+      verbs = new ArrayList();
       defaultVerb = null;
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.equals("verb")) {
-        XMLReaderTool.checkAttributes(anAttributes,
+        mir.util.xml.XMLReaderTool.checkAttributes(anAttributes,
                                       PRODUCER_VERB_REQUIRED_ATTRIBUTES,
                                       PRODUCER_VERB_OPTIONAL_ATTRIBUTES);
         currentVerb = (String) anAttributes.get(PRODUCER_VERB_NAME_ATTRIBUTE);
 
-        XMLReaderTool.checkValidIdentifier(currentVerb);
+        mir.util.xml.XMLReaderTool.checkValidIdentifier(currentVerb);
 
         if (verbNodes.containsKey(currentVerb))
-          throw new XMLReader.XMLReaderExc("Duplicate definition of verb '" +
+          throw new XMLParserExc("Duplicate definition of verb '" +
                                            currentVerb + "'");
 
         if (anAttributes.containsKey(PRODUCER_VERB_DEFAULT_ATTRIBUTE)) {
           if (defaultVerb != null)
-            throw new XMLReader.XMLReaderExc("Default verb already declared");
+            throw new XMLParserExc("Default verb already declared");
 
           defaultVerb = currentVerb;
         }
@@ -277,10 +289,10 @@ public class ProducerConfigReader {
         return new ProducerNodeSectionHandler();
       }
       else
-        throw new XMLReader.XMLReaderExc("Only 'verb' tags allowed here, '" + aTag + "' encountered.");
+        throw new XMLParserExc("Only 'verb' tags allowed here, '" + aTag + "' encountered.");
     }
 
-    public void endElement(XMLReader.SectionHandler aHandler) {
+    public void endElement(mir.util.xml.SectionHandler aHandler) {
       verbNodes.put(currentVerb, ((ProducerNodeSectionHandler) aHandler).getProducerNode());
       verbs.add(new SimpleProducerVerb(currentVerb, currentVerbDescription));
     }
@@ -301,19 +313,19 @@ public class ProducerConfigReader {
     }
   }
 
-  public class EmptySectionHandler extends XMLReader.AbstractSectionHandler {
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
-      throw new XMLReader.XMLReaderExc("No tags are allowed here");
+  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(XMLReader.SectionHandler aHandler) {
+    public void endElement(mir.util.xml.SectionHandler aHandler) {
     }
 
     public void finishSection() {
     }
   }
 
-  public class MultiProducerNodeSectionHandler extends XMLReader.AbstractSectionHandler {
+  public class MultiProducerNodeSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private Map nodeParameters;
     private Set validNodeParameters;
     private String currentNodeParameter;
@@ -330,25 +342,25 @@ public class ProducerConfigReader {
       this("", new HashSet(), aValidNodeParameters);
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       if (!validNodeParameters.contains(aTag))
-        throw new XMLReader.XMLReaderExc("Invalid node parameter: '" + aTag + "'");
+        throw new XMLParserExc("Invalid node parameter: '" + aTag + "'");
       else if (nodeParameters.containsKey(aTag))
-        throw new XMLReader.XMLReaderExc("Node parameter: '" + aTag + "' already specified");
+        throw new XMLParserExc("Node parameter: '" + aTag + "' already specified");
       else if (anAttributes.size()>0)
-        throw new XMLReader.XMLReaderExc("No parameters are allowed here");
+        throw new XMLParserExc("No parameters are allowed here");
 
       currentNodeParameter = aTag;
 
       return new ProducerNodeSectionHandler(scriptedNodeName, allowedNodeParameterReferences);
     }
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc  {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc  {
       if (aHandler instanceof ProducerNodeSectionHandler) {
         nodeParameters.put(currentNodeParameter, ((ProducerNodeSectionHandler) aHandler).getProducerNode());
       }
       else {
-        throw new XMLReader.XMLReaderExc("Internal error: unknown section handler '" + aHandler.getClass().getName() + "'" );
+        throw new XMLParserExc("Internal error: unknown section handler '" + aHandler.getClass().getName() + "'" );
       }
     }
 
@@ -360,7 +372,7 @@ public class ProducerConfigReader {
     }
   }
 
-  public class ProducerNodeSectionHandler extends XMLReader.AbstractSectionHandler {
+  public class ProducerNodeSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private CompositeProducerNode producerNode;
     private ProducerNodeBuilder currentBuilder;
     private String scriptedNodeName;
@@ -376,11 +388,11 @@ public class ProducerConfigReader {
       this("", new HashSet());
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       try {
         if (allowedNodeParameterReferences.contains( (aTag))) {
           if (!anAttributes.isEmpty()) {
-            throw new XMLReader.XMLReaderExc("No attributes allowed");
+            throw new XMLParserExc("No attributes allowed");
           }
 
           currentBuilder = new DefaultProducerNodeBuilders.
@@ -411,14 +423,14 @@ public class ProducerConfigReader {
           }
         }
         else
-          throw new XMLReader.XMLReaderExc("Unknown producer node tag: '" + aTag + "'");
+          throw new XMLParserExc("Unknown producer node tag: '" + aTag + "'");
       }
       catch (Throwable t) {
-        throw new XMLReader.XMLReaderFailure(t);
+        throw new XMLParserFailure(t);
       }
     }
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc  {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc  {
       try {
         if (aHandler instanceof ProducerNodeSectionHandler) {
           currentBuilder.setSubNode(
@@ -443,7 +455,7 @@ public class ProducerConfigReader {
           // deliberately empty: nothing expected, so nothing to process
         }
         else {
-          throw new XMLReader.XMLReaderExc(
+          throw new XMLParserExc(
               "Internal error: unknown section handler '" +
               aHandler.getClass().getName() + "'");
         }
@@ -452,7 +464,7 @@ public class ProducerConfigReader {
         currentBuilder = null;
       }
       catch (Throwable t) {
-        throw new XMLReader.XMLReaderFailure(t);
+        throw new XMLParserFailure(t);
       }
     }
 
@@ -469,7 +481,7 @@ public class ProducerConfigReader {
     }
   }
 
-  public class NodeDefinitionSectionHandler extends XMLReader.AbstractSectionHandler {
+  public class NodeDefinitionSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private ScriptedProducerNodeDefinition nodeDefinition;
     private ProducerNode body;
     private Map stringParameters;
@@ -485,30 +497,30 @@ public class ProducerConfigReader {
       name = aName;
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.equals("parameters")) {
         if (!anAttributes.isEmpty()) {
-          throw new XMLReader.XMLReaderExc( "No attributes allowed for tag 'parameters'" );
+          throw new XMLParserExc( "No attributes allowed for tag 'parameters'" );
         }
         if (nodeParameters!=null) {
-          throw new XMLReader.XMLReaderExc( "Parameters have already been declared" );
+          throw new XMLParserExc( "Parameters have already been declared" );
         }
         if (body!=null) {
-          throw new XMLReader.XMLReaderExc( "Parameters should come before definition in nodedefinition '" + name +"'" );
+          throw new XMLParserExc( "Parameters should come before definition in nodedefinition '" + name +"'" );
         }
 
         return new NodeDefinitionParametersSectionHandler();
       }
       else if (aTag.equals("definition")) {
         if (nodeParameters==null)
-          throw new XMLReader.XMLReaderExc( "Parameters should come before definition in nodedefinition '" + name +"'"  );
+          throw new XMLParserExc( "Parameters should come before definition in nodedefinition '" + name +"'"  );
 
         return new ProducerNodeSectionHandler(name, nodeParameters.keySet());
       }
-      else throw new XMLReader.XMLReaderExc("Only 'definition' or 'parameters' tags allowed here, '" + aTag + "' encountered.");
+      else throw new XMLParserExc("Only 'definition' or 'parameters' tags allowed here, '" + aTag + "' encountered.");
     }
 
-    public void endElement(XMLReader.SectionHandler aHandler) {
+    public void endElement(mir.util.xml.SectionHandler aHandler) {
       if (aHandler instanceof NodeDefinitionParametersSectionHandler) {
         stringParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getStringParameters();
         integerParameters = ((NodeDefinitionParametersSectionHandler) aHandler).getIntegerParameters();
@@ -519,10 +531,10 @@ public class ProducerConfigReader {
       }
     }
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
       Iterator i;
       if (body == null)
-        throw new XMLReader.XMLReaderExc( "Definition missing" );
+        throw new XMLParserExc( "Definition missing" );
 
       nodeDefinition = new ScriptedProducerNodeDefinition(name);
 
@@ -557,7 +569,7 @@ public class ProducerConfigReader {
   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 XMLReader.AbstractSectionHandler {
+  public class NodeDefinitionParametersSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private Map nodeParameters;
     private Map stringParameters;
     private Map integerParameters;
@@ -568,29 +580,29 @@ public class ProducerConfigReader {
       integerParameters = new HashMap();
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       String parameterName;
       String defaultValue;
 
       if (aTag.equals("node")) {
-        XMLReaderTool.checkAttributes(anAttributes,
+        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 XMLReader.XMLReaderExc("Duplicate parameter name: '" +
+          throw new XMLParserExc("Duplicate parameter name: '" +
                                            parameterName + "'");
 
-        XMLReaderTool.checkValidIdentifier(parameterName);
+        mir.util.xml.XMLReaderTool.checkValidIdentifier(parameterName);
 
         nodeParameters.put(parameterName, parameterName);
 
         return new EmptySectionHandler();
       }
       else if (aTag.equals("string") || aTag.equals("integer")) {
-        XMLReaderTool.checkAttributes(anAttributes,
+        mir.util.xml.XMLReaderTool.checkAttributes(anAttributes,
             NODE_DEFINITION_PARAMETER_REQUIRED_ATTRIBUTES,
             NODE_DEFINITION_PARAMETER_OPTIONAL_ATTRIBUTES);
         parameterName = (String) anAttributes.get(
@@ -598,10 +610,10 @@ public class ProducerConfigReader {
 
         if (stringParameters.containsKey(parameterName) ||
             integerParameters.containsKey(parameterName))
-          throw new XMLReader.XMLReaderExc("Duplicate parameter name: '" +
+          throw new XMLParserExc("Duplicate parameter name: '" +
                                            parameterName + "'");
 
-        XMLReaderTool.checkValidIdentifier(parameterName);
+        mir.util.xml.XMLReaderTool.checkValidIdentifier(parameterName);
 
         defaultValue = (String) anAttributes.get(
             NODE_DEFINITION_PARAMETER_DEFAULTVALUE_ATTRIBUTE);
@@ -614,11 +626,11 @@ public class ProducerConfigReader {
         return new EmptySectionHandler();
       }
       else
-        throw new XMLReader.XMLReaderExc(
+        throw new XMLParserExc(
             "Only 'string', 'integer' and 'node' tags allowed here, '" + aTag + "' encountered.");
     }
 
-    public void endElement(XMLReader.SectionHandler aHandler) {
+    public void endElement(mir.util.xml.SectionHandler aHandler) {
     }
 
     public void finishSection() {
index 3a5c10b..6b47dde 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
@@ -33,10 +33,10 @@ import java.util.Map;
 import java.util.Set;
 
 import mir.producer.ProducerNode;
-import mir.util.XMLReader;
+import mir.util.xml.XMLParserExc;
 
 public interface ProducerNodeBuilder  {
-  public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLReader.XMLReaderExc;
+  public void setAttributes(Map anAttributes) throws ProducerConfigExc, XMLParserExc;
   public void setSubNode(String aName, ProducerNode aNode) throws ProducerConfigExc;
   public Set getAvailableSubNodes() throws ProducerConfigExc;
   public ProducerNode constructNode() throws ProducerConfigExc;
@@ -48,7 +48,7 @@ public interface ProducerNodeBuilder  {
   public class DefaultProducerNodeBuilderFactory implements ProducerNodeBuilderFactory {
     private Class producerNodeBuilderClass;
 
-    public DefaultProducerNodeBuilderFactory(Class aProducerNodeBuilderClass) throws ProducerConfigExc, XMLReader.XMLReaderExc  {
+    public DefaultProducerNodeBuilderFactory(Class aProducerNodeBuilderClass) throws ProducerConfigExc, XMLParserExc  {
       if (!ProducerNodeBuilder.class.isAssignableFrom(aProducerNodeBuilderClass))
         throw new ProducerConfigExc("supplied class is not a ProducerNodeBuilder class but a " + aProducerNodeBuilderClass.getClass().getName());
 
index 58503d5..1964b3c 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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;
@@ -60,6 +60,10 @@ public class ScriptedProducerFactory implements ProducerFactory {
     return name;
   }
 
+  public boolean allowVerb(String aVerb) {
+    return verbNodes.containsKey(aVerb) || defaultVerb!=null;
+  }
+
   public ScriptedProducerFactory(String aName, List aVerbs, Map aVerbNodes, ProducerNode aBody) {
     this(aName, aVerbs, aVerbNodes, aBody, null);
   }
@@ -83,7 +87,7 @@ public class ScriptedProducerFactory implements ProducerFactory {
     return new NodedProducer(rootNode, aVerb, aStartingValues);
   };
 
-  public Iterator verbs() {
-    return verbs.iterator();
+  public List verbs() {
+    return verbs;
   }
 }
\ No newline at end of file
index b0c68a9..2aa8eaf 100755 (executable)
@@ -29,7 +29,7 @@
  */
 package mir.rss;
 
-import java.util.HashMap;\r
+import java.util.HashMap;
 import java.util.Map;
 
 public class RDFResource {
index 85fd95c..a6556b7 100755 (executable)
@@ -31,13 +31,15 @@ package mir.rss;
 
 import java.io.InputStream;
 import java.net.URL;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
-import java.util.*;
+import java.util.Map;
 import java.util.Vector;
-import java.text.*;
 
-import mir.util.XMLReader;
-import mir.util.*;
+import mir.util.HTTPClientHelper;
+import mir.util.xml.*;
+import mir.util.xml.XMLParserEngine;
 
 /**
  *
@@ -84,9 +86,8 @@ public class RSS091Reader {
 
   public RSSData parseInputStream(InputStream aStream) throws RSSExc, RSSFailure {
     try {
-      XMLReader xmlReader = new XMLReader(false);
       RSSData result = new RSSData();
-      xmlReader.parseInputStream(aStream, new RootSectionHandler(result));
+      XMLParserEngine.getInstance().parse("html", aStream, new RootSectionHandler(result));
 
       return result;
     }
@@ -95,48 +96,82 @@ public class RSS091Reader {
     }
   }
 
-  public RSSData parseUrl(String anUrl) throws RSSExc, RSSFailure {
+  public RSSData parseInputStream(InputStream aStream, String anEncoding) throws RSSExc, RSSFailure {
     try {
-      InputStream inputStream = (InputStream) new URL(anUrl).getContent(new Class[] {InputStream.class});
+      RSSData result = new RSSData();
+      XMLParserEngine.getInstance().parse("html", aStream, anEncoding, new RootSectionHandler(result));
+
+      return result;
+    }
+    catch (Throwable t) {
+      throw new RSSFailure(t);
+    }
+  }
 
+  public RSSData parseUrl(String anUrl) throws RSSExc, RSSFailure {
+    try {
+      HTTPClientHelper httpClientHelper = new HTTPClientHelper();      
+      InputStream inputStream = httpClientHelper.getUrl(anUrl);
       if (inputStream==null)
         throw new RSSExc("RSSChannel.parseUrl: Can't get url content");
 
-      return parseInputStream(inputStream);
+      RSSData theRSSData =  parseInputStream(inputStream);
+      httpClientHelper.releaseHTTPConnection();
+      return theRSSData;
+
     }
     catch (Throwable t) {
       throw new RSSFailure(t);
     }
   }
 
-  private class RootSectionHandler extends XMLReader.AbstractSectionHandler {
+  public RSSData parseUrl(String anUrl, String anEncoding) throws RSSExc, RSSFailure {
+    try {
+      HTTPClientHelper httpClientHelper = new HTTPClientHelper();      
+      InputStream inputStream = httpClientHelper.getUrl(anUrl);
+
+      if (inputStream==null)
+        throw new RSSExc("RSSChannel.parseUrl: Can't get url content");
+      
+      RSSData theRSSData = parseInputStream(inputStream, anEncoding);
+      httpClientHelper.releaseHTTPConnection();
+      return theRSSData;
+    }
+
+    catch (Throwable t) {
+      throw new RSSFailure(t);
+    }
+  }
+
+  private class RootSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private RSSData data;
 
     public RootSectionHandler(RSSData aData) {
       data = aData;
     }
 
-    public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.getLocalName().equals("rss")) {
         return new RSS091SectionHandler(data);
       }
       else
-        throw new XMLReader.XMLReaderFailure(new RSSExc("'rss' tag expected"));
+        throw new XMLParserFailure(new RSSExc("'rss' tag expected"));
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       if (aCharacters.trim().length()>0)
-        throw new XMLReader.XMLReaderExc("No character data allowed here");
+        throw new XMLParserExc("No character data allowed here");
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
   }
 
-  private class RSS091SectionHandler extends XMLReader.AbstractSectionHandler {
+  private class RSS091SectionHandler extends mir.util.xml.AbstractSectionHandler {
     private RSSData data;
 
 
@@ -144,23 +179,23 @@ public class RSS091Reader {
       data = aData;
     }
 
-    public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.getLocalName().equals("channel"))
         return new RSS091ChannelSectionHandler(data);
       else
-        throw new XMLReader.XMLReaderExc("channel tag expected, " + aTag.getLocalName() + " found");
+        throw new XMLParserExc("channel tag expected, " + aTag.getLocalName() + " found");
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       if (aCharacters.trim().length()>0)
-        throw new XMLReader.XMLReaderExc("No character data allowed here");
+        throw new XMLParserExc("No character data allowed here");
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
   }
 
-  private class RSS091ChannelSectionHandler extends XMLReader.AbstractSectionHandler {
+  private class RSS091ChannelSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private String currentTag;
 
     private RSSData data;
@@ -175,7 +210,7 @@ public class RSS091Reader {
       attributes = new HashMap();
     }
 
-    public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
       String tag = aTag.getLocalName();
 
       if (tag.equals("item"))
@@ -188,7 +223,7 @@ public class RSS091Reader {
         return new DiscardingSectionHandler();
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
       if (aHandler instanceof PCDATASectionHandler) {
         attributes.put(currentTag, (((PCDATASectionHandler) aHandler).getData()));
       }
@@ -197,12 +232,12 @@ public class RSS091Reader {
       }
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       if (aCharacters.trim().length()>0)
-        throw new XMLReader.XMLReaderExc("No character data allowed here");
+        throw new XMLParserExc("No character data allowed here");
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
       Iterator i = items.iterator();
 
       while (i.hasNext()) {
@@ -211,7 +246,7 @@ public class RSS091Reader {
     };
   }
 
-  private class RSS091ItemSectionHandler extends XMLReader.AbstractSectionHandler {
+  private class RSS091ItemSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private String currentTag;
 
     private RDFResource item;
@@ -221,9 +256,8 @@ public class RSS091Reader {
       attributes = new HashMap();
     }
 
-    public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
       String tag = aTag.getLocalName();
-      System.out.println(tag);
 
       if (mappedItemProperties.containsKey(tag)) {
         currentTag=(String) mappedItemProperties.get(tag);
@@ -233,18 +267,18 @@ public class RSS091Reader {
         return new DiscardingSectionHandler();
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
       if (aHandler instanceof PCDATASectionHandler) {
         attributes.put(currentTag, (((PCDATASectionHandler) aHandler).getData()));
       }
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       if (aCharacters.trim().length()>0)
-        throw new XMLReader.XMLReaderExc("No character data allowed here");
+        throw new XMLParserExc("No character data allowed here");
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
       item = new RDFResource("rss:item", (String) attributes.get("rss:link"));
 
       Iterator i = attributes.entrySet().iterator();
@@ -261,25 +295,25 @@ public class RSS091Reader {
   }
 
 
-  private class PCDATASectionHandler extends XMLReader.AbstractSectionHandler {
+  private class PCDATASectionHandler extends mir.util.xml.AbstractSectionHandler {
     private StringBuffer data;
 
     public PCDATASectionHandler() {
       data = new StringBuffer();
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
-      throw new XMLReader.XMLReaderFailure(new RSSExc("No subtags allowed here"));
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      throw new XMLParserFailure(new RSSExc("No subtags allowed here"));
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       data.append(aCharacters);
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
 
     public String getData() {
@@ -288,14 +322,14 @@ public class RSS091Reader {
   }
 
 
-  private class RDFSequenceSectionHandler extends XMLReader.AbstractSectionHandler {
+  private class RDFSequenceSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private List items;
 
     public RDFSequenceSectionHandler() {
       items = new Vector();
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.equals("rdf:li")) {
         String item = (String) anAttributes.get("rdf:resource");
 
@@ -306,13 +340,13 @@ public class RSS091Reader {
       return new DiscardingSectionHandler();
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
 
     public List getItems() {
@@ -320,18 +354,18 @@ public class RSS091Reader {
     }
   }
 
-  private class DiscardingSectionHandler extends XMLReader.AbstractSectionHandler {
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+  private class DiscardingSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       return this;
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
   }
 }
index bdc6ae0..8b44191 100755 (executable)
@@ -30,7 +30,9 @@
 
 package mir.rss;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
 public class RSSAggregator {
   private String orderBy;
@@ -44,7 +46,7 @@ public class RSSAggregator {
     orderBy = anOrderBy;
     orderReversed = anOrderReversed;
     capacity = aCapacity;
-    items = new Vector();
+    items = new ArrayList();
     selectionValue = aSelectionValue;
     selectionField = aSelectionField;
   }
index a5e6181..d858aed 100755 (executable)
@@ -32,7 +32,7 @@ package mir.rss;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Vector;
+import java.util.ArrayList;
 
 public class RSSData {
   private List resources;
@@ -40,7 +40,7 @@ public class RSSData {
   private Map identifierToResource;
 
   protected RSSData() {
-    resources = new Vector();
+    resources = new ArrayList();
     rdfClassToResources = new HashMap();
     identifierToResource = new HashMap();
   }
@@ -53,7 +53,7 @@ public class RSSData {
     resources.add(aResource);
     List resourcesForClass = (List) rdfClassToResources.get(aResource.getRdfClass());
     if (resourcesForClass==null) {
-      resourcesForClass = new Vector();
+      resourcesForClass = new ArrayList();
       rdfClassToResources.put(aResource.getRdfClass(), resourcesForClass);
     }
     resourcesForClass.add(aResource);
index bdc850b..6d89d49 100755 (executable)
 package mir.rss;
 
 import java.io.InputStream;
-import java.net.URL;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Vector;
 
 import mir.util.DateTimeFunctions;
-import mir.util.XMLReader;
+import mir.util.HTTPClientHelper;
+import mir.util.xml.XMLParserEngine;
+import mir.util.xml.XMLParserExc;
+import mir.util.xml.XMLParserFailure;
 
 /**
  *
@@ -60,22 +62,22 @@ public class RSSReader {
   public static final String CONTENT_NAMESPACE_URI = "http://purl.org/rss/1.0/modules/content/";
 
   // ML: to be localized:
-  public static final String V2V_NAMESPACE_URI = "http://v2v.indymedia.de/rss/";
+  public static final String V2V_NAMESPACE_URI = "http://v2v.cc/rss/";
 
-  private static final XMLReader.XMLName RDF_ABOUT_PARAMETER = new XMLReader.XMLName(RDF_NAMESPACE_URI, "about");
-  private static final XMLReader.XMLName RDF_SEQUENCE_TAG = new XMLReader.XMLName(RDF_NAMESPACE_URI, "Seq");
-  private static final XMLReader.XMLName RDF_BAG_PARAMETER = new XMLReader.XMLName(RDF_NAMESPACE_URI, "Bag");
+  private static final mir.util.xml.XMLName RDF_ABOUT_PARAMETER = new mir.util.xml.XMLName(RDF_NAMESPACE_URI, "about");
+  private static final mir.util.xml.XMLName RDF_SEQUENCE_TAG = new mir.util.xml.XMLName(RDF_NAMESPACE_URI, "Seq");
+  private static final mir.util.xml.XMLName RDF_BAG_PARAMETER = new mir.util.xml.XMLName(RDF_NAMESPACE_URI, "Bag");
 
-  private static final XMLReader.XMLName RSS_CHANNEL_TAG = new XMLReader.XMLName(RSS_1_0_NAMESPACE_URI, "channel");
-  private static final XMLReader.XMLName RSS_ITEM_TAG = new XMLReader.XMLName(RSS_1_0_NAMESPACE_URI, "item");
-  private static final XMLReader.XMLName RSS_ITEMS_TAG = new XMLReader.XMLName(RSS_1_0_NAMESPACE_URI, "items");
+  private static final mir.util.xml.XMLName RSS_CHANNEL_TAG = new mir.util.xml.XMLName(RSS_1_0_NAMESPACE_URI, "channel");
+  private static final mir.util.xml.XMLName RSS_ITEM_TAG = new mir.util.xml.XMLName(RSS_1_0_NAMESPACE_URI, "item");
+  private static final mir.util.xml.XMLName RSS_ITEMS_TAG = new mir.util.xml.XMLName(RSS_1_0_NAMESPACE_URI, "items");
 
   private List modules;
   private Map namespaceURItoModule;
   private Map moduleToPrefix;
 
   public RSSReader() {
-    modules = new Vector();
+    modules = new ArrayList();
     namespaceURItoModule = new HashMap();
     moduleToPrefix = new HashMap();
 
@@ -115,9 +117,20 @@ public class RSSReader {
 
   public RSSData parseInputStream(InputStream aStream) throws RSSExc, RSSFailure {
     try {
-      XMLReader xmlReader = new XMLReader(true);
       RSSData result = new RSSData();
-      xmlReader.parseInputStream(aStream, new RootSectionHandler(result));
+      XMLParserEngine.getInstance().parse("xml", aStream, new RootSectionHandler(result));
+
+      return result;
+    }
+    catch (Throwable t) {
+      throw new RSSFailure(t);
+    }
+  }
+
+  public RSSData parseInputStream(InputStream aStream, String anEncoding) throws RSSExc, RSSFailure {
+    try {
+      RSSData result = new RSSData();
+      XMLParserEngine.getInstance().parse("xml", aStream, anEncoding, new RootSectionHandler(result));
 
       return result;
     }
@@ -128,46 +141,64 @@ public class RSSReader {
 
   public RSSData parseUrl(String anUrl) throws RSSExc, RSSFailure {
     try {
-      InputStream inputStream = (InputStream) new URL(anUrl).getContent(new Class[] {InputStream.class});
+      HTTPClientHelper httpClientHelper = new HTTPClientHelper();      
+      InputStream inputStream = httpClientHelper.getUrl(anUrl);
+      if (inputStream==null)
+        throw new RSSExc("RSSChannel.parseUrl: Can't get url content");
+
+      RSSData theRSSData =  parseInputStream(inputStream);
+      httpClientHelper.releaseHTTPConnection();
+      return theRSSData;
+    }
+    catch (Throwable t) {
+      throw new RSSFailure(t);
+    }
+  }
 
+  public RSSData parseUrl(String anUrl, String anEncoding) throws RSSExc, RSSFailure {
+    try {
+      HTTPClientHelper httpClientHelper = new HTTPClientHelper();      
+      InputStream inputStream = httpClientHelper.getUrl(anUrl);
       if (inputStream==null)
         throw new RSSExc("RSSChannel.parseUrl: Can't get url content");
 
-      return parseInputStream(inputStream);
+      RSSData theRSSData =  parseInputStream(inputStream, anEncoding);
+      httpClientHelper.releaseHTTPConnection();
+      return theRSSData;
     }
     catch (Throwable t) {
       throw new RSSFailure(t);
     }
   }
 
-  private class RootSectionHandler extends XMLReader.AbstractSectionHandler {
+  private class RootSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private RSSData data;
 
     public RootSectionHandler(RSSData aData) {
       data = aData;
     }
 
-    public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.getLocalName().equals("RDF")) {
         return new RDFSectionHandler(data);
       }
       else
-        throw new XMLReader.XMLReaderFailure(new RSSExc("'RDF' tag expected"));
+        throw new XMLParserFailure(new RSSExc("'RDF' tag expected"));
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       if (aCharacters.trim().length()>0)
-        throw new XMLReader.XMLReaderExc("No character data allowed here");
+        throw new XMLParserExc("No character data allowed here");
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
   }
 
-  private class RDFSectionHandler extends XMLReader.AbstractSectionHandler {
+  private class RDFSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private RSSData data;
 
 
@@ -175,29 +206,29 @@ public class RSSReader {
       data = aData;
     }
 
-    public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
       String identifier = (String) anAttributes.get(RDF_ABOUT_PARAMETER);
       String rdfClass = makeQualifiedName(aTag);
 
       return new RDFResourceSectionHandler(rdfClass, identifier);
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
       if (aHandler instanceof RDFResourceSectionHandler) {
         data.addResource(((RDFResourceSectionHandler) aHandler).getResource());
       }
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       if (aCharacters.trim().length()>0)
-        throw new XMLReader.XMLReaderExc("No character data allowed here");
+        throw new XMLParserExc("No character data allowed here");
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
   }
 
-  private XMLReader.SectionHandler makePropertyValueSectionHandler(XMLReader.XMLName aTag, Map anAttributes) {
+  private mir.util.xml.SectionHandler makePropertyValueSectionHandler(mir.util.xml.XMLName aTag, Map anAttributes) {
     RSSModule module = (RSSModule) namespaceURItoModule.get(aTag.getNamespaceURI());
 
     if (module!=null) {
@@ -224,7 +255,7 @@ public class RSSReader {
     return new FlexiblePropertyValueSectionHandler();
   }
 
-  private void usePropertyValueSectionHandler(RDFResource aResource, PropertyValueSectionHandler aHandler, XMLReader.XMLName aTag) {
+  private void usePropertyValueSectionHandler(RDFResource aResource, PropertyValueSectionHandler aHandler, mir.util.xml.XMLName aTag) {
     RSSModule module = (RSSModule) namespaceURItoModule.get(aTag.getNamespaceURI());
 
     if (module!=null) {
@@ -234,7 +265,7 @@ public class RSSReader {
         List value = (List) aResource.get(makeQualifiedName(aTag));
 
         if (value==null) {
-          value = new Vector();
+          value = new ArrayList();
           aResource.set(makeQualifiedName(aTag), value);
         }
 
@@ -247,7 +278,7 @@ public class RSSReader {
     aResource.set(makeQualifiedName(aTag), aHandler.getValue());
   }
 
-  private String makeQualifiedName(XMLReader.XMLName aName) {
+  private String makeQualifiedName(mir.util.xml.XMLName aName) {
     String result=aName.getLocalName();
     RSSModule module = (RSSModule) namespaceURItoModule.get(aName.getNamespaceURI());
     if (module!=null) {
@@ -260,38 +291,38 @@ public class RSSReader {
     return result;
   }
 
-  private class RDFResourceSectionHandler extends XMLReader.AbstractSectionHandler {
+  private class RDFResourceSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private String image;
-    private XMLReader.XMLName currentTag;
+    private mir.util.xml.XMLName currentTag;
     private RDFResource resource;
 
     public RDFResourceSectionHandler(String anRDFClass, String anIdentifier) {
       resource = new RDFResource(anRDFClass, anIdentifier);
     }
 
-    public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(mir.util.xml.XMLName aTag, Map anAttributes) throws XMLParserExc {
       currentTag = aTag;
 
       return makePropertyValueSectionHandler(aTag, anAttributes);
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
       if (aHandler instanceof PropertyValueSectionHandler) {
         usePropertyValueSectionHandler(resource, (PropertyValueSectionHandler) aHandler, currentTag);
-//        resource.set(makeQualifiedName(currentTag), ( (PropertyValueSectionHandler) aHandler).getValue());
+//        resource.set(makeQualifiedName(currentTag), ( (PropertyValueSectionHandler) aHandler).getFieldValue());
       }
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       if (aCharacters.trim().length()>0)
-        throw new XMLReader.XMLReaderExc("No character data allowed here");
+        throw new XMLParserExc("No character data allowed here");
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
 
     public RDFResource getResource() {
-      if (resource.getIdentifier()==null || resource.getIdentifier().length()==0) {
+      if ((resource.getIdentifier()==null || resource.getIdentifier().length()==0) && resource.get("rss:link")!=null) {
         resource.setIdentifier(resource.get("rss:link").toString());
       }
 
@@ -299,7 +330,7 @@ public class RSSReader {
     }
   }
 
-  private abstract class PropertyValueSectionHandler extends XMLReader.AbstractSectionHandler {
+  private abstract class PropertyValueSectionHandler extends mir.util.xml.AbstractSectionHandler {
     public abstract Object getValue();
   }
 
@@ -312,24 +343,24 @@ public class RSSReader {
       structuredData=null;
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.equals(RDF_SEQUENCE_TAG))
         return new RDFSequenceSectionHandler();
       else
         return new DiscardingSectionHandler();
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
       if (aHandler instanceof RDFSequenceSectionHandler) {
         structuredData= ((RDFSequenceSectionHandler) aHandler).getItems();
       }
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       stringData.append(aCharacters);
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
 
     public String getData() {
@@ -348,28 +379,28 @@ public class RSSReader {
     private List items;
 
     public RDFCollectionSectionHandler() {
-      items = new Vector();
+      items = new ArrayList();
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.equals(RDF_SEQUENCE_TAG))
         return new RDFSequenceSectionHandler();
       else
         return new DiscardingSectionHandler();
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
       if (aHandler instanceof RDFSequenceSectionHandler) {
         items.addAll(((RDFSequenceSectionHandler) aHandler).getItems());
       }
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       if (aCharacters.trim().length()>0)
-        throw new XMLReader.XMLReaderExc("No character data allowed here");
+        throw new XMLParserExc("No character data allowed here");
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
 
     public List getItems() {
@@ -388,18 +419,18 @@ public class RSSReader {
       data = new StringBuffer();
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
-      throw new XMLReader.XMLReaderFailure(new RSSExc("No subtags allowed here"));
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      throw new XMLParserFailure(new RSSExc("No subtags allowed here"));
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       data.append(aCharacters);
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
 
     public String getData() {
@@ -418,24 +449,20 @@ public class RSSReader {
       data = new StringBuffer();
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
-      throw new XMLReader.XMLReaderFailure(new RSSExc("No subtags allowed here"));
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
+      throw new XMLParserFailure(new RSSExc("No subtags allowed here"));
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       data.append(aCharacters);
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
 
-    private final static String SPACE = "[\t\n\r ]*";
-    private final static String NUMBER = "[0-9]*";
-    private final static String SIGN = "[-+]";
-
     public Object getValue() {
       try {
         String expression = data.toString().trim();
@@ -450,14 +477,14 @@ public class RSSReader {
   }
 
 
-  private class RDFSequenceSectionHandler extends XMLReader.AbstractSectionHandler {
+  private class RDFSequenceSectionHandler extends mir.util.xml.AbstractSectionHandler {
     private List items;
 
     public RDFSequenceSectionHandler() {
-      items = new Vector();
+      items = new ArrayList();
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       if (aTag.equals("rdf:li")) {
         String item = (String) anAttributes.get("rdf:resource");
 
@@ -468,13 +495,13 @@ public class RSSReader {
       return new DiscardingSectionHandler();
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
 
     public List getItems() {
@@ -494,23 +521,23 @@ public class RSSReader {
       return data;
     }
 
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       tag=aTag;
       data.append("<"+tag+">");
 
       return new RDFLiteralSectionHandler();
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
       data.append(((RDFLiteralSectionHandler) aHandler).getData());
       data.append("</"+tag+">");
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
       data.append(aCharacters);
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
 
     public Object getValue() {
@@ -518,18 +545,18 @@ public class RSSReader {
     }
   }
 
-  private class DiscardingSectionHandler extends XMLReader.AbstractSectionHandler {
-    public XMLReader.SectionHandler startElement(String aTag, Map anAttributes) throws XMLReader.XMLReaderExc {
+  private class DiscardingSectionHandler extends mir.util.xml.AbstractSectionHandler {
+    public mir.util.xml.SectionHandler startElement(String aTag, Map anAttributes) throws XMLParserExc {
       return this;
     };
 
-    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {
+    public void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc {
     };
 
-    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {
+    public void characters(String aCharacters) throws XMLParserExc {
     };
 
-    public void finishSection() throws XMLReader.XMLReaderExc {
+    public void finishSection() throws XMLParserExc {
     };
   }
 }
diff --git a/source/mir/rss/RSSTest.java b/source/mir/rss/RSSTest.java
deleted file mode 100755 (executable)
index 92f102c..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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,
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
- * (or with modified versions of the above that use the same license as the above),
- * 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.rss;
-
-import java.util.*;
-import mir.util.*;
-import gnu.regexp.RE;
-
-
-public class RSSTest {
-
-  public static void main(String[] args) {
-
-    RSSReader reader = new RSSReader();
-//..    RSS091Reader reader2 = new RSS091Reader();
-    try {
-//      RE test = new RE(".*\\bLB\\b.*", RE.REG_ICASE);
-//      System.out.println(" LB II : " + test.isMatch("LB II"));
-//      System.out.println(" revised LB: " + test.isMatch("revised LB"));
-//      System.out.println(" revised LB II : " + test.isMatch("revised LB II"));
-//      System.out.println(" buLB: " + test.isMatch("buLB"));
-
-      RSSData nl = reader.parseUrl("http://biotechdev.mir.dnsalias.net/test.rss");
-//      RSSData it = reader.parseUrl("http://g8.mir.dnsalias.net/italynewswire.rss");
-//      Object result = StructuredContentParser.parse(" { a = 'b' 'as a' = [ 'asd' asd 'asdas asd as''asd' ] }") ;
-//      System.out.println("" + wvl.get("rss:item"));
-//      RSSData fr = reader2.parseUrl("http://paris.indymedia.org/backendg8.php3");
-//      RSSData be = reader.parseUrl("http://belgium.indymedia.org/features.rdf");
-
-//      RSSAggregator agg = new RSSAggregator(10, "dc:date", true, null, null);
-
-//      agg.appendItems(wvl.getResourcesForRdfClass("rss:item"));
-//      agg.appendItems(be.getResourcesForRdfClass("rss:item"));
-
-//      System.out.println(fr);
-
-//      Iterator i = fr.getResourcesForRdfClass("rss:item").iterator();
-//      while (i.hasNext())
-//        System.out.println(ParameterExpander.evaluateExpression((RDFResource) i.next(), "['dc:date']"));
-
-//      System.out.println(agg.getItems());
-    }
-    catch (Throwable t) {
-      System.out.println("Exception: " + t.toString());
-      t.printStackTrace(System.out);
-    }
-  }
-}
index 5308bcc..5cfc53e 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  any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two.  You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries.  If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-package mir.servlet;\r
-\r
-import java.io.IOException;\r
-import java.lang.reflect.InvocationTargetException;\r
-import java.lang.reflect.Method;\r
-import java.sql.Connection;\r
-import java.util.Locale;\r
-\r
-import javax.servlet.ServletConfig;\r
-import javax.servlet.ServletException;\r
-import javax.servlet.http.HttpServlet;\r
-import javax.servlet.http.HttpServletRequest;\r
-import javax.servlet.http.HttpServletResponse;\r
-import javax.servlet.http.HttpSession;\r
-\r
-import com.codestudio.util.JDBCPool;\r
-import com.codestudio.util.JDBCPoolMetaData;\r
-import com.codestudio.util.SQLManager;\r
-\r
-import mir.config.MirPropertiesConfiguration;\r
-import mir.log.LoggerWrapper;\r
-\r
-import mircoders.global.MirGlobal;\r
-\r
-/**\r
- * Title:        Mir\r
- * Description:  Abstract servlet-class\r
- * Copyright:    Copyright (c) 2001, 2002\r
- * Company:      Mir-coders group\r
- * @author       idfx, the Mir-coders group\r
- * @version      $Id: AbstractServlet.java,v 1.31 2003/09/03 18:29:03 zapata Exp $\r
- */\r
-\r
-public abstract class AbstractServlet extends HttpServlet {\r
-  protected static String lang;\r
-  protected LoggerWrapper logger;\r
-  protected MirPropertiesConfiguration configuration;\r
-\r
-  /**\r
-   * Constructor for AbstractServlet.\r
-   */\r
-  public AbstractServlet() {\r
-    super();\r
-  }\r
-\r
-  protected void setNoCaching(HttpServletResponse aResponse) {\r
-    //nothing in Mir can or should be cached as it's all dynamic...\r
-    //\r
-    //this needs to be done here and not per page (via meta tags) as some\r
-    //browsers have problems w/ it per-page -mh\r
-    aResponse.setHeader("Pragma", "no-cache");\r
-    aResponse.setDateHeader("Expires", 0);\r
-    aResponse.setHeader("Cache-Control", "no-cache");\r
-  }\r
-\r
-  /**\r
-   * Bind the language to the session\r
-   */\r
-  protected void setLanguage(HttpSession session, String language) {\r
-    logger.debug("setting language to " + language);\r
-\r
-    session.setAttribute("language", language);\r
-    session.setAttribute("locale", new Locale(language, ""));\r
-  }\r
-\r
-  /**\r
-   * Get the session-bound language\r
-   */\r
-  protected String getLanguage(HttpServletRequest aRequest, HttpSession session) {\r
-    String lang = (String) session.getAttribute("language");\r
-\r
-    if (lang == null || lang.length()==0) {\r
-      lang = getAcceptLanguage(aRequest);\r
-    }\r
-\r
-    return lang;\r
-  }\r
-\r
-  /**\r
-   * get the locale either from the session or the accept-language header ot the request\r
-   * this supersedes getLanguage for the new i18n\r
-   */\r
-  public Locale getLocale(HttpServletRequest aRequest) {\r
-    Locale loc = null;\r
-    HttpSession session = aRequest.getSession(false);\r
-    if (session != null) {\r
-      // session can be null in case of logout\r
-      loc = (Locale) session.getAttribute("locale");\r
-    }\r
-    // if there is nothing in the session get it fron the accept-language\r
-    if (loc == null) {\r
-      loc = aRequest.getLocale();\r
-    }\r
-\r
-    logger.debug("getting locale: " + loc.getLanguage());\r
-\r
-    return loc;\r
-  }\r
-\r
-  /**\r
-   * Checks the Accept-Language of the client browser.\r
-   * If this language is available it returns its country-code,\r
-   * else it returns the standard-language\r
-   */\r
-  protected String getAcceptLanguage(HttpServletRequest aRequest) {\r
-    Locale loc = aRequest.getLocale();\r
-    lang = loc.getLanguage();\r
-    return lang;\r
-  }\r
-\r
-  /**\r
-   * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)\r
-   */\r
-  public void init(ServletConfig config) throws ServletException {\r
-    super.init(config);\r
-\r
-    MirPropertiesConfiguration.setContext(config.getServletContext());\r
-    try {\r
-      configuration = MirPropertiesConfiguration.instance();\r
-    }\r
-    catch (Throwable t) {\r
-      throw new ServletException("can't read configuration: " + t.toString());\r
-    }\r
-\r
-    logger = new LoggerWrapper("Servlet");\r
-\r
-    try {\r
-      MirGlobal.localizer();\r
-    }\r
-    catch (Throwable t) {\r
-      logger.fatal("can't get localizer: " + t.toString());\r
-      throw new ServletException("can't get localizer: " + t.toString());\r
-    }\r
-\r
-    String dbUser = configuration.getString("Database.Username");\r
-    String dbPassword = configuration.getString("Database.Password");\r
-    String dbHost = configuration.getString("Database.Host");\r
-    String dbPort = configuration.getString("Database.Port");\r
-    String dbAdapName = configuration.getString("Database.Adaptor");\r
-    String dbName = configuration.getString("Database.Name");\r
-    String dbDriver = configuration.getString("Database.Driver");\r
-    String dbUrl = "jdbc:postgresql://"+dbHost+":"+dbPort+"/"+dbName;\r
-    int dbMin = configuration.getInteger("Database.poolMin", 1);\r
-    int dbMax = configuration.getInteger("Database.poolMax", 10);\r
-\r
-    JDBCPoolMetaData meta = new JDBCPoolMetaData();\r
-    meta.setDbname(dbName);\r
-    meta.setDriver(dbDriver);\r
-    meta.setURL(dbUrl);\r
-    meta.setUserName(dbUser);\r
-    meta.setPassword(dbPassword);\r
-    meta.setJNDIName("mir");\r
-    meta.setMaximumSize(dbMax);\r
-    meta.setMinimumSize(dbMin);\r
-    meta.setPoolPreparedStatements(false);\r
-    meta.setCacheEnabled(false);\r
-    meta.setCacheSize(15);\r
-    meta.setDebugging(false);\r
-\r
-    SQLManager manager = SQLManager.getInstance();\r
-\r
-    JDBCPool pool = null;\r
-    if (manager != null) {\r
-      pool = manager.createPool(meta);\r
-    }\r
-\r
-    Connection connection;\r
-    try {\r
-      connection = pool.requestConnection();\r
-      pool.closeConnection(connection);\r
-    }\r
-    catch (Throwable t) {\r
-      logger.fatal("Can't connect to database: " + t.toString());\r
-      throw new ServletException("Can't connect to database: " + t.toString());\r
-    }\r
-  }\r
-\r
-  private void setEncoding(HttpServletRequest request){\r
-    try {\r
-      logger.info("Request has encoding: " + request.getCharacterEncoding());\r
-      logger.info("Config stipulates encoding: " + configuration.getString("Mir.DefaultHTMLCharset"));\r
-      Class reqClass = request.getClass();\r
-      Method method = reqClass.getMethod("setCharacterEncoding", new Class[]{String.class});\r
-      String encoding = configuration.getString("Mir.DefaultHTMLCharset");\r
-      method.invoke(request, new Object[]{encoding});\r
-      logger.info("Request now has encoding: " + request.getCharacterEncoding());\r
-    }\r
-    catch (NoSuchMethodException e) {\r
-      // TODO set the encoding in a zapata-way\r
-//      logger.warn("set encoding not yet implemented: " + e.getMessage());\r
-    }\r
-    catch (SecurityException e) {\r
-      logger.error(e.getMessage());\r
-      e.printStackTrace();\r
-    }\r
-    catch (IllegalArgumentException e) {\r
-      logger.error(e.getMessage());\r
-      e.printStackTrace();\r
-    }\r
-    catch (IllegalAccessException e) {\r
-      logger.error(e.getMessage());\r
-      e.printStackTrace();\r
-    }\r
-    catch (InvocationTargetException e) {\r
-      logger.error(e.getMessage());\r
-      e.printStackTrace();\r
-    }\r
-  }\r
-\r
-  protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\r
-    doPost(request, response);\r
-  }\r
-\r
-  protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {\r
-    if ((configuration.getString("RootUri") == null) || configuration.getString("RootUri").equals("")) {\r
-      configuration.setProperty("RootUri", request.getContextPath());\r
-    }\r
-    setEncoding(request);\r
-    process(request, response);\r
-  }\r
-\r
-  abstract public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;\r
-\r
-  /**\r
-   * Selects the language for the response.\r
-   *\r
-   * @param session\r
-   * @param aRequest\r
-   */\r
-  protected void checkLanguage(HttpSession aSession, HttpServletRequest aRequest) {\r
-    String requestLanguage = aRequest.getParameter("language");\r
-    String sessionLanguage = (String) aSession.getAttribute("language");\r
-    String acceptLanguage = aRequest.getLocale().getLanguage();\r
-    String defaultLanguage = configuration.getString("Mir.Login.DefaultLanguage", "en");\r
-\r
-    String language = requestLanguage;\r
-\r
-    if (language==null)\r
-      language = sessionLanguage;\r
-\r
-    if (language==null)\r
-      language = acceptLanguage;\r
-\r
-    if (language==null)\r
-      language = defaultLanguage;\r
-\r
-    setLanguage(aSession, language);\r
-  }\r
-}\r
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.servlet;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.util.Locale;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import mir.config.MirPropertiesConfiguration;
+import mir.log.LoggerWrapper;
+import mircoders.global.MirGlobal;
+
+/**
+ * Title:        Mir
+ * Description:  Abstract servlet-class
+ * Copyright:    Copyright (c) 2001, 2002
+ * Company:      Mir-coders group
+ * @author       idfx, the Mir-coders group
+ * @version      $Id: AbstractServlet.java,v 1.32 2004/11/06 19:33:15 idfx Exp $
+ */
+
+public abstract class AbstractServlet extends HttpServlet {
+  protected LoggerWrapper logger;
+  protected MirPropertiesConfiguration configuration;
+
+  public AbstractServlet() {
+    super();
+  }
+
+  protected void setNoCaching(HttpServletResponse aResponse) {
+    //nothing in Mir can or should be cached as it's all dynamic...
+    //
+    //this needs to be done here and not per page (via meta tags) as some
+    //browsers have problems w/ it per-page -mh
+
+    aResponse.setHeader("Pragma", "no-cache");
+    aResponse.setDateHeader("Expires", 0);
+    aResponse.setHeader("Cache-Control", "no-cache");
+  }
+
+  /**
+   * Bind the language to the session
+   */
+  protected void setLanguage(HttpSession session, String language) {
+    logger.debug("setting language to " + language);
+
+    session.setAttribute("language", language);
+    session.setAttribute("locale", new Locale(language, ""));
+  }
+
+  /**
+   * Get the session-bound language
+   */
+  protected String getLanguage(HttpServletRequest aRequest, HttpSession session) {
+    String language = (String) session.getAttribute("language");
+
+    if (language == null || language.length()==0) {
+      language = getAcceptLanguage(aRequest);
+    }
+
+    return language;
+  }
+
+  /**
+   * get the locale either from the session or the accept-language header ot the request
+   * this supersedes getLanguage for the new i18n
+   */
+  public Locale getLocale(HttpServletRequest aRequest) {
+    Locale locale = null;
+    HttpSession session = aRequest.getSession(false);
+    if (session != null) {
+      // session can be null in case of logout
+      locale = (Locale) session.getAttribute("locale");
+    }
+    // if there is nothing in the session get it fron the accept-language
+    if (locale == null) {
+      locale = aRequest.getLocale();
+    }
+
+    logger.debug("getting locale: " + locale.getLanguage());
+
+    return locale;
+  }
+
+  /**
+   * Checks the Accept-Language of the client browser.
+   * If this language is available it returns its country-code,
+   * else it returns the standard-language
+   */
+  protected String getAcceptLanguage(HttpServletRequest aRequest) {
+    Locale loc = aRequest.getLocale();
+    String lang = loc.getLanguage();
+    return lang;
+  }
+
+  /**
+   * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
+   */
+  public void init(ServletConfig config) throws ServletException {
+    super.init(config);
+
+    MirPropertiesConfiguration.setContext(config.getServletContext());
+    try {
+      configuration = MirPropertiesConfiguration.instance();
+    }
+    catch (Throwable t) {
+      throw new ServletException("can't read configuration: " + t.toString());
+    }
+
+    logger = new LoggerWrapper("Servlet");
+
+    try {
+      MirGlobal.localizer();
+    }
+    catch (Throwable t) {
+      logger.fatal("can't get localizer: " + t.toString());
+      throw new ServletException("can't get localizer: " + t.toString());
+    }
+
+    Connection connection;
+    try {
+      connection = MirGlobal.getDatabaseEngine().obtainConnection();
+      MirGlobal.getDatabaseEngine().releaseConnection(connection);
+    }
+    catch (Throwable t) {
+      logger.fatal("Can't connect to database: " + t.toString());
+      throw new ServletException("Can't connect to database: " + t.toString());
+    }
+  }
+
+  private void setEncoding(HttpServletRequest request){
+    try {
+      logger.info("Request has encoding: " + request.getCharacterEncoding());
+      logger.info("Config stipulates encoding: " + configuration.getString("Mir.DefaultHTMLCharset"));
+      Class reqClass = request.getClass();
+      Method method = reqClass.getMethod("setCharacterEncoding", new Class[]{String.class});
+      String encoding = configuration.getString("Mir.DefaultHTMLCharset");
+      method.invoke(request, new Object[]{encoding});
+      logger.info("Request now has encoding: " + request.getCharacterEncoding());
+    }
+    catch (NoSuchMethodException e) {
+      // TODO set the encoding in a zapata-way
+    }
+    catch (SecurityException e) {
+      logger.error(e.getMessage());
+      e.printStackTrace();
+    }
+    catch (IllegalArgumentException e) {
+      logger.error(e.getMessage());
+      e.printStackTrace();
+    }
+    catch (IllegalAccessException e) {
+      logger.error(e.getMessage());
+      e.printStackTrace();
+    }
+    catch (InvocationTargetException e) {
+      logger.error(e.getMessage());
+      e.printStackTrace();
+    }
+  }
+
+  protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+    doPost(request, response);
+  }
+
+  protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+    if ((configuration.getString("RootUri") == null) || configuration.getString("RootUri").equals("")) {
+      configuration.setProperty("RootUri", request.getContextPath());
+    }
+    setEncoding(request);
+    process(request, response);
+  }
+
+  abstract public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
+
+  /**
+   * Selects the language for the response.
+   */
+  protected void checkLanguage(HttpSession aSession, HttpServletRequest aRequest) {
+    String requestLanguage = aRequest.getParameter("language");
+    String sessionLanguage = (String) aSession.getAttribute("language");
+    String acceptLanguage = aRequest.getLocale().getLanguage();
+    String defaultLanguage = configuration.getString("Mir.Login.DefaultLanguage", "en");
+
+    String language = requestLanguage;
+
+    if (language==null)
+      language = sessionLanguage;
+
+    if (language==null)
+      language = acceptLanguage;
+
+    if (language==null)
+      language = defaultLanguage;
+
+    setLanguage(aSession, language);
+  }
+}
index 42519db..b6f4ce1 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  any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two.  You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries.  If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-package mir.servlet;\r
-\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Locale;\r
-import java.util.Map;\r
-import javax.servlet.http.HttpServletRequest;\r
-import javax.servlet.http.HttpServletResponse;\r
-import javax.servlet.http.HttpSession;\r
-\r
-import mir.config.MirPropertiesConfiguration;\r
-import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;\r
-import mir.entity.adapter.EntityAdapterDefinition;\r
-import mir.entity.adapter.EntityAdapterEngine;\r
-import mir.entity.adapter.EntityAdapterModel;\r
-import mir.log.LoggerWrapper;\r
-import mir.module.AbstractModule;\r
-import mir.storage.StorageObject;\r
-import mir.util.HTTPRequestParser;\r
-import mir.util.URLBuilder;\r
-import mircoders.servlet.ServletHelper;\r
-\r
-/**\r
- *\r
- * <p>Title: </p>\r
- * <p>Description: </p>\r
- * <p>Copyright: Copyright (c) 2003</p>\r
- * <p>Company: </p>\r
- * @author not attributable\r
- * @version 1.0\r
- */\r
-\r
-public abstract class ServletModule {\r
-  public String defaultAction;\r
-  protected LoggerWrapper logger;\r
-  protected MirPropertiesConfiguration configuration;\r
-  protected Locale fallbackLocale;\r
-\r
-  protected AbstractModule mainModule;\r
-  protected String definition;\r
-  protected EntityAdapterModel model;\r
-\r
-  protected String listGenerator;\r
-  protected String editGenerator;\r
-  protected String deleteConfirmationGenerator;\r
-  protected int nrEntitiesPerListPage;\r
-\r
-\r
-  public ServletModule(){\r
-    definition = null;\r
-    model = null;\r
-\r
-    try {\r
-      configuration = MirPropertiesConfiguration.instance();\r
-    }\r
-    catch (PropertiesConfigExc e) {\r
-      throw new RuntimeException("Can't get configuration: " + e.getMessage());\r
-    }\r
-\r
-    listGenerator = configuration.getString("ServletModule."+getOperationModuleName()+".ListTemplate");\r
-    editGenerator = configuration.getString("ServletModule."+getOperationModuleName()+".EditTemplate");\r
-    deleteConfirmationGenerator = configuration.getString("ServletModule."+getOperationModuleName()+".DeleteConfirmationTemplate");\r
-    nrEntitiesPerListPage =\r
-        configuration.getInt("ServletModule."+getOperationModuleName()+".ListSize",\r
-        configuration.getInt("ServletModule.Default.ListSize", 20));\r
-\r
-    fallbackLocale = new Locale(configuration.getString("Mir.Admin.FallbackLanguage", "en"), "");\r
-  }\r
-\r
-\r
-  /**\r
-   * Singleton instance retrievel method. MUST be overridden in subclasses.\r
-   *\r
-   * @return ServletModule the single instance of the servletmodule class\r
-   */\r
-  public static ServletModule getInstance() {\r
-    return null;\r
-  }\r
-\r
-  /**\r
-   * Get the module name\r
-   *\r
-   * @return\r
-   */\r
-  protected String getOperationModuleName() {\r
-    return getClass().getName().substring((new String("mircoders.servlet.ServletModule")).length());\r
-  }\r
-\r
-  /**\r
-   * get the locale either from the session or the accept-language header ot the request\r
-   * this supersedes getLanguage for the new i18n\r
-   */\r
-  public Locale getLocale(HttpServletRequest aRequest) {\r
-    Locale loc = null;\r
-    HttpSession session = aRequest.getSession(false);\r
-    if (session != null) {\r
-      // session can be null in case of logout\r
-      loc = (Locale) session.getAttribute("locale");\r
-    }\r
-    // if there is nothing in the session get it fron the accept-language\r
-    if (loc == null) {\r
-      loc = aRequest.getLocale();\r
-    }\r
-    return loc;\r
-  }\r
-\r
-  /**\r
-   * get the locale either from the session or the accept-language header ot the request\r
-   * this supersedes getLanguage for the new i18n\r
-   */\r
-  public Locale getFallbackLocale(HttpServletRequest aRequest) {\r
-    return fallbackLocale;\r
-  }\r
-\r
-  /**\r
-   * Function to specify the default ordering for lists. May be overridden.\r
-   *\r
-   *\r
-   * @return\r
-   */\r
-  public String getDefaultListOrdering() {\r
-\r
-    if (mainModule!=null && mainModule.getStorageObject()!=null){\r
-      if (mainModule.getStorageObject().getFields().contains("webdb_create"))\r
-        return "webdb_create desc";\r
-    }\r
-\r
-    return "id asc";\r
-  }\r
-\r
-  /**\r
-   *\r
-   * @param aResponse\r
-   * @param aQuery\r
-   * @throws ServletModuleExc\r
-   * @throws ServletModuleFailure\r
-   */\r
-  public void redirect(HttpServletResponse aResponse, String aQuery) throws ServletModuleExc, ServletModuleFailure {\r
-    try {\r
-      aResponse.sendRedirect(aResponse.encodeRedirectURL(MirPropertiesConfiguration.instance().getString("RootUri") + "/Mir?"+aQuery));\r
-    }\r
-    catch (Throwable t) {\r
-      throw new ServletModuleFailure("ServletModule.redirect: " +t.getMessage(), t);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Generic list method\r
-   *\r
-   * @param aRequest\r
-   * @param aResponse\r
-   * @throws ServletModuleExc\r
-   * @throws ServletModuleUserExc\r
-   * @throws ServletModuleFailure\r
-   */\r
-\r
-  public void list(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc\r
-  {\r
-    HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);\r
-\r
-    String where = requestParser.getParameter("where");\r
-    String order = requestParser.getParameterWithDefault("order", getDefaultListOrdering());\r
-    int offset = requestParser.getIntegerWithDefault("offset", 0);\r
-\r
-    returnList(aRequest, aResponse, where, order, offset);\r
-  }\r
-\r
-\r
-  public void returnList(HttpServletRequest aRequest, HttpServletResponse aResponse,\r
-     String aWhereClause, String anOrderByClause, int anOffset) throws ServletModuleExc {\r
-\r
-    HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);\r
-    URLBuilder urlBuilder = new URLBuilder();\r
-    int count;\r
-\r
-    try {\r
-      Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { getLocale(aRequest), getFallbackLocale(aRequest)});\r
-\r
-      List list =\r
-         EntityAdapterEngine.retrieveAdapterList(model, definition, aWhereClause, anOrderByClause, nrEntitiesPerListPage, anOffset);\r
-\r
-      responseData.put("nexturl", null);\r
-      responseData.put("prevurl", null);\r
-      responseData.put("module", getOperationModuleName());\r
-\r
-      count=mainModule.getSize(aWhereClause);\r
-\r
-      urlBuilder.setValue("module", getOperationModuleName());\r
-      urlBuilder.setValue("do", "list");\r
-      urlBuilder.setValue("where", aWhereClause);\r
-      urlBuilder.setValue("order", anOrderByClause);\r
-\r
-      urlBuilder.setValue("searchfield", requestParser.getParameter("searchfield"));\r
-      urlBuilder.setValue("searchtext", requestParser.getParameter("searchtext"));\r
-      urlBuilder.setValue("searchispublished", requestParser.getParameter("searchispublished"));\r
-      urlBuilder.setValue("searchstatus", requestParser.getParameter("searchstatus"));\r
-      urlBuilder.setValue("searchorder", requestParser.getParameter("searchorder"));\r
-\r
-      responseData.put("searchfield", requestParser.getParameter("searchfield"));\r
-      responseData.put("searchtext", requestParser.getParameter("searchtext"));\r
-      responseData.put("searchispublished", requestParser.getParameter("searchispublished"));\r
-      responseData.put("searchstatus", requestParser.getParameter("searchstatus"));\r
-      responseData.put("searchorder", requestParser.getParameter("searchorder"));\r
-\r
-      urlBuilder.setValue("offset", anOffset);\r
-      responseData.put("offset" , new Integer(anOffset).toString());\r
-      responseData.put("thisurl" , urlBuilder.getQuery());\r
-\r
-      if (count>anOffset+nrEntitiesPerListPage) {\r
-        urlBuilder.setValue("offset", anOffset + nrEntitiesPerListPage);\r
-        responseData.put("nexturl" , urlBuilder.getQuery());\r
-      }\r
-\r
-      if (anOffset>0) {\r
-        urlBuilder.setValue("offset", Math.max(anOffset - nrEntitiesPerListPage, 0));\r
-        responseData.put("prevurl" , urlBuilder.getQuery());\r
-      }\r
-\r
-      responseData.put("entities", list);\r
-      responseData.put("from" , Integer.toString(anOffset+1));\r
-      responseData.put("count", Integer.toString(count));\r
-      responseData.put("to", Integer.toString(Math.min(anOffset+nrEntitiesPerListPage, count)));\r
-\r
-      ServletHelper.generateResponse(aResponse.getWriter(), responseData, listGenerator);\r
-    }\r
-    catch (Throwable e) {\r
-      throw new ServletModuleFailure(e);\r
-    }\r
-  }\r
-\r
-  public void editObject(HttpServletRequest aRequest, HttpServletResponse aResponse, Object anObject, boolean anIsNew, String anId) throws ServletModuleExc {\r
-    HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);\r
-    URLBuilder urlBuilder = new URLBuilder();\r
-    EntityAdapterModel model;\r
-\r
-    try {\r
-      Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { getLocale(aRequest), getFallbackLocale(aRequest)});\r
-\r
-      responseData.put("module", getOperationModuleName());\r
-      responseData.put("entity", anObject);\r
-      responseData.put("new", new Boolean(anIsNew));\r
-\r
-\r
-      urlBuilder.setValue("module", getOperationModuleName());\r
-      urlBuilder.setValue("returnurl", requestParser.getParameter("returnurl"));\r
-      if (anIsNew)\r
-        urlBuilder.setValue("do", "add");\r
-      else {\r
-        urlBuilder.setValue("id", anId);\r
-        urlBuilder.setValue("do", "edit");\r
-      }\r
-      responseData.put("returnurl", requestParser.getParameter("returnurl"));\r
-      responseData.put("thisurl", urlBuilder.getQuery());\r
-\r
-      ServletHelper.generateResponse(aResponse.getWriter(), responseData, editGenerator);\r
-    }\r
-    catch (Throwable e) {\r
-      throw new ServletModuleFailure(e);\r
-    }\r
-  }\r
-\r
-\r
-  /**\r
-   * Generic add method\r
-   *\r
-   * @param aRequest\r
-   * @param aResponse\r
-   * @throws ServletModuleExc\r
-   * @throws ServletModuleUserExc\r
-   * @throws ServletModuleFailure\r
-   */\r
-  public void add(HttpServletRequest aRequest, HttpServletResponse aResponse)\r
-      throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
-\r
-    Map object = new HashMap();\r
-\r
-    Iterator i = mainModule.getStorageObject().getFields().iterator();\r
-\r
-    while (i.hasNext())\r
-      object.put(i.next(), "");\r
-\r
-    initializeNewObject(object, aRequest, aResponse);\r
-\r
-    editObject(aRequest, aResponse, object, true, null);\r
-  }\r
-\r
-  protected void initializeNewObject(Map aNewObject, HttpServletRequest aRequest, HttpServletResponse aResponse) {\r
-  }\r
-\r
-  /**\r
-   * Method called when the user edits an object.\r
-   *\r
-   * @param aRequest\r
-   * @param aResponse\r
-   * @throws ServletModuleExc\r
-   * @throws ServletModuleUserExc\r
-   * @throws ServletModuleFailure\r
-   */\r
-  public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
-    edit(aRequest, aResponse, aRequest.getParameter("id"));\r
-  }\r
-\r
-  /**\r
-   * Generic edit method\r
-   *\r
-   * @param aRequest\r
-   * @param aResponse\r
-   * @param anIdentifier\r
-   * @throws ServletModuleExc\r
-   * @throws ServletModuleUserExc\r
-   * @throws ServletModuleFailure\r
-   */\r
-  public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse, String anIdentifier)\r
-      throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
-    try {\r
-      editObject(aRequest, aResponse, model.makeEntityAdapter(definition, mainModule.getById(anIdentifier)), false, anIdentifier);\r
-    }\r
-    catch (Throwable e) {\r
-      throw new ServletModuleFailure(e);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Generic update method\r
-   *\r
-   * @param aRequest\r
-   * @param aResponse\r
-   * @throws ServletModuleExc\r
-   * @throws ServletModuleUserExc\r
-   * @throws ServletModuleFailure\r
-   */\r
-  public void update(HttpServletRequest aRequest, HttpServletResponse aResponse)\r
-      throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
-    try {\r
-      HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);\r
-\r
-      String id = aRequest.getParameter("id");\r
-      Map withValues = getIntersectingValues(aRequest, mainModule.getStorageObject());\r
-      mainModule.set(withValues);\r
-\r
-      String returnUrl = requestParser.getParameter("returnurl");\r
-\r
-      if (returnUrl!=null) {\r
-        redirect(aResponse, returnUrl);\r
-      }\r
-      else {\r
-        edit(aRequest, aResponse, id);\r
-      }\r
-    }\r
-    catch (Throwable e) {\r
-      throw new ServletModuleFailure(e);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Generic insert method\r
-   *\r
-   * @param aRequest\r
-   * @param aResponse\r
-   * @throws ServletModuleExc\r
-   * @throws ServletModuleUserExc\r
-   * @throws ServletModuleFailure\r
-   */\r
-  public void insert(HttpServletRequest aRequest, HttpServletResponse aResponse)\r
-      throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
-    try {\r
-      HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);\r
-\r
-      Map object = getIntersectingValues(aRequest, mainModule.getStorageObject());\r
-\r
-      String id = processInstertedObject(object, aRequest, aResponse);\r
-\r
-      String returnUrl = requestParser.getParameter("returnurl");\r
-\r
-      if (returnUrl!=null) {\r
-        redirect(aResponse, returnUrl);\r
-      }\r
-      else {\r
-        edit(aRequest, aResponse, id);\r
-      }\r
-    }\r
-    catch (Throwable e) {\r
-      throw new ServletModuleFailure(e);\r
-    }\r
-  }\r
-\r
-  public String processInstertedObject(Map anObject, HttpServletRequest aRequest, HttpServletResponse aResponse) {\r
-    try {\r
-      return mainModule.add(anObject);\r
-    }\r
-    catch (Throwable t) {\r
-      throw new ServletModuleFailure(t);\r
-    }\r
-  };\r
-\r
-  /**\r
-   *\r
-   * @param aRequest\r
-   * @param aResponse\r
-   */\r
-  public void confirmdelete(HttpServletRequest aRequest, HttpServletResponse aResponse) {\r
-    try {\r
-      String idParam = aRequest.getParameter("id");\r
-      String confirmParam = aRequest.getParameter("confirm");\r
-      String cancelParam = aRequest.getParameter("cancel");\r
-\r
-      if (confirmParam != null && !confirmParam.equals("")) {\r
-        mainModule.deleteById(idParam);\r
-        redirect(aResponse, aRequest.getParameter("okurl"));\r
-      }\r
-      else\r
-        redirect(aResponse, aRequest.getParameter("cancelurl"));\r
-    }\r
-    catch (Throwable t) {\r
-      throw new ServletModuleFailure(t);\r
-    }\r
-  }\r
-\r
-  /**\r
-   *\r
-   * @param aRequest\r
-   * @param aResponse\r
-   * @throws ServletModuleExc\r
-   * @throws ServletModuleUserExc\r
-   * @throws ServletModuleFailure\r
-   */\r
-  public void delete(HttpServletRequest aRequest, HttpServletResponse aResponse)\r
-      throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {\r
-    try {\r
-      String idParam = aRequest.getParameter("id");\r
-\r
-      if (idParam == null)\r
-        throw new ServletModuleExc("Invalid call to delete: no id supplied");\r
-\r
-      Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, new Locale[] { getLocale(aRequest), getFallbackLocale(aRequest)});\r
-\r
-      responseData.put("module", getOperationModuleName());\r
-      responseData.put("id", idParam);\r
-      responseData.put("cancelurl", aRequest.getParameter("cancelurl"));\r
-      responseData.put("okurl", aRequest.getParameter("okurl"));\r
-\r
-      ServletHelper.generateResponse(aResponse.getWriter(), responseData, deleteConfirmationGenerator);\r
-    }\r
-    catch (Throwable e) {\r
-      throw new ServletModuleFailure(e);\r
-    }\r
-  }\r
-\r
-  /**\r
-   *  Wenn die abgeleitete Klasse diese Methode ueberschreibt und einen String mit einem\r
-   *  Methodennamen zurueckliefert, dann wird diese Methode bei fehlender Angabe des\r
-   *  doParameters ausgefuehrt.\r
-   *\r
-   * @return Name der Default-Action\r
-   */\r
-  public String defaultAction() {\r
-    return defaultAction;\r
-  }\r
-\r
-  /**\r
-   * Gets the fields from a httprequest and matches them with the metadata from\r
-   * the storage object. Returns the keys that match, with their values.\r
-   *\r
-   * @return Map with the values\r
-   */\r
-  public Map getIntersectingValues(HttpServletRequest aRequest, StorageObject theStorage)\r
-      throws ServletModuleExc, ServletModuleFailure {\r
-\r
-    try {\r
-      HTTPRequestParser parser;\r
-      List theFieldList;\r
-\r
-      parser = new HTTPRequestParser(aRequest);\r
-\r
-      theFieldList = theStorage.getFields();\r
-\r
-      Map withValues = new HashMap();\r
-      String aField, aValue;\r
-\r
-      for (int i = 0; i < theFieldList.size(); i++) {\r
-        aField = (String) theFieldList.get(i);\r
-\r
-        aValue = parser.getParameter(aField);\r
-        if (aValue != null)\r
-          withValues.put(aField, aValue);\r
-      }\r
-      return withValues;\r
-    }\r
-    catch (Throwable e) {\r
-      e.printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));\r
-\r
-      throw new ServletModuleFailure( "ServletModule.getIntersectingValues: " + e.getMessage(), e);\r
-    }\r
-  }\r
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.servlet;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import mir.config.MirPropertiesConfiguration;
+import mir.entity.adapter.EntityAdapterEngine;
+import mir.entity.adapter.EntityAdapterModel;
+import mir.log.LoggerWrapper;
+import mir.module.AbstractModule;
+import mir.module.ModuleExc;
+import mir.storage.StorageObject;
+import mir.util.HTTPRequestParser;
+import mir.util.URLBuilder;
+import mircoders.global.MirGlobal;
+import mircoders.servlet.ServletHelper;
+import mircoders.localizer.MirLocalizerExc;
+import multex.Failure;
+
+/**
+ *
+ * <p>Title: </p>
+ * <p>Description: </p>
+ * <p>Copyright: Copyright (c) 2003</p>
+ * <p>Company: </p>
+ * @author not attributable
+ * @version 1.0
+ */
+
+public abstract class ServletModule {
+  public String defaultAction;
+  protected LoggerWrapper logger;
+  protected static MirPropertiesConfiguration configuration = MirPropertiesConfiguration.instance();
+  private static Locale fallbackLocale = new Locale(configuration.getString("Mir.Admin.FallbackLanguage", "en"), "");
+
+  protected AbstractModule mainModule;
+  protected String definition;
+  protected EntityAdapterModel model;
+
+  protected String listGenerator;
+  protected String editGenerator;
+  protected String deleteConfirmationGenerator;
+  protected int nrEntitiesPerListPage;
+
+
+  public ServletModule(){
+    definition = null;
+    try {
+      model = MirGlobal.localizer().dataModel().adapterModel();
+    }
+    catch (MirLocalizerExc e) {
+      logger.error("Can't create model: " + e.toString());
+      throw new ServletModuleFailure("Can't retrieve model", e);
+    }
+
+
+
+    listGenerator = configuration.getString("ServletModule."+getOperationModuleName()+".ListTemplate");
+    editGenerator = configuration.getString("ServletModule."+getOperationModuleName()+".EditTemplate");
+    deleteConfirmationGenerator = configuration.getString("ServletModule."+getOperationModuleName()+".DeleteConfirmationTemplate");
+    nrEntitiesPerListPage =
+        configuration.getInt("ServletModule."+getOperationModuleName()+".ListSize",
+        configuration.getInt("ServletModule.Default.ListSize", 20));
+
+  }
+
+
+  public void logAdminUsage(HttpServletRequest aRequest, String anObject, String aDescription) {
+    MirGlobal.logAdminUsage(ServletHelper.getUser(aRequest), getOperationModuleName() + ":" + anObject, aDescription);
+  }
+
+  /**
+   * Singleton instance retrievel method. MUST be overridden in subclasses.
+   *
+   * @return ServletModule the single instance of the servletmodule class
+   */
+  public static ServletModule getInstance() {
+    return null;
+  }
+
+  /**
+   * Return the module name
+   */
+  protected String getOperationModuleName() {
+    return getClass().getName().substring((new String("mircoders.servlet.ServletModule")).length());
+  }
+
+  public static Locale[] getLocales(HttpServletRequest aRequest) {
+    return new Locale[] { getLocale(aRequest), fallbackLocale };
+  }
+
+  /**
+   * Return the locale either from the session or the accept-language header ot the request
+   * this supersedes getLanguage for the new i18n
+   */
+  public static Locale getLocale(HttpServletRequest aRequest) {
+    Locale loc = null;
+    HttpSession session = aRequest.getSession(false);
+    if (session != null) {
+      // session can be null in case of logout
+      loc = (Locale) session.getAttribute("locale");
+    }
+    // if there is nothing in the session get it fron the accept-language
+    if (loc == null) {
+      loc = aRequest.getLocale();
+    }
+    return loc;
+  }
+
+  /**
+   * get the locale either from the session or the accept-language header ot the request
+   * this supersedes getLanguage for the new i18n
+   */
+  public Locale getFallbackLocale(HttpServletRequest aRequest) {
+    return fallbackLocale;
+  }
+
+  /**
+   * Function to specify the default ordering for lists. May be overridden.
+   *
+   *
+   * @return
+   */
+  public String getDefaultListOrdering() {
+
+    if (mainModule!=null && mainModule.getStorageObject()!=null){
+      if (mainModule.getStorageObject().getFields().contains("webdb_create"))
+        return "webdb_create desc";
+    }
+
+    return "id asc";
+  }
+
+  /**
+   * Generic list servlet method
+   */
+
+  public void list(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc
+  {
+    HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
+
+    String where = requestParser.getParameter("where");
+    String order = requestParser.getParameterWithDefault("order", getDefaultListOrdering());
+    int offset = requestParser.getIntegerWithDefault("offset", 0);
+
+    returnList(aRequest, aResponse, where, order, offset);
+  }
+
+
+  public void returnList(HttpServletRequest aRequest, HttpServletResponse aResponse,
+     String aWhereClause, String anOrderByClause, int anOffset) throws ServletModuleExc {
+
+    HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
+    URLBuilder urlBuilder = new URLBuilder();
+    int count;
+
+    try {
+      Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, getLocales(aRequest));
+
+      List list =
+         EntityAdapterEngine.retrieveAdapterList(model, definition, aWhereClause, anOrderByClause, nrEntitiesPerListPage, anOffset);
+
+      responseData.put("nexturl", null);
+      responseData.put("prevurl", null);
+      responseData.put("module", getOperationModuleName());
+
+      count=mainModule.getSize(aWhereClause);
+
+      urlBuilder.setValue("module", getOperationModuleName());
+      urlBuilder.setValue("do", "list");
+      urlBuilder.setValue("where", aWhereClause);
+      urlBuilder.setValue("order", anOrderByClause);
+
+      urlBuilder.setValue("searchfield", requestParser.getParameter("searchfield"));
+      urlBuilder.setValue("searchtext", requestParser.getParameter("searchtext"));
+      urlBuilder.setValue("searchispublished", requestParser.getParameter("searchispublished"));
+      urlBuilder.setValue("searchstatus", requestParser.getParameter("searchstatus"));
+      urlBuilder.setValue("searchorder", requestParser.getParameter("searchorder"));
+
+      responseData.put("searchfield", requestParser.getParameter("searchfield"));
+      responseData.put("searchtext", requestParser.getParameter("searchtext"));
+      responseData.put("searchispublished", requestParser.getParameter("searchispublished"));
+      responseData.put("searchstatus", requestParser.getParameter("searchstatus"));
+      responseData.put("searchorder", requestParser.getParameter("searchorder"));
+
+      urlBuilder.setValue("offset", anOffset);
+      responseData.put("offset" , new Integer(anOffset).toString());
+      responseData.put("thisurl" , urlBuilder.getQuery());
+
+      if (count>anOffset+nrEntitiesPerListPage) {
+        urlBuilder.setValue("offset", anOffset + nrEntitiesPerListPage);
+        responseData.put("nexturl" , urlBuilder.getQuery());
+      }
+
+      if (anOffset>0) {
+        urlBuilder.setValue("offset", Math.max(anOffset - nrEntitiesPerListPage, 0));
+        responseData.put("prevurl" , urlBuilder.getQuery());
+      }
+
+      responseData.put("entities", list);
+      responseData.put("from" , Integer.toString(anOffset+1));
+      responseData.put("count", Integer.toString(count));
+      responseData.put("to", Integer.toString(Math.min(anOffset+nrEntitiesPerListPage, count)));
+
+      ServletHelper.generateResponse(aResponse.getWriter(), responseData, listGenerator);
+    }
+    catch (Throwable e) {
+      throw new ServletModuleFailure(e);
+    }
+  }
+
+  public void editObject(HttpServletRequest aRequest, HttpServletResponse aResponse, String anId) throws ServletModuleExc {
+    try {
+      editObject(aRequest, aResponse, model.makeEntityAdapter(definition, mainModule.getById(anId)), false, anId);
+    }
+    catch (Throwable t) {
+      throw new ServletModuleFailure(t);
+    }
+  }
+
+  public void editObject(HttpServletRequest aRequest, HttpServletResponse aResponse, Object anObject, boolean anIsNew, String anId) throws ServletModuleExc {
+    HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
+    URLBuilder urlBuilder = new URLBuilder();
+
+    try {
+      Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, getLocales(aRequest));
+
+      responseData.put("module", getOperationModuleName());
+      responseData.put("entity", anObject);
+      responseData.put("new", new Boolean(anIsNew));
+
+
+      urlBuilder.setValue("module", getOperationModuleName());
+      urlBuilder.setValue("returnurl", requestParser.getParameter("returnurl"));
+      if (anIsNew)
+        urlBuilder.setValue("do", "add");
+      else {
+        urlBuilder.setValue("id", anId);
+        urlBuilder.setValue("do", "edit");
+      }
+      responseData.put("returnurl", requestParser.getParameter("returnurl"));
+      responseData.put("thisurl", urlBuilder.getQuery());
+
+      ServletHelper.generateResponse(aResponse.getWriter(), responseData, editGenerator);
+    }
+    catch (Throwable e) {
+      throw new ServletModuleFailure(e);
+    }
+  }
+
+  /**
+   * Generic add servlet method
+   */
+  public void add(HttpServletRequest aRequest, HttpServletResponse aResponse)
+      throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
+
+    Map object = new HashMap();
+
+    Iterator i = mainModule.getStorageObject().getFields().iterator();
+
+    while (i.hasNext())
+      object.put(i.next(), "");
+
+    initializeNewObject(object, aRequest, aResponse);
+
+    editObject(aRequest, aResponse, object, true, null);
+  }
+
+  protected void initializeNewObject(Map aNewObject, HttpServletRequest aRequest, HttpServletResponse aResponse) {
+  }
+
+  /**
+   * Generic edit servlet method
+   */
+  public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse) throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
+    edit(aRequest, aResponse, aRequest.getParameter("id"));
+  }
+
+  /**
+   */
+  public void edit(HttpServletRequest aRequest, HttpServletResponse aResponse, String anIdentifier)
+      throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
+    try {
+      editObject(aRequest, aResponse, model.makeEntityAdapter(definition, mainModule.getById(anIdentifier)), false, anIdentifier);
+    }
+    catch (Throwable e) {
+      throw new ServletModuleFailure(e);
+    }
+  }
+
+  /**
+   * Generic update servlet method
+   */
+  public void update(HttpServletRequest aRequest, HttpServletResponse aResponse)
+      throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
+    try {
+      HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
+
+      String id = aRequest.getParameter("id");
+      Map withValues = getIntersectingValues(aRequest, mainModule.getStorageObject());
+      mainModule.set(withValues);
+
+      logAdminUsage(aRequest, id, "object modified");
+
+      String returnUrl = requestParser.getParameter("returnurl");
+
+      if (returnUrl!=null) {
+        ServletHelper.redirect(aResponse, returnUrl);
+      }
+      else {
+        edit(aRequest, aResponse, id);
+      }
+    }
+    catch (Throwable e) {
+      throw new ServletModuleFailure(e);
+    }
+  }
+
+  /**
+   * Generic insert servlet method
+   */
+  public void insert(HttpServletRequest aRequest, HttpServletResponse aResponse)
+      throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
+    try {
+      HTTPRequestParser requestParser = new HTTPRequestParser(aRequest);
+
+      Map object = getIntersectingValues(aRequest, mainModule.getStorageObject());
+
+      String id = processInstertedObject(object, aRequest, aResponse);
+
+      logAdminUsage(aRequest, id, "object inserted");
+
+      String returnUrl = requestParser.getParameter("returnurl");
+
+      if (returnUrl!=null) {
+        ServletHelper.redirect(aResponse, returnUrl);
+      }
+      else {
+        edit(aRequest, aResponse, id);
+      }
+    }
+    catch (Throwable e) {
+      throw new ServletModuleFailure(e);
+    }
+  }
+
+  /**
+   *
+   */
+  public String processInstertedObject(Map anObject, HttpServletRequest aRequest, HttpServletResponse aResponse) {
+    try {
+      return mainModule.add(anObject);
+    }
+    catch (ModuleExc t) {
+      throw new ServletModuleFailure(t);
+    }
+  };
+
+  /**
+   * Generic delete confirmation servlet method
+   */
+  public void confirmdelete(HttpServletRequest aRequest, HttpServletResponse aResponse) {
+    try {
+      String idParam = aRequest.getParameter("id");
+      String confirmParam = aRequest.getParameter("confirm");
+
+      if (confirmParam != null && !confirmParam.equals("")) {
+        mainModule.deleteById(idParam);
+        logAdminUsage(aRequest, idParam, "object deleted");
+        ServletHelper.redirect(aResponse, aRequest.getParameter("okurl"));
+      }
+      else
+        ServletHelper.redirect(aResponse, aRequest.getParameter("cancelurl"));
+    }
+    catch (Throwable t) {
+      throw new ServletModuleFailure(t);
+    }
+  }
+
+  /**
+   * Generic delete servlet method
+   */
+  public void delete(HttpServletRequest aRequest, HttpServletResponse aResponse)
+      throws ServletModuleExc, ServletModuleUserExc, ServletModuleFailure  {
+    try {
+      String idParam = aRequest.getParameter("id");
+
+      if (idParam == null)
+        throw new ServletModuleExc("Invalid call to delete: no id supplied");
+
+      Map responseData = ServletHelper.makeGenerationData(aRequest, aResponse, getLocales(aRequest));
+
+      responseData.put("module", getOperationModuleName());
+      responseData.put("id", idParam);
+      responseData.put("cancelurl", aRequest.getParameter("cancelurl"));
+      responseData.put("okurl", aRequest.getParameter("okurl"));
+
+      ServletHelper.generateResponse(aResponse.getWriter(), responseData, deleteConfirmationGenerator);
+    }
+    catch (Throwable e) {
+      throw new ServletModuleFailure(e);
+    }
+  }
+
+  /**
+   */
+  public String defaultAction() {
+    return defaultAction;
+  }
+
+  /**
+   * Gets the fields from a httprequest and matches them with the metadata from
+   * the storage object. Returns the keys that match, with their values.
+   *
+   * @return Map with the values
+   */
+  public Map getIntersectingValues(HttpServletRequest aRequest, StorageObject theStorage)
+      throws ServletModuleExc, ServletModuleFailure {
+
+    HTTPRequestParser parser;
+    List theFieldList;
+
+    parser = new HTTPRequestParser(aRequest);
+
+    theFieldList = theStorage.getFields();
+
+    Map withValues = new HashMap();
+    String aField, aValue;
+
+    for (int i = 0; i < theFieldList.size(); i++) {
+      aField = (String) theFieldList.get(i);
+
+      aValue = parser.getParameter(aField);
+      if (aValue != null)
+        withValues.put(aField, aValue);
+    }
+    return withValues;
+  }
 }
\ No newline at end of file
index 4b607ca..95509eb 100755 (executable)
  */
 package mir.session;
 
-import java.io.InputStream;
-
 import org.apache.commons.fileupload.FileItem;
 
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+
 public class CommonsUploadedFileAdapter implements UploadedFile {
   private FileItem fileItem;
 
@@ -40,14 +42,24 @@ public class CommonsUploadedFileAdapter implements UploadedFile {
     fileItem = aFileItem;
   }
 
-  public InputStream getInputStream() throws SessionExc, SessionFailure{
+  public void writeToFile(File aFile) throws SessionExc, SessionFailure {
+    try {
+      aFile.getParentFile().mkdirs();
+      fileItem.write(aFile);
+    }
+    catch (Exception e) {
+      throw new SessionFailure(e);
+    }
+  }
+
+  public InputStream getInputStream() throws SessionExc, SessionFailure {
     try {
       return fileItem.getInputStream();
     }
-    catch (Throwable t) {
-      throw new SessionFailure(t);
+    catch (IOException e) {
+      throw new SessionFailure(e);
     }
-  };
+  }
 
   public String getFileName() {
     return fileItem.getName();
index 319a8c8..af01846 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  any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two.  You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries.  If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-package mir.session;\r
-\r
-import java.util.Arrays;\r
-import java.util.List;\r
-import java.util.Vector;\r
-import javax.servlet.http.HttpServletRequest;\r
-import javax.servlet.http.HttpSession;\r
-\r
-import org.apache.commons.fileupload.FileItem;\r
-\r
-import mir.util.HTTPParsedRequest;\r
-\r
-public class HTTPAdapters {\r
-  public static class HTTPRequestAdapter implements Request {\r
-    private HttpServletRequest request;\r
-\r
-    public HTTPRequestAdapter(HttpServletRequest aRequest) {\r
-      request = aRequest;\r
-    }\r
-\r
-    public String getHeader(String aHeaderName) {\r
-      if (aHeaderName.equals("ip"))\r
-        return request.getRemoteAddr();\r
-\r
-      return request.getHeader(aHeaderName);\r
-    };\r
-\r
-    public String getParameter(String aName) {\r
-      return request.getParameter(aName);\r
-    };\r
-\r
-    public List getUploadedFiles() {\r
-      return new Vector();\r
-    };\r
-\r
-    public List getParameters(String aName) {\r
-      return Arrays.asList(request.getParameterValues(aName));\r
-    };\r
-\r
-    public HttpServletRequest getRequest() {\r
-      return request;\r
-    }\r
-  }\r
-\r
-  public static class HTTPParsedRequestAdapter implements Request {\r
-    private HTTPParsedRequest request;\r
-\r
-    public HTTPParsedRequestAdapter(HTTPParsedRequest aRequest) {\r
-      request = aRequest;\r
-    }\r
-\r
-    public String getHeader(String aHeaderName) {\r
-      if (aHeaderName.equals("ip"))\r
-        return request.getRequest().getRemoteAddr();\r
-\r
-      return request.getHeader(aHeaderName);\r
-    };\r
-\r
-    public String getParameter(String aName) {\r
-      return request.getParameter(aName);\r
-    };\r
-\r
-    public List getParameters(String aName) {\r
-      return request.getParameterList(aName);\r
-    };\r
-\r
-    public List getUploadedFiles() {\r
-      List result = new Vector();\r
-      List files = request.getFiles();\r
-\r
-      for (int i=0; i<files.size(); i++) {\r
-        result.add(new CommonsUploadedFileAdapter((FileItem) files.get(i)));\r
-      }\r
-\r
-      return result;\r
-    };\r
-\r
-    public HttpServletRequest getRequest() {\r
-      return request.getRequest();\r
-    }\r
-  }\r
-\r
-  public static class HTTPSessionAdapter implements Session {\r
-    private HttpSession session;\r
-\r
-    public HTTPSessionAdapter(HttpSession aSession) {\r
-      session = aSession;\r
-    }\r
-    public Object getAttribute(String aName) {\r
-      return session.getAttribute(aName);\r
-    }\r
-\r
-    public void deleteAttribute(String aName) {\r
-      session.removeAttribute(aName);\r
-    }\r
-\r
-    public void setAttribute(String aName, Object aNewValue) {\r
-      if (aName.equals("$httpsessiontimeout")) {\r
-        if (aNewValue instanceof Number) {\r
-          try {\r
-            session.setMaxInactiveInterval( ( (Number) aNewValue).intValue());\r
-          }\r
-          catch (Throwable t) {\r
-          }\r
-        }\r
-      }\r
-      else {\r
-        if (aNewValue == null)\r
-          deleteAttribute(aName);\r
-        else\r
-          session.setAttribute(aName, aNewValue);\r
-      }\r
-    }\r
-\r
-    public void terminate() {\r
-      session.invalidate();\r
-    }\r
-  }\r
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.session;
+
+import java.util.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+
+import mir.util.HTTPParsedRequest;
+import org.apache.commons.fileupload.FileItem;
+
+public class HTTPAdapters {
+  public static class HTTPRequestAdapter implements Request {
+    private HttpServletRequest request;
+
+    public HTTPRequestAdapter(HttpServletRequest aRequest) {
+      request = aRequest;
+    }
+
+    public String getHeader(String aHeaderName) {
+      if (aHeaderName.equals("ip"))
+        return request.getRemoteAddr();
+
+      if (aHeaderName.equals("hostname")) {
+        return request.getRemoteAddr();
+      }
+
+      return request.getHeader(aHeaderName);
+    };
+
+    public String getParameter(String aName) {
+      return request.getParameter(aName);
+    };
+
+    public List getPrefixedParameterNames(String aPrefix) {
+      List result = new ArrayList();
+
+      Enumeration enumeration = request.getParameterNames();
+      while (enumeration.hasMoreElements()) {
+        String name = (String) enumeration.nextElement();
+        if (name.startsWith(aPrefix)) {
+          result.add(name);
+        }
+      }
+
+      return result;
+    };
+
+    public List getUploadedFiles() {
+      return Collections.EMPTY_LIST;
+    };
+
+    public List getParameters(String aName) {
+      return Arrays.asList(request.getParameterValues(aName));
+    };
+
+    public HttpServletRequest getRequest() {
+      return request;
+    }
+  }
+
+  public static class HTTPParsedRequestAdapter implements Request {
+    private HTTPParsedRequest request;
+
+    public HTTPParsedRequestAdapter(HTTPParsedRequest aRequest) {
+      request = aRequest;
+    }
+
+    public String getHeader(String aHeaderName) {
+      if (aHeaderName.equals("ip"))
+        return request.getRequest().getRemoteAddr();
+
+      if (aHeaderName.equals("hostname")) {
+        return request.getRequest().getRemoteAddr();
+      }
+
+      return request.getHeader(aHeaderName);
+    }
+
+    public String getParameter(String aName) {
+      return request.getParameter(aName);
+    };
+
+    public List getParameters(String aName) {
+      return request.getParameterList(aName);
+    };
+
+    public List getPrefixedParameterNames(String aPrefix) {
+      List result = new ArrayList();
+
+      Iterator i = request.getParameterNames().iterator();
+
+      while (i.hasNext()) {
+        String name = (String) i.next();
+        if (name.startsWith(aPrefix)) {
+          result.add(name);
+        }
+      }
+
+      return result;
+    };
+
+    public List getUploadedFiles() {
+      List result = new ArrayList();
+      List files = request.getFiles();
+
+      for (int i=0; i<files.size(); i++) {
+        result.add(new CommonsUploadedFileAdapter((FileItem) files.get(i)));
+      }
+
+      return result;
+    };
+
+    public HttpServletRequest getRequest() {
+      return request.getRequest();
+    }
+  }
+
+  public static class HTTPSessionAdapter implements Session {
+    private HttpSession session;
+
+    public HTTPSessionAdapter(HttpSession aSession) {
+      session = aSession;
+    }
+    public Object getAttribute(String aName) {
+      return session.getAttribute(aName);
+    }
+
+    public void deleteAttribute(String aName) {
+      session.removeAttribute(aName);
+    }
+
+    public void setAttribute(String aName, Object aNewValue) {
+      if (aName.equals("$httpsessiontimeout")) {
+        if (aNewValue instanceof Number) {
+          try {
+            session.setMaxInactiveInterval( ( (Number) aNewValue).intValue());
+          }
+          catch (Throwable t) {
+          }
+        }
+      }
+      else {
+        if (aNewValue == null)
+          deleteAttribute(aName);
+        else
+          session.setAttribute(aName, aNewValue);
+      }
+    }
+
+    public void terminate() {
+      session.invalidate();
+    }
+  }
 }
\ No newline at end of file
index 3133000..ce0bf07 100755 (executable)
@@ -35,5 +35,6 @@ public interface Request {
   public String getParameter(String aName);
   public List getUploadedFiles();
   public List getParameters(String aName);
+  public List getPrefixedParameterNames(String aPrefix);
   public String getHeader(String aHeaderName);
 }
\ No newline at end of file
index 731fcee..89e54bd 100755 (executable)
  */
 package mir.session;
 
+import java.io.File;
 import java.io.InputStream;
 
 public interface UploadedFile {
-  InputStream getInputStream() throws SessionExc, SessionFailure;
-  String getFileName();
-  String getFieldName();
-  String getContentType();
+  /**
+   * Writes the uploaded content to a file
+   */
+  public void writeToFile(File aFile) throws SessionExc, SessionFailure;
+
+  /**
+   * Creates an <code>InputStream</code> to access the uploaded content  
+   */
+  public InputStream getInputStream() throws SessionExc, SessionFailure;
+
+  /**
+   * Return the filename supplied by the uploader if available.
+   * <code>null</code> if no filename is available.
+   */
+  public String getFileName();
+
+  /**
+   * Return the field name associated with the uploaded file
+   */
+  public String getFieldName();
+
+  /**
+   * Return the content type (if it's present) of the uploaded file.
+   * <code>null</code> if no content type is available. 
+   */
+  public String getContentType();
 }
\ No newline at end of file
index 015b9ab..9ac7e08 100755 (executable)
@@ -32,9 +32,6 @@ package mir.session;
 
 import java.util.List;
 
-import mir.session.Request;
-import mir.session.ValidationError;
-
 
 public class ValidationHelper {
   /**
index 468c06b..5317cea 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  any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two.  You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries.  If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-package mir.storage;\r
-\r
-import java.io.IOException;\r
-import java.io.InputStreamReader;\r
-import java.sql.Connection;\r
-import java.sql.PreparedStatement;\r
-import java.sql.ResultSet;\r
-import java.sql.ResultSetMetaData;\r
-import java.sql.SQLException;\r
-import java.sql.Statement;\r
-import java.sql.Timestamp;\r
-import java.text.ParseException;\r
-import java.text.SimpleDateFormat;\r
-import java.util.ArrayList;\r
-import java.util.Calendar;\r
-import java.util.GregorianCalendar;\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.TimeZone;\r
-import java.util.Vector;\r
-\r
-import com.codestudio.util.SQLManager;\r
-import mir.config.MirPropertiesConfiguration;\r
-import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;\r
-import mir.entity.Entity;\r
-import mir.entity.EntityList;\r
-import mir.entity.StorableObjectEntity;\r
-import mir.log.LoggerWrapper;\r
-import mir.misc.StringUtil;\r
-import mir.storage.store.ObjectStore;\r
-import mir.storage.store.StorableObject;\r
-import mir.storage.store.StoreContainerType;\r
-import mir.storage.store.StoreIdentifier;\r
-import mir.storage.store.StoreUtil;\r
-import mir.util.JDBCStringRoutines;\r
-\r
-\r
-/**\r
- * Diese Klasse implementiert die Zugriffsschicht auf die Datenbank.\r
- * Alle Projektspezifischen Datenbankklassen erben von dieser Klasse.\r
- * In den Unterklassen wird im Minimalfall nur die Tabelle angegeben.\r
- * Im Konfigurationsfile findet sich eine Verweis auf den verwendeten\r
- * Treiber, Host, User und Passwort, ueber den der Zugriff auf die\r
- * Datenbank erfolgt.\r
- *\r
- * @version $Id: Database.java,v 1.46 2003/09/03 18:29:03 zapata Exp $\r
- * @author rk\r
- *\r
- */\r
-public class Database implements StorageObject {\r
-  private static Class GENERIC_ENTITY_CLASS = mir.entity.StorableObjectEntity.class;\r
-  private static Class STORABLE_OBJECT_ENTITY_CLASS = mir.entity.StorableObjectEntity.class;\r
-\r
-\r
-  private static Map POPUP_EMPTYLINE = new HashMap();\r
-  protected static final ObjectStore o_store = ObjectStore.getInstance();\r
-  private static final int _millisPerHour = 60 * 60 * 1000;\r
-  private static final int _millisPerMinute = 60 * 1000;\r
-\r
-  static {\r
-    // always same object saves a little space\r
-    POPUP_EMPTYLINE.put("key", "");\r
-    POPUP_EMPTYLINE.put("value", "--");\r
-  }\r
-\r
-  protected LoggerWrapper logger;\r
-  protected MirPropertiesConfiguration configuration;\r
-  protected String theTable;\r
-  protected String theCoreTable = null;\r
-  protected String thePKeyName = "id";\r
-  protected int thePKeyType;\r
-  protected int thePKeyIndex;\r
-  protected boolean evaluatedMetaData = false;\r
-  protected ArrayList metadataFields;\r
-  protected ArrayList metadataLabels;\r
-  protected ArrayList metadataNotNullFields;\r
-  protected int[] metadataTypes;\r
-  protected Class theEntityClass;\r
-  protected List popupCache = null;\r
-  protected boolean hasPopupCache = false;\r
-  protected Map hashCache = null;\r
-  protected boolean hasTimestamp = true;\r
-  private String database_driver;\r
-  private String database_url;\r
-  private int defaultLimit;\r
-\r
-  TimeZone timezone;\r
-  SimpleDateFormat internalDateFormat;\r
-  SimpleDateFormat userInputDateFormat;\r
-/*\r
-  private SimpleDateFormat _dateFormatterOut;\r
-  private SimpleDateFormat _dateFormatterIn;\r
-  _dateFormatterOut = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\r
-  _dateFormatterIn = new SimpleDateFormat("yyyy-MM-dd HH:mm");\r
-*/\r
-\r
-  /**\r
-   * Kontruktor bekommt den Filenamen des Konfigurationsfiles ?bergeben.\r
-   * Aus diesem file werden <code>Database.Logfile</code>,\r
-   * <code>Database.Username</code>,<code>Database.Password</code>,\r
-   * <code>Database.Host</code> und <code>Database.Adaptor</code>\r
-   * ausgelesen und ein Broker f?r die Verbindugen zur Datenbank\r
-   * erzeugt.\r
-   *\r
-   * @param   String confFilename Dateiname der Konfigurationsdatei\r
-   */\r
-  public Database() throws StorageObjectFailure {\r
-    try {\r
-      configuration = MirPropertiesConfiguration.instance();\r
-    }\r
-    catch (PropertiesConfigExc e) {\r
-      throw new StorageObjectFailure(e);\r
-    }\r
-    logger = new LoggerWrapper("Database");\r
-    timezone = TimeZone.getTimeZone(configuration.getString("Mir.DefaultTimezone"));\r
-    internalDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");\r
-    internalDateFormat.setTimeZone(timezone);\r
-\r
-    userInputDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");\r
-    userInputDateFormat.setTimeZone(timezone);\r
-\r
-\r
-    String theAdaptorName = configuration.getString("Database.Adaptor");\r
-    defaultLimit = Integer.parseInt(configuration.getString("Database.Limit"));\r
-\r
-    try {\r
-      theEntityClass = GENERIC_ENTITY_CLASS;\r
-    }\r
-    catch (Throwable e) {\r
-      logger.error("Error in Database() constructor with " + theAdaptorName + " -- " + e.getMessage());\r
-      throw new StorageObjectFailure("Error in Database() constructor.", e);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Liefert die Entity-Klasse zur?ck, in der eine Datenbankzeile gewrappt\r
-   * wird. Wird die Entity-Klasse durch die erbende Klasse nicht ?berschrieben,\r
-   * wird eine mir.entity.GenericEntity erzeugt.\r
-   *\r
-   * @return Class-Objekt der Entity\r
-   */\r
-  public java.lang.Class getEntityClass() {\r
-    return theEntityClass;\r
-  }\r
-\r
-  /**\r
-   * Liefert die Standardbeschr?nkung von select-Statements zur?ck, also\r
-   * wieviel Datens?tze per Default selektiert werden.\r
-   *\r
-   * @return Standard-Anzahl der Datens?tze\r
-   */\r
-  public int getLimit() {\r
-    return defaultLimit;\r
-  }\r
-\r
-  /**\r
-   * Liefert den Namen des Primary-Keys zur?ck. Wird die Variable nicht von\r
-   * der erbenden Klasse ?berschrieben, so ist der Wert <code>PKEY</code>\r
-   * @return Name des Primary-Keys\r
-   */\r
-  public String getIdName() {\r
-    return thePKeyName;\r
-  }\r
-\r
-  /**\r
-   * Liefert den Namen der Tabelle, auf das sich das Datenbankobjekt bezieht.\r
-   *\r
-   * @return Name der Tabelle\r
-   */\r
-  public String getTableName() {\r
-    return theTable;\r
-  }\r
-\r
-  /*\r
-  *   Dient dazu vererbte Tabellen bei objectrelationalen DBMS\r
-  *   zu speichern, wenn die id einer Tabelle in der parenttabelle verwaltet\r
-  *   wird.\r
-  *   @return liefert theCoreTabel als String zurueck, wenn gesetzt, sonst\r
-  *    the Table\r
-   */\r
-  public String getCoreTable() {\r
-    if (theCoreTable != null) {\r
-      return theCoreTable;\r
-    }\r
-    else {\r
-      return theTable;\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Liefert Feldtypen der Felder der Tabelle zurueck (s.a. java.sql.Types)\r
-   * @return int-Array mit den Typen der Felder\r
-   * @exception StorageObjectException\r
-   */\r
-  public int[] getTypes() throws StorageObjectFailure {\r
-    if (metadataTypes == null) {\r
-      get_meta_data();\r
-    }\r
-\r
-    return metadataTypes;\r
-  }\r
-\r
-  /**\r
-   * Liefert eine Liste der Labels der Tabellenfelder\r
-   * @return ArrayListe mit Labeln\r
-   * @exception StorageObjectException\r
-   */\r
-  public List getLabels() throws StorageObjectFailure {\r
-    if (metadataLabels == null) {\r
-      get_meta_data();\r
-    }\r
-\r
-    return metadataLabels;\r
-  }\r
-\r
-  /**\r
-   * Liefert eine Liste der Felder der Tabelle\r
-   * @return ArrayList mit Feldern\r
-   * @exception StorageObjectException\r
-   */\r
-  public List getFields() throws StorageObjectFailure {\r
-    if (metadataFields == null) {\r
-      get_meta_data();\r
-    }\r
-\r
-    return metadataFields;\r
-  }\r
-\r
-  /*\r
-  *   Gets value out of ResultSet according to type and converts to String\r
-  *   @param inValue  Wert aus ResultSet.\r
-  *   @param aType  Datenbanktyp.\r
-  *   @return liefert den Wert als String zurueck. Wenn keine Umwandlung moeglich\r
-  *           dann /unsupported value/\r
-   */\r
-  private String getValueAsString(ResultSet rs, int valueIndex, int aType)\r
-    throws StorageObjectFailure {\r
-    String outValue = null;\r
-\r
-    if (rs != null) {\r
-      try {\r
-        switch (aType) {\r
-          case java.sql.Types.BIT:\r
-            outValue = (rs.getBoolean(valueIndex) == true) ? "1" : "0";\r
-\r
-            break;\r
-\r
-          case java.sql.Types.INTEGER:\r
-          case java.sql.Types.SMALLINT:\r
-          case java.sql.Types.TINYINT:\r
-          case java.sql.Types.BIGINT:\r
-\r
-            int out = rs.getInt(valueIndex);\r
-\r
-            if (!rs.wasNull()) {\r
-              outValue = new Integer(out).toString();\r
-            }\r
-\r
-            break;\r
-\r
-          case java.sql.Types.NUMERIC:\r
-\r
-            /** @todo Numeric can be float or double depending upon\r
-             *  metadata.getScale() / especially with oracle */\r
-            long outl = rs.getLong(valueIndex);\r
-\r
-            if (!rs.wasNull()) {\r
-              outValue = new Long(outl).toString();\r
-            }\r
-\r
-            break;\r
-\r
-          case java.sql.Types.REAL:\r
-\r
-            float tempf = rs.getFloat(valueIndex);\r
-\r
-            if (!rs.wasNull()) {\r
-              tempf *= 10;\r
-              tempf += 0.5;\r
-\r
-              int tempf_int = (int) tempf;\r
-              tempf = (float) tempf_int;\r
-              tempf /= 10;\r
-              outValue = "" + tempf;\r
-              outValue = outValue.replace('.', ',');\r
-            }\r
-\r
-            break;\r
-\r
-          case java.sql.Types.DOUBLE:\r
-\r
-            double tempd = rs.getDouble(valueIndex);\r
-\r
-            if (!rs.wasNull()) {\r
-              tempd *= 10;\r
-              tempd += 0.5;\r
-\r
-              int tempd_int = (int) tempd;\r
-              tempd = (double) tempd_int;\r
-              tempd /= 10;\r
-              outValue = "" + tempd;\r
-              outValue = outValue.replace('.', ',');\r
-            }\r
-\r
-            break;\r
-\r
-          case java.sql.Types.CHAR:\r
-          case java.sql.Types.VARCHAR:\r
-          case java.sql.Types.LONGVARCHAR:\r
-            outValue = rs.getString(valueIndex);\r
-\r
-            break;\r
-\r
-          case java.sql.Types.LONGVARBINARY:\r
-            outValue = rs.getString(valueIndex);\r
-\r
-            break;\r
-\r
-          case java.sql.Types.TIMESTAMP:\r
-\r
-            // it's important to use Timestamp here as getting it\r
-            // as a string is undefined and is only there for debugging\r
-            // according to the API. we can make it a string through formatting.\r
-            // -mh\r
-            Timestamp timestamp = (rs.getTimestamp(valueIndex));\r
-\r
-            if (!rs.wasNull()) {\r
-              java.util.Date date = new java.util.Date(timestamp.getTime());\r
-\r
-              Calendar calendar = new GregorianCalendar();\r
-              calendar.setTime(date);\r
-              calendar.setTimeZone(timezone);\r
-              outValue = internalDateFormat.format(date);\r
-\r
-              int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);\r
-              String tzOffset = StringUtil.zeroPaddingNumber(Math.abs(offset) / _millisPerHour, 2, 2);\r
-\r
-              if (offset<0)\r
-                outValue = outValue + "-";\r
-              else\r
-                outValue = outValue + "+";\r
-              outValue = outValue + tzOffset;\r
-            }\r
-\r
-            break;\r
-\r
-          default:\r
-            outValue = "<unsupported value>";\r
-            logger.warn("Unsupported Datatype: at " + valueIndex + " (" + aType + ")");\r
-        }\r
-      } catch (SQLException e) {\r
-        throw new StorageObjectFailure("Could not get Value out of Resultset -- ",\r
-          e);\r
-      }\r
-    }\r
-\r
-    return outValue;\r
-  }\r
-\r
-  /*\r
-  *   select-Operator um einen Datensatz zu bekommen.\r
-  *   @param id Primaerschluessel des Datensatzes.\r
-  *   @return liefert EntityObject des gefundenen Datensatzes oder null.\r
-   */\r
-  public Entity selectById(String id) throws StorageObjectExc {\r
-    if ((id == null) || id.equals("")) {\r
-      throw new StorageObjectExc("Database.selectById: Missing id");\r
-    }\r
-\r
-    // ask object store for object\r
-    if (StoreUtil.implementsStorableObject(theEntityClass)) {\r
-      String uniqueId = id;\r
-\r
-      if (theEntityClass.equals(StorableObjectEntity.class)) {\r
-        uniqueId += ("@" + theTable);\r
-      }\r
-\r
-      StoreIdentifier search_sid = new StoreIdentifier(theEntityClass, uniqueId);\r
-      logger.debug("CACHE: (dbg) looking for sid " + search_sid.toString());\r
-\r
-      Entity hit = (Entity) o_store.use(search_sid);\r
-\r
-      if (hit != null) {\r
-        return hit;\r
-      }\r
-    }\r
-\r
-    Statement stmt = null;\r
-    Connection con = getPooledCon();\r
-    Entity returnEntity = null;\r
-\r
-    try {\r
-      ResultSet rs;\r
-\r
-      /** @todo better prepared statement */\r
-      String selectSql =\r
-        "select * from " + theTable + " where " + thePKeyName + "=" + id;\r
-      stmt = con.createStatement();\r
-      rs = executeSql(stmt, selectSql);\r
-\r
-      if (rs != null) {\r
-        if (evaluatedMetaData == false) {\r
-          evalMetaData(rs.getMetaData());\r
-        }\r
-\r
-        if (rs.next()) {\r
-          returnEntity = makeEntityFromResultSet(rs);\r
-        }\r
-        else {\r
-          logger.debug("No data for id: " + id + " in table " + theTable);\r
-        }\r
-\r
-        rs.close();\r
-      }\r
-      else {\r
-        logger.debug("No Data for Id " + id + " in Table " + theTable);\r
-      }\r
-    }\r
-    catch (SQLException sqe) {\r
-      throwSQLException(sqe, "selectById");\r
-      return null;\r
-    }\r
-    catch (NumberFormatException e) {\r
-      logger.error("ID is no number: " + id);\r
-    }\r
-    finally {\r
-      freeConnection(con, stmt);\r
-    }\r
-\r
-    return returnEntity;\r
-  }\r
-\r
-  /**\r
-   *   select-Operator um Datensaetze zu bekommen, die key = value erfuellen.\r
-   *   @param key  Datenbankfeld der Bedingung.\r
-   *   @param value  Wert die der key anehmen muss.\r
-   *   @return EntityList mit den gematchten Entities\r
-   */\r
-  public EntityList selectByFieldValue(String aField, String aValue) throws StorageObjectFailure {\r
-    return selectByFieldValue(aField, aValue, 0);\r
-  }\r
-\r
-  /**\r
-   *   select-Operator um Datensaetze zu bekommen, die key = value erfuellen.\r
-   *   @param key  Datenbankfeld der Bedingung.\r
-   *   @param value  Wert die der key anehmen muss.\r
-   *   @param offset  Gibt an ab welchem Datensatz angezeigt werden soll.\r
-   *   @return EntityList mit den gematchten Entities\r
-   */\r
-  public EntityList selectByFieldValue(String aField, String aValue, int offset) throws StorageObjectFailure {\r
-    return selectByWhereClause(aField + "=" + aValue, offset);\r
-  }\r
-\r
-  /**\r
-   * select-Operator liefert eine EntityListe mit den gematchten Datens?tzen zur?ck.\r
-   * Also offset wird der erste Datensatz genommen.\r
-   *\r
-   * @param wc where-Clause\r
-   * @return EntityList mit den gematchten Entities\r
-   * @exception StorageObjectException\r
-   */\r
-  public EntityList selectByWhereClause(String where) throws StorageObjectFailure {\r
-    return selectByWhereClause(where, 0);\r
-  }\r
-\r
-  /**\r
-   * select-Operator liefert eine EntityListe mit den gematchten Datens?tzen zur?ck.\r
-   * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.\r
-   *\r
-   * @param wc where-Clause\r
-   * @param offset ab welchem Datensatz.\r
-   * @return EntityList mit den gematchten Entities\r
-   * @exception StorageObjectException\r
-   */\r
-  public EntityList selectByWhereClause(String whereClause, int offset) throws StorageObjectFailure {\r
-    return selectByWhereClause(whereClause, null, offset);\r
-  }\r
-\r
-  /**\r
-   * select-Operator liefert eine EntityListe mit den gematchten Datens?tzen zur?ck.\r
-   * Also offset wird der erste Datensatz genommen.\r
-   * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.\r
-   *\r
-   * @param wc where-Clause\r
-   * @param ob orderBy-Clause\r
-   * @return EntityList mit den gematchten Entities\r
-   * @exception StorageObjectException\r
-   */\r
-  public EntityList selectByWhereClause(String where, String order) throws StorageObjectFailure {\r
-    return selectByWhereClause(where, order, 0);\r
-  }\r
-\r
-  /**\r
-   * select-Operator liefert eine EntityListe mit den gematchten Datens?tzen zur?ck.\r
-   * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.\r
-   *\r
-   * @param wc where-Clause\r
-   * @param ob orderBy-Clause\r
-   * @param offset ab welchem Datensatz\r
-   * @return EntityList mit den gematchten Entities\r
-   * @exception StorageObjectException\r
-   */\r
-  public EntityList selectByWhereClause(String whereClause, String orderBy, int offset) throws StorageObjectFailure {\r
-    return selectByWhereClause(whereClause, orderBy, offset, defaultLimit);\r
-  }\r
-\r
-  /**\r
-   * select-Operator liefert eine EntityListe mit den gematchten Datens?tzen zur?ck.\r
-   * @param aWhereClause where-Clause\r
-   * @param anOrderByClause orderBy-Clause\r
-   * @param offset ab welchem Datensatz\r
-   * @param limit wieviele Datens?tze\r
-   * @return EntityList mit den gematchten Entities\r
-   * @exception StorageObjectException\r
-   */\r
-  public EntityList selectByWhereClause(String aWhereClause, String anOrderByClause,\r
-            int offset, int limit) throws StorageObjectFailure {\r
-\r
-    // check o_store for entitylist\r
-    if (StoreUtil.implementsStorableObject(theEntityClass)) {\r
-      StoreIdentifier search_sid =\r
-          new StoreIdentifier(\r
-            theEntityClass, StoreContainerType.STOC_TYPE_ENTITYLIST,\r
-            StoreUtil.getEntityListUniqueIdentifierFor(theTable, aWhereClause, anOrderByClause, offset, limit));\r
-      EntityList hit = (EntityList) o_store.use(search_sid);\r
-\r
-      if (hit != null) {\r
-        logger.debug("CACHE (hit): " + search_sid.toString());\r
-\r
-        return hit;\r
-      }\r
-    }\r
-\r
-    // local\r
-    EntityList theReturnList = null;\r
-    Connection con = null;\r
-    Statement stmt = null;\r
-    ResultSet rs;\r
-    int offsetCount = 0;\r
-    int count = 0;\r
-\r
-    // build sql-statement\r
-\r
-    /** @todo count sql string should only be assembled if we really count\r
-     *  see below at the end of method //rk */\r
-    if ((aWhereClause != null) && (aWhereClause.trim().length() == 0)) {\r
-      aWhereClause = null;\r
-    }\r
-\r
-    StringBuffer countSql =\r
-      new StringBuffer("select count(*) from ").append(theTable);\r
-    StringBuffer selectSql =\r
-      new StringBuffer("select * from ").append(theTable);\r
-\r
-    if (aWhereClause != null) {\r
-      selectSql.append(" where ").append(aWhereClause);\r
-      countSql.append(" where ").append(aWhereClause);\r
-    }\r
-\r
-    if ((anOrderByClause != null) && !(anOrderByClause.trim().length() == 0)) {\r
-      selectSql.append(" order by ").append(anOrderByClause);\r
-    }\r
-\r
-    if ((limit > -1) && (offset > -1)) {\r
-      selectSql.append(" LIMIT ").append(limit).append(" OFFSET ").append(offset);\r
-    }\r
-\r
-    // execute sql\r
-    try {\r
-      con = getPooledCon();\r
-      stmt = con.createStatement();\r
-\r
-      // selecting...\r
-      rs = executeSql(stmt, selectSql.toString());\r
-\r
-      if (rs != null) {\r
-        if (!evaluatedMetaData) {\r
-          evalMetaData(rs.getMetaData());\r
-        }\r
-\r
-        theReturnList = new EntityList();\r
-\r
-        Entity theResultEntity;\r
-\r
-        while (rs.next()) {\r
-          theResultEntity = makeEntityFromResultSet(rs);\r
-          theReturnList.add(theResultEntity);\r
-          offsetCount++;\r
-        }\r
-\r
-        rs.close();\r
-      }\r
-\r
-      // making entitylist infos\r
-      count = offsetCount;\r
-\r
-      if (theReturnList != null) {\r
-        // now we decide if we have to know an overall count...\r
-        count = offsetCount;\r
-\r
-        if ((limit > -1) && (offset > -1)) {\r
-          if (offsetCount == limit) {\r
-            /** @todo counting should be deffered to entitylist\r
-             *  getSize() should be used */\r
-            rs = executeSql(stmt, countSql.toString());\r
-\r
-            if (rs != null) {\r
-              if (rs.next()) {\r
-                count = rs.getInt(1);\r
-              }\r
-\r
-              rs.close();\r
-            }\r
-            else {\r
-              logger.error("Could not count: " + countSql);\r
-            }\r
-          }\r
-        }\r
-\r
-        theReturnList.setCount(count);\r
-        theReturnList.setOffset(offset);\r
-        theReturnList.setWhere(aWhereClause);\r
-        theReturnList.setOrder(anOrderByClause);\r
-        theReturnList.setStorage(this);\r
-        theReturnList.setLimit(limit);\r
-\r
-        if (offset >= limit) {\r
-          theReturnList.setPrevBatch(offset - limit);\r
-        }\r
-\r
-        if ((offset + offsetCount) < count) {\r
-          theReturnList.setNextBatch(offset + limit);\r
-        }\r
-\r
-        if (StoreUtil.implementsStorableObject(theEntityClass)) {\r
-          StoreIdentifier sid = theReturnList.getStoreIdentifier();\r
-          logger.debug("CACHE (add): " + sid.toString());\r
-          o_store.add(sid);\r
-        }\r
-      }\r
-    }\r
-    catch (SQLException sqe) {\r
-      throwSQLException(sqe, "selectByWhereClause");\r
-    }\r
-    finally {\r
-      try {\r
-        if (con != null) {\r
-          freeConnection(con, stmt);\r
-        }\r
-      } catch (Throwable t) {\r
-      }\r
-    }\r
-\r
-    return theReturnList;\r
-  }\r
-\r
-  /**\r
-   *  Bastelt aus einer Zeile der Datenbank ein EntityObjekt.\r
-   *\r
-   *  @param rs Das ResultSetObjekt.\r
-   *  @return Entity Die Entity.\r
-   */\r
-  private Entity makeEntityFromResultSet(ResultSet rs)\r
-    throws StorageObjectFailure {\r
-    /** @todo OS: get Pkey from ResultSet and consult ObjectStore */\r
-    Map theResultHash = new HashMap();\r
-    String theResult = null;\r
-    int theType;\r
-    Entity returnEntity = null;\r
-\r
-    try {\r
-      int size = metadataFields.size();\r
-\r
-      for (int i = 0; i < size; i++) {\r
-        // alle durchlaufen bis nix mehr da\r
-        theType = metadataTypes[i];\r
-\r
-        if (theType == java.sql.Types.LONGVARBINARY) {\r
-          InputStreamReader is =\r
-            (InputStreamReader) rs.getCharacterStream(i + 1);\r
-\r
-          if (is != null) {\r
-            char[] data = new char[32768];\r
-            StringBuffer theResultString = new StringBuffer();\r
-            int len;\r
-\r
-            while ((len = is.read(data)) > 0) {\r
-              theResultString.append(data, 0, len);\r
-            }\r
-\r
-            is.close();\r
-            theResult = theResultString.toString();\r
-          } else {\r
-            theResult = null;\r
-          }\r
-        } else {\r
-          theResult = getValueAsString(rs, (i + 1), theType);\r
-        }\r
-\r
-        if (theResult != null) {\r
-          theResultHash.put(metadataFields.get(i), theResult);\r
-        }\r
-      }\r
-\r
-      if (theEntityClass != null) {\r
-        returnEntity = (Entity) theEntityClass.newInstance();\r
-        returnEntity.setStorage(this);\r
-        returnEntity.setValues(theResultHash);\r
-\r
-        if (returnEntity instanceof StorableObject) {\r
-          logger.debug("CACHE: ( in) " + returnEntity.getId() + " :" + theTable);\r
-          o_store.add(((StorableObject) returnEntity).getStoreIdentifier());\r
-        }\r
-      } else {\r
-        throwStorageObjectException("Internal Error: theEntityClass not set!");\r
-      }\r
-    }\r
-    catch (IllegalAccessException e) {\r
-      throwStorageObjectException("No access! -- " + e.getMessage());\r
-    }\r
-    catch (IOException e) {\r
-      throwStorageObjectException("IOException! -- " + e.getMessage());\r
-    }\r
-    catch (InstantiationException e) {\r
-      throwStorageObjectException("No Instatiation! -- " + e.getMessage());\r
-    }\r
-    catch (SQLException sqe) {\r
-      throwSQLException(sqe, "makeEntityFromResultSet");\r
-\r
-      return null;\r
-    }\r
-\r
-    return returnEntity;\r
-  }\r
-\r
-  /**\r
-   * Inserts an entity into the database.\r
-   *\r
-   * @param theEntity\r
-   * @return der Wert des Primary-keys der eingef?gten Entity\r
-   */\r
-  public String insert(Entity theEntity) throws StorageObjectFailure {\r
-    //cache\r
-    invalidatePopupCache();\r
-\r
-    // invalidating all EntityLists corresponding with theEntityClass\r
-    if (StoreUtil.implementsStorableObject(theEntityClass)) {\r
-      StoreContainerType stoc_type =\r
-        StoreContainerType.valueOf(theEntityClass,\r
-          StoreContainerType.STOC_TYPE_ENTITYLIST);\r
-      o_store.invalidate(stoc_type);\r
-    }\r
-\r
-    String returnId = null;\r
-    Connection con = null;\r
-    PreparedStatement pstmt = null;\r
-\r
-    try {\r
-      List streamedInput = theEntity.streamedInput();\r
-      StringBuffer f = new StringBuffer();\r
-      StringBuffer v = new StringBuffer();\r
-      String aField;\r
-      String aValue;\r
-      boolean firstField = true;\r
-\r
-      // make sql-string\r
-      for (int i = 0; i < getFields().size(); i++) {\r
-        aField = (String) getFields().get(i);\r
-\r
-        if (!aField.equals(thePKeyName)) {\r
-          aValue = null;\r
-\r
-          // exceptions\r
-          if (!theEntity.hasValueForField(aField) && (\r
-              aField.equals("webdb_create") ||\r
-              aField.equals("webdb_lastchange"))) {\r
-            aValue = "NOW()";\r
-          }\r
-          else {\r
-            if ((streamedInput != null) && streamedInput.contains(aField)) {\r
-              aValue = "?";\r
-            }\r
-            else {\r
-              if (theEntity.hasValueForField(aField)) {\r
-                aValue =\r
-                  "'" +\r
-                   JDBCStringRoutines.escapeStringLiteral((String) theEntity.getValue(aField)) + "'";\r
-              }\r
-            }\r
-          }\r
-\r
-          // wenn Wert gegeben, dann einbauen\r
-          if (aValue != null) {\r
-            if (firstField == false) {\r
-              f.append(",");\r
-              v.append(",");\r
-            }\r
-            else {\r
-              firstField = false;\r
-            }\r
-\r
-            f.append(aField);\r
-            v.append(aValue);\r
-          }\r
-        }\r
-      }\r
-       // end for\r
-\r
-      // insert into db\r
-      StringBuffer sqlBuf =\r
-        new StringBuffer("insert into ").append(theTable).append("(").append(f)\r
-                                        .append(") values (").append(v).append(")");\r
-      String sql = sqlBuf.toString();\r
-\r
-      logger.debug("INSERT: " + sql);\r
-      con = getPooledCon();\r
-      con.setAutoCommit(false);\r
-      pstmt = con.prepareStatement(sql);\r
-\r
-      if (streamedInput != null) {\r
-        for (int i = 0; i < streamedInput.size(); i++) {\r
-          String inputString =\r
-            (String) theEntity.getValue((String) streamedInput.get(i));\r
-          pstmt.setBytes(i + 1, inputString.getBytes());\r
-        }\r
-      }\r
-\r
-      int ret = pstmt.executeUpdate();\r
-\r
-      if (ret == 0) {\r
-        //insert failed\r
-        return null;\r
-      }\r
-\r
-      pstmt = con.prepareStatement("select currval('" + getCoreTable() + "_id_seq')");\r
-\r
-      ResultSet rs = pstmt.executeQuery();\r
-      rs.next();\r
-      returnId = rs.getString(1);\r
-      theEntity.setId(returnId);\r
-    }\r
-    catch (SQLException sqe) {\r
-      throwSQLException(sqe, "insert");\r
-    }\r
-    finally {\r
-      try {\r
-        con.setAutoCommit(true);\r
-      }\r
-      catch (Exception e) {\r
-      }\r
-\r
-      freeConnection(con, pstmt);\r
-    }\r
-\r
-    /** @todo store entity in o_store */\r
-    return returnId;\r
-  }\r
-\r
-  /**\r
-   * Updates an entity in the database\r
-   *\r
-   * @param theEntity\r
-   */\r
-  public void update(Entity theEntity) throws StorageObjectFailure {\r
-    Connection con = null;\r
-    PreparedStatement pstmt = null;\r
-\r
-    /** @todo this is stupid: why do we prepare statement, when we\r
-     *  throw it away afterwards. should be regular statement\r
-     *  update/insert could better be one routine called save()\r
-     *  that chooses to either insert or update depending if we\r
-     *  have a primary key in the entity. i don't know if we\r
-     *  still need the streamed input fields. // rk  */\r
-    /** @todo extension: check if Entity did change, otherwise we don't need\r
-     *  the roundtrip to the database */\r
-    /** invalidating corresponding entitylists in o_store*/\r
-    if (StoreUtil.implementsStorableObject(theEntityClass)) {\r
-      StoreContainerType stoc_type =\r
-        StoreContainerType.valueOf(theEntityClass,\r
-          StoreContainerType.STOC_TYPE_ENTITYLIST);\r
-      o_store.invalidate(stoc_type);\r
-    }\r
-\r
-    List streamedInput = theEntity.streamedInput();\r
-    String id = theEntity.getId();\r
-    String aField;\r
-    StringBuffer fv = new StringBuffer();\r
-    boolean firstField = true;\r
-\r
-    //cache\r
-    invalidatePopupCache();\r
-\r
-    // build sql statement\r
-    for (int i = 0; i < getFields().size(); i++) {\r
-      aField = (String) metadataFields.get(i);\r
-\r
-      // only normal cases\r
-      if (  !(aField.equals(thePKeyName) ||\r
-            aField.equals("webdb_create") ||\r
-            aField.equals("webdb_lastchange") ||\r
-            ((streamedInput != null) && streamedInput.contains(aField)))) {\r
-        if (theEntity.hasValueForField(aField)) {\r
-          if (firstField == false) {\r
-            fv.append(", ");\r
-          }\r
-          else {\r
-            firstField = false;\r
-          }\r
-\r
-          fv.append(aField).append("='").append(JDBCStringRoutines.escapeStringLiteral((String) theEntity.getValue(aField))).append("'");\r
-\r
-          //              fv.append(aField).append("='").append(StringUtil.quote((String)theEntity.getValue(aField))).append("'");\r
-        }\r
-      }\r
-    }\r
-\r
-    StringBuffer sql =\r
-      new StringBuffer("update ").append(theTable).append(" set ").append(fv);\r
-\r
-    // exceptions\r
-    if (metadataFields.contains("webdb_lastchange")) {\r
-      sql.append(",webdb_lastchange=NOW()");\r
-    }\r
-\r
-    // special case: the webdb_create requires the field in yyyy-mm-dd HH:mm\r
-    // format so anything extra will be ignored. -mh\r
-    if (metadataFields.contains("webdb_create") &&\r
-        theEntity.hasValueForField("webdb_create")) {\r
-      // minimum of 10 (yyyy-mm-dd)...\r
-      if (theEntity.getValue("webdb_create").length() >= 10) {\r
-        String dateString = theEntity.getValue("webdb_create");\r
-\r
-        // if only 10, then add 00:00 so it doesn't throw a ParseException\r
-        if (dateString.length() == 10) {\r
-          dateString = dateString + " 00:00";\r
-        }\r
-\r
-        // TimeStamp stuff\r
-        try {\r
-          java.util.Date d = userInputDateFormat.parse(dateString);\r
-//          Timestamp tStamp = new Timestamp(d.getTime());\r
-          sql.append(",webdb_create='" + JDBCStringRoutines.formatDate(d) + "'");\r
-        }\r
-        catch (ParseException e) {\r
-          throw new StorageObjectFailure(e);\r
-        }\r
-      }\r
-    }\r
-\r
-    if (streamedInput != null) {\r
-      for (int i = 0; i < streamedInput.size(); i++) {\r
-        sql.append(",").append(streamedInput.get(i)).append("=?");\r
-      }\r
-    }\r
-\r
-    sql.append(" where id=").append(id);\r
-    logger.debug("UPDATE: " + sql);\r
-\r
-    try {\r
-      con = getPooledCon();\r
-      con.setAutoCommit(false);\r
-      pstmt = con.prepareStatement(sql.toString());\r
-\r
-      if (streamedInput != null) {\r
-        for (int i = 0; i < streamedInput.size(); i++) {\r
-          String inputString =\r
-            theEntity.getValue((String) streamedInput.get(i));\r
-          pstmt.setBytes(i + 1, inputString.getBytes());\r
-        }\r
-      }\r
-\r
-      pstmt.executeUpdate();\r
-    }\r
-    catch (SQLException sqe) {\r
-      throwSQLException(sqe, "update");\r
-    }\r
-    finally {\r
-      try {\r
-        con.setAutoCommit(true);\r
-      }\r
-      catch (Exception e) {\r
-        ;\r
-      }\r
-\r
-      freeConnection(con, pstmt);\r
-    }\r
-  }\r
-\r
-  /*\r
-  *   delete-Operator\r
-  *   @param id des zu loeschenden Datensatzes\r
-  *   @return boolean liefert true zurueck, wenn loeschen erfolgreich war.\r
-   */\r
-  public boolean delete(String id) throws StorageObjectFailure {\r
-    invalidatePopupCache();\r
-\r
-    // ostore send notification\r
-    if (StoreUtil.implementsStorableObject(theEntityClass)) {\r
-      String uniqueId = id;\r
-\r
-      if (theEntityClass.equals(StorableObjectEntity.class)) {\r
-        uniqueId += ("@" + theTable);\r
-      }\r
-\r
-      logger.debug("CACHE: (del) " + id);\r
-\r
-      StoreIdentifier search_sid =\r
-        new StoreIdentifier(theEntityClass,\r
-          StoreContainerType.STOC_TYPE_ENTITY, uniqueId);\r
-      o_store.invalidate(search_sid);\r
-    }\r
-\r
-    /** @todo could be prepared Statement */\r
-    Statement stmt = null;\r
-    Connection con = null;\r
-    int res = 0;\r
-    String sql =\r
-      "delete from " + theTable + " where " + thePKeyName + "='" + id + "'";\r
-\r
-    //theLog.printInfo("DELETE " + sql);\r
-    try {\r
-      con = getPooledCon();\r
-      stmt = con.createStatement();\r
-      res = stmt.executeUpdate(sql);\r
-    } catch (SQLException sqe) {\r
-      throwSQLException(sqe, "delete");\r
-    } finally {\r
-      freeConnection(con, stmt);\r
-    }\r
-\r
-    return (res > 0) ? true : false;\r
-  }\r
-\r
-  /**\r
-   * Deletes entities based on a where clause\r
-   *\r
-   * @param aWhereClause\r
-   * @return\r
-   * @throws StorageObjectFailure\r
-   */\r
-  public int deleteByWhereClause(String aWhereClause) throws StorageObjectFailure {\r
-    invalidatePopupCache();\r
-    if (StoreUtil.implementsStorableObject(theEntityClass)) {\r
-      StoreContainerType stoc_type = StoreContainerType.valueOf(theEntityClass, StoreContainerType.STOC_TYPE_ENTITYLIST);\r
-      o_store.invalidate(stoc_type);\r
-    }\r
-\r
-    Statement stmt = null;\r
-    Connection con = null;\r
-    int res = 0;\r
-    String sql =\r
-      "delete from " + theTable + " where " + aWhereClause;\r
-\r
-    //theLog.printInfo("DELETE " + sql);\r
-    try {\r
-      con = getPooledCon();\r
-      stmt = con.createStatement();\r
-      res = stmt.executeUpdate(sql);\r
-    }\r
-    catch (SQLException sqe) {\r
-      throwSQLException(sqe, "delete");\r
-    }\r
-    finally {\r
-      freeConnection(con, stmt);\r
-    }\r
-\r
-    return res;\r
-  }\r
-\r
-  /* noch nicht implementiert.\r
-  * @return immer false\r
-   */\r
-  public boolean delete(EntityList theEntityList) {\r
-    invalidatePopupCache();\r
-\r
-    return false;\r
-  }\r
-\r
-  /* invalidates the popupCache\r
-   */\r
-  protected void invalidatePopupCache() {\r
-    /** @todo  invalidates toooo much */\r
-    popupCache = null;\r
-    hashCache = null;\r
-  }\r
-\r
-  /**\r
-   * Diese Methode fuehrt den Sqlstring <i>sql</i> aus und timed im Logfile.\r
-   * @param stmt Statemnt\r
-   * @param sql Sql-String\r
-   * @return ResultSet\r
-   * @exception StorageObjectException\r
-   */\r
-  public ResultSet executeSql(Statement stmt, String sql)\r
-                            throws StorageObjectFailure, SQLException {\r
-    ResultSet rs;\r
-    long startTime = System.currentTimeMillis();\r
-\r
-    try {\r
-      rs = stmt.executeQuery(sql);\r
-\r
-      logger.debug((System.currentTimeMillis() - startTime) + "ms. for: " + sql);\r
-    }\r
-    catch (SQLException e) {\r
-      logger.error(e.getMessage() +"\n" + (System.currentTimeMillis() - startTime) + "ms. for: " + sql);\r
-      throw e;\r
-    }\r
-\r
-    return rs;\r
-  }\r
-/*\r
-  public ResultSet executeSql(String sql) throws StorageObjectFailure, SQLException {\r
-    long startTime = System.currentTimeMillis();\r
-    Connection connection = null;\r
-    Statement statement = null;\r
-\r
-    try {\r
-      connection = getPooledCon();\r
-      statement = connection.createStatement();\r
-      ResultSet result;\r
-\r
-      result = statement.executeQuery(sql);\r
-\r
-      logger.debug((System.currentTimeMillis() - startTime) + "ms. for: " + sql);\r
-      return result;\r
-    }\r
-    catch (Throwable e) {\r
-      logger.error(e.getMessage() +"\n" + (System.currentTimeMillis() - startTime) + "ms. for: " + sql);\r
-      throw new StorageObjectFailure(e);\r
-    }\r
-    finally {\r
-      if (connection!=null) {\r
-        freeConnection(connection, statement);\r
-      }\r
-    }\r
-  }\r
-*/\r
-  private Map processRow(ResultSet aResultSet) throws StorageObjectFailure, StorageObjectExc {\r
-    try {\r
-      Map result = new HashMap();\r
-      ResultSetMetaData metaData = aResultSet.getMetaData();\r
-      int nrColumns = metaData.getColumnCount();\r
-      for (int i=0; i<nrColumns; i++) {\r
-        result.put(metaData.getColumnName(i+1), getValueAsString(aResultSet, i+1, metaData.getColumnType(i+1)));\r
-      }\r
-\r
-      return result;\r
-    }\r
-    catch (Throwable e) {\r
-      throw new StorageObjectFailure(e);\r
-    }\r
-  }\r
-\r
-  public List executeFreeSql(String sql, int aLimit) throws StorageObjectFailure, StorageObjectExc {\r
-    Connection connection = null;\r
-    Statement statement = null;\r
-    try {\r
-      List result = new Vector();\r
-      connection = getPooledCon();\r
-      statement = connection.createStatement();\r
-      ResultSet resultset = executeSql(statement, sql);\r
-      try {\r
-        while (resultset.next() && result.size() < aLimit) {\r
-          result.add(processRow(resultset));\r
-        }\r
-      }\r
-      finally {\r
-        resultset.close();\r
-      }\r
-\r
-      return result;\r
-    }\r
-    catch (Throwable e) {\r
-      throw new StorageObjectFailure(e);\r
-    }\r
-    finally {\r
-      if (connection!=null) {\r
-        freeConnection(connection, statement);\r
-      }\r
-    }\r
-  };\r
-\r
-  public Map executeFreeSingleRowSql(String anSqlStatement) throws StorageObjectFailure, StorageObjectExc {\r
-    try {\r
-      List resultList = executeFreeSql(anSqlStatement, 1);\r
-      try {\r
-        if (resultList.size()>0)\r
-          return (Map) resultList.get(0);\r
-        else\r
-          return null;\r
-      }\r
-      finally {\r
-      }\r
-    }\r
-    catch (Throwable t) {\r
-      throw new StorageObjectFailure(t);\r
-    }\r
-  };\r
-\r
-  public String executeFreeSingleValueSql(String sql) throws StorageObjectFailure, StorageObjectExc {\r
-    Map row = executeFreeSingleRowSql(sql);\r
-\r
-    if (row==null)\r
-      return null;\r
-\r
-    Iterator i = row.values().iterator();\r
-    if (i.hasNext())\r
-      return (String) i.next();\r
-    else\r
-      return null;\r
-  };\r
-\r
-  /**\r
-   * returns the number of rows in the table\r
-   */\r
-  public int getSize(String where) throws SQLException, StorageObjectFailure {\r
-    long startTime = System.currentTimeMillis();\r
-    String sql = "SELECT Count(*) FROM " + theTable;\r
-\r
-    if ((where != null) && (where.length() != 0)) {\r
-      sql = sql + " where " + where;\r
-    }\r
-\r
-    Connection con = null;\r
-    Statement stmt = null;\r
-    int result = 0;\r
-\r
-    try {\r
-      con = getPooledCon();\r
-      stmt = con.createStatement();\r
-\r
-      ResultSet rs = executeSql(stmt, sql);\r
-\r
-      while (rs.next()) {\r
-        result = rs.getInt(1);\r
-      }\r
-    }\r
-    catch (SQLException e) {\r
-      logger.error("Database.getSize: " + e.getMessage());\r
-    }\r
-    finally {\r
-      freeConnection(con, stmt);\r
-    }\r
-\r
-    //theLog.printInfo(theTable + " has "+ result +" rows where " + where);\r
-    logger.debug((System.currentTimeMillis() - startTime) + "ms. for: " + sql);\r
-\r
-    return result;\r
-  }\r
-\r
-  public int executeUpdate(Statement stmt, String sql)\r
-    throws StorageObjectFailure, SQLException {\r
-    int rs;\r
-    long startTime = System.currentTimeMillis();\r
-\r
-    try {\r
-      rs = stmt.executeUpdate(sql);\r
-\r
-      logger.debug((System.currentTimeMillis() - startTime) + "ms. for: " + sql);\r
-    }\r
-    catch (SQLException e) {\r
-      logger.error("Failed: " + (System.currentTimeMillis() - startTime) + "ms. for: " + sql);\r
-      throw e;\r
-    }\r
-\r
-    return rs;\r
-  }\r
-\r
-  public int executeUpdate(String sql)\r
-    throws StorageObjectFailure, SQLException {\r
-    int result = -1;\r
-    long startTime = System.currentTimeMillis();\r
-    Connection con = null;\r
-    PreparedStatement pstmt = null;\r
-\r
-    try {\r
-      con = getPooledCon();\r
-      pstmt = con.prepareStatement(sql);\r
-      result = pstmt.executeUpdate();\r
-    }\r
-    catch (Throwable e) {\r
-      logger.error("Database.executeUpdate(" + sql + "): " + e.getMessage());\r
-      throw new StorageObjectFailure("Database.executeUpdate(" + sql + "): " + e.getMessage(), e);\r
-    }\r
-    finally {\r
-      freeConnection(con, pstmt);\r
-    }\r
-\r
-    logger.debug((System.currentTimeMillis() - startTime) + "ms. for: " + sql);\r
-    return result;\r
-  }\r
-\r
-  /**\r
-   * Wertet ResultSetMetaData aus und setzt interne Daten entsprechend\r
-   * @param md ResultSetMetaData\r
-   * @exception StorageObjectException\r
-   */\r
-  private void evalMetaData(ResultSetMetaData md) throws StorageObjectFailure {\r
-    this.evaluatedMetaData = true;\r
-    this.metadataFields = new ArrayList();\r
-    this.metadataLabels = new ArrayList();\r
-    this.metadataNotNullFields = new ArrayList();\r
-\r
-    try {\r
-      int numFields = md.getColumnCount();\r
-      this.metadataTypes = new int[numFields];\r
-\r
-      String aField;\r
-      int aType;\r
-\r
-      for (int i = 1; i <= numFields; i++) {\r
-        aField = md.getColumnName(i);\r
-        metadataFields.add(aField);\r
-        metadataLabels.add(md.getColumnLabel(i));\r
-        aType = md.getColumnType(i);\r
-        metadataTypes[i - 1] = aType;\r
-\r
-        if (aField.equals(thePKeyName)) {\r
-          thePKeyType = aType;\r
-          thePKeyIndex = i;\r
-        }\r
-\r
-        if (md.isNullable(i) == ResultSetMetaData.columnNullable) {\r
-          metadataNotNullFields.add(aField);\r
-        }\r
-      }\r
-    }\r
-    catch (SQLException e) {\r
-      throwSQLException(e, "evalMetaData");\r
-    }\r
-  }\r
-\r
-  /**\r
-   *  Wertet die Metadaten eines Resultsets fuer eine Tabelle aus,\r
-   *  um die alle Columns und Typen einer Tabelle zu ermitteln.\r
-   */\r
-  private void get_meta_data() throws StorageObjectFailure {\r
-    Connection con = null;\r
-    PreparedStatement pstmt = null;\r
-    String sql = "select * from " + theTable + " where 0=1";\r
-\r
-    try {\r
-      con = getPooledCon();\r
-      pstmt = con.prepareStatement(sql);\r
-\r
-      logger.debug("METADATA: " + sql);\r
-      ResultSet rs = pstmt.executeQuery();\r
-      evalMetaData(rs.getMetaData());\r
-      rs.close();\r
-    }\r
-    catch (SQLException e) {\r
-      throwSQLException(e, "get_meta_data");\r
-    }\r
-    finally {\r
-      freeConnection(con, pstmt);\r
-    }\r
-  }\r
-\r
-  public Connection getPooledCon() throws StorageObjectFailure {\r
-    Connection con = null;\r
-\r
-    try {\r
-      con = SQLManager.getInstance().requestConnection();\r
-    }\r
-    catch (SQLException e) {\r
-      logger.error("could not connect to the database " + e.getMessage());\r
-\r
-      throw new StorageObjectFailure("Could not connect to the database", e);\r
-    }\r
-\r
-    return con;\r
-  }\r
-\r
-  public void freeConnection(Connection con, Statement stmt)\r
-    throws StorageObjectFailure {\r
-    SQLManager.closeStatement(stmt);\r
-    SQLManager.getInstance().returnConnection(con);\r
-  }\r
-\r
-  /**\r
-   * Wertet SQLException aus und wirft dannach eine StorageObjectException\r
-   * @param sqe SQLException\r
-   * @param wo Funktonsname, in der die SQLException geworfen wurde\r
-   * @exception StorageObjectException\r
-   */\r
-  protected void throwSQLException(SQLException sqe, String aFunction) throws StorageObjectFailure {\r
-    String state = "";\r
-    String message = "";\r
-    int vendor = 0;\r
-\r
-    if (sqe != null) {\r
-      state = sqe.getSQLState();\r
-      message = sqe.getMessage();\r
-      vendor = sqe.getErrorCode();\r
-    }\r
-\r
-    String information =\r
-        "SQL Error: " +\r
-        "state= " + state +\r
-        ", vendor= " + vendor +\r
-        ", message=" + message +\r
-        ", function= " + aFunction;\r
-\r
-    logger.error(information);\r
-\r
-    throw new StorageObjectFailure(information, sqe);\r
-  }\r
-\r
-  protected void _throwStorageObjectException(Exception e, String aFunction)\r
-    throws StorageObjectFailure {\r
-\r
-    if (e != null) {\r
-      logger.error(e.getMessage() + aFunction);\r
-      throw new StorageObjectFailure(aFunction, e);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * Loggt Fehlermeldung mit dem Parameter Message und wirft dannach\r
-   * eine StorageObjectException\r
-   * @param message Nachricht mit dem Fehler\r
-   * @exception StorageObjectException\r
-   */\r
-  void throwStorageObjectException(String aMessage) throws StorageObjectFailure {\r
-    logger.error(aMessage);\r
-    throw new StorageObjectFailure(aMessage, null);\r
-  }\r
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.storage;
+
+import mir.config.MirPropertiesConfiguration;
+import mir.entity.Entity;
+import mir.entity.EntityList;
+import mir.entity.StorableObjectEntity;
+import mir.log.LoggerWrapper;
+import mir.misc.StringUtil;
+import mir.storage.store.*;
+import mir.util.JDBCStringRoutines;
+import mircoders.global.MirGlobal;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.sql.*;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * Implements database access.
+ *
+ * @author rk
+ *
+ */
+public class Database implements StorageObject {
+  private static Class GENERIC_ENTITY_CLASS = mir.entity.StorableObjectEntity.class;
+  protected static final ObjectStore o_store = ObjectStore.getInstance();
+  private static final int _millisPerHour = 60 * 60 * 1000;
+
+  protected LoggerWrapper logger;
+
+  protected MirPropertiesConfiguration configuration;
+  protected String mainTable;
+  protected String primaryKeySequence = null;
+  protected String primaryKeyField = "id";
+
+  protected boolean evaluatedMetaData = false;
+  protected ArrayList metadataFields;
+  protected ArrayList metadataLabels;
+  protected ArrayList metadataNotNullFields;
+  protected int[] metadataTypes;
+  protected Class theEntityClass;
+  protected boolean hasTimestamp = true;
+  private int defaultLimit;
+
+  TimeZone timezone;
+  SimpleDateFormat internalDateFormat;
+  SimpleDateFormat userInputDateFormat;
+
+  /**
+   * Kontruktor bekommt den Filenamen des Konfigurationsfiles ?bergeben.
+   * Aus diesem file werden <code>Database.Logfile</code>,
+   * <code>Database.Username</code>,<code>Database.Password</code>,
+   * <code>Database.Host</code> und <code>Database.Adaptor</code>
+   * ausgelesen und ein Broker f?r die Verbindugen zur Datenbank
+   * erzeugt.
+   */
+  public Database() throws StorageObjectFailure {
+    configuration = MirPropertiesConfiguration.instance();
+    logger = new LoggerWrapper("Database");
+    timezone = TimeZone.getTimeZone(configuration.getString("Mir.DefaultTimezone"));
+    internalDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+    internalDateFormat.setTimeZone(timezone);
+
+    userInputDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+    userInputDateFormat.setTimeZone(timezone);
+
+    String theAdaptorName = configuration.getString("Database.Adaptor");
+    defaultLimit = Integer.parseInt(configuration.getString("Database.Limit"));
+
+    try {
+      theEntityClass = GENERIC_ENTITY_CLASS;
+    }
+    catch (Throwable e) {
+      logger.error("Error in Database() constructor with " + theAdaptorName + " -- " + e.getMessage());
+      throw new StorageObjectFailure("Error in Database() constructor.", e);
+    }
+  }
+
+  /**
+   * Liefert die Entity-Klasse zur?ck, in der eine Datenbankzeile gewrappt
+   * wird. Wird die Entity-Klasse durch die erbende Klasse nicht ?berschrieben,
+   * wird eine mir.entity.GenericEntity erzeugt.
+   *
+   * @return Class-Objekt der Entity
+   */
+  public java.lang.Class getEntityClass() {
+    return theEntityClass;
+  }
+
+  /**
+   * Liefert die Standardbeschr?nkung von select-Statements zur?ck, also
+   * wieviel Datens?tze per Default selektiert werden.
+   *
+   * @return Standard-Anzahl der Datens?tze
+   */
+  public int getLimit() {
+    return defaultLimit;
+  }
+
+  /**
+   * Liefert den Namen des Primary-Keys zur?ck. Wird die Variable nicht von
+   * der erbenden Klasse ?berschrieben, so ist der Wert <code>PKEY</code>
+   * @return Name des Primary-Keys
+   */
+  public String getIdName() {
+    return primaryKeyField;
+  }
+
+  /**
+   * Liefert den Namen der Tabelle, auf das sich das Datenbankobjekt bezieht.
+   *
+   * @return Name der Tabelle
+   */
+  public String getTableName() {
+    return mainTable;
+  }
+
+  /**
+   * Returns the id that was most recently added to the database
+   */
+  private String getLatestInsertedId(Connection aConnection) throws SQLException {
+    if (primaryKeySequence==null)
+      primaryKeySequence = mainTable+"_id_seq";
+
+    PreparedStatement statement = aConnection.prepareStatement("select currval('" + primaryKeySequence + "')");
+
+    ResultSet rs = statement.executeQuery();
+    rs.next();
+    return rs.getString(1);
+  }
+
+  /**
+   * Liefert eine Liste der Felder der Tabelle
+   * @return ArrayList mit Feldern
+   */
+  public List getFields() throws StorageObjectFailure {
+    if (metadataFields == null) {
+      get_meta_data();
+    }
+
+    return metadataFields;
+  }
+
+  /**
+   *   Gets value out of ResultSet according to type and converts to String
+   *   @param rs  ResultSet.
+   *   @param aType  a type from java.sql.Types.*
+   *   @param valueIndex  index in ResultSet
+   *   @return returns the value as String. If no conversion is possible
+   *                            /unsupported value/ is returned
+   */
+  private String getValueAsString(ResultSet rs, int valueIndex, int aType)
+    throws StorageObjectFailure {
+    String outValue = null;
+
+    if (rs != null) {
+      try {
+        switch (aType) {
+          case java.sql.Types.BIT:
+            outValue = (rs.getBoolean(valueIndex) == true) ? "1" : "0";
+
+            break;
+
+          case java.sql.Types.INTEGER:
+          case java.sql.Types.SMALLINT:
+          case java.sql.Types.TINYINT:
+          case java.sql.Types.BIGINT:
+
+            int out = rs.getInt(valueIndex);
+
+            if (!rs.wasNull()) {
+              outValue = new Integer(out).toString();
+            }
+
+            break;
+
+          case java.sql.Types.NUMERIC:
+
+            /** todo Numeric can be float or double depending upon
+             *  metadata.getScale() / especially with oracle */
+            long outl = rs.getLong(valueIndex);
+
+            if (!rs.wasNull()) {
+              outValue = new Long(outl).toString();
+            }
+
+            break;
+
+          case java.sql.Types.REAL:
+
+            float tempf = rs.getFloat(valueIndex);
+
+            if (!rs.wasNull()) {
+              tempf *= 10;
+              tempf += 0.5;
+
+              int tempf_int = (int) tempf;
+              tempf = (float) tempf_int;
+              tempf /= 10;
+              outValue = "" + tempf;
+              outValue = outValue.replace('.', ',');
+            }
+
+            break;
+
+          case java.sql.Types.DOUBLE:
+
+            double tempd = rs.getDouble(valueIndex);
+
+            if (!rs.wasNull()) {
+              tempd *= 10;
+              tempd += 0.5;
+
+              int tempd_int = (int) tempd;
+              tempd = (double) tempd_int;
+              tempd /= 10;
+              outValue = "" + tempd;
+              outValue = outValue.replace('.', ',');
+            }
+
+            break;
+
+          case java.sql.Types.CHAR:
+          case java.sql.Types.VARCHAR:
+          case java.sql.Types.LONGVARCHAR:
+            outValue = rs.getString(valueIndex);
+
+            break;
+
+          case java.sql.Types.LONGVARBINARY:
+            outValue = rs.getString(valueIndex);
+
+            break;
+
+          case java.sql.Types.TIMESTAMP:
+
+            // it's important to use Timestamp here as getting it
+            // as a string is undefined and is only there for debugging
+            // according to the API. we can make it a string through formatting.
+            // -mh
+            Timestamp timestamp = (rs.getTimestamp(valueIndex));
+
+            if (!rs.wasNull()) {
+              java.util.Date date = new java.util.Date(timestamp.getTime());
+
+              Calendar calendar = new GregorianCalendar();
+              calendar.setTime(date);
+              calendar.setTimeZone(timezone);
+              outValue = internalDateFormat.format(date);
+
+              int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
+              String tzOffset = StringUtil.zeroPaddingNumber(Math.abs(offset) / _millisPerHour, 2, 2);
+
+              if (offset<0)
+                outValue = outValue + "-";
+              else
+                outValue = outValue + "+";
+              outValue = outValue + tzOffset;
+            }
+
+            break;
+
+          default:
+            outValue = "<unsupported value>";
+            logger.warn("Unsupported Datatype: at " + valueIndex + " (" + aType + ")");
+        }
+      } catch (SQLException e) {
+        throw new StorageObjectFailure("Could not get Value out of Resultset -- ",
+          e);
+      }
+    }
+
+    return outValue;
+  }
+
+  /**
+   *   select-Operator um einen Datensatz zu bekommen.
+   *   @param id Primaerschluessel des Datensatzes.
+   *   @return liefert EntityObject des gefundenen Datensatzes oder null.
+   */
+  public Entity selectById(String id) throws StorageObjectExc {
+    if ((id == null) || id.equals("")) {
+      throw new StorageObjectExc("Database.selectById: Missing id");
+    }
+
+    // ask object store for object
+    if (StoreUtil.extendsStorableEntity(theEntityClass)) {
+      String uniqueId = id;
+
+      if (theEntityClass.equals(StorableObjectEntity.class)) {
+        uniqueId += ("@" + mainTable);
+      }
+
+      StoreIdentifier search_sid = new StoreIdentifier(theEntityClass, uniqueId);
+      logger.debug("CACHE: (dbg) looking for sid " + search_sid.toString());
+
+      Entity hit = (Entity) o_store.use(search_sid);
+
+      if (hit != null) {
+        return hit;
+      }
+    }
+
+    Statement stmt = null;
+    Connection con = obtainConnection();
+    Entity returnEntity = null;
+
+    try {
+      ResultSet rs;
+
+      /** todo better prepared statement */
+      String selectSql =
+        "select * from " + mainTable + " where " + primaryKeyField + "=" + id;
+      stmt = con.createStatement();
+      rs = executeSql(stmt, selectSql);
+
+      if (rs != null) {
+        if (evaluatedMetaData == false) {
+          evalMetaData(rs.getMetaData());
+        }
+
+        if (rs.next()) {
+          returnEntity = makeEntityFromResultSet(rs);
+        }
+        else {
+          logger.warn("No data for id: " + id + " in table " + mainTable);
+        }
+
+        rs.close();
+      }
+      else {
+        logger.warn("No Data for Id " + id + " in Table " + mainTable);
+      }
+    }
+    catch (SQLException sqe) {
+      throwSQLException(sqe, "selectById");
+      return null;
+    }
+    catch (NumberFormatException e) {
+      logger.error("ID is no number: " + id);
+    }
+    finally {
+      freeConnection(con, stmt);
+    }
+
+    return returnEntity;
+  }
+
+  /**
+   * This method makes it possible to make selects across multiple tables
+   *
+   * @param mainTablePrefix prefix for the mainTable
+   * @param extraTables a vector of tables for relational select
+   * @param aWhereClause whereClause
+   * @return EntityList of selected Objects
+   * @throws StorageObjectFailure
+   */
+
+  public EntityList selectByWhereClauseWithExtraTables(String mainTablePrefix,
+                                               List extraTables, String aWhereClause )
+   throws StorageObjectFailure {
+       return selectByWhereClause( mainTablePrefix, extraTables, aWhereClause, "", 0, defaultLimit);
+  }
+
+  public EntityList selectByFieldValue(String aField, String aValue) throws StorageObjectFailure {
+    return selectByFieldValue(aField, aValue, 0);
+  }
+
+  public EntityList selectByFieldValue(String aField, String aValue, int offset) throws StorageObjectFailure {
+    return selectByWhereClause(aField + "='" + JDBCStringRoutines.escapeStringLiteral(aValue)+"'", offset);
+  }
+
+  /**
+   * select-Operator liefert eine EntityListe mit den gematchten Datens?tzen zur?ck.
+   * Also offset wird der erste Datensatz genommen.
+   *
+   * @param where where-Clause
+   * @return EntityList mit den gematchten Entities
+   * @exception StorageObjectFailure
+   */
+  public EntityList selectByWhereClause(String where) throws StorageObjectFailure {
+    return selectByWhereClause(where, 0);
+  }
+
+  /**
+   * select-Operator liefert eine EntityListe mit den gematchten Datens?tzen zur?ck.
+   * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.
+   *
+   * @param whereClause where-Clause
+   * @param offset ab welchem Datensatz.
+   * @return EntityList mit den gematchten Entities
+   * @exception StorageObjectFailure
+   */
+  public EntityList selectByWhereClause(String whereClause, int offset) throws StorageObjectFailure {
+    return selectByWhereClause(whereClause, null, offset);
+  }
+
+  /**
+   * select-Operator liefert eine EntityListe mit den gematchten Datens?tzen zur?ck.
+   * Also offset wird der erste Datensatz genommen.
+   * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.
+   *
+   * @param where where-Clause
+   * @param order orderBy-Clause
+   * @return EntityList mit den gematchten Entities
+   * @exception StorageObjectFailure
+   */
+  public EntityList selectByWhereClause(String where, String order) throws StorageObjectFailure {
+    return selectByWhereClause(where, order, 0);
+  }
+
+  public EntityList selectByWhereClause(String mainTablePrefix, List extraTables, String where, String order) throws StorageObjectFailure {
+    return selectByWhereClause(mainTablePrefix, extraTables, where, order, 0, defaultLimit);
+  }
+
+  /**
+   * select-Operator liefert eine EntityListe mit den gematchten Datens?tzen zur?ck.
+   * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.
+   *
+   * @param whereClause where-Clause
+   * @param orderBy orderBy-Clause
+   * @param offset ab welchem Datensatz
+   * @return EntityList mit den gematchten Entities
+   * @exception StorageObjectFailure
+   */
+  public EntityList selectByWhereClause(String whereClause, String orderBy, int offset) throws StorageObjectFailure {
+    return selectByWhereClause(whereClause, orderBy, offset, defaultLimit);
+  }
+
+  /**
+   * select-Operator returns EntityList with matching rows in Database.
+   * @param aWhereClause where-Clause
+   * @param anOrderByClause orderBy-Clause
+   * @param offset ab welchem Datensatz
+   * @param limit wieviele Datens?tze
+   * @return EntityList mit den gematchten Entities
+   * @exception StorageObjectFailure
+   */
+  public EntityList selectByWhereClause(String aWhereClause, String anOrderByClause,
+            int offset, int limit) throws StorageObjectFailure {
+    return selectByWhereClause("", null, aWhereClause, anOrderByClause, offset, limit);
+  }
+
+
+  /**
+   * select-Operator returns EntityList with matching rows in Database.
+   * @param aWhereClause where-Clause
+   * @param anOrderByClause orderBy-Clause
+   * @param offset ab welchem Datensatz
+   * @param limit wieviele Datens?tze
+   * @return EntityList mit den gematchten Entities
+   * @exception StorageObjectFailure
+   */
+  public EntityList selectByWhereClause(String mainTablePrefix, List extraTables,
+      String aWhereClause, String anOrderByClause,
+                       int offset, int limit) throws StorageObjectFailure {
+
+    // TODO get rid of emtpy Strings in extraTables
+    // make extraTables null, if single empty String in it
+    // cause StringUtil.splitString puts in emptyString
+    if (extraTables != null && ((String)extraTables.get(0)).trim().equals(""))
+      {
+        logger.debug("+++ made extraTables to null!");
+        extraTables=null;
+      }
+
+      String useTable = mainTable;
+          String selectStar = "*";
+          if (mainTablePrefix!=null && mainTablePrefix.trim().length()>0) {
+            useTable+=" "+mainTablePrefix;
+            selectStar=mainTablePrefix.trim() + ".*";
+          }
+
+    // check o_store for entitylist
+    // only if no relational select
+    if (extraTables==null) {
+      if (StoreUtil.extendsStorableEntity(theEntityClass)) {
+         StoreIdentifier searchSid = new StoreIdentifier(theEntityClass,
+               StoreContainerType.STOC_TYPE_ENTITYLIST,
+               StoreUtil.getEntityListUniqueIdentifierFor(mainTable,
+                aWhereClause, anOrderByClause, offset, limit));
+         EntityList hit = (EntityList) o_store.use(searchSid);
+
+         if (hit != null) {
+            return hit;
+         }
+      }
+    }
+
+    // local
+    EntityList theReturnList = null;
+    Connection con = null;
+    Statement stmt = null;
+    ResultSet rs;
+    int offsetCount = 0;
+    int count = 0;
+
+    // build sql-statement
+
+    if ((aWhereClause != null) && (aWhereClause.trim().length() == 0)) {
+      aWhereClause = null;
+    }
+
+    StringBuffer countSql =
+      new StringBuffer("select count(*) from ").append(useTable);
+    StringBuffer selectSql =
+      new StringBuffer("select "+selectStar+" from ").append(useTable);
+
+    // append extratables, if necessary
+    if (extraTables!=null) {
+      for (int i=0;i < extraTables.size();i++) {
+        if (!extraTables.get(i).equals("")) {
+          countSql.append( ", " + extraTables.get(i));
+          selectSql.append( ", " + extraTables.get(i));
+        }
+      }
+    }
+
+    if (aWhereClause != null) {
+      selectSql.append(" where ").append(aWhereClause);
+      countSql.append(" where ").append(aWhereClause);
+    }
+
+    if ((anOrderByClause != null) && !(anOrderByClause.trim().length() == 0)) {
+      selectSql.append(" order by ").append(anOrderByClause);
+    }
+
+    if ((limit > -1) && (offset > -1)) {
+      selectSql.append(" LIMIT ").append(limit).append(" OFFSET ").append(offset);
+    }
+
+    // execute sql
+    try {
+      con = obtainConnection();
+      stmt = con.createStatement();
+
+      // selecting...
+      rs = executeSql(stmt, selectSql.toString());
+
+      if (rs != null) {
+        if (!evaluatedMetaData) {
+          evalMetaData(rs.getMetaData());
+        }
+
+        theReturnList = new EntityList();
+        Entity theResultEntity;
+        while (rs.next()) {
+          theResultEntity = makeEntityFromResultSet(rs);
+          theReturnList.add(theResultEntity);
+          offsetCount++;
+        }
+        rs.close();
+      }
+
+      // making entitylist infos
+      count = offsetCount;
+
+      if (theReturnList != null) {
+        // now we decide if we have to know an overall count...
+        count = offsetCount;
+
+        if ((limit > -1) && (offset > -1)) {
+          if (offsetCount == limit) {
+            rs = executeSql(stmt, countSql.toString());
+
+            if (rs != null) {
+              if (rs.next()) {
+                count = rs.getInt(1);
+              }
+
+              rs.close();
+            }
+            else {
+              logger.error("Could not count: " + countSql);
+            }
+          }
+        }
+
+        theReturnList.setCount(count);
+        theReturnList.setOffset(offset);
+        theReturnList.setWhere(aWhereClause);
+        theReturnList.setOrder(anOrderByClause);
+        theReturnList.setStorage(this);
+        theReturnList.setLimit(limit);
+
+        if (offset >= limit) {
+          theReturnList.setPrevBatch(offset - limit);
+        }
+
+        if ((offset + offsetCount) < count) {
+          theReturnList.setNextBatch(offset + limit);
+        }
+
+        if (extraTables==null && StoreUtil.extendsStorableEntity(theEntityClass)) {
+          StoreIdentifier sid = theReturnList.getStoreIdentifier();
+          logger.debug("CACHE (add): " + sid.toString());
+          o_store.add(sid);
+        }
+      }
+    }
+    catch (SQLException sqe) {
+      throwSQLException(sqe, "selectByWhereClause");
+    }
+    finally {
+      try {
+        if (con != null) {
+          freeConnection(con, stmt);
+        }
+      } catch (Throwable t) {
+      }
+    }
+
+    return theReturnList;
+  }
+
+  /**
+   *  Bastelt aus einer Zeile der Datenbank ein EntityObjekt.
+   *
+   *  @param rs Das ResultSetObjekt.
+   *  @return Entity Die Entity.
+   */
+  private Entity makeEntityFromResultSet(ResultSet rs)
+    throws StorageObjectFailure {
+    Map theResultHash = new HashMap();
+    String theResult = null;
+    int theType;
+    Entity returnEntity = null;
+
+    try {
+      if (StoreUtil.extendsStorableEntity(theEntityClass)) {
+         StoreIdentifier searchSid = StorableObjectEntity.getStoreIdentifier(this,
+               theEntityClass, rs);
+         Entity hit = (Entity) o_store.use(searchSid);
+         if (hit != null) return hit;
+      }
+
+
+      int size = metadataFields.size();
+
+      for (int i = 0; i < size; i++) {
+        // alle durchlaufen bis nix mehr da
+        theType = metadataTypes[i];
+
+        if (theType == java.sql.Types.LONGVARBINARY) {
+          InputStreamReader is =
+            (InputStreamReader) rs.getCharacterStream(i + 1);
+
+          if (is != null) {
+            char[] data = new char[32768];
+            StringBuffer theResultString = new StringBuffer();
+            int len;
+
+            while ((len = is.read(data)) > 0) {
+              theResultString.append(data, 0, len);
+            }
+
+            is.close();
+            theResult = theResultString.toString();
+          } else {
+            theResult = null;
+          }
+        } else {
+          theResult = getValueAsString(rs, (i + 1), theType);
+        }
+
+        if (theResult != null) {
+          theResultHash.put(metadataFields.get(i), theResult);
+        }
+      }
+
+      if (theEntityClass != null) {
+        returnEntity = (Entity) theEntityClass.newInstance();
+        returnEntity.setStorage(this);
+        returnEntity.setFieldValues(theResultHash);
+
+        if (returnEntity instanceof StorableObject) {
+          logger.debug("CACHE: ( in) " + returnEntity.getId() + " :" + mainTable);
+          o_store.add(((StorableObject) returnEntity).getStoreIdentifier());
+        }
+      } else {
+        throwStorageObjectException("Internal Error: theEntityClass not set!");
+      }
+    }
+    catch (IllegalAccessException e) {
+      throwStorageObjectException("No access! -- " + e.getMessage());
+    }
+    catch (IOException e) {
+      throwStorageObjectException("IOException! -- " + e.getMessage());
+    }
+    catch (InstantiationException e) {
+      throwStorageObjectException("No Instatiation! -- " + e.getMessage());
+    }
+    catch (SQLException sqe) {
+      throwSQLException(sqe, "makeEntityFromResultSet");
+
+      return null;
+    }
+
+    return returnEntity;
+  }
+
+  /**
+   * Inserts an entity into the database.
+   *
+   * @param theEntity
+   * @return der Wert des Primary-keys der eingef?gten Entity
+   */
+  public String insert(Entity theEntity) throws StorageObjectFailure {
+    invalidateStore();
+
+    String returnId = null;
+    Connection con = null;
+    PreparedStatement pstmt = null;
+
+    try {
+      StringBuffer f = new StringBuffer();
+      StringBuffer v = new StringBuffer();
+      String aField;
+      String aValue;
+      boolean firstField = true;
+
+      // make sql-string
+      for (int i = 0; i < getFields().size(); i++) {
+        aField = (String) getFields().get(i);
+
+        if (!aField.equals(primaryKeyField)) {
+          aValue = null;
+
+          // exceptions
+          if (!theEntity.hasFieldValue(aField) && (
+              aField.equals("webdb_create") ||
+              aField.equals("webdb_lastchange"))) {
+            aValue = "NOW()";
+          }
+          else {
+              if (theEntity.hasFieldValue(aField)) {
+                aValue =
+                  "'" +
+                   JDBCStringRoutines.escapeStringLiteral(theEntity.getFieldValue(aField)) + "'";
+              }
+          }
+
+          // wenn Wert gegeben, dann einbauen
+          if (aValue != null) {
+            if (firstField == false) {
+              f.append(",");
+              v.append(",");
+            }
+            else {
+              firstField = false;
+            }
+
+            f.append(aField);
+            v.append(aValue);
+          }
+        }
+      }
+       // end for
+
+      // insert into db
+      StringBuffer sqlBuf =
+        new StringBuffer("insert into ").append(mainTable).append("(").append(f)
+                                        .append(") values (").append(v).append(")");
+      String sql = sqlBuf.toString();
+
+      logger.info("INSERT: " + sql);
+      con = obtainConnection();
+      con.setAutoCommit(false);
+      pstmt = con.prepareStatement(sql);
+
+      int ret = pstmt.executeUpdate();
+
+      if (ret == 0) {
+        //insert failed
+        return null;
+      }
+
+//      pstmt = con.prepareStatement("select currval('" +  + "_id_seq')");
+
+      returnId = getLatestInsertedId(con);
+      theEntity.setId(returnId);
+    }
+    catch (SQLException sqe) {
+      throwSQLException(sqe, "insert");
+    }
+    finally {
+      try {
+        con.setAutoCommit(true);
+      }
+      catch (Exception e) {
+      }
+
+      freeConnection(con, pstmt);
+    }
+
+    /** todo store entity in o_store */
+    return returnId;
+  }
+
+  /**
+   * Updates an entity in the database
+   *
+   * @param theEntity
+   */
+  public void update(Entity theEntity) throws StorageObjectFailure {
+    Connection con = null;
+    PreparedStatement pstmt = null;
+
+    /** todo this is stupid: why do we prepare statement, when we
+     *  throw it away afterwards. should be regular statement
+     *  update/insert could better be one routine called save()
+     *  that chooses to either insert or update depending if we
+     *  have a primary key in the entity. i don't know if we
+     *  still need the streamed input fields. // rk  */
+
+    /** todo extension: check if Entity did change, otherwise we don't need
+     *  the roundtrip to the database */
+    /** invalidating corresponding entitylists in o_store*/
+
+    invalidateStore();
+
+    String id = theEntity.getId();
+    String aField;
+    StringBuffer fv = new StringBuffer();
+    boolean firstField = true;
+
+    // build sql statement
+    for (int i = 0; i < getFields().size(); i++) {
+      aField = (String) metadataFields.get(i);
+
+      // only normal cases
+      // todo if entity.hasFieldValue returns false, then the value should be stored as null
+      if (!(aField.equals(primaryKeyField) ||
+            aField.equals("webdb_create") ||
+            aField.equals("webdb_lastchange"))) {
+        if (theEntity.hasFieldValue(aField)) {
+          if (firstField == false) {
+            fv.append(", ");
+          }
+          else {
+            firstField = false;
+          }
+
+          fv.append(aField).append("='").append(JDBCStringRoutines.escapeStringLiteral(theEntity.getFieldValue(aField))).append("'");
+
+          //              fv.append(aField).append("='").append(StringUtil.quote((String)theEntity.getFieldValue(aField))).append("'");
+        }
+      }
+    }
+
+    StringBuffer sql =
+      new StringBuffer("update ").append(mainTable).append(" set ").append(fv);
+
+    // exceptions
+    if (metadataFields.contains("webdb_lastchange")) {
+      sql.append(",webdb_lastchange=NOW()");
+    }
+
+    // special case: the webdb_create requires the field in yyyy-mm-dd HH:mm
+    // format so anything extra will be ignored. -mh
+    if (metadataFields.contains("webdb_create") &&
+        theEntity.hasFieldValue("webdb_create")) {
+      // minimum of 10 (yyyy-mm-dd)...
+      if (theEntity.getFieldValue("webdb_create").length() >= 10) {
+        String dateString = theEntity.getFieldValue("webdb_create");
+
+        // if only 10, then add 00:00 so it doesn't throw a ParseException
+        if (dateString.length() == 10) {
+          dateString = dateString + " 00:00";
+        }
+
+        // TimeStamp stuff
+        try {
+          java.util.Date d = userInputDateFormat.parse(dateString);
+//          Timestamp tStamp = new Timestamp(d.getTime());
+          sql.append(",webdb_create='" + JDBCStringRoutines.formatDate(d) + "'");
+        }
+        catch (ParseException e) {
+          throw new StorageObjectFailure(e);
+        }
+      }
+    }
+
+    sql.append(" where id=").append(id);
+    logger.info("UPDATE: " + sql);
+
+    try {
+      con = obtainConnection();
+      con.setAutoCommit(false);
+      pstmt = con.prepareStatement(sql.toString());
+
+      pstmt.executeUpdate();
+    }
+    catch (SQLException sqe) {
+      throwSQLException(sqe, "update");
+    }
+    finally {
+      try {
+        con.setAutoCommit(true);
+      }
+      catch (Exception e) {
+        ;
+      }
+
+      freeConnection(con, pstmt);
+    }
+  }
+
+  /*
+  *   delete-Operator
+  *   @param id des zu loeschenden Datensatzes
+  *   @return boolean liefert true zurueck, wenn loeschen erfolgreich war.
+   */
+  public boolean delete(String id) throws StorageObjectFailure {
+    // ostore send notification
+    if (StoreUtil.extendsStorableEntity(theEntityClass)) {
+      String uniqueId = id;
+
+      if (theEntityClass.equals(StorableObjectEntity.class)) {
+        uniqueId += ("@" + mainTable);
+      }
+
+      logger.debug("CACHE: (del) " + id);
+
+      StoreIdentifier search_sid =
+        new StoreIdentifier(theEntityClass,
+          StoreContainerType.STOC_TYPE_ENTITY, uniqueId);
+      o_store.invalidate(search_sid);
+    }
+
+    /** todo could be prepared Statement */
+    Statement stmt = null;
+    Connection con = null;
+    int res = 0;
+    String sql =
+      "delete from " + mainTable + " where " + primaryKeyField + "='" + id + "'";
+
+    logger.debug("DELETE " + sql);
+    try {
+      con = obtainConnection();
+      stmt = con.createStatement();
+      res = stmt.executeUpdate(sql);
+    }
+    catch (SQLException sqe) {
+      throwSQLException(sqe, "delete");
+    }
+    finally {
+      freeConnection(con, stmt);
+    }
+
+    invalidateStore();
+
+    return (res > 0) ? true : false;
+  }
+
+  /**
+   * Deletes entities based on a where clause
+   *
+   * @param aWhereClause
+   * @return
+   * @throws StorageObjectFailure
+   */
+  public int deleteByWhereClause(String aWhereClause) throws StorageObjectFailure {
+    invalidateStore();
+
+    Statement stmt = null;
+    Connection con = null;
+    int res = 0;
+    String sql =
+      "delete from " + mainTable + " where " + aWhereClause;
+
+    //theLog.printInfo("DELETE " + sql);
+    try {
+      con = obtainConnection();
+      stmt = con.createStatement();
+      res = stmt.executeUpdate(sql);
+    }
+    catch (SQLException sqe) {
+      throwSQLException(sqe, "delete");
+    }
+    finally {
+      freeConnection(con, stmt);
+    }
+
+    return res;
+  }
+
+  /* noch nicht implementiert.
+  * @return immer false
+   */
+  public boolean delete(EntityList theEntityList) {
+    return false;
+  }
+
+  /**
+   * Diese Methode fuehrt den Sqlstring <i>sql</i> aus und timed im Logfile.
+   * @param stmt Statemnt
+   * @param sql Sql-String
+   */
+  public ResultSet executeSql(Statement stmt, String sql)
+                            throws StorageObjectFailure, SQLException {
+    ResultSet rs;
+    long startTime = System.currentTimeMillis();
+
+    try {
+      rs = stmt.executeQuery(sql);
+
+      logger.info((System.currentTimeMillis() - startTime) + "ms. for: " + sql);
+    }
+    catch (SQLException e) {
+      logger.error(e.getMessage() +"\n" + (System.currentTimeMillis() - startTime) + "ms. for: " + sql);
+      throw e;
+    }
+
+    return rs;
+  }
+
+  private Map processRow(ResultSet aResultSet) throws StorageObjectFailure {
+    try {
+      Map result = new HashMap();
+      ResultSetMetaData metaData = aResultSet.getMetaData();
+      int nrColumns = metaData.getColumnCount();
+      for (int i=0; i<nrColumns; i++) {
+        result.put(metaData.getColumnName(i+1), getValueAsString(aResultSet, i+1, metaData.getColumnType(i+1)));
+      }
+
+      return result;
+    }
+    catch (Throwable e) {
+      throw new StorageObjectFailure(e);
+    }
+  }
+
+  public List executeFreeSql(String sql, int aLimit) throws StorageObjectFailure, StorageObjectExc {
+    Connection connection = null;
+    Statement statement = null;
+    try {
+      List result = new ArrayList();
+      connection = obtainConnection();
+      statement = connection.createStatement();
+      ResultSet resultset = executeSql(statement, sql);
+      try {
+        while (resultset.next() && result.size() < aLimit) {
+          result.add(processRow(resultset));
+        }
+      }
+      finally {
+        resultset.close();
+      }
+
+      return result;
+    }
+    catch (Throwable e) {
+      throw new StorageObjectFailure(e);
+    }
+    finally {
+      if (connection!=null) {
+        freeConnection(connection, statement);
+      }
+    }
+  };
+
+  public Map executeFreeSingleRowSql(String anSqlStatement) throws StorageObjectFailure, StorageObjectExc {
+    try {
+      List resultList = executeFreeSql(anSqlStatement, 1);
+      try {
+        if (resultList.size()>0)
+          return (Map) resultList.get(0);
+        else
+          return null;
+      }
+      finally {
+      }
+    }
+    catch (Throwable t) {
+      throw new StorageObjectFailure(t);
+    }
+  };
+
+  public String executeFreeSingleValueSql(String sql) throws StorageObjectFailure, StorageObjectExc {
+    Map row = executeFreeSingleRowSql(sql);
+
+    if (row==null)
+      return null;
+
+    Iterator i = row.values().iterator();
+    if (i.hasNext())
+      return (String) i.next();
+    else
+      return null;
+  };
+
+  public int getSize(String where) throws SQLException, StorageObjectFailure {
+    return getSize("", null, where);
+  }
+  /**
+   * returns the number of rows in the table
+   */
+  public int getSize(String mainTablePrefix, List extraTables, String where) throws SQLException, StorageObjectFailure {
+
+    long startTime = System.currentTimeMillis();
+
+    String useTable = mainTable;
+    if (mainTablePrefix!=null && mainTablePrefix.trim().length()>0) {
+          useTable+=" "+mainTablePrefix;
+    }
+    StringBuffer countSql =
+      new StringBuffer("select count(*) from ").append(useTable);
+        // append extratables, if necessary
+      if (extraTables!=null) {
+        for (int i=0;i < extraTables.size();i++) {
+          if (!extraTables.get(i).equals("")) {
+            countSql.append( ", " + extraTables.get(i));
+          }
+        }
+      }
+
+    if ((where != null) && (where.length() != 0)) {
+      countSql.append( " where " + where);
+    }
+
+    Connection con = null;
+    Statement stmt = null;
+    int result = 0;
+
+    try {
+      con = obtainConnection();
+      stmt = con.createStatement();
+
+      ResultSet rs = executeSql(stmt, countSql.toString());
+
+      while (rs.next()) {
+        result = rs.getInt(1);
+      }
+    }
+    catch (SQLException e) {
+      logger.error("Database.getSize: " + e.getMessage());
+    }
+    finally {
+      freeConnection(con, stmt);
+    }
+    logger.info((System.currentTimeMillis() - startTime) + "ms. for: " + countSql);
+
+    return result;
+  }
+
+  public int executeUpdate(Statement stmt, String sql)
+    throws StorageObjectFailure, SQLException {
+    int rs;
+    long startTime = System.currentTimeMillis();
+
+    try {
+      rs = stmt.executeUpdate(sql);
+
+      logger.info((System.currentTimeMillis() - startTime) + "ms. for: " + sql);
+    }
+    catch (SQLException e) {
+      logger.error("Failed: " + (System.currentTimeMillis() - startTime) + "ms. for: " + sql);
+      throw e;
+    }
+
+    return rs;
+  }
+
+  public int executeUpdate(String sql)
+    throws StorageObjectFailure, SQLException {
+    int result = -1;
+    long startTime = System.currentTimeMillis();
+    Connection con = null;
+    PreparedStatement pstmt = null;
+
+    try {
+      con = obtainConnection();
+      pstmt = con.prepareStatement(sql);
+      result = pstmt.executeUpdate();
+    }
+    catch (Throwable e) {
+      logger.error("Database.executeUpdate(" + sql + "): " + e.getMessage());
+      throw new StorageObjectFailure("Database.executeUpdate(" + sql + "): " + e.getMessage(), e);
+    }
+    finally {
+      freeConnection(con, pstmt);
+    }
+
+    logger.info((System.currentTimeMillis() - startTime) + "ms. for: " + sql);
+    return result;
+  }
+
+  /**
+   * Wertet ResultSetMetaData aus und setzt interne Daten entsprechend
+   * @param md ResultSetMetaData
+   */
+  private void evalMetaData(ResultSetMetaData md) throws StorageObjectFailure {
+    this.evaluatedMetaData = true;
+    this.metadataFields = new ArrayList();
+    this.metadataLabels = new ArrayList();
+    this.metadataNotNullFields = new ArrayList();
+
+    try {
+      int numFields = md.getColumnCount();
+      this.metadataTypes = new int[numFields];
+
+      String aField;
+      int aType;
+
+      for (int i = 1; i <= numFields; i++) {
+        aField = md.getColumnName(i);
+        metadataFields.add(aField);
+        metadataLabels.add(md.getColumnLabel(i));
+        aType = md.getColumnType(i);
+        metadataTypes[i - 1] = aType;
+
+        if (aField.equals(primaryKeyField)) {
+        }
+
+        if (md.isNullable(i) == ResultSetMetaData.columnNullable) {
+          metadataNotNullFields.add(aField);
+        }
+      }
+    }
+    catch (SQLException e) {
+      throwSQLException(e, "evalMetaData");
+    }
+  }
+
+  /**
+   *  Wertet die Metadaten eines Resultsets fuer eine Tabelle aus,
+   *  um die alle Columns und Typen einer Tabelle zu ermitteln.
+   */
+  private void get_meta_data() throws StorageObjectFailure {
+    Connection con = null;
+    PreparedStatement pstmt = null;
+    String sql = "select * from " + mainTable + " where 0=1";
+
+    try {
+      con = obtainConnection();
+      pstmt = con.prepareStatement(sql);
+
+      logger.debug("METADATA: " + sql);
+      ResultSet rs = pstmt.executeQuery();
+      evalMetaData(rs.getMetaData());
+      rs.close();
+    }
+    catch (SQLException e) {
+      throwSQLException(e, "get_meta_data");
+    }
+    finally {
+      freeConnection(con, pstmt);
+    }
+  }
+
+  public Connection obtainConnection() throws StorageObjectFailure {
+    try {
+      return MirGlobal.getDatabaseEngine().obtainConnection();
+    }
+    catch (Exception e) {
+      throw new StorageObjectFailure(e);
+    }
+  }
+
+  public void freeConnection(Connection aConnection, Statement aStatement) throws StorageObjectFailure {
+    try {
+      aStatement.close();
+    }
+    catch (Throwable t) {
+      logger.warn("Can't close statemnet: " + t.toString());
+    }
+
+    try {
+      MirGlobal.getDatabaseEngine().releaseConnection(aConnection);
+    }
+    catch (Throwable t) {
+      logger.warn("Can't release connection: " + t.toString());
+    }
+  }
+
+  /**
+   * Wertet SQLException aus und wirft dannach eine StorageObjectException
+   * @param sqe SQLException
+   * @param aFunction Funktonsname, in der die SQLException geworfen wurde
+   */
+  protected void throwSQLException(SQLException sqe, String aFunction) throws StorageObjectFailure {
+    String state = "";
+    String message = "";
+    int vendor = 0;
+
+    if (sqe != null) {
+      state = sqe.getSQLState();
+      message = sqe.getMessage();
+      vendor = sqe.getErrorCode();
+    }
+
+    String information =
+        "SQL Error: " +
+        "state= " + state +
+        ", vendor= " + vendor +
+        ", message=" + message +
+        ", function= " + aFunction;
+
+    logger.error(information);
+
+    throw new StorageObjectFailure(information, sqe);
+  }
+
+  protected void _throwStorageObjectException(Exception e, String aFunction)
+    throws StorageObjectFailure {
+
+    if (e != null) {
+      logger.error(e.getMessage() + aFunction);
+      throw new StorageObjectFailure(aFunction, e);
+    }
+  }
+
+  /**
+   * Loggt Fehlermeldung mit dem Parameter Message und wirft dannach
+   * eine StorageObjectException
+   * @param aMessage Nachricht mit dem Fehler
+   * @exception StorageObjectFailure
+   */
+  void throwStorageObjectException(String aMessage) throws StorageObjectFailure {
+    logger.error(aMessage);
+    throw new StorageObjectFailure(aMessage, null);
+  }
+
+  /**
+   * Invalidates any cached entity list
+   */
+  private void invalidateStore() {
+    // invalidating all EntityLists corresponding with theEntityClass
+    if (StoreUtil.extendsStorableEntity(theEntityClass)) {
+      StoreContainerType stoc_type =
+        StoreContainerType.valueOf(theEntityClass, StoreContainerType.STOC_TYPE_ENTITYLIST);
+      o_store.invalidate(stoc_type);
+    }
+  }
+
+  /**
+   * Retrieves a binary value
+   */
+  public InputStream getBinaryField(String aQuery) throws StorageObjectFailure, SQLException {
+    Connection connection=null;
+    Statement statement=null;
+    InputStream inputStream;
+    InputStream imageInputStream = null;
+
+    try {
+      connection = obtainConnection();
+      try {
+        connection.setAutoCommit(false);
+        statement = connection.createStatement();
+        ResultSet resultSet = executeSql(statement, aQuery);
+
+        if(resultSet!=null) {
+          if (resultSet.next()) {
+            inputStream = resultSet.getBlob(1).getBinaryStream();
+            imageInputStream = new BinaryFieldInputStream(inputStream, connection, statement);
+          }
+          resultSet.close();
+        }
+      }
+      finally {
+      }
+    }
+    catch (Throwable t) {
+      logger.error("EntityImages.getImage failed: " + t.toString());
+      t.printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
+
+      try {
+        connection.setAutoCommit(true);
+      }
+      catch (Throwable e) {
+        logger.error("EntityImages.getImage resetting transaction mode failed: " + e.toString());
+        e.printStackTrace(logger.asPrintWriter(LoggerWrapper.DEBUG_MESSAGE));
+      }
+
+      try {
+        freeConnection(connection, statement);
+      }
+      catch (Throwable e) {
+        logger.error("EntityImages.getImage freeing connection failed: " +e.toString());
+      }
+
+      throw new StorageObjectFailure(t);
+    }
+
+    return imageInputStream;
+  }
+
+  /**
+   * Sets a binary value. The query is supposed to contain 1 ? denoting where the
+   * binary value should be inserted.
+   *
+   * e.g. <code>update images set image_data = ? where id= 22</code>
+   */
+  public void setBinaryField(String aQuery, byte aData[]) throws StorageObjectFailure, SQLException {
+    PreparedStatement statement = null;
+    Connection connection = obtainConnection();
+    try {
+      connection.setAutoCommit(false);
+      try {
+        statement = connection.prepareStatement(aQuery);
+        statement.setBinaryStream(1, new ByteArrayInputStream(aData), aData.length);
+        statement.execute();
+        connection.commit();
+      }
+      finally {
+        connection.setAutoCommit(true);
+      }
+    }
+    finally {
+      freeConnection(connection, statement);
+    }
+  }
+
+  /**
+   * a small wrapper class that allows us to store the DB connection resources
+   * that the BlobInputStream is using and free them upon closing of the stream
+   */
+  private class BinaryFieldInputStream extends InputStream {
+    InputStream inputStream;
+    Connection connection;
+    Statement statement;
+
+    public BinaryFieldInputStream(InputStream aBlobInputStream, Connection aConnection, Statement aStatement ) {
+      inputStream = aBlobInputStream;
+      connection = aConnection;
+      statement = aStatement;
+    }
+
+    public void close () throws IOException {
+      inputStream.close();
+      try {
+        connection.setAutoCommit(true);
+        freeConnection(connection, statement);
+      }
+      catch (Exception e) {
+        throw new IOException("close(): "+e.toString());
+      }
+    }
+
+    public int read() throws IOException {
+      return inputStream.read();
+    }
+  }
 }
index 921ce85..c716a0f 100755 (executable)
@@ -35,208 +35,82 @@ import java.sql.SQLException;
 import java.sql.Statement;
 import java.util.List;
 import java.util.Map;
+import java.io.InputStream;
 
 import mir.entity.Entity;
 import mir.entity.EntityList;
 
-
 /**
- * Implementiert Interface f?r die Speicherschicht.
- * Bislang gibt es in der Bibliothek nur die M?glichkeit
- * in einer Datenbank zu speichern.
- * @author RK
- * @version        29.6.1999
+ * Interface for low-level database actions.
  */
+
 public interface StorageObject {
-  /**
-   * Dokumentation siehe Database.java
-   * @param id
-   * @return Entity
-   * @exception StorageObjectException
-   */
-  abstract public Entity selectById(String id) throws StorageObjectExc;
+  public Entity selectById(String id) throws StorageObjectExc;
 
-  /**
-   * Dokumentation siehe Database.java
-   * @param aField
-   * @param aValue
-   * @return EntityList
-   * @exception StorageObjectException
-   */
-  abstract public EntityList selectByFieldValue(String aField, String aValue)
-    throws StorageObjectFailure;
+  public EntityList selectByFieldValue(String aField, String aValue) throws StorageObjectFailure;
 
-  /**
-   * Dokumentation siehe Database.java
-   * @param whereClause
-   * @return EntityList
-   * @exception StorageObjectException
-   */
-  abstract public EntityList selectByWhereClause(String whereClause)
-    throws StorageObjectFailure;
+  public EntityList selectByWhereClause(String whereClause) throws StorageObjectFailure;
 
-  /**
-   * Dokumentation siehe Database.java
-   * @param whereClause
-   * @param offset
-   * @return EntityList
-   * @exception StorageObjectException
-   */
-  abstract public EntityList selectByWhereClause(String whereClause, int offset)
-    throws StorageObjectFailure;
+  public EntityList selectByWhereClause(String whereClause, int offset) throws StorageObjectFailure;
 
-  /**
-   * Dokumentation siehe Database.java
-   * @param whereClause
-   * @param orderBy
-   * @param offset
-   * @return EntityList
-   * @exception StorageObjectException
-   */
-  abstract public EntityList selectByWhereClause(String whereClause,
-    String orderBy, int offset) throws StorageObjectFailure;
+  public EntityList selectByWhereClause(String whereClause, String orderBy, int offset) throws StorageObjectFailure;
 
-  /**
-   * Dokumentation siehe Database.java
-   * @param whereClause
-   * @param orderBy
-   * @param offset
-   * @param limit
-   * @return EntityList
-   * @exception StorageObjectException
-   */
-  abstract public EntityList selectByWhereClause(String whereClause,
-    String orderBy, int offset, int limit) throws StorageObjectFailure;
+  public EntityList selectByWhereClause(String whereClause, String orderBy, int offset, int limit) throws StorageObjectFailure;
 
-  /**
-   * Dokumentation siehe Database.java
-   * @param id
-   * @return boolen
-   * @exception StorageObjectException
-   */
-  abstract public boolean delete(String id) throws StorageObjectFailure;
+  public EntityList selectByWhereClause(String mainTablePrefix, List extraTables, String aWhereClause, String anOrderByClause, int offset, int limit) throws StorageObjectFailure;
+
+  public boolean delete(String id) throws StorageObjectFailure;
 
   /**
    * Deletes entities based on a where clause
-   *
-   * @param aWhereClause
-   * @return
-   * @throws StorageObjectFailure
    */
   public int deleteByWhereClause(String aWhereClause) throws StorageObjectFailure;
 
-  /**
-   * Dokumentation siehe Database.java
-   * @return ArrayList
-   * @exception StorageObjectException
-   */
-  abstract public List getFields() throws StorageObjectFailure;
-
-  /**
-   * Dokumentation siehe Database.java
-   * @return int[]
-   * @exception StorageObjectException
-   */
-  abstract public int[] getTypes() throws StorageObjectFailure;
-
-  /**
-   * Dokumentation siehe Database.java
-   * @return ArrayList
-   * @exception StorageObjectException
-   */
-  abstract public List getLabels() throws StorageObjectFailure;
+  public List getFields() throws StorageObjectFailure;
 
-  /**
-   * Dokumentation siehe Database.java
-   * @param a
-   * @exception StorageObjectException
-   */
-  abstract public void update(Entity a) throws StorageObjectFailure;
+  public void update(Entity a) throws StorageObjectFailure;
 
-  /**
-   * Dokumentation siehe Database.java
-   * @param a
-   * @return String id
-   * @exception StorageObjectException
-   */
-  abstract public String insert(Entity a) throws StorageObjectFailure;
+  public String insert(Entity a) throws StorageObjectFailure;
 
-  /**
-   * Dokumentation siehe Database.java
-   * @return Class Klasse der Entity
-   */
-  abstract public Class getEntityClass();
+  public Class getEntityClass();
 
-  /**
-   * put your documentation comment here
-   * @return
-   */
-  abstract public String getIdName();
+  public String getIdName();
 
-  /**
-   * Dokumentation siehe Database.java
-   * @return String
-   */
-  abstract public String getTableName();
+  public String getTableName();
 
-  /**
-   * Dokumentation siehe Database.java
-   * @return Connection
-   * @exception StorageObjectException
-   */
-  abstract public Connection getPooledCon() throws StorageObjectFailure;
+  public Connection obtainConnection() throws StorageObjectFailure;
 
-  /**
-   *
-   * @param a
-   * @param sql
-   * @return
-   * @throws StorageObjectFailure
-   * @throws SQLException
-   */
-  abstract public ResultSet executeSql(Statement a, String sql) throws StorageObjectFailure, SQLException;
+  public ResultSet executeSql(Statement a, String sql) throws StorageObjectFailure, SQLException;
 
   /**
-   * Executes 1 sql statement and returns the results as a <code>List</code> of <code>Map</code>s
-   *
-   * @param sql
-   * @return
-   * @throws StorageObjectFailure
-   * @throws StorageObjectExc
+   * Executes 1 sql statement and returns the results as a <code>List</code> of
+   * <code>Map</code>s
    */
-  abstract public List executeFreeSql(String sql, int aLimit) throws StorageObjectFailure, StorageObjectExc;
+  public List executeFreeSql(String sql, int aLimit) throws StorageObjectFailure, StorageObjectExc;
 
   /**
    * Executes 1 sql statement and returns the first result row as a <<code>Map</code>s
    * (<code>null</code> if there wasn't any row)
-   *
-   * @param sql
-   * @return
-   * @throws StorageObjectFailure
-   * @throws StorageObjectExc
    */
-  abstract public Map executeFreeSingleRowSql(String sql) throws StorageObjectFailure, StorageObjectExc ;
+  public Map executeFreeSingleRowSql(String sql) throws StorageObjectFailure, StorageObjectExc ;
 
   /**
    * Executes 1 sql statement and returns the first column of the first result row as a <<code>String</code>s
    * (<code>null</code> if there wasn't any row)
-   *
-   * @param sql
-   * @return
-   * @throws StorageObjectFailure
-   * @throws StorageObjectExc
    */
-  abstract public String executeFreeSingleValueSql(String sql) throws StorageObjectFailure, StorageObjectExc ;
+  public String executeFreeSingleValueSql(String sql) throws StorageObjectFailure, StorageObjectExc ;
 
-  /**
-   * @param con
-   * @param stmt
-   */
-  abstract public void freeConnection(Connection con, Statement stmt) throws StorageObjectFailure;
+  public void freeConnection(Connection con, Statement stmt) throws StorageObjectFailure;
+
+  public int executeUpdate(Statement a, String sql) throws StorageObjectFailure, SQLException;
+
+  public int executeUpdate(String sql) throws StorageObjectFailure, SQLException;
+
+  public int getSize(String where) throws SQLException, StorageObjectFailure;
 
-  abstract public int executeUpdate(Statement a, String sql) throws StorageObjectFailure, SQLException;
+  public int getSize(String mainTablePrefix, List extraTables, String where) throws SQLException, StorageObjectFailure;
 
-  abstract public int executeUpdate(String sql) throws StorageObjectFailure, SQLException;
+  public InputStream getBinaryField(String aQuery) throws SQLException, StorageObjectFailure;
 
-  abstract public int getSize(String where) throws SQLException, StorageObjectFailure;
+  public void setBinaryField(String aQuery, byte aData[]) throws StorageObjectFailure, SQLException;
 }
index 72b3400..0c65b1c 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.storage.store;
@@ -62,9 +62,10 @@ package mir.storage.store;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-
+import java.util.MissingResourceException;
 import javax.servlet.http.HttpServletRequest;
 
+import mir.config.MirPropertiesConfiguration;
 import mir.log.LoggerWrapper;
 
 public class ObjectStore {
@@ -72,10 +73,12 @@ public class ObjectStore {
   private final static ObjectStore INSTANCE = new ObjectStore();
   private final static Map containerMap = new HashMap(); // StoreContainerType/StoreContainer
   private static long storeHit = 0, storeMiss = 0;
+  private MirPropertiesConfiguration configuration;
   private LoggerWrapper logger;
 
   private ObjectStore() {
-       logger = new LoggerWrapper("Database");
+    logger = new LoggerWrapper("Database.ObjectStore");
+    configuration = MirPropertiesConfiguration.instance();
   }
 
   public static ObjectStore getInstance() {
@@ -142,14 +145,11 @@ public class ObjectStore {
   }
 
   /**
-   *  Method:       invalidate(StoreContainerType)
-   *  Description:  serves to invalidate a whole StoreContainer
-   *
-   *  @return
+   * serves to invalidate a whole StoreContainer
    */
   public void invalidate(StoreContainerType stoc_type) {
     if (stoc_type != null) {
-      /** @todo invalidates too much:
+      /*  @todo invalidates too much:
        *  improvement: if instanceof StoreContainerEntity && EntityList
        *  then invalidate only StoreIdentifier matching the right table
        */
@@ -190,6 +190,18 @@ public class ObjectStore {
     return (stoc != null && stoc.has(sid)) ? true : false;
   }
 
+  public String getConfProperty(String name) {
+    if (name != null) {
+      try {
+        return configuration.getString(name);
+      }
+      catch (MissingResourceException e) {
+        logger.error("getConfProperty: " + e.toString());
+      }
+    }
+    return null;
+  }
+
   /**
    *  Method:       toString()
    *  Description:  Displays statistical information about the ObjectStore.
index 9ad70f7..dafe141 100755 (executable)
@@ -50,8 +50,6 @@ import java.util.ListIterator;
 
 import javax.servlet.http.HttpServletRequest;
 
-import mir.config.MirPropertiesConfiguration;
-import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;
 import mir.log.LoggerWrapper;
 import mir.misc.StringUtil;
 
@@ -66,8 +64,7 @@ public class StoreContainer {
   private int hitCount = 0, missCount = 0;
   private static ObjectStore o_store = ObjectStore.getInstance();
 
-  protected LoggerWrapper logger = new LoggerWrapper("Database");
-  private MirPropertiesConfiguration configuration;
+  protected LoggerWrapper logger = new LoggerWrapper("Database.ObjectStore");
 
   // avoid construction without parameters
   private StoreContainer() {};
@@ -77,14 +74,9 @@ public class StoreContainer {
     this.uniqueId = ++uniqueCounter;
     this.stocType = stoc_type;
     this.container = new LinkedList();
-    try {
-                       configuration = MirPropertiesConfiguration.instance();
-               } catch (PropertiesConfigExc e) {
-                       e.printStackTrace(logger.asPrintWriter(LoggerWrapper.ERROR_MESSAGE));
-               }
     int defaultSize = stoc_type.getDefaultSize();
     String confProperty = stoc_type.getConfPrefix() + ".DefaultSize";
-    String confedSize = configuration.getString(confProperty);
+    String confedSize = o_store.getConfProperty(confProperty);
     if (confedSize != null) {
       this.maxSize = StringUtil.parseInt(confedSize, defaultSize);
     }
index 9443e08..8e8bbcb 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.storage.store;
@@ -47,9 +47,6 @@ package mir.storage.store;
 import java.util.HashMap;
 import java.util.Map;
 
-import mir.config.MirPropertiesConfiguration;
-import mir.config.MirPropertiesConfiguration.PropertiesConfigExc;
-import mir.log.LoggerWrapper;
 import mir.misc.StringUtil;
 
 public class StoreContainerType {
@@ -63,8 +60,6 @@ public class StoreContainerType {
   private static ObjectStore o_store = ObjectStore.getInstance();
   private Class stocClass = null;
   private int stocType = STOC_TYPE_UNKNOWN;
-  private MirPropertiesConfiguration configuration;
-  private LoggerWrapper logger;
 
   static {
     uniqueTypes[STOC_TYPE_ENTITY] = new HashMap();
@@ -76,12 +71,6 @@ public class StoreContainerType {
   private StoreContainerType(Class stocClass, int stocType) {
     this.stocClass = stocClass;
     this.stocType = stocType;
-    logger = new LoggerWrapper("Database");
-    try {
-                       configuration = MirPropertiesConfiguration.instance();
-               } catch (PropertiesConfigExc e) {
-                       e.printStackTrace(logger.asPrintWriter(LoggerWrapper.ERROR_MESSAGE));
-               }
   }
 
   public static StoreContainerType valueOf(Class stoc_class, int stoc_type) {
@@ -115,7 +104,7 @@ public class StoreContainerType {
     String confProperty = "StoreContainer." + stringForStoreType(stocType) +
         ".DefaultSize";
     return
-        StringUtil.parseInt(configuration.getString(confProperty), 10);
+        StringUtil.parseInt(o_store.getConfProperty(confProperty), 10);
   }
 
   public String toString() {
index 26f8af1..358a5c5 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.storage.store;
index efd8148..f1717e2 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.storage.store;
 
+import mir.entity.StorableObjectEntity;
+
 /**
  * Title:
  * Description:
@@ -67,25 +69,17 @@ public final class StoreUtil {
     return sb.toString();
   }
 
-       /**
-        *  Method:       implementsStorableObject
-        *  Description:  internall helper method to find out if a class implements
-        *                interface StorableObject.
-        *
-        *  @return       true if yes, otherwise no.
-        */
-       public final static boolean implementsStorableObject(Class aClass) {
-               if (aClass!=null) {
-                       Class[] interfaces = aClass.getInterfaces();
-                       if (interfaces.length>0) {
-                               for (int i=0;i<interfaces.length;i++) {
-                                       if (interfaces[i]==storableObjectInterface) return true;
-                               }
-                       }
-               }
-               return false;
-       }
-
+  /**
+   * Description:  internall helper method to find out if a class extends
+   * class StorableEntity.
+   *
+   * @param aClass DOCUMENT ME!
+   *
+   * @return true if yes, otherwise no.
+   */
+  public static final boolean extendsStorableEntity(Class aClass) {
+    return StorableObjectEntity.class.isAssignableFrom(aClass);
+  }
 
 
 }
\ No newline at end of file
index 1edf779..5b6b2a3 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.util;
@@ -32,6 +32,7 @@ package mir.util;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Vector;
+import java.util.ArrayList;
 
 public class CachingRewindableIterator implements RewindableIterator {
   private Iterator master;
@@ -40,7 +41,7 @@ public class CachingRewindableIterator implements RewindableIterator {
 
   public CachingRewindableIterator(Iterator anIterator) {
     master = anIterator;
-    cachedItems = new Vector();
+    cachedItems = new ArrayList();
     iterationPosition = 0;
   }
 
index 691bd57..f89ef89 100755 (executable)
@@ -33,7 +33,6 @@ import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
-import java.util.SimpleTimeZone;
 import java.util.TimeZone;
 
 public class DateTimeFunctions {
diff --git a/source/mir/util/EntityUtility.java b/source/mir/util/EntityUtility.java
new file mode 100755 (executable)
index 0000000..aca1e66
--- /dev/null
@@ -0,0 +1,62 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.util;\r
+\r
+import mir.entity.Entity;\r
+\r
+/**\r
+ * Utility methods for entity manipulation\r
+ */\r
+public class EntityUtility {\r
+  /**\r
+   * This class should never get instances\r
+   */\r
+  private EntityUtility() {\r
+\r
+  }\r
+\r
+  /**\r
+   * Helper method to append a line to a field\r
+   */\r
+  public static void appendLineToField(Entity anEntity, String aFieldName, String aLine) {\r
+    StringBuffer fieldContent = new StringBuffer();\r
+    try {\r
+      fieldContent.append(StringRoutines.interpretAsString(anEntity.getFieldValue(aFieldName)));\r
+    }\r
+    catch (Throwable t) {\r
+    }\r
+    if (fieldContent.length() > 0 && fieldContent.charAt(fieldContent.length() - 1) != '\n') {\r
+      fieldContent.append('\n');\r
+    }\r
+\r
+    fieldContent.append(aLine);\r
+    anEntity.setFieldValue(aFieldName, fieldContent.toString());\r
+  }\r
+}\r
index 218213e..d831028 100755 (executable)
@@ -30,6 +30,9 @@
 package mir.util;
 
 import java.lang.reflect.InvocationTargetException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
 
 import multex.Failure;
 
@@ -53,7 +56,6 @@ public class ExceptionFunctions {
    * Traces an exception to it's root cause, using all known exception types that support
    *   cause exceptions.
    *
-   * @param anException
    * @return the cause (if found)
    */
 
@@ -76,4 +78,13 @@ public class ExceptionFunctions {
 
     return result;
   }
+
+  /**
+   * Prints an exception's stacktrace to a <code>String</code> 
+   */
+  public static String getStackTrace(Throwable aThrowable) {
+    StringWriter writer = new StringWriter();
+    aThrowable.printStackTrace(new PrintWriter(writer));
+    return writer.toString();
+  }
 }
index 4df8058..c9e6a10 100755 (executable)
  */
 package mir.util;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FilenameFilter;
-import java.io.IOException;
+import java.io.*;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
-import java.util.Vector;
 
 import gnu.regexp.RE;
 
@@ -47,18 +43,20 @@ public class FileFunctions {
   }
 
   public static void copyFile(File aSourceFile, File aDestinationFile) throws IOException {
-    FileInputStream inputStream;
-    FileOutputStream outputStream;
+    BufferedInputStream inputStream;
+    BufferedOutputStream outputStream;
     int nrBytesRead;
     byte[] buffer = new byte[FILE_COPY_BUFFER_SIZE];
 
-    inputStream = new FileInputStream(aSourceFile);
+    inputStream = new BufferedInputStream(
+      new FileInputStream(aSourceFile));
     try {
       File directory = new File(aDestinationFile.getParent());
         if (directory!=null && !directory.exists()){
           directory.mkdirs();
       }
-      outputStream = new FileOutputStream(aDestinationFile);
+      outputStream = new BufferedOutputStream(
+        new FileOutputStream(aDestinationFile),8192);
       try {
         do {
           nrBytesRead = inputStream.read(buffer);
@@ -111,6 +109,46 @@ public class FileFunctions {
     }
   }
 
+  /**
+   * Copy the contents of an {@link InputStream} to a {@link File}
+   */
+  public static void copy(InputStream aSource, File aDestination) throws IOException {
+    BufferedOutputStream outputStream =
+        new BufferedOutputStream(new FileOutputStream(aDestination), 8192);
+
+    int read;
+    byte[] buf = new byte[8 * 1024];
+
+    while ((read = aSource.read(buf)) != -1) {
+      outputStream.write(buf, 0, read);
+    }
+
+    aSource.close();
+    outputStream.close();
+  }
+
+  /**
+   * Moves a {@link File} to a new location
+   */
+  public static void move(File aSource, File aDestination) throws IOException {
+    aDestination.getParentFile().mkdirs();
+    if (!aSource.renameTo(aDestination)) {
+      byte[] buffer = new byte[16384];
+      FileInputStream inputStream = new FileInputStream(aSource);
+      FileOutputStream outputStream = new FileOutputStream(aDestination);
+      try {
+        while (inputStream.read(buffer)>0) {
+          outputStream.write(buffer);
+        }
+      }
+      finally {
+        outputStream.close();
+        inputStream.close();
+      }
+      aSource.delete();
+    };
+  }
+
   public static class RegExpFileFilter implements FilenameFilter {
     private RE expression;
 
@@ -135,16 +173,36 @@ public class FileFunctions {
     public boolean accept(File aDir, String aName) {
       return new File(aDir, aName).isDirectory();
     }
-
   }
 
   public static List getDirectoryContentsAsList(File aDirectory, FilenameFilter aFilter) {
     Object[] contents = aDirectory.list(aFilter);
     if (contents==null)
-      return new Vector();
+      return Collections.EMPTY_LIST;
     else
       return Arrays.asList(contents);
   }
 
+  public static String getExtension(String aPath) {
+    int position = aPath.lastIndexOf('.');
+    if (position>=0) {
+      return aPath.substring(position+1);
+    }
+    else {
+      return "";
+    }
+  }
+
+  public static boolean isAbsolutePath(String aPath) {
+    return new File(aPath).isAbsolute();
+  }
 
+  public static File getAbsoluteOrRelativeFile(File aParentIfRelative, String aPath) {
+    if (isAbsolutePath(aPath)) {
+      return new File(aPath);
+    }
+    else {
+      return new File(aParentIfRelative, aPath);
+    }
+  }
 }
\ No newline at end of file
index e535f1a..d7d88be 100755 (executable)
@@ -42,7 +42,7 @@ public class GeneratorDateTimeFunctions {
   private GeneratorDateTimeFunctions() {
   }
 
-  public static class FormatDateFunction implements Generator.GeneratorFunction {
+  public static class FormatDateFunction implements Generator.Function {
     private String defaultTimezone;
 
     public FormatDateFunction(String aDefaultTimeZone) {
@@ -96,13 +96,13 @@ public class GeneratorDateTimeFunctions {
 
   public static class DateTimeFunctions  {
     private String defaultTimezone;
-    private Generator.GeneratorFunction formatDate;
+    private Generator.Function formatDate;
 
     public DateTimeFunctions(String aDefaultTimezone) {
       defaultTimezone = aDefaultTimezone;
     }
 
-    public Generator.GeneratorFunction getFormatDate() {
+    public Generator.Function getFormatDate() {
       if (formatDate == null) {
         formatDate = new FormatDateFunction(defaultTimezone);
       }
diff --git a/source/mir/util/GeneratorExpressionFunctions.java b/source/mir/util/GeneratorExpressionFunctions.java
deleted file mode 100755 (executable)
index 1cec25d..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.util;
-
-import java.util.List;
-import java.util.Map;
-
-import mir.generator.Generator;
-import mir.generator.GeneratorExc;
-import mir.generator.GeneratorFailure;
-
-public class GeneratorExpressionFunctions {
-  private GeneratorExpressionFunctions() {
-  }
-
-  public static class evaluateExpressionFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
-      try {
-        if (aParameters.size()!=2)
-          throw new GeneratorExc("evaluateExpressionFunction <map> <expression>: 2 parameters expected");
-
-        Object parameter1=aParameters.get(0);
-
-        if (!(parameter1 instanceof Map))
-          throw new GeneratorExc("evaluateExpressionFunction <map> <expression>: first parameter must be a map");
-
-        return ParameterExpander.expandExpression((Map) parameter1, StringRoutines.interpretAsString(aParameters.get(1)));
-      }
-      catch (GeneratorExc e) {
-        throw e;
-      }
-      catch (Throwable t) {
-        throw new GeneratorFailure("encodeURIGeneratorFunction: " + t.getMessage(), t);
-      }
-    };
-  }
-
-
-
-}
\ No newline at end of file
index 2da18e5..becea34 100755 (executable)
@@ -54,11 +54,11 @@ public class GeneratorFormatAdapters {
       value = aValue;
     }
 
-    public Generator.GeneratorFunction getFormat() {
+    public Generator.Function getFormat() {
       return new NumberFormattingFunction();
     }
 
-    private class NumberFormattingFunction implements Generator.GeneratorFunction {
+    private class NumberFormattingFunction implements Generator.Function {
       public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
         try {
           if (aParameters.size() != 1 || ! (aParameters.get(0)instanceof String))
@@ -106,7 +106,7 @@ public class GeneratorFormatAdapters {
       return defaultTimezone;
     }
 
-    public Generator.GeneratorFunction getFormat() {
+    public Generator.Function getFormat() {
       return new DateFormattingFunction();
     }
 
@@ -118,7 +118,7 @@ public class GeneratorFormatAdapters {
       return value;
     }
 
-    private class DateFormattingFunction implements Generator.GeneratorFunction {
+    private class DateFormattingFunction implements Generator.Function {
       public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
         try {
           if (aParameters.size() < 1 || aParameters.size() > 2 ||
diff --git a/source/mir/util/GeneratorHTMLFunctions.java b/source/mir/util/GeneratorHTMLFunctions.java
deleted file mode 100755 (executable)
index 511f0b2..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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,
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
- * (or with modified versions of the above that use the same license as the above),
- * 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.util;
-
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-
-import mir.generator.Generator;
-import mir.generator.GeneratorExc;
-import mir.generator.GeneratorFailure;
-
-public class GeneratorHTMLFunctions {
-  private GeneratorHTMLFunctions() {}
-
-  public static class encodeURIGeneratorFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
-      try {
-        if (aParameters.size()<1 || aParameters.size()>2)
-          throw new GeneratorExc("encodeURIGeneratorFunction <text> [<encoding>]: only 1 or 2 parameters expected");
-
-        if (aParameters.size()>=2)
-          return HTMLRoutines.encodeURL(StringRoutines.interpretAsString(aParameters.get(0)), (StringRoutines.interpretAsString(aParameters.get(1))));
-        else
-          return HTMLRoutines.encodeURL(StringRoutines.interpretAsString(aParameters.get(0)));
-
-
-      }
-      catch (GeneratorExc e) {
-        throw e;
-      }
-      catch (Throwable t) {
-        throw new GeneratorFailure("encodeURIGeneratorFunction: " + t.getMessage(), t);
-      }
-    };
-  }
-
-  public static class encodeHTMLGeneratorFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc {
-      try {
-        if (aParameters.size()!=1)
-          throw new GeneratorExc("encodeHTMLGeneratorFunction: only 1 parameter expected");
-
-        return HTMLRoutines.encodeHTML(StringRoutines.interpretAsString(aParameters.get(0)));
-      }
-      catch (GeneratorExc e) {
-        throw e;
-      }
-      catch (Throwable t) {
-        throw new GeneratorFailure("encodeHTMLGeneratorFunction: " + t.getMessage(), t);
-      }
-    };
-  }
-
-  public static class encodeXMLGeneratorFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc {
-      try {
-        if (aParameters.size()!=1)
-          throw new GeneratorExc("encodeHTMLGeneratorFunction: only 1 parameter expected");
-
-        return HTMLRoutines.encodeXML(StringRoutines.interpretAsString(aParameters.get(0)));
-      }
-      catch (GeneratorExc e) {
-        throw e;
-      }
-      catch (Throwable t) {
-        throw new GeneratorFailure("encodeHTMLGeneratorFunction: " + t.getMessage(), t);
-      }
-    };
-  }
-  
-       public static class encodeLinksGeneratorFunction implements Generator.GeneratorFunction {
-               private HttpServletResponse _response;
-               public encodeLinksGeneratorFunction(HttpServletResponse response){
-                       _response = response;
-               }
-               public Object perform(List aParameters) throws GeneratorExc {
-                       try {
-                               if (aParameters.size()!=1)
-                                       throw new GeneratorExc("encodeHTMLGeneratorFunction: only 1 parameter expected");
-
-                               return _response.encodeURL((String)aParameters.get(0));
-                       }
-                       catch (GeneratorExc e) {
-                               throw e;
-                       }
-                       catch (Throwable t) {
-                               throw new GeneratorFailure("encodeHTMLGeneratorFunction: " + t.getMessage(), t);
-                       }
-               };
-       }
-}
diff --git a/source/mir/util/GeneratorIntegerFunctions.java b/source/mir/util/GeneratorIntegerFunctions.java
deleted file mode 100755 (executable)
index e323866..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.util;
-
-import java.util.List;
-
-import mir.generator.Generator;
-import mir.generator.GeneratorExc;
-import mir.generator.GeneratorFailure;
-
-public class GeneratorIntegerFunctions {
-
-  private GeneratorIntegerFunctions() {}
-
-  public static class incrementFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
-      int incrementValue = 1;
-
-      try {
-        if (aParameters.size()>2 || aParameters.size()<1)
-          throw new GeneratorExc("incrementFunction: 1 or 2 parameters expected: value [increment value]");
-
-        if (aParameters.size()>1)
-          incrementValue = StringRoutines.interpretAsInteger(aParameters.get(1));
-
-        return new Integer(StringRoutines.interpretAsInteger(aParameters.get(0)) + incrementValue);
-      }
-      catch (GeneratorExc e) {
-        throw e;
-      }
-      catch (Throwable t) {
-        throw new GeneratorFailure("incrementFunction: " + t.getMessage(), t);
-      }
-    };
-  }
-
-  public static class isOddFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
-      try {
-        if (aParameters.size()!=1)
-          throw new GeneratorExc("isOddFunction: 1 parameters expected: value");
-
-        return new Boolean((StringRoutines.interpretAsInteger(aParameters.get(0)) & 1) == 1);
-      }
-      catch (GeneratorExc e) {
-        throw e;
-      }
-      catch (Throwable t) {
-        throw new GeneratorFailure("isOddFunction: " + t.getMessage(), t);
-      }
-    };
-  }
-}
\ No newline at end of file
diff --git a/source/mir/util/GeneratorListFunctions.java b/source/mir/util/GeneratorListFunctions.java
deleted file mode 100755 (executable)
index 039d202..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.util;
-
-import java.util.List;
-import java.util.Vector;
-
-import mir.generator.Generator;
-import mir.generator.GeneratorExc;
-import mir.generator.GeneratorFailure;
-
-public class GeneratorListFunctions {
-  private GeneratorListFunctions() {}
-
-  public static class subListFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
-      try {
-        int skip;
-        int maxSize;
-
-        if (aParameters.size()>3 || aParameters.size()<2)
-          throw new GeneratorExc("iteratorSubsetFunction: 2 or 3 parameters expected");
-        if (aParameters.get(0)==null)
-          return "";
-
-        if (!(aParameters.get(0) instanceof RewindableIterator) && !(aParameters.get(0) instanceof List))
-          throw new GeneratorExc("iteratorSubsetFunction: first parameter must be a RewindableIterator (not a "+aParameters.get(0).getClass().getName()+")");
-
-        skip = StringRoutines.interpretAsInteger(aParameters.get(1));
-        if (aParameters.size()>=2)
-          maxSize = StringRoutines.interpretAsInteger(aParameters.get(2));
-        else
-          maxSize = -1;
-
-
-        if ((aParameters.get(0) instanceof RewindableIterator))
-          return new SubsetIterator((RewindableIterator) aParameters.get(0), skip, maxSize);
-        else {
-          List list = (List) aParameters.get(0);
-
-          if (skip>=list.size())
-            return new Vector();
-          if (maxSize<0 || (skip+maxSize)>=list.size())
-            return list.subList(skip, list.size());
-          else
-            return list.subList(skip, skip+maxSize);
-        }
-      }
-      catch (GeneratorExc e) {
-        throw e;
-      }
-      catch (GeneratorFailure e) {
-        throw e;
-      }
-      catch (Throwable e) {
-        throw new GeneratorFailure(e);
-      }
-    };
-  }
-}
diff --git a/source/mir/util/GeneratorRegularExpressionFunctions.java b/source/mir/util/GeneratorRegularExpressionFunctions.java
deleted file mode 100755 (executable)
index ed6d3f0..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.util;
-
-import java.util.List;
-
-import mir.generator.Generator;
-import mir.generator.GeneratorExc;
-import mir.generator.GeneratorFailure;
-
-public class GeneratorRegularExpressionFunctions {
-
-  private GeneratorRegularExpressionFunctions() {}
-
-  public static class regularExpressionReplaceFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
-      try {
-        if (aParameters.size()!=3)
-          throw new GeneratorExc("regularExpressionReplaceFunction: exactly 3 parameters expected: data, search expression, replacement");
-        if (aParameters.get(0)==null)
-          return "";
-        if (!(aParameters.get(0) instanceof String) || !(aParameters.get(1) instanceof String)  || !(aParameters.get(2) instanceof String))
-          throw new GeneratorExc("regularExpressionReplaceFunction: parameters must be strings");
-
-        return StringRoutines.performRegularExpressionReplacement((String) aParameters.get(0), (String) aParameters.get(1), (String) aParameters.get(2));
-      }
-      catch (Throwable t) {
-        throw new GeneratorFailure(t);
-      }
-    };
-  }
-}
\ No newline at end of file
diff --git a/source/mir/util/GeneratorStringFunctions.java b/source/mir/util/GeneratorStringFunctions.java
deleted file mode 100755 (executable)
index e147b07..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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,
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
- * (or with modified versions of the above that use the same license as the above),
- * 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.util;
-
-import java.util.List;
-
-import mir.generator.Generator;
-import mir.generator.GeneratorExc;
-import mir.generator.GeneratorFailure;
-
-public class GeneratorStringFunctions {
-
-  private GeneratorStringFunctions() {}
-
-  public static class subStringFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
-      try {
-        if (aParameters.size()>3 || aParameters.size()<2)
-          throw new GeneratorExc("subStringFunction: 2 or 3 parameters expected: string from [length]");
-
-        if (aParameters.size()==3) {
-          return StringRoutines.interpretAsString(aParameters.get(0)).substring(
-              StringRoutines.interpretAsInteger(aParameters.get(1)),
-              StringRoutines.interpretAsInteger(aParameters.get(2)));
-        }
-        else {
-          return StringRoutines.interpretAsString(aParameters.get(0)).substring(
-              StringRoutines.interpretAsInteger(aParameters.get(1)));
-        }
-      }
-      catch (GeneratorExc e) {
-        throw e;
-      }
-      catch (Throwable t) {
-        throw new GeneratorFailure(t);
-      }
-    };
-  }
-
-  public static class jdbcStringEscapeFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
-      try {
-        if (aParameters.size()!=1 || !(aParameters.get(0) instanceof String))
-          throw new GeneratorExc("jdbcStringEscapeFunction: 1 parameter expected: string ");
-
-        return JDBCStringRoutines.escapeStringLiteral((String) aParameters.get(0));
-      }
-      catch (GeneratorExc e) {
-        throw e;
-      }
-      catch (Throwable t) {
-        throw new GeneratorFailure(t);
-      }
-    };
-  }
-
-  public static class constructStructuredStringFunction implements Generator.GeneratorFunction {
-    public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {
-      try {
-        if (aParameters.size()!=1)
-          throw new GeneratorExc("constructStructureStringFunction: 1 parameter expected: string ");
-
-        if (aParameters.get(0)==null)
-          return StructuredContentParser.constructStringLiteral("");
-        else
-          return StructuredContentParser.constructStringLiteral("" + aParameters.get(0));
-      }
-      catch (GeneratorExc e) {
-        throw e;
-      }
-      catch (Throwable t) {
-        throw new GeneratorFailure(t);
-      }
-    };
-  }
-}
\ No newline at end of file
index 07f40a0..c532e51 100755 (executable)
 package mir.util;
 
 import java.net.URLEncoder;
+import java.util.HashMap;
+import java.util.Map;
 
 public class HTMLRoutines {
-
+  /**
+   * Encodes a URL: escapes reserved URL characters like &, = into % escape
+   *    constructions.
+   */
   public static String encodeURL(String aString) {
     return URLEncoder.encode(aString);
   }
 
-  /**
-   *
-   *
-   * @param aString
-   * @param anEncoding the encoding to use (Note: JDK 1.3 does not seem to support custom
-   *             encodings, so this parameter is ignored for now)
-   * @return
-   */
-
   public static String encodeURL(String aString, String anEncoding) {
     try {
       return URLEncoder.encode(aString);
@@ -63,8 +59,13 @@ public class HTMLRoutines {
     return StringRoutines.replaceStringCharacters(aText, CHARACTERS_TO_ESCAPE, ESCAPE_CODES);
   }
 
+  public static String prettyEncodeHTML(String aText) throws UtilExc {
+    return
+        StringRoutines.performRegularExpressionReplacement(encodeHTML(aText), "\\n", "<br>\n");
+  }
+
   public static String encodeXML(String aText) {
-//#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
+    //#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]
     final char[] CHARACTERS_TO_ESCAPE = { '&', '<', '>', '"', '\'',
         '\u0000', '\u0001', '\u0003', '\u0004', '\u0005', '\u0006', '\u0007', '\u0008', '\u0000', '\u000B',
         '\u000C', '\u000E', '\u000F', '\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015', '\u0016',
@@ -74,7 +75,137 @@ public class HTMLRoutines {
         "", "", "", "", "", "", "", "", "", "",
         "", "", "", "", "", "", "", ""};
 
-
     return StringRoutines.replaceStringCharacters(aText, CHARACTERS_TO_ESCAPE, ESCAPE_CODES);
   }
+
+  private static final Map htmlEntities = new HashMap();
+
+  private static final String[] HTML_ENTITY_TABLE = {
+      "nbsp",    "\u00a0", "iexcl",   "\u00a1", "cent",    "\u00a2", "pound",   "\u00a3", "curren",  "\u00a4", "yen",     "\u00a5",
+      "brvbar",  "\u00a6", "sect",    "\u00a7", "uml",     "\u00a8", "copy",    "\u00a9", "ordf",    "\u00aa", "laquo",   "\u00ab",
+      "not",     "\u00ac", "shy",     "\u00ad", "reg",     "\u00ae", "macr",    "\u00af", "deg",     "\u00b0", "plusmn",  "\u00b1",
+      "sup2",    "\u00b2", "sup3",    "\u00b3", "acute",   "\u00b4", "micro",   "\u00b5", "para",    "\u00b6", "middot",  "\u00b7",
+      "cedil",   "\u00b8", "sup1",    "\u00b9", "ordm",    "\u00ba", "raquo",   "\u00bb", "frac14",  "\u00bc", "frac12",  "\u00bd",
+      "frac34",  "\u00be", "iquest",  "\u00bf", "Agrave",  "\u00c0", "Aacute",  "\u00c1", "Acirc",   "\u00c2", "Atilde",  "\u00c3",
+      "Auml",    "\u00c4", "Aring",   "\u00c5", "AElig",   "\u00c6", "Ccedil",  "\u00c7", "Egrave",  "\u00c8", "Eacute",  "\u00c9",
+      "Ecirc",   "\u00ca", "Euml",    "\u00cb", "Igrave",  "\u00cc", "Iacute",  "\u00cd", "Icirc",   "\u00ce", "Iuml",    "\u00cf",
+      "ETH",     "\u00d0", "Ntilde",  "\u00d1", "Ograve",  "\u00d2", "Oacute",  "\u00d3", "Ocirc",   "\u00d4", "Otilde",  "\u00d5",
+      "Ouml",    "\u00d6", "times",   "\u00d7", "Oslash",  "\u00d8", "Ugrave",  "\u00d9", "Uacute",  "\u00da", "Ucirc",   "\u00db",
+      "Uuml",    "\u00dc", "Yacute",  "\u00dd", "THORN",   "\u00de", "szlig",   "\u00df", "agrave",  "\u00e0", "aacute",  "\u00e1",
+      "acirc",   "\u00e2", "atilde",  "\u00e3", "auml",    "\u00e4", "aring",   "\u00e5", "aelig",   "\u00e6", "ccedil",  "\u00e7",
+      "egrave",  "\u00e8", "eacute",  "\u00e9", "ecirc",   "\u00ea", "euml",    "\u00eb", "igrave",  "\u00ec", "iacute",  "\u00ed",
+      "icirc",   "\u00ee", "iuml",    "\u00ef", "eth",     "\u00f0", "ntilde",  "\u00f1", "ograve",  "\u00f2", "oacute",  "\u00f3",
+      "ocirc",   "\u00f4", "otilde",  "\u00f5", "ouml",    "\u00f6", "divide",  "\u00f7", "oslash",  "\u00f8", "ugrave",  "\u00f9",
+      "uacute",  "\u00fa", "ucirc",   "\u00fb", "uuml",    "\u00fc", "yacute",  "\u00fd", "thorn",   "\u00fe", "yuml",    "\u00ff",
+      "fnof",    "\u0192", "Alpha",   "\u0391", "Beta",    "\u0392", "Gamma",   "\u0393", "Delta",   "\u0394", "Epsilon", "\u0395",
+      "Zeta",    "\u0396", "Eta",     "\u0397", "Theta",   "\u0398", "Iota",    "\u0399", "Kappa",   "\u039a", "Lambda",  "\u039b",
+      "Mu",      "\u039c", "Nu",      "\u039d", "Xi",      "\u039e", "Omicron", "\u039f", "Pi",      "\u03a0", "Rho",     "\u03a1",
+      "Sigma",   "\u03a3", "Tau",     "\u03a4", "Upsilon", "\u03a5", "Phi",     "\u03a6", "Chi",     "\u03a7", "Psi",     "\u03a8",
+      "Omega",   "\u03a9", "alpha",   "\u03b1", "beta",    "\u03b2", "gamma",   "\u03b3", "delta",   "\u03b4", "epsilon", "\u03b5",
+      "zeta",    "\u03b6", "eta",     "\u03b7", "theta",   "\u03b8", "iota",    "\u03b9", "kappa",   "\u03ba", "lambda",  "\u03bb",
+      "mu",      "\u03bc", "nu",      "\u03bd", "xi",      "\u03be", "omicron", "\u03bf", "pi",      "\u03c0", "rho",     "\u03c1",
+      "sigmaf",  "\u03c2", "sigma",   "\u03c3", "tau",     "\u03c4", "upsilon", "\u03c5", "phi",     "\u03c6", "chi",     "\u03c7",
+      "psi",     "\u03c8", "omega",   "\u03c9", "thetasym","\u03d1", "upsih",   "\u03d2", "piv",     "\u03d6", "bull",    "\u2022",
+      "hellip",  "\u2026", "prime",   "\u2032", "Prime",   "\u2033", "oline",   "\u203e", "frasl",   "\u2044", "weierp",  "\u2118",
+      "image",   "\u2111", "real",    "\u211c", "trade",   "\u2122", "alefsym", "\u2135", "larr",    "\u2190", "uarr",    "\u2191",
+      "rarr",    "\u2192", "darr",    "\u2193", "harr",    "\u2194", "crarr",   "\u21b5", "lArr",    "\u21d0", "uArr",    "\u21d1",
+      "rArr",    "\u21d2", "dArr",    "\u21d3", "hArr",    "\u21d4", "forall",  "\u2200", "part",    "\u2202", "exist",   "\u2203",
+      "empty",   "\u2205", "nabla",   "\u2207", "isin",    "\u2208", "notin",   "\u2209", "ni",      "\u220b", "prod",    "\u220f",
+      "sum",     "\u2211", "minus",   "\u2212", "lowast",  "\u2217", "radic",   "\u221a", "prop",    "\u221d", "infin",   "\u221e",
+      "ang",     "\u2220", "and",     "\u2227", "or",      "\u2228", "cap",     "\u2229", "cup",     "\u222a", "int",     "\u222b",
+      "there4",  "\u2234", "sim",     "\u223c", "cong",    "\u2245", "asymp",   "\u2248", "ne",      "\u2260", "equiv",   "\u2261",
+      "le",      "\u2264", "ge",      "\u2265", "sub",     "\u2282", "sup",     "\u2283", "nsub",    "\u2284", "sube",    "\u2286",
+      "supe",    "\u2287", "oplus",   "\u2295", "otimes",  "\u2297", "perp",    "\u22a5", "sdot",    "\u22c5", "lceil",   "\u2308",
+      "rceil",   "\u2309", "lfloor",  "\u230a", "rfloor",  "\u230b", "lang",    "\u2329", "rang",    "\u232a", "loz",     "\u25ca",
+      "spades",  "\u2660", "clubs",   "\u2663", "hearts",  "\u2665", "diams",   "\u2666", "quot",    "\"",     "amp",     "\u0026",
+      "lt",      "\u003c", "gt",      "\u003e", "OElig",   "\u0152", "oelig",   "\u0153", "Scaron",  "\u0160", "scaron",  "\u0161",
+      "Yuml",    "\u0178", "circ",    "\u02c6", "tilde",   "\u02dc", "ensp",    "\u2002", "emsp",    "\u2003", "thinsp",  "\u2009",
+      "zwnj",    "\u200c", "zwj",     "\u200d", "lrm",     "\u200e", "rlm",     "\u200f", "ndash",   "\u2013", "mdash",   "\u2014",
+      "lsquo",   "\u2018", "rsquo",   "\u2019", "sbquo",   "\u201a", "ldquo",   "\u201c", "rdquo",   "\u201d", "bdquo",   "\u201e",
+      "dagger",  "\u2020", "Dagger",  "\u2021", "permil",  "\u2030", "lsaquo",  "\u2039", "rsaquo",  "\u203a", "euro",    "\u20ac"
+  };
+
+  static {
+    for (int i=0; i+1<HTML_ENTITY_TABLE.length; i+=2) {
+      htmlEntities.put(HTML_ENTITY_TABLE[i], HTML_ENTITY_TABLE[i+1]);
+    }
+  }
+
+  /**
+   * Resolves an html entity if possible, returns the unresolved entity otherwise
+   *
+   * Possible entities:
+   *   &#<decimal number>;
+   *   &#x<hexadecimal number>;
+   *   &<entity name>;
+   */
+  public static String resolveHTMLEntity(String anEntity) {
+    if (anEntity.length()<3 || anEntity.length()>10 ||
+        anEntity.charAt(0)!='&' ||
+        anEntity.charAt(anEntity.length()-1)!=';')
+      return anEntity;
+
+    if (anEntity.charAt(1)=='#') {
+      try {
+        int number=-1;
+
+        if (anEntity.charAt(2)=='x') {
+          number = Integer.parseInt(anEntity.substring(3,anEntity.length()-1), 16);
+        }
+        else {
+          number = Integer.parseInt(anEntity.substring(2,anEntity.length()-1), 10);
+        }
+
+        if (number>=Character.MIN_VALUE  && number<=Character.MAX_VALUE &&
+            Character.isDefined((char) number)) {
+          return new String(new char[]{(char) number});
+        }
+      }
+      catch (NumberFormatException e) {
+      }
+    }
+    else {
+      String name = anEntity.substring(1,anEntity.length()-1);
+
+      String result = (String) htmlEntities.get(name);
+
+      if (result!=null)
+        return result;
+    }
+
+    return anEntity;
+  }
+
+  /**
+   * Resolve all HTML entities (&....;) in a text
+   */
+  public static String resolveHTMLEntites(String aText) {
+    StringBuffer result = new StringBuffer();
+
+    int oldPosition = 0;
+    int position;
+
+    do {
+      position = aText.indexOf("&", oldPosition);
+      if (position<0)
+        position = aText.length();
+
+      result.append(aText.substring(oldPosition,position));
+
+      if (position<aText.length()) {
+        int position2 = aText.indexOf(";", position);
+
+        if (position2>position+1) {
+          result.append(resolveHTMLEntity(aText.substring(position, position2+1)));
+          oldPosition=position2+1;
+        }
+        else {
+          result.append(aText.charAt(position));
+          oldPosition = position+1;
+        }
+      }
+    } while (position<aText.length());
+
+    return result.toString();
+  }
 }
\ No newline at end of file
diff --git a/source/mir/util/HTTPClientHelper.java b/source/mir/util/HTTPClientHelper.java
new file mode 100755 (executable)
index 0000000..666f4cf
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.util;
+
+
+import java.io.InputStream;
+import java.io.IOException;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.methods.GetMethod;
+
+import mir.util.UtilExc;
+
+public class HTTPClientHelper {
+  private HttpClient client;
+  private HttpMethod method;
+  
+  public HTTPClientHelper() {
+      client = new HttpClient();
+      client.setConnectionTimeout(5000);
+      client.setTimeout(5000);
+  }
+
+
+  public InputStream getUrl(String anUrl) throws UtilExc{
+    try{
+      method = new GetMethod(anUrl);
+      method.setFollowRedirects(true);
+      method.setStrictMode(false);
+      client.executeMethod(method);
+      InputStream inputStream  = method.getResponseBodyAsStream();
+      return inputStream;
+    }
+    catch (IOException e){
+       throw new UtilExc(e.getMessage());
+    }
+  }
+  
+  public void releaseHTTPConnection() {
+    method.releaseConnection();
+    method.recycle();
+  }
+
+}
index 3ca02f1..3d9d96f 100755 (executable)
  */
 package mir.util;
 
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Vector;
-
-import javax.servlet.http.HttpServletRequest;
-
 import mir.log.LoggerWrapper;
-
+import org.apache.commons.fileupload.DiskFileUpload;
 import org.apache.commons.fileupload.FileItem;
-import org.apache.commons.fileupload.FileUpload;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.*;
 
 public class HTTPParsedRequest {
   static final String MULTIPART_FORMDATA_CONTENTTYPE = "multipart/form-data";
@@ -52,23 +44,21 @@ public class HTTPParsedRequest {
   private int maxUploadSize;
   private String tempDir;
 
-  private Map stringValues;
-  private Map listValues;
+  private Map parameterStringValues;
+  private Map parameterListValues;
   private List files;
 
-  private LoggerWrapper logger;
+  private LoggerWrapper logger = new LoggerWrapper("Utility.HTTPParsedRequest");
 
   public HTTPParsedRequest(HttpServletRequest aRequest, String anEncoding, int aMaxUploadSize, String aTempDir) throws UtilExc, UtilFailure {
-    logger = new LoggerWrapper("Utility.HTTPParsedRequest");
-
     request = aRequest;
     encoding = anEncoding;
     maxUploadSize = aMaxUploadSize;
     tempDir = aTempDir;
 
-    stringValues = new HashMap();
-    listValues = new HashMap();
-    files = new Vector();
+    parameterStringValues = new HashMap();
+    parameterListValues = new HashMap();
+    files = new ArrayList();
 
     parseRequest(aRequest);
   }
@@ -82,7 +72,11 @@ public class HTTPParsedRequest {
   }
 
   public String getParameter(String aName) {
-    return (String) stringValues.get(aName);
+    return (String) parameterStringValues.get(aName);
+  }
+
+  public Collection getParameterNames() {
+    return parameterStringValues.keySet();
   }
 
   public String getHeader(String aName) {
@@ -94,10 +88,10 @@ public class HTTPParsedRequest {
   }
 
   public List getParameterList(String aName) {
-    if (listValues.containsKey(aName))
-      return (List) listValues.get(aName);
+    if (parameterListValues.containsKey(aName))
+      return (List) parameterListValues.get(aName);
     else
-      return new Vector();
+      return Collections.EMPTY_LIST;
   }
 
   protected void parseRequest(HttpServletRequest aRequest) throws UtilExc, UtilFailure {
@@ -111,9 +105,9 @@ public class HTTPParsedRequest {
       while (e.hasMoreElements()) {
         String name = (String) e.nextElement();
 
-        stringValues.put(name, aRequest.getParameter(name));
-        List listValue = new Vector(Arrays.asList(aRequest.getParameterValues(name)));
-        listValues.put(name, listValue);
+        parameterStringValues.put(name, aRequest.getParameter(name));
+        List listValue = new ArrayList(Arrays.asList(aRequest.getParameterValues(name)));
+        parameterListValues.put(name, listValue);
       }
 
       if (parts.size()>0 && ((String) parts.get(0)).trim().toLowerCase().equals(MULTIPART_FORMDATA_CONTENTTYPE)) {
@@ -129,10 +123,11 @@ public class HTTPParsedRequest {
 
   protected void parseMultipartRequest() throws UtilExc, UtilFailure {
     try {
-      FileUpload upload = new FileUpload();
+      DiskFileUpload upload = new DiskFileUpload();
 
+      upload.setSizeThreshold(100000);
       upload.setSizeMax(maxUploadSize);
-      upload.setSizeThreshold(4096);
+      upload.setHeaderEncoding(encoding);
       upload.setRepositoryPath(tempDir);
 
       List items = upload.parseRequest(request);
@@ -142,14 +137,14 @@ public class HTTPParsedRequest {
         FileItem item = (FileItem) i.next();
 
         if (item.isFormField()) {
-          if (!stringValues.containsKey(item.getName())) {
-            stringValues.put(item.getFieldName(), item.getString(encoding));
+          if (!parameterStringValues.containsKey(item.getName())) {
+            parameterStringValues.put(item.getFieldName(), item.getString(encoding));
           }
 
-          List listValue = (List) listValues.get(item.getFieldName());
+          List listValue = (List) parameterListValues.get(item.getFieldName());
           if (listValue == null) {
-            listValue = new Vector();
-            listValues.put(item.getFieldName(), listValue);
+            listValue = new ArrayList();
+            parameterListValues.put(item.getFieldName(), listValue);
           }
           listValue.add(item.getString(encoding));
         }
index 54dbea5..9b50247 100755 (executable)
@@ -30,8 +30,8 @@
 
 package mir.util;
 
-import java.util.*;
-
+import java.util.ArrayList;
+import java.util.List;
 import javax.servlet.http.HttpServletRequest;
 
 public class HTTPRequestParser {
@@ -78,7 +78,7 @@ public class HTTPRequestParser {
 
   public List getParameterList(String aName) {
     try {
-      List result = new Vector();
+      List result = new ArrayList();
       String items[] = request.getParameterValues(aName);
 
       if (items!=null) {
index 171e8f8..2260d4d 100755 (executable)
 package mir.util;
 
 import java.util.List;
+import java.net.InetAddress;
 
 public class InternetFunctions {
   private InternetFunctions() {
   }
 
   public static boolean isIpAddressInNetwork(String anIpAddress, String aNetwork) throws Exception {
-    long ipAddress = parseIPAddress(anIpAddress);
+    long ipAddress = parseHostNameOrIPAddress(anIpAddress);
     long network = 0;
     long netMask = (1L<<32)-1;
     List networkParts = StringRoutines.separateString(aNetwork, "/");
 
-    network = parseIPAddress((String) networkParts.get(0));
+    network = parseHostNameOrIPAddress((String) networkParts.get(0));
     if (networkParts.size()>=2) {
       netMask=parseNetmask((String) networkParts.get(1));
     }
@@ -51,10 +52,18 @@ public class InternetFunctions {
     return (ipAddress & netMask ) == (network & netMask);
   }
 
+  public static long parseHostNameOrIPAddress(String aHostName) throws Exception {
+    InetAddress addr = InetAddress.getByName(aHostName.trim());
+    return
+        ((((long) addr.getAddress()[0])&255) << 24) +
+        ((((long) addr.getAddress()[1])&255) << 16) +
+        ((((long) addr.getAddress()[2])&255) << 8) +
+        ((((long) addr.getAddress()[3])&255));
+  }
+
   public static long parseIPAddress(String anIpAddress) throws Exception {
     int[] parts = {0,0,0,0};
     int i;
-    long result;
     List stringParts = StringRoutines.splitString(anIpAddress, ".");
 
     if (stringParts.size()!=4)
@@ -62,7 +71,7 @@ public class InternetFunctions {
 
     try {
       for (i=0; i<4; i++) {
-        parts[i] = Integer.parseInt((String) stringParts.get(i));
+        parts[i] = Integer.parseInt(((String) stringParts.get(i)).trim());
       }
     }
     catch (Throwable t) {
@@ -94,4 +103,5 @@ public class InternetFunctions {
 
     return (1L<<32)-1;
   }
+
 }
\ No newline at end of file
index cae60e5..4d3bff8 100755 (executable)
@@ -38,8 +38,9 @@ package mir.util;
  * @version 1.0
  */
 
-import java.util.*;
-import java.text.*;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
 
 public class JDBCStringRoutines {
   private JDBCStringRoutines() {
index a65015b..734bec9 100755 (executable)
@@ -35,17 +35,47 @@ import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 
-import org.apache.commons.beanutils.*;
-
-import multex.Exc;
-
 import mir.generator.Generator;
 import mir.generator.GeneratorExc;
+import multex.Exc;
+
+import org.apache.commons.beanutils.MethodUtils;
+import org.apache.commons.beanutils.PropertyUtils;
 
+/**
+ * Class to work with expressions. Will be gradually phased out and replaced
+ * with {@link mir.util.expressions.ExpressionParser}
+ */
 public class ParameterExpander {
   final static String NODE_SEPARATOR = ".";
   final static char STRING_ESCAPE_CHARACTER = '\\';
 
+  /**
+   * Fundamental method to retrieve a field of an object. Supported are
+   *  maps, beans and objects with a generic get method  
+   */
+  public static Object getObjectField(Object anObject, Object aField) {
+    if (anObject instanceof Map) {
+      return ((Map) anObject).get(aField);
+    }
+    else if ((aField instanceof String) && PropertyUtils.isReadable(anObject, (String) aField)) {
+      try {
+        return PropertyUtils.getProperty(anObject, (String) aField);
+      }
+      catch (Throwable t) {
+        throw new RuntimeException(t.getMessage());
+      }
+    }
+    else {
+      try {
+        return MethodUtils.invokeExactMethod(anObject, "get", aField);
+      }
+      catch (Throwable t) {
+        throw new RuntimeException("Invalid reference of " + aField + " into " + anObject);
+      }
+    }
+  }
+
   private static Object findNode(String aKey, Map aMap, List aParts, boolean aMakeIfNotPresent) throws Exception {
     Iterator i;
     String location = "";
@@ -74,7 +104,7 @@ public class ParameterExpander {
           ((Map) node).put(part, newNode);
         }
         else
-          throw new ParameterExpanderExc( "Can't expand key {1}: {2} does not exist", new Object[]{aKey,location} );
+          throw new ParameterExpanderExc( "Can't expand key " + aKey + ": " + location + " does not exist");
 
       node = newNode;
     }
@@ -95,7 +125,7 @@ public class ParameterExpander {
     Object expandedValue = findValueForKey(aMap, aKey);
 
     if (!(expandedValue instanceof String))
-      throw new ParameterExpanderExc( "Value of key is not a string but a {1}", new Object[]{expandedValue.getClass().getName()} );
+      throw new ParameterExpanderExc( "Value of key is not a string but a " + expandedValue.getClass().getName());
 
     return (String) expandedValue;
   }
@@ -108,14 +138,15 @@ public class ParameterExpander {
 
     Object node=findNode(aKey, aMap, parts, true);
 
+    // todo: bean support
     if (node instanceof Map) {
       ((Map) node).put(key, aValue);
     }
     else
-      throw new ParameterExpanderExc( "Can't set key {1}: not inside a Map", new Object[]{aKey} );
+      throw new ParameterExpanderExc( "Can't set key " + aKey + " : not inside a Map");
   }
 
-  public static String expandExpression(Map aMap, String anExpression) throws Exception {
+  public static String expandExpression(Object aContext, String anExpression) throws Exception {
     int previousPosition = 0;
     int position;
     int endOfExpressionPosition;
@@ -143,17 +174,17 @@ public class ParameterExpander {
                 endOfExpressionPosition++;
               }
               if (endOfExpressionPosition>=anExpression.length()) {
-                throw new ParameterExpanderExc("Unterminated string in {1}",new Object[]{anExpression});
+                throw new ParameterExpanderExc("Unterminated string in '" +anExpression+"'");
               }
             }
             endOfExpressionPosition++;
           }
           if (endOfExpressionPosition<anExpression.length()) {
-            result.append(evaluateStringExpression(aMap, anExpression.substring(position+2, endOfExpressionPosition)));
+            result.append(evaluateStringExpression(aContext, anExpression.substring(position+2, endOfExpressionPosition)));
             previousPosition=endOfExpressionPosition+1;
           }
           else {
-            throw new ParameterExpanderExc("Missing } in {1}",new Object[]{anExpression});
+            throw new ParameterExpanderExc("Missing } in " + anExpression);
           }
         }
         else
@@ -573,28 +604,6 @@ public class ParameterExpander {
       return result;
     }
 
-    private Object evaluateObjectField(Object anObject, Object aField) {
-      if (anObject instanceof Map) {
-        return ((Map) anObject).get(aField);
-      }
-      else if ((aField instanceof String) && PropertyUtils.isReadable(anObject, (String) aField)) {
-        try {
-          return PropertyUtils.getProperty(anObject, (String) aField);
-        }
-        catch (Throwable t) {
-          throw new RuntimeException(t.getMessage());
-        }
-      }
-      else {
-        try {
-          return MethodUtils.invokeExactMethod(anObject, "get", aField);
-        }
-        catch (Throwable t) {
-          throw new RuntimeException("Invalid reference of " + aField + "into " + anObject);
-        }
-      }
-    }
-
     private Object parseVariable() {
       boolean done;
       Token token;
@@ -612,19 +621,19 @@ public class ParameterExpander {
           if (!(token instanceof RightSquareBraceToken))
             throw new RuntimeException("] expected");
 
-          currentValue = evaluateObjectField(currentValue, qualifier);
+          currentValue = getObjectField(currentValue, qualifier);
         }
         else if (token instanceof IdentifierToken) {
           scanner.scan();
           qualifier = ((IdentifierToken) token).getName();
 
-          currentValue = evaluateObjectField(currentValue, qualifier);
+          currentValue = getObjectField(currentValue, qualifier);
         }
         else if (token instanceof LeftParenthesisToken) {
-          if (currentValue instanceof Generator.GeneratorFunction) {
+          if (currentValue instanceof Generator.Function) {
             parameters = parseList();
             try {
-              currentValue = ((Generator.GeneratorFunction) currentValue).perform(parameters);
+              currentValue = ((Generator.Function) currentValue).perform(parameters);
             }
             catch (GeneratorExc t) {
               throw new RuntimeException(t.getMessage());
@@ -781,6 +790,22 @@ public class ParameterExpander {
       if (aValue instanceof Boolean)
         return ((Boolean) aValue).booleanValue();
 
+      if (aValue instanceof RewindableIterator) {
+        ((RewindableIterator) aValue).rewind();
+      }
+
+      if (aValue instanceof Iterator) {
+        return ((Iterator) aValue).hasNext();
+      }
+
+      if (aValue instanceof List) {
+        return ((List) aValue).size()>0;
+      }
+
+      if (aValue instanceof String) {
+        return ((String) aValue).length()>0;
+      }
+
       return aValue!=null;
     }
 
@@ -805,7 +830,7 @@ public class ParameterExpander {
       if (aValue instanceof String)
         return (String) aValue;
       if (aValue instanceof Integer)
-        return ((Integer) aValue).toString();
+        return aValue.toString();
 
       throw new RuntimeException("Not a string");
     }
@@ -877,8 +902,8 @@ public class ParameterExpander {
   }
 
   public static class ParameterExpanderExc extends Exc {
-    public ParameterExpanderExc(String msg, Object[] objects) {
-      super(msg, objects);
+    public ParameterExpanderExc(String msg) {
+      super(msg);
     }
   }
 }
\ No newline at end of file
index c76cbbd..25d3e55 100755 (executable)
@@ -117,7 +117,6 @@ public class PropertiesManipulator {
   private final static String ESCAPE= "\\\\[ tn]";
   private final static String UNICODE= "\\\\u[a-fA-F0-9][a-fA-F0-9][a-fA-F0-9][a-fA-F0-9]";
 
-
   private static String decode(String aValue) {
     try {
       SimpleParser parser = new SimpleParser(aValue);
diff --git a/source/mir/util/ReflectionRoutines.java b/source/mir/util/ReflectionRoutines.java
new file mode 100755 (executable)
index 0000000..b15014f
--- /dev/null
@@ -0,0 +1,60 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.util;\r
+\r
+import org.apache.commons.beanutils.MethodUtils;\r
+\r
+import java.lang.reflect.InvocationTargetException;\r
+\r
+public class ReflectionRoutines {\r
+  private ReflectionRoutines() {\r
+  }\r
+\r
+  /**\r
+   * Method to overcome a shortcoming in {@link org.apache.commons.beanutils}'s\r
+   *     {@link MethodUtils#invokeMethod(Object, String, Object[])} involving\r
+   *     parameters that are <code>null</code> \r
+   */\r
+  public static Object invokeMethod(Object aTarget, String aMethodName, Object[] aParameters)\r
+      throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {\r
+    Class parameterTypes[] = new Class[aParameters.length];\r
+\r
+    for (int i=0; i<aParameters.length; i++) {\r
+      if (aParameters[i] == null) {\r
+        parameterTypes[i] = Object.class;\r
+      }\r
+      else {\r
+        parameterTypes[i] = aParameters[i].getClass();\r
+      }\r
+    }\r
+\r
+    return MethodUtils.invokeMethod(aTarget, aMethodName, aParameters, parameterTypes);\r
+  }\r
+}\r
diff --git a/source/mir/util/ResourceBundleGeneratorFunction.java b/source/mir/util/ResourceBundleGeneratorFunction.java
deleted file mode 100755 (executable)
index c31b85e..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.util;
-
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Vector;
-
-import mir.generator.Generator;
-import mir.generator.GeneratorExc;
-
-import org.apache.struts.util.MessageResources;
-
-public class ResourceBundleGeneratorFunction implements Generator.GeneratorFunction {
-  private List messages;
-  private List locales;
-
-  public ResourceBundleGeneratorFunction(Locale aLocale, MessageResources aMessages) {
-    this(new Locale[] { aLocale}, new MessageResources[] {aMessages} );
-  }
-
-  public ResourceBundleGeneratorFunction(Locale[] aLocales, MessageResources[] aMessages) {
-    locales = new Vector();
-    messages = new Vector();
-
-    for(int i=0; i<aMessages.length; i++) {
-      messages.add(aMessages[i]);
-    }
-
-    for(int i=0; i<aLocales.length; i++) {
-      locales.add(aLocales[i]);
-    }
-  }
-
-  public Object perform(List aParameters) throws GeneratorExc {
-    List extraParameters = new Vector(aParameters);
-
-    if (aParameters.size()<1)
-      throw new GeneratorExc("ResourceBundleGeneratorFunction: at least 1 parameter expected");
-
-    if (!(aParameters.get(0) instanceof String))
-      throw new GeneratorExc("encodeHTMLGeneratorFunction: parameters must be strings");
-
-    String key = (String) aParameters.get(0);
-    extraParameters.remove(0);
-
-    String message=null;
-    Iterator j = locales.iterator();
-    while (j.hasNext() && (message == null || message.trim().length()==0)) {
-      Locale locale = (Locale) j.next();
-
-      Iterator i = messages.iterator();
-      while (i.hasNext() && (message == null || message.trim().length()==0)) {
-        message = ( (MessageResources) i.next()).getMessage(locale, key, extraParameters.toArray());
-      }
-    }
-
-    if (message == null) {
-      return new String("??" + key + "??");
-    }
-    else {
-      return message;
-    }
-  };
-}
\ No newline at end of file
diff --git a/source/mir/util/StreamCopier.java b/source/mir/util/StreamCopier.java
new file mode 100755 (executable)
index 0000000..b259b9a
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.util;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+public class StreamCopier {
+  public static void copy(InputStream aSource, OutputStream aDestination) throws IOException {
+    byte buffer[] = new byte[16000];
+    int amountRead;
+
+    do {
+      amountRead = aSource.read(buffer);
+      if (amountRead>0)
+        aDestination.write(buffer, 0, amountRead);
+    }
+    while (amountRead>0);
+    aDestination.flush();
+  }
+}
index ee08f21..04bbc72 100755 (executable)
  * 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.  
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.
  */
 
@@ -32,6 +32,8 @@ package mir.util;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
 
 public class StringParseRoutines {
 
@@ -41,8 +43,9 @@ public class StringParseRoutines {
   private final static String VALUE = "[^;]*";
   private final static String SEMICOLON = ";";
 
-  //  a=sdfb; c=d; e=f
-
+  /**
+   * Parses an expression of the form " a = b ; c = d" into a map
+   */
   public static Map parseValueList(String anExpression) throws SimpleParser.SimpleParserFailure, SimpleParser.SimpleParserExc {
     String key;
     String value;
@@ -67,4 +70,58 @@ public class StringParseRoutines {
 
     return result;
   }
+
+  /**
+   * Utility function for {@link #parseBracketedExpression}:
+   * Adds a single part of a bracketed expression by looking for a
+   * terminator.
+   */
+  private static  int findNextBracketedPart(String anExpression, int aStartingPosition, char anEscape, String aTerminator, List aResult) {
+    int position = aStartingPosition;
+    StringBuffer result = new StringBuffer();
+
+    while (position<anExpression.length()) {
+      if (anExpression.charAt(position)==anEscape && position+1<anExpression.length()) {
+        result.append(anExpression.charAt(position+1));
+        position++;
+        position++;
+      }
+      else if (anExpression.startsWith(aTerminator, position)) {
+        aResult.add(result.toString());
+        return position;
+      }
+      else {
+        result.append(anExpression.charAt(position));
+        position++;
+      }
+    }
+
+    aResult.add(result.toString());
+    return -1;
+  }
+
+  /**
+   * Parses a "bracketed expression" into parts.
+   * "Bracketed" here means the expression consists of plain text and bracketed
+   * parts. e.g. <code>"some string {some expression} some string"</code>.
+   * { here starts a bracket, } ends one.
+   */
+  public static List parseBracketedExpression(String anExpression, char anEscape,
+      String anOpeningBracket, String aClosingBracket) {
+    List result = new ArrayList();
+    int position = 0;
+
+    do {
+      position = findNextBracketedPart(anExpression, position, anEscape, anOpeningBracket, result);
+      if (position>=0) {
+        position+=anOpeningBracket.length();
+        position = findNextBracketedPart(anExpression, position, anEscape, aClosingBracket, result);
+        if (position>0) {
+          position+=aClosingBracket.length();
+        }
+      }
+    } while (position>=0);
+
+    return result;
+  }
 }
\ No newline at end of file
index a3ac35c..a7a41b6 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  any library licensed under the Apache Software License,\r
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
- * (or with modified versions of the above that use the same license as the above),\r
- * and distribute linked combinations including the two.  You must obey the\r
- * GNU General Public License in all respects for all of the code used other than\r
- * the above mentioned libraries.  If you modify this file, you may extend this\r
- * exception to your version of the file, but you are not obligated to do so.\r
- * If you do not wish to do so, delete this exception statement from your version.\r
- */\r
-package mir.util;\r
-\r
-import gnu.regexp.RE;\r
-import gnu.regexp.REException;\r
-\r
-import java.util.List;\r
-import java.util.Vector;\r
-\r
-public class StringRoutines {\r
-\r
-  private StringRoutines() {\r
-  }\r
-\r
-  public static int indexOfCharacters(String aString, char[] aCharacters, int aFrom) {\r
-    int i;\r
-    int result=-1;\r
-    int position;\r
-\r
-    for (i=0; i<aCharacters.length ; i++) {\r
-      position = aString.indexOf(aCharacters[i], aFrom);\r
-\r
-      if (position != -1 && ( result == -1 || position < result )) {\r
-        result = position;\r
-      }\r
-    }\r
-\r
-    return result;\r
-  }\r
-\r
-  public static String replaceStringCharacters(String aText, char[] aCharactersToReplace, String[] aStringsToSubstitute) {\r
-    if (aText==null)\r
-      return null;\r
-\r
-    int position, nextPosition;\r
-    int i;\r
-    StringBuffer result = new StringBuffer();\r
-\r
-    position=0;\r
-    do {\r
-      nextPosition = StringRoutines.indexOfCharacters(aText, aCharactersToReplace, position);\r
-\r
-      if (nextPosition<0)\r
-        nextPosition = aText.length();\r
-\r
-      result.append(aText.substring(position, nextPosition));\r
-\r
-      if (nextPosition<aText.length())\r
-        for (i=0; i<aCharactersToReplace.length; i++) {\r
-          if (aCharactersToReplace[i] == aText.charAt(nextPosition)) {\r
-            result.append(aStringsToSubstitute[i]);\r
-            break;\r
-          }\r
-        }\r
-      position=nextPosition+1;\r
-    }\r
-    while (nextPosition<aText.length()) ;\r
-\r
-    return result.toString();\r
-  }\r
-\r
-\r
-  public static String interpretAsString(Object aValue) throws Exception {\r
-    if (aValue instanceof String)\r
-      return (String) aValue;\r
-\r
-    if (aValue instanceof Integer)\r
-      return ((Integer) aValue).toString();\r
-\r
-    if (aValue == null)\r
-      return "";\r
-\r
-    throw new Exception("String expected, "+aValue+" found");\r
-  }\r
-\r
-  public static int interpretAsInteger(Object aValue) throws Exception {\r
-    if (aValue instanceof Integer)\r
-      return ((Integer) aValue).intValue();\r
-\r
-    if (aValue instanceof String)\r
-      try {\r
-        return Integer.parseInt((String) aValue);\r
-      }\r
-      catch (Throwable t) {\r
-        throw new Exception("Integer expected, "+aValue+" found");\r
-      }\r
-\r
-    throw new Exception("Integer expected, "+aValue+" found");\r
-  }\r
-\r
-  /**\r
-   *\r
-   * @param aSource\r
-   * @param aSearchExpression\r
-   * @param aReplacement\r
-   * @return\r
-   * @throws Exception\r
-   */\r
-  public static String performRegularExpressionReplacement(String aSource,\r
-      String aSearchExpression, String aReplacement) throws Exception {\r
-\r
-    RE regularExpression;\r
-\r
-    regularExpression = new RE(aSearchExpression);\r
-\r
-    return regularExpression.substituteAll(aSource, aReplacement);\r
-  }\r
-\r
-  /**\r
-   *\r
-   * @param aSource\r
-   * @param aSearchExpression\r
-   * @return\r
-   * @throws REException\r
-   */\r
-  public static boolean performRegularExpressionSearch(String aSource,\r
-      String aSearchExpression) throws REException {\r
-    RE regularExpression;\r
-\r
-    regularExpression = new RE(aSearchExpression);\r
-\r
-    return regularExpression.isMatch(aSource);\r
-  }\r
-\r
-  /**\r
-   * Separates a string based on a separator:\r
-   *     <code>seperateString("a:b:c", ":");</code> will lead to\r
-   *     a List with 3 Strings: <code>"a"</code>, <code>"b"</code> and <code>"c"</code>\r
-   *\r
-   * @param aString     The string to split\r
-   * @param aSeparator\r
-   * @return\r
-   */\r
-\r
-  public static List splitString(String aString, String aSeparator) {\r
-    List result= new Vector();\r
-    int previousPosition = 0;\r
-    int position;\r
-    int endOfNamePosition;\r
-\r
-    if (aString!=null) {\r
-      while ( (position = aString.indexOf(aSeparator, previousPosition)) >= 0) {\r
-        result.add(aString.substring(previousPosition, position));\r
-        previousPosition = position + aSeparator.length();\r
-      }\r
-      result.add(aString.substring(previousPosition, aString.length()));\r
-    }\r
-\r
-    return result;\r
-  }\r
-\r
-  /**\r
-   * Separates a String into at most 2 parts based on a separator:\r
-   * <ul>\r
-   *   <li>\r
-   *     <code>seperateString("a:b:c", ":");</code> will lead to\r
-   *     a List with 2 Strings: <code>"a"</code> and <code>"b:c"</code>\r
-   *   <li>\r
-   *     <code>seperateString("abc", ":");</code> will lead to\r
-   *     a List with a single String: <code>"abc"</code>\r
-   * </ul>\r
-   *\r
-   *\r
-   * @param aString\r
-   * @param aSeparator\r
-   * @return\r
-   */\r
-  public static List separateString(String aString, String aSeparator) {\r
-    List result= new Vector();\r
-    int previousPosition = 0;\r
-    int position;\r
-\r
-    if((position = aString.indexOf(aSeparator, previousPosition))>=0) {\r
-      result.add(aString.substring(previousPosition, position));\r
-      previousPosition = position + aSeparator.length();\r
-    }\r
-\r
-    result.add(aString.substring(previousPosition, aString.length()));\r
-\r
-    return result;\r
-  }\r
-\r
-  public static List splitStringWithEscape(String aString, char aSeparator, char anEscape) {\r
-    List result= new Vector();\r
-    int previousPosition = 0;\r
-    int position;\r
-    int endOfNamePosition;\r
-    StringBuffer currentItem = new StringBuffer();\r
-\r
-    if (aString!=null) {\r
-      while ((position = indexOfCharacters(aString, new char[] {aSeparator, anEscape}, previousPosition))>=0) {\r
-        currentItem.append(aString.substring(previousPosition, position));\r
-\r
-        if (aString.charAt(position)==aSeparator) {\r
-          result.add(currentItem.toString());\r
-          currentItem.delete(0, currentItem.length());\r
-        }\r
-        else {\r
-          if (aString.length()>position+1) {\r
-            position=position+1;\r
-            currentItem.append(aString.charAt(position));\r
-          }\r
-        }\r
-        previousPosition = position + 1;\r
-      }\r
-      currentItem.append(aString.substring(previousPosition, aString.length()));\r
-      result.add(currentItem.toString());\r
-    }\r
-\r
-    return result;\r
-  }\r
-\r
-  public static String replicateString(String aString, int aCount) {\r
-    StringBuffer result = new StringBuffer();\r
-\r
-    for (int i=0; i<aCount; i++)\r
-      result.append(aString);\r
-\r
-    return result.toString();\r
-  }\r
-\r
-  public static String replicateChar(char aCharacter, int aCount) {\r
-    char result[] = new char[aCount];\r
-\r
-    for (int i=0; i<aCount; i++)\r
-      result[i]= aCharacter;\r
-\r
-    return new String(result);\r
-  }\r
-\r
-  public static String padStringLeft(String aString, int aLength, char aPadCharacter) {\r
-    if (aString.length()<aLength)\r
-      return replicateChar(aPadCharacter, aLength-aString.length()) + aString;\r
-    else\r
-      return aString;\r
-  }\r
-\r
-  private static final char HEX_CHARACTERS[] = {\r
-      '0', '1', '2', '3', '4', '5', '6', '7',\r
-      '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'\r
-  };\r
-\r
-  public static String convertToHex(long aData, int aNumberOfDigits) {\r
-    StringBuffer result = new StringBuffer();\r
-\r
-    for (int digit = aNumberOfDigits-1; digit>=0; digit--) {\r
-      int value = (int) (aData >> (digit*4)) & 0xf;\r
-      result.append(HEX_CHARACTERS[value]);\r
-    }\r
-\r
-    return result.toString();\r
-  }\r
-\r
-  public static String convertToHex(byte[] aData) {\r
-    StringBuffer result = new StringBuffer();\r
-\r
-    for (int i = 0; i<aData.length; i++) {\r
-      result.append(convertToHex(aData[i], 2));\r
-\r
-    }\r
-\r
-    return result.toString();\r
-  }\r
-}
\ No newline at end of file
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.util;
+
+import gnu.regexp.RE;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class StringRoutines {
+
+  private StringRoutines() {
+  }
+
+  public static int indexOfCharacters(String aString, char[] aCharacters, int aFrom) {
+    int i;
+    int result=-1;
+    int position;
+
+    for (i=0; i<aCharacters.length ; i++) {
+      position = aString.indexOf(aCharacters[i], aFrom);
+
+      if (position != -1 && ( result == -1 || position < result )) {
+        result = position;
+      }
+    }
+
+    return result;
+  }
+
+  public static String replaceStringCharacters(String aText, char[] aCharactersToReplace, String[] aStringsToSubstitute) {
+    if (aText==null)
+      return null;
+
+    int position, nextPosition;
+    int i;
+    StringBuffer result = new StringBuffer();
+
+    position=0;
+    do {
+      nextPosition = StringRoutines.indexOfCharacters(aText, aCharactersToReplace, position);
+
+      if (nextPosition<0)
+        nextPosition = aText.length();
+
+      result.append(aText.substring(position, nextPosition));
+
+      if (nextPosition<aText.length())
+        for (i=0; i<aCharactersToReplace.length; i++) {
+          if (aCharactersToReplace[i] == aText.charAt(nextPosition)) {
+            result.append(aStringsToSubstitute[i]);
+            break;
+          }
+        }
+      position=nextPosition+1;
+    }
+    while (nextPosition<aText.length()) ;
+
+    return result.toString();
+  }
+  /**
+   */
+
+  public static String replaceEscapedStringCharacters(String aText, char anEscapeCharacter, char[] aCharactersToReplace, String[] aStringsToSubstitute) {
+    if (aText==null)
+      return null;
+
+    int position, nextPosition;
+    int i;
+    StringBuffer result = new StringBuffer();
+
+    position=0;
+    do {
+      nextPosition = aText.indexOf(anEscapeCharacter, position);
+
+      if (nextPosition<0)
+        nextPosition = aText.length();
+
+      result.append(aText.substring(position, nextPosition));
+
+      if (nextPosition+1<aText.length()) {
+        nextPosition = nextPosition+1;
+
+        boolean found = false;
+        for (i = 0; i < aCharactersToReplace.length; i++) {
+          if (aCharactersToReplace[i] == aText.charAt(nextPosition)) {
+            result.append(aStringsToSubstitute[i]);
+            found=true;
+            break;
+          }
+        }
+
+        if (!found) {
+          result.append(aText.charAt(nextPosition));
+        }
+      }
+      position=nextPosition+1;
+    }
+    while (nextPosition<aText.length()) ;
+
+    return result.toString();
+  }
+
+  public static String interpretAsString(Object aValue) throws Exception {
+    if (aValue instanceof String)
+      return (String) aValue;
+
+    if (aValue instanceof Integer)
+      return aValue.toString();
+
+    if (aValue == null)
+      return "";
+
+    throw new Exception("String expected, "+aValue+" found");
+  }
+
+  public static int interpretAsInteger(Object aValue) throws Exception {
+    if (aValue instanceof Integer)
+      return ((Integer) aValue).intValue();
+
+    if (aValue instanceof String)
+      try {
+        return Integer.parseInt((String) aValue);
+      }
+      catch (Throwable t) {
+        throw new Exception("Integer expected, "+aValue+" found");
+      }
+
+    throw new Exception("Integer expected, "+aValue+" found");
+  }
+
+  public static String performRegularExpressionReplacement(String aSource, String aSearchExpression, String aReplacement) {
+    try {
+      RE regularExpression;
+
+      regularExpression = new RE(aSearchExpression);
+
+      return regularExpression.substituteAll(aSource, aReplacement);
+    }
+    catch (Throwable t) {
+      throw new UtilFailure("StringRoutines.performRegularExpressionReplacement: " + t.toString(), t);
+    }
+  }
+
+  public static String performCaseInsensitiveRegularExpressionReplacement(String aSource, String aSearchExpression, String aReplacement) {
+    try {
+      RE regularExpression;
+
+      regularExpression = new RE(aSearchExpression, RE.REG_ICASE);
+
+      return regularExpression.substituteAll(aSource, aReplacement);
+    }
+    catch (Throwable t) {
+      throw new UtilFailure("StringRoutines.performRegularExpressionReplacement: " + t.toString(), t);
+    }
+  }
+
+  public static boolean performRegularExpressionSearch(String aSource, String aSearchExpression) {
+    try {
+      RE regularExpression;
+
+      regularExpression = new RE(aSearchExpression);
+
+      return regularExpression.isMatch(aSource);
+    }
+    catch (Throwable t) {
+      throw new UtilFailure("StringRoutines.performRegularExpressionSearch: " + t.toString(), t);
+    }
+  }
+
+  /**
+   * Separates a string based on a separator:
+   *     <code>seperateString("a:b:c", ":");</code> will lead to
+   *     a List with 3 Strings: <code>"a"</code>, <code>"b"</code> and <code>"c"</code>
+   *
+   * @param aString     The string to split
+   * @param aSeparator
+   * @return
+   */
+
+  public static List splitString(String aString, String aSeparator) {
+    List result= new ArrayList();
+    int previousPosition = 0;
+    int position;
+
+    if (aString!=null) {
+      while ( (position = aString.indexOf(aSeparator, previousPosition)) >= 0) {
+        result.add(aString.substring(previousPosition, position));
+        previousPosition = position + aSeparator.length();
+      }
+      result.add(aString.substring(previousPosition, aString.length()));
+    }
+
+    return result;
+  }
+
+  /**
+   * Separates a String into at most 2 parts based on a separator:
+   * <ul>
+   *   <li>
+   *     <code>seperateString("a:b:c", ":");</code> will lead to
+   *     a List with 2 Strings: <code>"a"</code> and <code>"b:c"</code>
+   *   <li>
+   *     <code>seperateString("abc", ":");</code> will lead to
+   *     a List with a single String: <code>"abc"</code>
+   * </ul>
+   *
+   *
+   * @param aString
+   * @param aSeparator
+   * @return
+   */
+  public static List separateString(String aString, String aSeparator) {
+    List result= new ArrayList();
+    int previousPosition = 0;
+    int position;
+
+    if((position = aString.indexOf(aSeparator, previousPosition))>=0) {
+      result.add(aString.substring(previousPosition, position));
+      previousPosition = position + aSeparator.length();
+    }
+
+    result.add(aString.substring(previousPosition, aString.length()));
+
+    return result;
+  }
+
+  /**
+   * Separates a string based on a separator, taking into account an escape character:
+   *     <code>seperateString("a:/::b", ":", "/");</code> will lead to
+   *     a List with 3 Strings: <code>"a"</code>, <code>":"</code> and <code>"b"</code>
+   *
+   * @param aString     The string to split
+   * @param aSeparator
+   * @return
+   */
+
+  public static List splitStringWithEscape(String aString, char aSeparator, char anEscape) {
+    List result= new ArrayList();
+    int previousPosition = 0;
+    int position;
+
+    StringBuffer currentItem = new StringBuffer();
+
+    if (aString!=null && aString.length()>0) {
+      while ((position = indexOfCharacters(aString, new char[] {aSeparator, anEscape}, previousPosition))>=0) {
+        currentItem.append(aString.substring(previousPosition, position));
+
+        if (aString.charAt(position)==aSeparator) {
+          result.add(currentItem.toString());
+          currentItem.delete(0, currentItem.length());
+        }
+        else {
+          if (aString.length()>position+1) {
+            position=position+1;
+            currentItem.append(aString.charAt(position));
+          }
+          else {
+            currentItem.append(aString.charAt(position));
+          }
+        }
+        previousPosition = position + 1;
+      }
+      currentItem.append(aString.substring(previousPosition, aString.length()));
+      result.add(currentItem.toString());
+    }
+
+    return result;
+  }
+
+  public static String replicateString(String aString, int aCount) {
+    StringBuffer result = new StringBuffer();
+
+    for (int i=0; i<aCount; i++)
+      result.append(aString);
+
+    return result.toString();
+  }
+
+  public static String replicateChar(char aCharacter, int aCount) {
+    char result[] = new char[aCount];
+
+    for (int i=0; i<aCount; i++)
+      result[i]= aCharacter;
+
+    return new String(result);
+  }
+
+  public static String padStringLeft(String aString, int aLength, char aPadCharacter) {
+    if (aString.length()<aLength)
+      return replicateChar(aPadCharacter, aLength-aString.length()) + aString;
+    else
+      return aString;
+  }
+
+  private static final char HEX_CHARACTERS[] = {
+      '0', '1', '2', '3', '4', '5', '6', '7',
+      '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
+  };
+
+  public static String convertToHex(long aData, int aNumberOfDigits) {
+    StringBuffer result = new StringBuffer();
+
+    for (int digit = aNumberOfDigits-1; digit>=0; digit--) {
+      int value = (int) (aData >> (digit*4)) & 0xf;
+      result.append(HEX_CHARACTERS[value]);
+    }
+
+    return result.toString();
+  }
+
+  public static String convertToHex(byte[] aData) {
+    StringBuffer result = new StringBuffer();
+
+    for (int i = 0; i<aData.length; i++) {
+      result.append(convertToHex(aData[i], 2));
+
+    }
+
+    return result.toString();
+  }
+}
index cc42565..412ecad 100755 (executable)
 
 package mir.util;
 
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
 
 
 /**
- *
  * <p>Title: </p>
  * <p>Description:
  *   Class to parse structured content:
@@ -55,10 +57,6 @@ import java.util.*;
  *  <p>
  *    Parsing is be very optimistic: no exception is ever to be thrown.
  *  </p>
- * <p>Copyright: Copyright (c) 2003</p>
- * <p>Company: </p>
- * @author not attributable
- * @version 1.0
  */
 public class StructuredContentParser {
   public StructuredContentParser() {
@@ -130,7 +128,7 @@ public class StructuredContentParser {
 
     public char scan() {
       if (!isAtEnd()) {
-        char result =data.charAt(position);
+        char result = data.charAt(position);
         position++;
         return result;
       }
@@ -193,9 +191,7 @@ public class StructuredContentParser {
   }
 
   public static Object parseObject(Scanner aScanner) {
-    Object result = null;
-
-    aScanner.skipSpace();
+   aScanner.skipSpace();
 
     if (!aScanner.isAtEnd()) {
       char data = aScanner.peek();
diff --git a/source/mir/util/XMLReader.java b/source/mir/util/XMLReader.java
deleted file mode 100755 (executable)
index 954b2e7..0000000
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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,
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
- * (or with modified versions of the above that use the same license as the above),
- * 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.util;
-
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Stack;
-
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-
-import multex.Exc;
-import multex.Failure;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.helpers.DefaultHandler;
-
-public class XMLReader {
-  private Locator locator;
-  private String filename;
-  private boolean namespaceAware;
-
-  public XMLReader() {
-    this(false);
-  }
-
-  public XMLReader(boolean aNameSpaceAware) {
-    namespaceAware = aNameSpaceAware;
-    filename="";
-  }
-
-  public void parseFile(String aFileName, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
-    filename= aFileName;
-    try {
-      parseInputStream(new FileInputStream(aFileName), aRootHandler);
-    }
-    catch (Throwable t) {
-      throw new XMLReaderFailure(t);
-    }
-  }
-
-  public void parseInputStream(InputStream anInputStream, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
-    try {
-      SAXParserFactory parserFactory = SAXParserFactory.newInstance();
-
-      parserFactory.setNamespaceAware(true);
-      parserFactory.setValidating(true);
-
-      XMLReaderHandler handler = new XMLReaderHandler(parserFactory, aRootHandler);
-
-      handler.processInputStream(anInputStream);
-    }
-    catch (Throwable e) {
-      Throwable t = ExceptionFunctions.traceCauseException(e);
-
-      if (t instanceof XMLReaderExc) {
-        throw (XMLReaderExc) t;
-      }
-
-      if (t instanceof XMLReaderFailure) {
-        throw (XMLReaderFailure) t;
-      }
-
-      throw new XMLReaderFailure(t);
-    }
-  }
-
-  private class XMLReaderHandler extends DefaultHandler {
-    private SAXParserFactory parserFactory;
-    private SectionsManager manager;
-    private InputSource inputSource;
-
-    public XMLReaderHandler(SAXParserFactory aParserFactory, SectionHandler aRootHandler) {
-      super();
-
-      parserFactory=aParserFactory;
-      manager = new SectionsManager();
-      manager.pushHandler(aRootHandler);
-   }
-
-    public void setDocumentLocator(Locator aLocator) {
-      locator=aLocator;
-    }
-
-    private void processInputStream(InputStream anInputStream) throws XMLReaderExc, XMLReaderFailure {
-      try {
-        SAXParser parser=parserFactory.newSAXParser();
-
-        inputSource = new InputSource(anInputStream);
-        parser.parse(inputSource, this);
-      }
-      catch (Throwable e) {
-        Throwable t = ExceptionFunctions.traceCauseException(e);
-
-        if (t instanceof XMLReaderExc) {
-          if (locator!=null && filename!=null)
-            ((XMLReaderExc) t).setLocation(filename, locator.getLineNumber(), locator.getColumnNumber());
-          throw (XMLReaderExc) t;
-        }
-
-        if (t instanceof SAXParseException) {
-          XMLReaderExc r = new XMLReaderExc(t.getMessage());
-
-          if (locator!=null && filename!=null)
-            r.setLocation(filename, locator.getLineNumber(), locator.getColumnNumber());
-
-          throw r;
-        }
-
-        if (t instanceof XMLReaderFailure) {
-          throw (XMLReaderFailure) t;
-        }
-
-        if (t instanceof ParserConfigurationException) {
-          throw new XMLReaderFailure("Internal exception: "+t.toString(), t);
-        }
-
-        throw new XMLReaderFailure(t);
-      }
-    }
-
-    public void startElement(String aUri, String aLocalName, String aQualifiedName, Attributes anAttributes) throws SAXException {
-      Map attributesMap;
-      int i;
-
-      try {
-        attributesMap = new HashMap();
-
-        if (namespaceAware)
-          for (i=0; i<anAttributes.getLength(); i++)
-            attributesMap.put(new XMLName(anAttributes.getURI(i), anAttributes.getLocalName(i)), anAttributes.getValue(i));
-        else
-          for (i=0; i<anAttributes.getLength(); i++)
-            attributesMap.put(anAttributes.getLocalName(i), anAttributes.getValue(i));
-
-        SectionHandler handler = manager.currentHandler().startElement(new XMLName(aUri, aLocalName), attributesMap);
-
-        manager.pushHandler( handler );
-      }
-      catch (XMLReaderExc e) {
-        throw new SAXParseException(e.getMessage(), null, e);
-      }
-      catch (Exception e) {
-        throw new SAXException(e);
-      }
-    }
-
-    public void endElement(String aUri, String aLocalName, String aQualifiedName) throws SAXException {
-      try
-      {
-        if (!aQualifiedName.equals("include")) {
-          SectionHandler handler = manager.popHandler();
-
-          handler.finishSection();
-
-          if (!manager.isEmpty()) {
-            manager.currentHandler().endElement(handler);
-          }
-        }
-      }
-      catch (XMLReaderExc e) {
-        throw new SAXParseException(e.getMessage(), null, e);
-      }
-      catch (Exception e) {
-        throw new SAXException(e);
-      }
-    }
-
-    public void characters(char[] aBuffer, int aStart, int anEnd) throws SAXException {
-      try {
-        String text = new String(aBuffer, aStart, anEnd);
-
-        manager.currentHandler().characters(text);
-      }
-      catch (XMLReaderExc e) {
-        throw new SAXParseException(e.getMessage(), null, e);
-      }
-      catch (Exception e) {
-        throw new SAXException(e);
-      }
-    }
-  }
-
-  private class SectionsManager {
-    Stack handlerStack;
-
-    public SectionsManager() {
-      handlerStack = new Stack();
-    }
-
-    public void pushHandler(SectionHandler aSectionHandler) {
-      handlerStack.push(aSectionHandler);
-    }
-
-    public SectionHandler popHandler() {
-      return (SectionHandler) handlerStack.pop();
-    }
-
-    public SectionHandler currentHandler() {
-      return (SectionHandler) handlerStack.peek();
-    }
-
-    public boolean isEmpty() {
-      return handlerStack.isEmpty();
-    }
-  }
-
-  public static interface SectionHandler {
-    public abstract SectionHandler startElement(XMLName aTag, Map anAttributes) throws XMLReaderExc;
-
-    public abstract void endElement(SectionHandler aHandler) throws XMLReaderExc;
-
-    public void characters(String aCharacters) throws XMLReaderExc;
-
-    public void finishSection() throws XMLReaderExc;
-  }
-
-  public static abstract class AbstractSectionHandler implements SectionHandler {
-    public SectionHandler startElement(XMLName aTag, Map anAttributes) throws XMLReaderExc {
-      return startElement(aTag.getLocalName(), anAttributes);
-    };
-
-    public SectionHandler startElement(String aLocalName, Map anAttributes) throws XMLReaderExc {
-      return null;
-    };
-
-    public void endElement(SectionHandler aHandler) throws XMLReaderExc {
-    };
-
-    public void finishSection() throws XMLReaderExc {
-    }
-
-    public void characters(String aCharacters) throws XMLReaderExc {
-      if ( aCharacters.trim().length() > 0) {
-        throw new XMLReaderExc("Text not allowed");
-      }
-    }
-  }
-
-  public static class XMLReaderExc extends Exc {
-    private boolean hasLocation;
-    private String filename;
-    private int lineNr;
-    private int columnNr;
-
-    public XMLReaderExc(String aMessage) {
-      super(aMessage);
-      hasLocation = false;
-    }
-
-    protected void setLocation(String aFilename, int aLineNr, int aColumnNr) {
-      filename = aFilename;
-      lineNr = aLineNr;
-      columnNr = aColumnNr;
-      hasLocation = true;
-    }
-
-    public boolean getHasLocation() {
-      return hasLocation;
-    }
-
-    public int getLineNr() {
-      return lineNr;
-    }
-
-    public int getColumnNr() {
-      return columnNr;
-    }
-
-    public String getFilename() {
-      return filename;
-    }
-  }
-
-  public static class XMLReaderFailure extends Failure {
-    public XMLReaderFailure(String aMessage, Throwable aCause) {
-      super(aMessage, aCause);
-    }
-
-    public XMLReaderFailure(Throwable aCause) {
-      super(aCause.getMessage(), aCause);
-    }
-  }
-
-  public static class XMLName {
-    private String namespaceURI;
-    private String localName;
-
-    public XMLName(String aLocalName) {
-      this(aLocalName, null);
-    }
-
-    public XMLName(String aNamespaceURI, String aLocalName) {
-      namespaceURI = aNamespaceURI;
-      localName = aLocalName;
-    }
-
-    public String getNamespaceURI() {
-      return namespaceURI;
-    }
-
-    public String getLocalName() {
-      return localName;
-    }
-
-    public int hashCode() {
-      if (namespaceURI == null)
-        return localName.hashCode();
-      else
-        return localName.hashCode() + 3*namespaceURI.hashCode();
-    }
-
-    public String toString() {
-      return namespaceURI+":"+localName;
-    }
-
-    public boolean equals(Object anObject) {
-      if (anObject instanceof XMLName) {
-        if (namespaceURI==null)
-          return (((XMLName) anObject).namespaceURI == null) &&
-                 localName.equals(((XMLName) anObject).localName);
-        else
-          return namespaceURI.equals(((XMLName) anObject).namespaceURI) &&
-                 localName.equals(((XMLName) anObject).localName);
-      }
-      else
-        return false;
-    }
-  }
-
-}
\ No newline at end of file
diff --git a/source/mir/util/XMLReaderTool.java b/source/mir/util/XMLReaderTool.java
deleted file mode 100755 (executable)
index 2bae6d2..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2001, 2002 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, 
- * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library 
- * (or with modified versions of the above that use the same license as the above), 
- * 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.util;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-public class XMLReaderTool {
-
-  public static void checkValidIdentifier(String anIdentifier) throws XMLReader.XMLReaderExc {
-  }
-
-  public static String getStringAttributeWithDefault(Map anAttributes, String aKey, String aDefault) {
-    if (anAttributes.containsKey(aKey))
-      return (String) anAttributes.get(aKey);
-    else
-      return aDefault;
-  }
-
-  public static void checkIntegerAttribute(Map anAttributes, String aKey) throws XMLReader.XMLReaderExc {
-    try {
-      Integer.parseInt((String) anAttributes.get(aKey));
-    }
-    catch (Throwable t) {
-      throw new XMLReader.XMLReaderExc("attribute '"+aKey+"' is not an integer" );
-    }
-  }
-
-  public static int getIntegerAttributeWithDefault(Map anAttributes, String aKey, int aDefault) throws XMLReader.XMLReaderExc  {
-    String value;
-
-    if (anAttributes.containsKey(aKey)) {
-      checkIntegerAttribute(anAttributes, aKey);
-      return Integer.parseInt((String) anAttributes.get(aKey));
-    }
-    else
-      return aDefault;
-  }
-
-  public static void checkAttributes(Map anAttributes, String[] aRequiredAttributes, String[] anOptionalAttributes)  throws XMLReader.XMLReaderExc {
-    checkAttributeSet(anAttributes.keySet(),
-       new HashSet(Arrays.asList(aRequiredAttributes)),
-       new HashSet(Arrays.asList(anOptionalAttributes)));
-  }
-
-  public static void checkAttributeSet(Set aSet, Set aRequiredElements, Set anOptionalElements) throws XMLReader.XMLReaderExc{
-    Iterator i;
-
-    i = aSet.iterator();
-    while (i.hasNext()) {
-      Object item = i.next();
-
-      if (!(aRequiredElements.contains(item) || anOptionalElements.contains(item)))
-        throw new XMLReader.XMLReaderExc("unknown attribute '" + item + "'" );
-    }
-
-    i = aRequiredElements.iterator();
-    while (i.hasNext()) {
-      Object item = i.next();
-
-      if (!(aSet.contains(item)))
-        throw new XMLReader.XMLReaderExc("missing required attribute '" + item + "'" );
-    }
-
-  }
-
-  /**
-   * Returns the namespace part of a qualified XML Tag name <br>
-   * Example:<br>
-   * <code>getNameSpaceFromQualifiedName("dc:creator");</code> <br>
-   * will return <code>"dc"</code>
-   *
-   * @param aQualifiedName
-   * @return
-   */
-
-  public static String getNameSpaceFromQualifiedName(String aQualifiedName) {
-    List parts = StringRoutines.splitString(aQualifiedName, ":");
-
-    if (parts.size()<=1)
-      return null;
-    else
-      return (String) parts.get(0);
-  }
-
-  /**
-   * Returns the localname part of a qualified XML Tag name <br>
-   * Example:<br>
-   * <code>getLocalNameFromQualifiedName("dc:creator");</code> <br>
-   * will return <code>"creator"</code>
-   *
-   * @param aQualifiedName
-   * @return
-   */
-
-  public static String getLocalNameFromQualifiedName(String aQualifiedName) {
-    List parts = StringRoutines.splitString(aQualifiedName, ":");
-
-    if (parts.size()<1)
-      return null;
-    if (parts.size()==1)
-      return (String) parts.get(0);
-    else
-      return (String) parts.get(1);
-  }
-
-}
diff --git a/source/mir/util/generator/BundleGeneratorFunction.java b/source/mir/util/generator/BundleGeneratorFunction.java
new file mode 100755 (executable)
index 0000000..a33a5ed
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.util.generator;
+
+import mir.bundle.Bundle;
+import mir.generator.Generator;
+import mir.generator.GeneratorExc;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+public class BundleGeneratorFunction implements Generator.Function {
+  private Bundle bundles[];
+
+  public BundleGeneratorFunction(Bundle aBundles[]) {
+    bundles = aBundles;
+  }
+
+  public Object perform(List aParameters) throws GeneratorExc {
+    List extraParameters = new ArrayList(aParameters);
+
+    if (aParameters.size()<1)
+      throw new GeneratorExc("ResourceBundleGeneratorFunction: at least 1 parameter expected");
+
+    String key = (String) aParameters.get(0);
+    extraParameters.remove(0);
+
+    String message=null;
+    for (int j=0; j<bundles.length; j++) {
+      message= bundles[j].getValue(key, extraParameters);
+      if (message!=null)
+        break;
+    }
+
+    if (message == null) {
+      return new String("[" + key + "]");
+    }
+    else {
+      return message;
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/util/generator/ReflectionGeneratorFunctionAdapter.java b/source/mir/util/generator/ReflectionGeneratorFunctionAdapter.java
new file mode 100755 (executable)
index 0000000..1e98f7c
--- /dev/null
@@ -0,0 +1,75 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.util.generator;\r
+\r
+import mir.generator.Generator;\r
+import mir.generator.GeneratorExc;\r
+import mir.generator.GeneratorFailure;\r
+import mir.util.ReflectionRoutines;\r
+\r
+import java.util.List;\r
+import java.lang.reflect.InvocationTargetException;\r
+\r
+import org.apache.commons.beanutils.MethodUtils;\r
+\r
+/**\r
+ * Class to adapt methods with some name to a\r
+ * {@link Generator.Function}\r
+ */\r
+\r
+public class ReflectionGeneratorFunctionAdapter implements Generator.Function {\r
+  private Object target;\r
+  private String methodName;\r
+\r
+  public ReflectionGeneratorFunctionAdapter(Object aTarget, String aMethodName) {\r
+    target = aTarget;\r
+    methodName = aMethodName;\r
+  }\r
+\r
+  /** {@inheritDoc} */\r
+  public Object perform(List aParameters) throws GeneratorExc, GeneratorFailure {\r
+    try {\r
+      return ReflectionRoutines.invokeMethod(target, methodName, aParameters.toArray());\r
+    }\r
+    catch (InvocationTargetException t) {\r
+      if (t.getTargetException() instanceof GeneratorExc) {\r
+        throw (GeneratorExc) t.getTargetException();\r
+      }\r
+\r
+      throw new GeneratorFailure(t.getTargetException());\r
+    }\r
+    catch (IllegalAccessException t) {\r
+      throw new GeneratorFailure(t);\r
+    }\r
+    catch (NoSuchMethodException t) {\r
+      throw new GeneratorFailure(t);\r
+    }\r
+  }\r
+}\r
diff --git a/source/mir/util/generator/ReflectionGeneratorFunctionsAdapter.java b/source/mir/util/generator/ReflectionGeneratorFunctionsAdapter.java
new file mode 100755 (executable)
index 0000000..3ac9bb7
--- /dev/null
@@ -0,0 +1,53 @@
+/*\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  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.util.generator;\r
+\r
+import mir.generator.Generator;\r
+\r
+/**\r
+ * Helper class to expose methods from an ordinary object as\r
+ * {@link Generator.Function}s;\r
+ */\r
+public class ReflectionGeneratorFunctionsAdapter {\r
+  private Object object;\r
+\r
+  public ReflectionGeneratorFunctionsAdapter(Object anObject) {\r
+    object = anObject;\r
+  }\r
+\r
+  /**\r
+   * Returns a {@link Generator.Function} for <code>aName</code>\r
+   * by adapting methods by the same name from the wrapped\r
+   * <code>object</code>.\r
+   */\r
+  public Generator.Function get(String aName) {\r
+    return new ReflectionGeneratorFunctionAdapter(object, aName);\r
+  }\r
+}\r
diff --git a/source/mir/util/xml/AbstractSectionHandler.java b/source/mir/util/xml/AbstractSectionHandler.java
new file mode 100755 (executable)
index 0000000..cd2dda5
--- /dev/null
@@ -0,0 +1,39 @@
+package mir.util.xml;\r
+\r
+/**\r
+ *\r
+ * <p>Title: </p>\r
+ * <p>Description: </p>\r
+ * <p>Copyright: Copyright (c) 2003</p>\r
+ * <p>Company: </p>\r
+ * @author not attributable\r
+ * @version 1.0\r
+ */\r
+\r
+public abstract class AbstractSectionHandler implements SectionHandler {\r
+  public void extra(String anExtraData) throws XMLParserExc, XMLParserFailure {\r
+  }\r
+\r
+  public SectionHandler startElement(XMLName aTag, java.util.Map anAttributes) throws XMLParserExc{\r
+    return startElement(aTag.getLocalName(), XMLReaderTool.convertXMLAttributeMap(anAttributes));\r
+  };\r
+\r
+  public SectionHandler startElement(String aLocalName, java.util.Map anAttributes) throws XMLParserExc{\r
+    return new AbstractSectionHandler() {};\r
+  };\r
+\r
+  public void endElement(SectionHandler aHandler) throws XMLParserExc{\r
+  };\r
+\r
+  public void startSection() throws XMLParserExc{\r
+  }\r
+\r
+  public void finishSection() throws XMLParserExc{\r
+  }\r
+\r
+  public void characters(String aCharacters) throws XMLParserExc{\r
+    if ( aCharacters.trim().length() > 0) {\r
+      throw new XMLParserExc("Text not allowed");\r
+    }\r
+  }\r
+}\r
diff --git a/source/mir/util/xml/SectionHandler.java b/source/mir/util/xml/SectionHandler.java
new file mode 100755 (executable)
index 0000000..6e278d5
--- /dev/null
@@ -0,0 +1,51 @@
+package mir.util.xml;\r
+\r
+public interface SectionHandler {\r
+  /**\r
+   *\r
+   * @param anExtraData\r
+   * @throws XMLParserExc\r
+   * @throws XMLParserFailure\r
+   */\r
+  public void extra(String anExtraData) throws XMLParserExc, XMLParserFailure;\r
+\r
+  /**\r
+   *\r
+   * @param aTag\r
+   * @param anAttributes\r
+   * @return\r
+   * @throws XMLParserExc\r
+   * @throws XMLParserFailure\r
+   */\r
+  public abstract mir.util.xml.SectionHandler startElement(XMLName aTag, java.util.Map anAttributes) throws XMLParserExc, XMLParserFailure;\r
+\r
+  /**\r
+   *\r
+   * @param aHandler\r
+   * @throws XMLParserExc\r
+   * @throws XMLParserFailure\r
+   */\r
+  public abstract void endElement(mir.util.xml.SectionHandler aHandler) throws XMLParserExc, XMLParserFailure;\r
+\r
+  /**\r
+   *\r
+   * @param aCharacters\r
+   * @throws XMLParserExc\r
+   * @throws XMLParserFailure\r
+   */\r
+  public void characters(String aCharacters) throws XMLParserExc, XMLParserFailure;\r
+\r
+  /**\r
+   *\r
+   * @throws XMLParserExc\r
+   * @throws XMLParserFailure\r
+   */\r
+  public void startSection() throws XMLParserExc, XMLParserFailure;\r
+\r
+  /**\r
+   *\r
+   * @throws XMLParserExc\r
+   * @throws XMLParserFailure\r
+   */\r
+  public void finishSection() throws XMLParserExc, XMLParserFailure;\r
+}\r
diff --git a/source/mir/util/xml/XMLName.java b/source/mir/util/xml/XMLName.java
new file mode 100755 (executable)
index 0000000..a9f6058
--- /dev/null
@@ -0,0 +1,88 @@
+package mir.util.xml;\r
+\r
+/**\r
+ * Class to encapsulate an XML-style name (either for tagnames,\r
+ * or attribute names).\r
+ *\r
+ * <p>\r
+ * Usage requirements:\r
+ * <ul>\r
+ *   <li> Namespace aware parsers must supply a local name\r
+ *        and a namespace URI\r
+ *   <li> Non-namespace aware parsers should supply a local name,\r
+ *        and, if present and applicable, also a prefix\r
+ * </ul>\r
+ */\r
+\r
+public class XMLName {\r
+  private String namespaceURI;\r
+  private String localName;\r
+  private String prefix;\r
+\r
+  public XMLName(String aLocalName) {\r
+    this(null, null, aLocalName);\r
+  }\r
+\r
+  public XMLName(String aNamespaceURI, String aPrefix, String aLocalName) {\r
+    localName="";\r
+    prefix="";\r
+    namespaceURI="";\r
+\r
+    if (aLocalName!=null)\r
+      localName = aLocalName;\r
+    if (aPrefix!=null)\r
+      prefix = aPrefix;\r
+    if (aNamespaceURI!=null)\r
+      namespaceURI = aNamespaceURI;\r
+  }\r
+\r
+  public XMLName(String aNamespaceURI, String aLocalName) {\r
+    this (aNamespaceURI, null, aLocalName);\r
+  }\r
+\r
+  /**\r
+   * Returns the namespace URI if available\r
+   */\r
+  public String getNamespaceURI() {\r
+    return namespaceURI;\r
+  }\r
+\r
+  /**\r
+   * Returns the name of the tag, stripped from prefix\r
+   */\r
+  public String getLocalName() {\r
+    return localName;\r
+  }\r
+\r
+  /**\r
+   * Returns the prefix of the tag, if present\r
+   */\r
+  public String getPrefix() {\r
+    return prefix;\r
+  }\r
+\r
+  public int hashCode() {\r
+    if (namespaceURI == null)\r
+      return localName.hashCode() + 3*prefix.hashCode();\r
+    else\r
+      return localName.hashCode() + 3*namespaceURI.hashCode();\r
+  }\r
+\r
+  public String toString() {\r
+    return ((namespaceURI.length()>0)? "["+namespaceURI+"]":"")+((prefix.length()>0)?prefix+":":"")+localName;\r
+  }\r
+\r
+  public boolean equals(Object anObject) {\r
+    if (anObject instanceof mir.util.xml.XMLName) {\r
+      if (namespaceURI==null)\r
+        return (((mir.util.xml.XMLName) anObject).namespaceURI == null) &&\r
+               prefix.equals(((mir.util.xml.XMLName) anObject).prefix) &&\r
+               localName.equals(((mir.util.xml.XMLName) anObject).localName);\r
+      else\r
+        return namespaceURI.equals(((mir.util.xml.XMLName) anObject).namespaceURI) &&\r
+               localName.equals(((mir.util.xml.XMLName) anObject).localName);\r
+    }\r
+    else\r
+      return false;\r
+  }\r
+}\r
diff --git a/source/mir/util/xml/XMLParserEngine.java b/source/mir/util/xml/XMLParserEngine.java
new file mode 100755 (executable)
index 0000000..ee70a13
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.util.xml;
+
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.io.File;
+import java.io.Reader;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+
+import java.util.Stack;
+
+import mir.util.ExceptionFunctions;
+import mir.util.xml.html.XMLHTMLParserProvider;
+
+public class XMLParserEngine {
+  private Map providers;
+  private XMLParserProvider defaultProvider;
+
+  private static XMLParserEngine instance = new XMLParserEngine();
+
+  public static XMLParserEngine getInstance() {
+    return instance;
+  }
+
+  private XMLParserEngine() {
+    providers = new HashMap();
+    defaultProvider = new XMLSAXParserProvider(false);
+    providers.put("xml", defaultProvider);
+    providers.put("xml.namespaceaware", new XMLSAXParserProvider(true));
+    providers.put("html", new XMLHTMLParserProvider());
+  }
+
+  /**
+   *
+   * @param aString
+   * @param aRootHandler
+   * @throws XMLParserFailure
+   * @throws XMLParserExc
+   */
+  public void parseString(String aProvider, String aString, SectionHandler aRootHandler) throws XMLParserFailure, XMLParserExc{
+    try {
+      parse(aProvider, new StringReader(aString), aRootHandler);
+    }
+    catch (Throwable t) {
+      throw new XMLParserFailure(t);
+    }
+  }
+
+  /**
+   *
+   * @param aFile
+   * @param aRootHandler
+   */
+  public void parse(String aProvider, File aFile, SectionHandler aRootHandler) throws XMLParserFailure, XMLParserExc {
+//    filename = aFileName;
+
+    try {
+      parse(aProvider, new BufferedInputStream(new FileInputStream(aFile), 8192), aRootHandler);
+    }
+    catch (XMLParserExc e) {
+      throw e;
+    }
+    catch (Throwable t) {
+      throw new XMLParserFailure(t);
+    }
+  }
+
+  /**
+   * Parse xml coming from an input stream with the system default encoding
+   */
+  public void parse(String aProvider, InputStream anInputStream, SectionHandler aRootHandler) throws XMLParserFailure, XMLParserExc{
+    parse(aProvider, new InputStreamReader(anInputStream), aRootHandler);
+  }
+
+  /**
+   * Parse xml coming from an input stream according to the given encoding
+   */
+  public void parse(String aProvider, InputStream anInputStream, String anEncoding, SectionHandler aRootHandler) throws XMLParserFailure, XMLParserExc{
+    try {
+      parse(aProvider, new InputStreamReader(anInputStream, anEncoding), aRootHandler);
+    }
+    catch (UnsupportedEncodingException e) {
+      throw new XMLParserExc("Unsupported encoding: " + anEncoding);
+    }
+  }
+
+
+  /**
+   *
+   * @param aRootHandler
+   * @throws mir.util.xml.XMLParserFailure
+   * @throws mir.util.xml.XMLParserExc
+   */
+  public void parse(String aProvider, Reader aReader, SectionHandler aRootHandler) throws XMLParserFailure, XMLParserExc{
+    XMLParserProvider provider = (XMLParserProvider) providers.get(aProvider);
+
+    if (provider==null)
+      provider = defaultProvider;
+
+    XMLParserRunner runner = new XMLParserRunner(aRootHandler);
+
+    try {
+      provider.parse(aReader, runner);
+    }
+    catch (Throwable e) {
+      Throwable t = ExceptionFunctions.traceCauseException(e);
+
+      if (t instanceof XMLParserExc && runner.getLocator()!=null) {
+        ((XMLParserExc) t).setLocation(runner.getLocator().getLineNr(), runner.getLocator().getColumnNr());
+      }
+
+      if (t instanceof XMLParserExc) {
+        throw (XMLParserExc) t;
+      }
+
+      if (t instanceof XMLParserFailure) {
+        throw (XMLParserFailure) t;
+      }
+
+      throw new XMLParserFailure(t);
+    }
+  }
+
+  public interface XMLLocator {
+    public int getLineNr();
+    public int getColumnNr();
+  }
+
+  public interface XMLParserReceiver {
+    /**
+     * Provides an object with which it's possible to track the parser's
+     *    position.
+     */
+    public void setLocator(XMLLocator aLocator);
+
+    /**
+     * Extra document data, outside of tags and CDATA, will be passed verbatim
+     * to this method. This may include comments, DTDs, XML specifications,
+     * etc.
+     */
+    public void extra(String aPreAmble) throws XMLParserExc, XMLParserFailure;
+
+    public void startElement(XMLName anElement, Map anAttributes) throws XMLParserExc, XMLParserFailure;
+    public void endElement(XMLName anElement) throws XMLParserExc, XMLParserFailure;
+    public void startDocument() throws XMLParserExc, XMLParserFailure;
+    public void endDocument() throws XMLParserExc, XMLParserFailure;
+    public void text(String aText) throws XMLParserExc, XMLParserFailure;
+  }
+
+  public interface XMLParserProvider {
+    public void parse(Reader aReader, XMLParserReceiver aReceiver) throws XMLParserExc, XMLParserFailure;
+  }
+
+  private class XMLParserRunner implements XMLParserReceiver {
+    private SectionsManager manager;
+    private XMLLocator locator;
+    private SectionHandler rootHandler;
+
+    public XMLParserRunner(SectionHandler aRootHandler) {
+      super();
+
+      locator = null;
+      manager = new SectionsManager();
+      rootHandler = aRootHandler;
+    }
+
+    public void setLocator(XMLLocator aLocator) {
+      locator=aLocator;
+    }
+
+    public void extra(String anExtraData) throws XMLParserExc, XMLParserFailure {
+      SectionHandler handler = manager.currentHandler();
+
+      handler.extra(anExtraData);
+    }
+
+    public void startElement(XMLName anElement, Map anAttributes) throws XMLParserExc, XMLParserFailure {
+      SectionHandler handler = manager.currentHandler().startElement(anElement, anAttributes);
+
+      handler.startSection();
+
+      manager.pushHandler(handler);
+    }
+
+    public void endElement(XMLName anElement) throws XMLParserExc, XMLParserFailure {
+      SectionHandler handler = manager.popHandler();
+
+      handler.finishSection();
+
+      manager.currentHandler().endElement(handler);
+    }
+
+    public void startDocument() throws XMLParserExc, XMLParserFailure {
+      rootHandler.startSection();
+      manager.pushHandler(rootHandler);
+    }
+
+    public void endDocument() throws XMLParserExc, XMLParserFailure {
+      SectionHandler handler = manager.popHandler();
+
+      handler.finishSection();
+    }
+
+    public void text(String aText) throws XMLParserExc, XMLParserFailure {
+      manager.currentHandler().characters(aText);
+    }
+
+    public XMLLocator getLocator() {
+      return locator;
+    }
+  }
+
+  /**
+   *
+   * <p>Title: </p>
+   * <p>Description: </p>
+   * <p>Copyright: Copyright (c) 2003</p>
+   * <p>Company: </p>
+   * @author not attributable
+   * @version 1.0
+   */
+  private class SectionsManager {
+    private Stack handlerStack;
+
+    public SectionsManager() {
+      handlerStack = new Stack();
+    }
+
+    public void pushHandler(SectionHandler aSectionHandler) {
+      handlerStack.push(aSectionHandler);
+    }
+
+    public SectionHandler popHandler() {
+      return (SectionHandler) handlerStack.pop();
+    }
+
+    public SectionHandler currentHandler() {
+      return (SectionHandler) handlerStack.peek();
+    }
+
+    public boolean isEmpty() {
+      return handlerStack.isEmpty();
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/source/mir/util/xml/XMLParserExc.java b/source/mir/util/xml/XMLParserExc.java
new file mode 100755 (executable)
index 0000000..9754224
--- /dev/null
@@ -0,0 +1,34 @@
+package mir.util.xml;\r
+\r
+/**\r
+ * Exception during parsing with optional location information.\r
+ */\r
+\r
+public class XMLParserExc extends multex.Exc {\r
+  private boolean hasLocation;\r
+  private int lineNr;\r
+  private int columnNr;\r
+\r
+  public XMLParserExc(String aMessage) {\r
+    super(aMessage);\r
+    hasLocation = false;\r
+  }\r
+\r
+  protected void setLocation(int aLineNr, int aColumnNr) {\r
+    lineNr = aLineNr;\r
+    columnNr = aColumnNr;\r
+    hasLocation = true;\r
+  }\r
+\r
+  public boolean getHasLocation() {\r
+    return hasLocation;\r
+  }\r
+\r
+  public int getLineNr() {\r
+    return lineNr;\r
+  }\r
+\r
+  public int getColumnNr() {\r
+    return columnNr;\r
+  }\r
+}\r
diff --git a/source/mir/util/xml/XMLParserFailure.java b/source/mir/util/xml/XMLParserFailure.java
new file mode 100755 (executable)
index 0000000..b96d451
--- /dev/null
@@ -0,0 +1,20 @@
+package mir.util.xml;\r
+\r
+/**\r
+ *\r
+ * <p>Title: </p>\r
+ * <p>Description: </p>\r
+ * <p>Copyright: Copyright (c) 2003</p>\r
+ * <p>Company: </p>\r
+ * @author not attributable\r
+ * @version 1.0\r
+ */\r
+public class XMLParserFailure extends multex.Failure {\r
+  public XMLParserFailure(String aMessage, Throwable aCause) {\r
+    super(aMessage, aCause);\r
+  }\r
+\r
+  public XMLParserFailure(Throwable aCause) {\r
+    super(aCause.getMessage(), aCause);\r
+  }\r
+}\r
diff --git a/source/mir/util/xml/XMLReaderTool.java b/source/mir/util/xml/XMLReaderTool.java
new file mode 100755 (executable)
index 0000000..fb4859d
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2001, 2002 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,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * 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.util.xml;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class XMLReaderTool {
+  public static void checkValidIdentifier(String anIdentifier) throws XMLParserExc {
+  }
+
+  public static String getStringAttributeWithDefault(java.util.Map anAttributes, String aKey, String aDefault) {
+    if (anAttributes.containsKey(aKey))
+      return (String) anAttributes.get(aKey);
+    else
+      return aDefault;
+  }
+
+  public static void checkIntegerAttribute(java.util.Map anAttributes, String aKey) throws XMLParserExc {
+    try {
+      Integer.parseInt((String) anAttributes.get(aKey));
+    }
+    catch (Throwable t) {
+      throw new XMLParserExc("attribute '"+aKey+"' is not an integer" );
+    }
+  }
+
+  public static int getIntegerAttributeWithDefault(java.util.Map anAttributes, String aKey, int aDefault) throws XMLParserExc  {
+    if (anAttributes.containsKey(aKey)) {
+      checkIntegerAttribute(anAttributes, aKey);
+
+      return Integer.parseInt((String) anAttributes.get(aKey));
+    }
+    else
+      return aDefault;
+  }
+
+  public static void checkAttributes(java.util.Map anAttributes, String[] aRequiredAttributes, String[] anOptionalAttributes)  throws XMLParserExc {
+    checkAttributeSet(anAttributes.keySet(),
+       new java.util.HashSet(java.util.Arrays.asList(aRequiredAttributes)),
+       new java.util.HashSet(java.util.Arrays.asList(anOptionalAttributes)));
+  }
+
+  public static void checkAttributeSet(java.util.Set aSet, java.util.Set aRequiredElements, java.util.Set anOptionalElements) throws XMLParserExc{
+    java.util.Iterator i;
+
+    i = aSet.iterator();
+    while (i.hasNext()) {
+      Object item = i.next();
+
+      if (!(aRequiredElements.contains(item) || anOptionalElements.contains(item)))
+        throw new XMLParserExc("unknown attribute '" + item + "'" );
+    }
+
+    i = aRequiredElements.iterator();
+    while (i.hasNext()) {
+      Object item = i.next();
+
+      if (!(aSet.contains(item)))
+        throw new XMLParserExc("missing required attribute '" + item + "'" );
+    }
+
+  }
+
+  /**
+   * Returns the namespace part of a qualified XML Tag name <br>
+   * Example:<br>
+   * <code>getPrefixFromQualifiedName("dc:creator");</code> <br>
+   * will return <code>"dc"</code>
+   */
+
+  public static String getPrefixFromQualifiedName(String aQualifiedName) {
+    java.util.List parts = mir.util.StringRoutines.splitString(aQualifiedName, ":");
+
+    if (parts.size()<=1)
+      return "";
+    else
+      return (String) parts.get(0);
+  }
+
+  /**
+   * Returns the localname part of a qualified XML Tag name <br>
+   * Example:<br>
+   * <code>getLocalNameFromQualifiedName("dc:creator");</code> <br>
+   * will return <code>"creator"</code>
+   */
+  public static String getLocalNameFromQualifiedName(String aQualifiedName) {
+    java.util.List parts = mir.util.StringRoutines.separateString(aQualifiedName, ":");
+
+    if (parts.size()<1)
+      return null;
+
+    if (parts.size()==1)
+      return (String) parts.get(0);
+    else
+      return (String) parts.get(1);
+  }
+
+  /**
+   * Creates an {@link XMLName} out of qualified name by splitting on the
+   *    <code>:</code>.
+   */
+  public static XMLName getXMLNameForQualifiedName(String aQualifiedName) {
+    return new XMLName(
+        null,
+        getPrefixFromQualifiedName(aQualifiedName),
+        getLocalNameFromQualifiedName(aQualifiedName));
+  }
+
+  /**
+   * Turns a Map with {@link XMLName} keys into a map with {@link String} keys,
+   *    by taking the <code>XMLName</code>'s local name
+   */
+  public static Map convertXMLAttributeMap(Map anXMLAttributeMap) {
+    Map result = new HashMap();
+
+    Iterator i = anXMLAttributeMap.entrySet().iterator();
+
+    while (i.hasNext()) {
+      Map.Entry entry = (Map.Entry) i.next();
+
+      result.put(
+          ((XMLName) entry.getKey()).getLocalName(),
+          entry.getValue());
+    }
+
+    return result;
+  }
+
+  /** formats an XML name as it would look in an XML file */
+  public static String normalizeXMLName(mir.util.xml.XMLName aName) {
+    String result = aName.getLocalName();
+    if (aName.getPrefix().length() > 0)
+      result = aName.getPrefix() + ":" + result;
+
+    return result;
+  }
+}
diff --git a/source/mir/util/xml/XMLSAXParserProvider.java b/source/mir/util/xml/XMLSAXParserProvider.java
new file mode 100755 (executable)
index 0000000..0e8a851
--- /dev/null
@@ -0,0 +1,160 @@
+package mir.util.xml;\r
+\r
+import java.util.*;\r
+\r
+import org.xml.sax.InputSource;\r
+import org.xml.sax.SAXException;\r
+import org.xml.sax.Locator;\r
+import org.xml.sax.SAXParseException;\r
+import mir.util.ExceptionFunctions;\r
+\r
+/**\r
+ *\r
+ * <p>Title: </p>\r
+ * <p>Description: </p>\r
+ * <p>Copyright: Copyright (c) 2003</p>\r
+ * <p>Company: </p>\r
+ * @author not attributable\r
+ * @version 1.0\r
+ */\r
+class XMLSAXParserProvider implements XMLParserEngine.XMLParserProvider {\r
+  private boolean nameSpaceAware;\r
+\r
+  public XMLSAXParserProvider(boolean aNameSpaceAware) {\r
+    nameSpaceAware = aNameSpaceAware;\r
+  }\r
+\r
+  public void parse(java.io.Reader aReader, XMLParserEngine.XMLParserReceiver aReceiver) throws XMLParserExc, XMLParserFailure {\r
+    try {\r
+      javax.xml.parsers.SAXParserFactory parserFactory = javax.xml.parsers.SAXParserFactory.newInstance();\r
+\r
+      parserFactory.setNamespaceAware(true);\r
+      parserFactory.setValidating(true);\r
+      javax.xml.parsers.SAXParser parser = parserFactory.newSAXParser();\r
+\r
+      parser.parse(new InputSource(aReader), new SAXHandler(aReceiver));\r
+    }\r
+    catch (org.xml.sax.SAXException e) {\r
+      Throwable t = ExceptionFunctions.traceCauseException(e);\r
+\r
+      if (t instanceof XMLParserExc) {\r
+        throw (XMLParserExc) t;\r
+      }\r
+\r
+      if (t instanceof XMLParserFailure) {\r
+        throw (XMLParserFailure) t;\r
+      }\r
+\r
+      if (t instanceof SAXParseException) {\r
+        throw new XMLParserExc(t.getMessage());\r
+      }\r
+\r
+      throw new XMLParserFailure(t);\r
+    }\r
+    catch (Throwable t) {\r
+      throw new XMLParserFailure(t);\r
+    }\r
+  }\r
+\r
+  private class SAXHandler extends org.xml.sax.helpers.DefaultHandler {\r
+    private XMLParserEngine.XMLParserReceiver receiver;\r
+\r
+    public SAXHandler(XMLParserEngine.XMLParserReceiver aReceiver) throws XMLParserExc, XMLParserFailure {\r
+      super();\r
+\r
+      receiver = aReceiver;\r
+      receiver.startDocument();\r
+   }\r
+\r
+    public void setDocumentLocator(final Locator aLocator) {\r
+      receiver.setLocator(\r
+          new XMLParserEngine.XMLLocator() {\r
+            public int getLineNr() {\r
+              return aLocator.getLineNumber();\r
+            }\r
+\r
+            public int getColumnNr() {\r
+              return aLocator.getColumnNumber();\r
+            }\r
+          }\r
+      );\r
+    }\r
+\r
+    public void startElement(String aUri, String aLocalName, String aQualifiedName, org.xml.sax.Attributes anAttributes) throws org.xml.sax.SAXException {\r
+      try {\r
+        Map attributes = new java.util.HashMap();\r
+\r
+        XMLName tag;\r
+        if (nameSpaceAware) {\r
+          tag = new XMLName(aUri, XMLReaderTool.getPrefixFromQualifiedName(aQualifiedName), aLocalName);\r
+          for (int i=0; i<anAttributes.getLength(); i++)\r
+            attributes.put(\r
+                new XMLName(anAttributes.getURI(i),\r
+                            XMLReaderTool.getPrefixFromQualifiedName(anAttributes.getQName(i)),\r
+                            anAttributes.getLocalName(i)),\r
+                anAttributes.getValue(i));\r
+        }\r
+        else {\r
+          tag = new XMLName(aUri, XMLReaderTool.getPrefixFromQualifiedName(aQualifiedName),\r
+                      XMLReaderTool.getLocalNameFromQualifiedName(aQualifiedName));\r
+          for (int i=0; i<anAttributes.getLength(); i++)\r
+            attributes.put(\r
+                new XMLName(anAttributes.getURI(i),\r
+                           XMLReaderTool.getPrefixFromQualifiedName(anAttributes.getQName(i)),\r
+                           XMLReaderTool.getLocalNameFromQualifiedName(anAttributes.getQName(i))),\r
+                anAttributes.getValue(i));\r
+        }\r
+\r
+        receiver.startElement(tag, attributes);\r
+      }\r
+      catch (XMLParserExc e) {\r
+        throw new org.xml.sax.SAXParseException(e.getMessage(), null, e);\r
+      }\r
+      catch (Exception e) {\r
+        throw new SAXException(e);\r
+      }\r
+    }\r
+\r
+    public void endElement(String aUri, String aLocalName, String aQualifiedName) throws org.xml.sax.SAXException {\r
+      try\r
+      {\r
+        XMLName element = new XMLName(aUri, XMLReaderTool.getPrefixFromQualifiedName(aQualifiedName), aLocalName);\r
+\r
+        receiver.endElement(element);\r
+      }\r
+      catch (XMLParserExc e) {\r
+        throw new org.xml.sax.SAXParseException(e.getMessage(), null, e);\r
+      }\r
+      catch (Exception e) {\r
+        throw new org.xml.sax.SAXException(e);\r
+      }\r
+    }\r
+\r
+    public void endDocument() throws org.xml.sax.SAXException {\r
+      try\r
+      {\r
+        receiver.endDocument();\r
+      }\r
+      catch (XMLParserExc e) {\r
+        throw new org.xml.sax.SAXParseException(e.getMessage(), null, e);\r
+      }\r
+      catch (Exception e) {\r
+        throw new org.xml.sax.SAXException(e);\r
+      }\r
+    }\r
+\r
+    public void characters(char[] aBuffer, int aStart, int anEnd) throws org.xml.sax.SAXException {\r
+      try {\r
+        String text = new String(aBuffer, aStart, anEnd);\r
+\r
+        receiver.text(text);\r
+      }\r
+      catch (XMLParserExc e) {\r
+        throw new org.xml.sax.SAXParseException(e.getMessage(), null, e);\r
+      }\r
+      catch (Exception e) {\r
+        throw new org.xml.sax.SAXException(e);\r
+      }\r
+    }\r
+  }\r
+}\r
diff --git a/source/mir/util/xml/html/HTMLParser.java b/source/mir/util/xml/html/HTMLParser.java
new file mode 100755 (executable)
index 0000000..669a9bd
--- /dev/null
@@ -0,0 +1,154 @@
+package mir.util.xml.html;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ *
+ * TODO
+ *   [x] selfclosing <br/> tags
+ *   [ ] de-html-escaping of cdata, parameter values etc
+ *   [ ] Smarter corrections
+ *       [ ]
+ *   [ ] case sensitivity optional
+ */
+
+public class HTMLParser {
+  private HTMLSchemaInformation schemaInformation;
+
+  public HTMLParser() {
+    schemaInformation = new HTMLSchemaInformation();
+  }
+
+  public void parse(Reader aReader, ParserReceiver aReceiver) throws HTMLParserExc, HTMLParserFailure, IOException {
+    HTMLScanner scanner;
+    CoreParser parser;
+    parser = new CoreParser(aReceiver);
+    scanner = new HTMLScanner(parser, aReader);
+    scanner.run();
+  }
+
+  private class CoreParser implements HTMLScanner.ScannerReceiver {
+    private ParserReceiver receiver;
+    private Stack tagStack;
+
+    public CoreParser(ParserReceiver aReceiver) {
+      receiver = aReceiver;
+      tagStack = new Stack();
+    }
+
+    public void handleDTD(String aDTD) throws HTMLParserExc  {
+      receiver.dtd(aDTD);
+    }
+
+    public void handleOpenTag(String aTag, Map anAttributes) throws HTMLParserExc  {
+      String lowercaseTag = aTag.toLowerCase();
+
+      HTMLSchemaInformation.HTMLTagInformation tagInformation =
+          schemaInformation.lookupTag(lowercaseTag);
+
+      Map attributes = new HashMap();
+
+      Iterator i = anAttributes.entrySet().iterator();
+      while (i.hasNext()) {
+        Map.Entry entry = (Map.Entry) i.next();
+
+        attributes.put(((String) entry.getKey()).toLowerCase(), entry.getValue());
+      }
+
+      if (tagInformation!=null) {
+        if (tagInformation.getIsBlock()) {
+          closeAllInlineTags();
+        }
+
+        closeAllAutoclosingTags(tagInformation);
+
+        receiver.openTag(lowercaseTag, attributes);
+        if (tagInformation.getHasBody()) {
+          tagStack.push(lowercaseTag);
+        }
+        else {
+          receiver.closeTag(lowercaseTag);
+        }
+      }
+      else {
+        receiver.openTag(lowercaseTag, attributes);
+        tagStack.push(lowercaseTag);
+      }
+    }
+
+    public void handleClosingTag(String aTag) throws HTMLParserExc {
+      String lowercaseTag = aTag.toLowerCase();
+
+      HTMLSchemaInformation.HTMLTagInformation tagInformation =
+          schemaInformation.lookupTag(lowercaseTag);
+
+      if (tagInformation!=null) {
+        if (tagInformation.getIsBlock()) {
+          closeAllInlineTags();
+        }
+      }
+
+      int index = tagStack.search(lowercaseTag);
+
+      if (index>-1 && index<4) {
+        for (int i=0; i<index; i++) {
+          closeUpmostTag();
+        }
+      }
+    }
+
+    public void handleCData(String aData)  throws HTMLParserExc {
+      receiver.cdata(aData);
+    }
+
+    public void handleComment(String aTag) throws HTMLParserExc  {
+      receiver.comment(aTag);
+    }
+
+    public void handleEndOfStream() throws HTMLParserExc {
+      while (!tagStack.empty())
+        closeUpmostTag();
+    }
+
+    private void closeAllAutoclosingTags(HTMLSchemaInformation.HTMLTagInformation aTagInformation) throws HTMLParserExc {
+      while (!tagStack.empty()) {
+        String tag = (String) tagStack.peek();
+
+        if (aTagInformation.autoClose(tag)) {
+          closeUpmostTag();
+        }
+        else {
+          break;
+        }
+      }
+    }
+
+    private void closeAllInlineTags() throws HTMLParserExc {
+      while (!tagStack.empty()) {
+        HTMLSchemaInformation.HTMLTagInformation tagInformation =
+            schemaInformation.lookupTag((String) tagStack.peek());
+
+        if (tagInformation!=null && !tagInformation.getIsBlock()) {
+          closeUpmostTag();
+        }
+        else {
+          break;
+        }
+      }
+    }
+
+    private void closeUpmostTag() throws HTMLParserExc {
+      receiver.closeTag((String) tagStack.peek());
+      tagStack.pop();
+    }
+  }
+
+  public interface ParserReceiver {
+    public void dtd(String aDTD) throws HTMLParserExc;
+    public void openTag(String aTag, Map anAttributes) throws HTMLParserExc;
+    public void closeTag(String aTag) throws HTMLParserExc;
+    public void comment(String aData) throws HTMLParserExc;
+    public void cdata(String aData) throws HTMLParserExc;
+  }
+}
\ No newline at end of file
diff --git a/source/mir/util/xml/html/HTMLParserExc.java b/source/mir/util/xml/html/HTMLParserExc.java
new file mode 100755 (executable)
index 0000000..c1d48d1
--- /dev/null
@@ -0,0 +1,34 @@
+package mir.util.xml.html;\r
+\r
+/**\r
+ * Exception during parsing with optional location information.\r
+ */\r
+\r
+public class HTMLParserExc extends multex.Exc {\r
+  private boolean hasLocation;\r
+  private int lineNr;\r
+  private int columnNr;\r
+\r
+  public HTMLParserExc(String aMessage) {\r
+    super(aMessage);\r
+    hasLocation = false;\r
+  }\r
+\r
+  protected void setLocation(int aLineNr, int aColumnNr) {\r
+    lineNr = aLineNr;\r
+    columnNr = aColumnNr;\r
+    hasLocation = true;\r
+  }\r
+\r
+  public boolean getHasLocation() {\r
+    return hasLocation;\r
+  }\r
+\r
+  public int getLineNr() {\r
+    return lineNr;\r
+  }\r
+\r
+  public int getColumnNr() {\r
+    return columnNr;\r
+  }\r
+}\r
diff --git a/source/mir/util/xml/html/HTMLParserFailure.java b/source/mir/util/xml/html/HTMLParserFailure.java
new file mode 100755 (executable)
index 0000000..bbb40ec
--- /dev/null
@@ -0,0 +1,20 @@
+package mir.util.xml.html;\r
+\r
+/**\r
+ *\r
+ * <p>Title: </p>\r
+ * <p>Description: </p>\r
+ * <p>Copyright: Copyright (c) 2003</p>\r
+ * <p>Company: </p>\r
+ * @author not attributable\r
+ * @version 1.0\r
+ */\r
+public class HTMLParserFailure extends multex.Failure {\r
+  public HTMLParserFailure(String aMessage, Throwable aCause) {\r
+    super(aMessage, aCause);\r
+  }\r
+\r
+  public HTMLParserFailure(Throwable aCause) {\r
+    super(aCause.getMessage(), aCause);\r
+  }\r
+}\r
diff --git a/source/mir/util/xml/html/HTMLScanner.java b/source/mir/util/xml/html/HTMLScanner.java
new file mode 100755 (executable)
index 0000000..1c6ff42
--- /dev/null
@@ -0,0 +1,310 @@
+package mir.util.xml.html;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Map;
+
+import mir.util.HTMLRoutines;
+
+public class HTMLScanner {
+  private ReaderWrapper reader;
+  private ScannerReceiver receiver;
+
+  public HTMLScanner(ScannerReceiver aReceiver, Reader aReader) {
+    reader = new ReaderWrapper(aReader);
+    receiver = aReceiver;
+  }
+
+  public interface ScannerReceiver {
+    public void handleDTD(String aDTD) throws HTMLParserExc;
+    public void handleOpenTag(String aTag, Map anAttributes) throws HTMLParserExc;
+    public void handleClosingTag(String aTag) throws HTMLParserExc;
+    public void handleCData(String aData) throws HTMLParserExc;
+    public void handleComment(String aTag) throws HTMLParserExc;
+    public void handleEndOfStream() throws HTMLParserExc;
+  }
+
+  public void run() throws IOException, HTMLParserExc {
+
+    while (!reader.isAtEnd()) {
+      char c = reader.peek();
+
+      if (c != '<')
+        readCData();
+      else {
+        reader.get();
+        c = reader.peek();
+
+        switch (c) {
+          case '!':
+            reader.get();
+            readSpecial();
+            break;
+          case '/':
+            reader.get();
+            readEndTag();
+            break;
+          default:
+            readTag();
+        }
+      }
+    }
+
+    receiver.handleEndOfStream();
+  }
+
+  private boolean isValidTagNameCharacter(char aCharacter) {
+    int type = Character.getType(aCharacter);
+
+    return
+        (type == Character.UPPERCASE_LETTER)  ||
+        (type == Character.LOWERCASE_LETTER)  ||
+        (type == Character.DECIMAL_DIGIT_NUMBER)  ||
+        (aCharacter == '.') ||
+        (aCharacter == '-') ||
+        (aCharacter == '_') ||
+        (aCharacter == ':');
+  }
+
+  private boolean isValidUnQuotedAttributeCharacter(char aCharacter) {
+    int type = Character.getType(aCharacter);
+
+    return
+        (type == Character.UPPERCASE_LETTER)  ||
+        (type == Character.LOWERCASE_LETTER)  ||
+        (type == Character.DECIMAL_DIGIT_NUMBER)  ||
+        (aCharacter == '.') ||
+        (aCharacter == '#') ||
+        (aCharacter == '-') ||
+        (aCharacter == '_') ||
+        (aCharacter == ':');
+  }
+
+  private void skipWhiteSpace() throws IOException {
+    while (!reader.isAtEnd() && Character.isWhitespace(reader.peek())) {
+      reader.get();
+    }
+  }
+
+  private void readEndTag() throws IOException, HTMLParserExc {
+    StringBuffer result = new StringBuffer();
+
+    skipWhiteSpace();
+
+    while (!reader.isAtEnd() && isValidTagNameCharacter(reader.peek())) {
+      result.append(reader.get());
+    }
+
+    skipWhiteSpace();
+
+    if (!reader.isAtEnd() && reader.peek()=='>')
+      reader.get();
+
+    receiver.handleClosingTag(result.toString());
+  }
+
+  private String getName() throws IOException {
+    StringBuffer result = new StringBuffer();
+
+    skipWhiteSpace();
+
+    while (!reader.isAtEnd() && isValidTagNameCharacter(reader.peek())) {
+      result.append(reader.get());
+    }
+
+    if (result.length()==0)
+      return null;
+    else
+      return result.toString();
+  }
+
+  private String getAttributeValue() throws IOException {
+    StringBuffer result = new StringBuffer();
+
+    skipWhiteSpace();
+
+    if (!reader.isAtEnd()) {
+      if (reader.peek() == '\'' || reader.peek() == '\"') {
+        char boundary = reader.get();
+
+        while (!reader.isAtEnd() && reader.peek()!=boundary) {
+          result.append(reader.get());
+        }
+
+        if (!reader.isAtEnd() && reader.peek()==boundary)
+          reader.get();
+      }
+      else {
+        while (!reader.isAtEnd() && isValidUnQuotedAttributeCharacter(reader.peek())) {
+          result.append(reader.get());
+        }
+      }
+    }
+
+    return HTMLRoutines.resolveHTMLEntites(result.toString());
+  }
+
+  private void readTag() throws IOException, HTMLParserExc {
+    String tagName = getName();
+
+    Map attributes = new HashMap();
+
+    String attributeName = getName();
+    String attributeValue = null;
+
+    while (attributeName!=null) {
+      skipWhiteSpace();
+
+      if (!reader.isAtEnd() && reader.peek()=='=') {
+        reader.get();
+        attributeValue = getAttributeValue();
+      }
+
+      attributes.put(attributeName, attributeValue);
+
+      attributeName = getName();
+    }
+
+    boolean isClosed=false;
+
+    skipWhiteSpace();
+    if (!reader.isAtEnd() && reader.peek()=='/') {
+      isClosed = true;
+      reader.get();
+    }
+
+    skipWhiteSpace();
+    if (!reader.isAtEnd() && reader.peek()=='>') {
+      reader.get();
+    }
+
+    receiver.handleOpenTag(tagName, attributes);
+    if (isClosed)
+      receiver.handleClosingTag(tagName);
+  }
+
+  private void readSpecial() throws IOException, HTMLParserExc  {
+    StringBuffer result = new StringBuffer();
+
+    if (!reader.isAtEnd() && reader.peek()=='-') {
+      reader.get();
+      if (!reader.isAtEnd() && reader.peek()=='-') {
+        reader.get();
+
+        while (!reader.isAtEnd()) {
+          if (reader.peek()=='-') {
+            reader.get();
+            if (!reader.isAtEnd() && reader.peek()=='-') {
+              reader.get();
+              if (!reader.isAtEnd() && reader.peek()=='>') {
+                reader.get();
+                break;
+              }
+              result.append('-');
+            }
+            result.append('-');
+          }
+          if (!reader.isAtEnd())
+            result.append(reader.get());
+        }
+
+        skipWhiteSpace();
+
+        if (!reader.isAtEnd() && reader.peek()=='>')
+          reader.get();
+
+        receiver.handleComment(result.toString());
+
+        return;
+      }
+      else {
+        result.append('-');
+      }
+    }
+
+    while (!reader.isAtEnd() && reader.peek()!='>') {
+      result.append(reader.get());
+    }
+
+    if (!reader.isAtEnd() && reader.peek()=='>')
+      reader.get();
+
+    receiver.handleDTD("<!"+result.toString()+">");
+  }
+
+  private void readCData() throws IOException, HTMLParserExc {
+    StringBuffer result = new StringBuffer();
+
+    while (!reader.isAtEnd() && reader.peek()!='<') {
+      result.append(reader.get());
+    }
+
+
+
+    receiver.handleCData(HTMLRoutines.resolveHTMLEntites(result.toString()));
+  }
+
+  /**
+   * Class to provide for a 1 character look-ahead on a reader
+   */
+  public static class ReaderWrapper {
+    private Reader reader;
+    private char buffer;
+    private boolean haveBuffer;
+
+    public ReaderWrapper(Reader aReader) {
+      reader = aReader;
+      haveBuffer = false;
+    }
+
+    /**
+     * Returns <code>true</code> if the stream contains no more characters.
+     */
+    public boolean isAtEnd() throws IOException {
+      fillBuffer();
+
+      return !haveBuffer;
+    }
+
+    /**
+     * Gets the next character from the reader but will not remove it from the
+     *    stream.
+     *    {@link #isAtEnd()} must return <code>false</code> before call this
+     *    routine.
+     */
+    public char peek() throws IOException {
+      fillBuffer();
+
+      return buffer;
+    }
+
+    /**
+     * Gets the next character from the reader and removes it from the stream.
+     *    {@link #isAtEnd()} must return <code>false</code> before call this
+     *    routine.
+     */
+    public char get() throws IOException {
+      fillBuffer();
+      haveBuffer = false;
+
+      return buffer;
+    }
+
+    /**
+     * If the reader is not at it's end, then upon return, the buffer will
+     *    be filled. If the buffer was already filled, then this method won't
+     *    do anything.
+     */
+    public void fillBuffer() throws IOException {
+      if (!haveBuffer) {
+        int c = reader.read();
+
+        if (c!=-1) {
+          buffer = (char) c;
+          haveBuffer=true;
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/util/xml/html/HTMLSchemaInformation.java b/source/mir/util/xml/html/HTMLSchemaInformation.java
new file mode 100755 (executable)
index 0000000..5856214
--- /dev/null
@@ -0,0 +1,170 @@
+package mir.util.xml.html;
+
+import java.util.*;
+
+public class HTMLSchemaInformation {
+  private Map tags;
+
+  public HTMLSchemaInformation() {
+    tags = new HashMap();
+
+    addInlineTag("a");
+    addInlineTag("abbr");
+    addInlineTag("acronym");
+    addInlineTag("address");
+    addInlineTag("applet");
+    addInlineTag("area");
+    addInlineTag("b");
+    addInlineTag("base");
+    addInlineTag("basefont");
+    addInlineTag("bdo");
+    addInlineTag("big");
+    addInlineTag("blockquote");
+    addBlockTag("body", new String[] {"head"});
+    addBodylessTag("br");
+    addBodylessTag("button");
+    addInlineTag("caption");
+    addInlineTag("center");
+    addInlineTag("cite");
+    addInlineTag("code");
+    addInlineTag("col");
+    addInlineTag("colgroup");
+    addInlineTag("dd");
+    addInlineTag("del");
+    addInlineTag("dfn");
+    addInlineTag("dir");
+    addBlockTag("div");
+    addInlineTag("dl");
+    addInlineTag("dt");
+    addInlineTag("em");
+    addInlineTag("fieldset");
+    // Zapata: Removed because of frequent abuse by html writers
+    // addInlineTag("font");
+    addBlockTag("form");
+    addBodylessTag("frame");
+    addInlineTag("frameset");
+    addInlineTag("h1");
+    addInlineTag("h2");
+    addInlineTag("h3");
+    addInlineTag("h4");
+    addInlineTag("h5");
+    addInlineTag("h6");
+    addBlockTag("head");
+    addBodylessTag("hr");
+    addBlockTag("html");
+    addInlineTag("i");
+    addBlockTag("iframe");
+    addBodylessTag("img");
+    addBodylessTag("input");
+    addInlineTag("ins");
+    addInlineTag("isindex");
+    addInlineTag("kbd");
+    addInlineTag("label");
+    addInlineTag("legend");
+    addInlineTag("li");
+    addInlineTag("link");
+    addInlineTag("map");
+    addInlineTag("menu");
+    addBodylessTag("meta");
+    addBlockTag("noframes");
+    addInlineTag("noscript");
+    addBodylessTag("object");
+    addInlineTag("ol");
+    addInlineTag("optgroup");
+    addInlineTag("option");
+    addBlockTag("p", new String[] {"p"});
+    addInlineTag("param");
+    addInlineTag("pre");
+    addInlineTag("q");
+    addInlineTag("s");
+    addInlineTag("samp");
+    addInlineTag("script");
+    addInlineTag("select");
+    addInlineTag("small");
+    addInlineTag("span");
+    addInlineTag("strike");
+    addInlineTag("strong");
+    addInlineTag("style");
+    addInlineTag("sub");
+    addInlineTag("sup");
+    addBlockTag("table");
+    addBlockTag("tbody");
+    addBlockTag("td", new String[] {"td", "th"});
+    addInlineTag("textarea");
+    addInlineTag("tfoot");
+    addBlockTag("th", new String[] {"td", "th"});
+    addInlineTag("thead");
+    addInlineTag("title");
+    addBlockTag("tr", new String[] {"td", "th", "tr"});
+    addInlineTag("tt");
+    addInlineTag("u");
+    addInlineTag("ul");
+    addInlineTag("var");
+  }
+
+  public HTMLTagInformation lookupTag(String aTag) {
+    return (HTMLTagInformation) tags.get(aTag);
+  }
+
+  public void addInlineTag(String aTagName) {
+    addTag(aTagName, false, true, null);
+  }
+
+  public void addBodylessTag(String aTagName) {
+    addTag(aTagName, false, false, null);
+  }
+
+  public void addBlockTag(String aTagName) {
+    addTag(aTagName, true, true, null);
+  }
+
+  public void addBlockTag(String aTagName, String[] anAutoCloseList) {
+    addTag(aTagName, true, true, anAutoCloseList);
+  }
+
+  public void addTag(String aTagName, boolean anIsBlock, boolean aHasBody, String[] anAutoCloseList) {
+    HTMLTagInformation tagInformation = new HTMLTagInformation(aTagName, anIsBlock, aHasBody);
+
+    if (anAutoCloseList!=null) {
+      for (int i = 0; i < anAutoCloseList.length; i++) {
+        tagInformation.addAutoClosedTag(anAutoCloseList[i]);
+      }
+    }
+
+    tags.put(aTagName, tagInformation);
+  }
+
+  public class HTMLTagInformation {
+    private boolean isBlock;
+    private boolean hasBody;
+    private String tagName;
+    private List autoCloseList;
+
+    public HTMLTagInformation(String aTagName, boolean anIsBlock, boolean aHasBody) {
+      hasBody = aHasBody;
+      isBlock = anIsBlock;
+      tagName = aTagName;
+      autoCloseList = new ArrayList();
+    }
+
+    void addAutoClosedTag(String aTag) {
+      autoCloseList.add(aTag);
+    }
+
+    public boolean autoClose(String aTag) {
+      return autoCloseList.contains(aTag);
+    }
+
+    public boolean getIsBlock() {
+      return isBlock;
+    }
+
+    public boolean getHasBody() {
+      return hasBody;
+    }
+
+    public String getTagName() {
+      return tagName;
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/util/xml/html/XMLHTMLParserProvider.java b/source/mir/util/xml/html/XMLHTMLParserProvider.java
new file mode 100755 (executable)
index 0000000..31bcc85
--- /dev/null
@@ -0,0 +1,96 @@
+package mir.util.xml.html;\r
+\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Map;\r
+\r
+import mir.util.xml.XMLParserEngine;\r
+import mir.util.xml.XMLParserExc;\r
+import mir.util.xml.XMLParserFailure;\r
+import mir.util.xml.XMLReaderTool;\r
+import mir.util.xml.XMLName;\r
+\r
+/**\r
+ */\r
+\r
+public class XMLHTMLParserProvider implements XMLParserEngine.XMLParserProvider {\r
+  public XMLHTMLParserProvider() {\r
+  }\r
+\r
+  public void parse(java.io.Reader aReader, final XMLParserEngine.XMLParserReceiver aReceiver) throws XMLParserExc, XMLParserFailure {\r
+    HTMLParser parser = new HTMLParser();\r
+\r
+    try {\r
+      aReceiver.startDocument();\r
+\r
+      parser.parse(aReader, new HTMLParser.ParserReceiver() {\r
+        public void dtd(String aDTD) throws HTMLParserExc {\r
+          try {\r
+            aReceiver.extra(aDTD);\r
+          }\r
+          catch (XMLParserExc t) {\r
+            throw new HTMLParserFailure(t);\r
+          }\r
+        }\r
+\r
+        public void openTag(String aTag, Map anAttributes) {\r
+          Map attributes = new HashMap();\r
+          Iterator i = anAttributes.entrySet().iterator();\r
+\r
+          while (i.hasNext()) {\r
+            Map.Entry entry = (Map.Entry) i.next();\r
+            XMLName key = XMLReaderTool.getXMLNameForQualifiedName((String) entry.getKey());\r
+            String value = (String) entry.getValue();\r
+            if (value==null)\r
+              value = key.getLocalName();\r
+\r
+            attributes.put(key, value);\r
+          }\r
+\r
+          try {\r
+            aReceiver.startElement(XMLReaderTool.getXMLNameForQualifiedName(aTag), attributes);\r
+          }\r
+          catch (XMLParserExc e) {\r
+            throw new HTMLParserFailure(e);\r
+          }\r
+        }\r
+\r
+        public void closeTag(String aTag) {\r
+          try {\r
+            aReceiver.endElement(XMLReaderTool.getXMLNameForQualifiedName(aTag));\r
+          }\r
+          catch (XMLParserExc e) {\r
+            throw new HTMLParserFailure(e);\r
+          }\r
+        }\r
+\r
+        public void comment(String aData) {\r
+          try {\r
+            aReceiver.extra("<!--"+aData+"-->");\r
+          }\r
+          catch (XMLParserExc e) {\r
+            throw new HTMLParserFailure(e);\r
+          }\r
+        }\r
+\r
+        public void cdata(String aData) {\r
+          try {\r
+            aReceiver.text(aData);\r
+          }\r
+          catch (XMLParserExc e) {\r
+            throw new HTMLParserFailure(e);\r
+          }\r
+        }\r
+      });\r
+\r
+      aReceiver.endDocument();\r
+    }\r
+    catch (IOException e) {\r
+      throw new XMLParserFailure(e);\r
+    }\r
+    catch (HTMLParserExc e) {\r
+      throw new XMLParserFailure(e);\r
+    }\r
+  }\r
+}\r