Initial revision
authorrk <rk>
Wed, 29 Aug 2001 01:47:14 +0000 (01:47 +0000)
committerrk <rk>
Wed, 29 Aug 2001 01:47:14 +0000 (01:47 +0000)
34 files changed:
source/mir/entity/AbstractEntity.java [new file with mode: 0755]
source/mir/entity/Entity.java [new file with mode: 0755]
source/mir/entity/EntityList.java [new file with mode: 0755]
source/mir/entity/EntityRelation.java [new file with mode: 0755]
source/mir/entity/GenericEntity.java [new file with mode: 0755]
source/mir/misc/Configuration.java [new file with mode: 0755]
source/mir/misc/HTMLParseException.java [new file with mode: 0755]
source/mir/misc/HTMLTemplateProcessor.java [new file with mode: 0755]
source/mir/misc/Helper.java [new file with mode: 0755]
source/mir/misc/InputSourceResolver.java [new file with mode: 0755]
source/mir/misc/LineFilterWriter.java [new file with mode: 0755]
source/mir/misc/Logfile.java [new file with mode: 0755]
source/mir/misc/StringUtil.java [new file with mode: 0755]
source/mir/misc/WebdbImage.java [new file with mode: 0755]
source/mir/misc/WebdbMultipartRequest.java [new file with mode: 0755]
source/mir/misc/XmlSaxonStyler.java [new file with mode: 0755]
source/mir/misc/XmlStyler.java [new file with mode: 0755]
source/mir/misc/XslStyleCache.java [new file with mode: 0755]
source/mir/module/AbstractModule.java [new file with mode: 0755]
source/mir/module/ModuleException.java [new file with mode: 0755]
source/mir/servlet/AbstractServlet.java [new file with mode: 0755]
source/mir/servlet/ServletModule.java [new file with mode: 0755]
source/mir/servlet/ServletModuleDispatch.java [new file with mode: 0755]
source/mir/servlet/ServletModuleException.java [new file with mode: 0755]
source/mir/servlet/ServletModuleMonitor.java [new file with mode: 0755]
source/mir/servlet/ServletModuleShow.java [new file with mode: 0755]
source/mir/storage/Database.java [new file with mode: 0755]
source/mir/storage/DatabaseAdaptor.java [new file with mode: 0755]
source/mir/storage/DatabaseAdaptorMySQL.java [new file with mode: 0755]
source/mir/storage/DatabaseAdaptorOracle.java [new file with mode: 0755]
source/mir/storage/DatabaseAdaptorPostgresql.java [new file with mode: 0755]
source/mir/storage/DatabaseAdaptorSybase.java [new file with mode: 0755]
source/mir/storage/StorageObject.java [new file with mode: 0755]
source/mir/storage/StorageObjectException.java [new file with mode: 0755]

diff --git a/source/mir/entity/AbstractEntity.java b/source/mir/entity/AbstractEntity.java
new file mode 100755 (executable)
index 0000000..3f2c0db
--- /dev/null
@@ -0,0 +1,218 @@
+/**
+ * <b>abstrakte Basisklasse der Entity-Klassen</b><p>
+ */
+
+
+package  mir.entity;
+
+import java.lang.*;
+import java.io.*;
+import java.util.*;
+import java.sql.*;
+
+import mir.storage.*;
+import mir.misc.*;
+
+/**
+ * abstrakte Basisklasse der Entity-Klassen
+ *
+ * @author RK
+ * @version    29.6.1999
+ *
+ */
+
+public class AbstractEntity implements Entity
+{
+       private boolean             changed;
+       protected HashMap           theValuesHash;   // tablekey / value
+       protected StorageObject     theStorageObject;
+       protected static Logfile    theLog;
+       protected ArrayList         streamedInput=null;
+       private static int instances = 0;
+               static {
+                       theLog = Logfile.getInstance(Configuration.getProperty("Home") + Configuration.getProperty("Entity.Logfile"));
+               }
+
+               public AbstractEntity() {
+                       this.changed = false;
+                       instances++;
+               }
+
+       /**
+        * Konstruktor
+        */
+       public AbstractEntity (StorageObject StorageObject) {
+               this();
+               setStorage(StorageObject);
+       }
+
+       /*
+        * Setzt das StorageObject der Entity.
+        */
+       public void setStorage (StorageObject storage) {
+               this.theStorageObject = storage;
+       }
+
+       /**
+        * Setzt die Werte der Entity
+        * @param theStringValues
+        */
+
+       public void setValues(HashMap theStringValues)
+       {
+               /** @todo should be synchronized */
+               theValuesHash = new HashMap();
+               String aKey;
+               Set set = theStringValues.keySet();
+               Iterator it = set.iterator();
+               int size = set.size();
+               for (int i = 0; i < size; i++) {
+                       aKey = (String)it.next();
+                       theValuesHash.put(aKey, (String)theStringValues.get(aKey));
+               }
+ }
+
+       /**
+        * Liefert boolschen Wert, ob sich der Inhalt der Entity geändert hat.
+        * @return true wenn ja, sonst false
+        */
+       public boolean changed () {
+               return  changed;
+       }
+
+       /**
+        * Liefert den Primärschluessel der Entity zurueck
+        * @return String Id
+        */
+       public String getId () {
+               return  (String)getValue(theStorageObject.getIdName());
+       }
+
+       /**
+        * Setzt den Primaerschluessel der Entity
+        * @param id
+        */
+       public void setId (String id) {
+               theValuesHash.put(theStorageObject.getIdName(), id);
+                       }
+
+       /**
+        * Liefert den Wert für einen Feldnamen zurueck
+        * @param theFieldString
+        * @return Wert für Feld
+        */
+       public String getValue (String theFieldString) {
+               return  (String)theValuesHash.get(theFieldString);
+               }
+
+       /**
+        * Fügt Entity via StorageObject in Datenbank ein.
+        * @return Primary Key der Entity
+        * @exception StorageObjectException
+        */
+       public String insert () throws StorageObjectException {
+               theLog.printDebugInfo("Entity: trying to insert ...");
+               if (theStorageObject != null) {
+                       return  theStorageObject.insert((Entity)this);
+               }
+               else
+                       throw  new StorageObjectException("Kein StorageObject gesetzt!");
+       }
+
+       /**
+        * Aktualisiert Aenderungen an der Entity in der Datenbank
+        * @exception StorageObjectException
+        */
+       public void update () throws StorageObjectException {
+               theStorageObject.update((Entity)this);
+       }
+
+       /**
+        * Setzt den Wert fuer ein Feld
+        * @param theProp
+        * @param theValue
+        * @exception StorageObjectException
+        */
+       public void setValueForProperty (String theProp, String theValue) throws StorageObjectException {
+               this.changed = true;
+               if (isField(theProp))
+                       theValuesHash.put(theProp, theValue);
+               else
+                       theLog.printWarning("Property not found: " + theProp);
+       }
+
+       /**
+        * Gibt die Feldnamen der Entity als ArrayList zurueck
+        * @return ArrayList mit Feldnamen
+        * @exception StorageObjectException wird geworfen, wenn kein Zugriff auf die Datenbank
+        *    möglich.
+        */
+       public ArrayList getFields () throws StorageObjectException {
+               return  theStorageObject.getFields();
+               }
+
+       /**
+        * Liefert ein int[] mit den Typen der Felder zurueck
+        * @return int[] mit den Feldtypen
+        * @exception StorageObjectException
+        */
+       public int[] getTypes () throws StorageObjectException {
+               return  theStorageObject.getTypes();
+               }
+
+       /**
+        * Liefert ArrayListe mit Feldnamen zurueck.
+        * @return Liste mit Feldnamen
+        * @exception StorageObjectException
+        */
+       public ArrayList getLabels () throws StorageObjectException {
+               return  theStorageObject.getLabels();
+               }
+
+       /**
+        * Liefert eine Hashmap mit allen Werten der Entity zurueck
+        * @return HashMap mit Feldname/Wert
+        */
+               public HashMap getValues() {
+                       return theValuesHash;
+               }
+
+               /**
+                *  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
+                */
+
+       public ArrayList streamedInput() {
+               return streamedInput;
+       }
+
+        /* Fragt ab, ob fieldName einem Feld entspricht
+        * @param fieldName
+        * @return true, wennn ja, sonst false
+        * @exception StorageObjectException
+        */
+       public boolean isField (String fieldName) throws StorageObjectException {
+               return  theStorageObject.getFields().contains(fieldName);
+       }
+
+        /** Liefert Anzahl der Instanzen zurück
+        * @return int
+        */
+       public int getInstances() {
+     return instances;
+  }
+       /**
+        * Gibt eine Instanz frei
+        */
+       public void finalize () {
+    instances--;
+    try {
+      super.finalize();
+    } catch (Throwable t) {
+      System.err.println(t.toString());
+    }
+  }
+}
+
diff --git a/source/mir/entity/Entity.java b/source/mir/entity/Entity.java
new file mode 100755 (executable)
index 0000000..bff5eb2
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * put your module comment here
+ */
+
+
+package mir.entity;
+
+import java.lang.*;
+import java.util.*;
+import mir.storage.*;
+
+/**
+ * Interface-Definition für Entities
+ */
+
+public interface Entity {
+
+       /**
+        * Eine Entity muss setStorage implementieren, mit der eine Entity mit einem
+        * StorageObject assoziiert wird.
+        *
+        * @param st
+        */
+       public abstract void setStorage (StorageObject st);
+
+
+
+       /**
+        * Eine Entity muss setValues implementieren, mit der die Werte der Entity gesetzt werden
+        * können.
+        *
+        * @param ht
+        */
+               public abstract void setValues(HashMap ht);
+
+
+
+       /**
+        * Eine Entity muss getValues implementieren, mit der die Werte der Entity
+        * als HashMap zurueckgeliefert werden
+        * @return Werte der Entity
+        */
+               public abstract HashMap getValues();
+
+
+
+       /**
+        * Eine Entity muss getFields implementieren, mit der die Feldnamen der
+        * Entity zurueckgegeben werden.
+        * @return ArrayList der Feldnamen
+        * @exception StorageObjectException
+        */
+       public abstract ArrayList getFields () throws StorageObjectException;
+
+
+
+       /**
+        * Eine Entity muss getTypes implementieren, mit der die Feldtype der
+        * Entity zurueckgegeben werden.
+        * @return int[] der Feldtypen
+        * @exception StorageObjectException
+        */
+       public abstract int[] getTypes () throws StorageObjectException;
+
+
+
+       /**
+        * Eine Entity muss getLabels implementieren, mit der die Feldnamen der
+        * Entity zurueckgegeben werden.
+        * @return ArrayList der Feldnamen
+        * @exception StorageObjectException
+        */
+       public abstract ArrayList getLabels () throws StorageObjectException;
+
+
+
+       /**
+        * Eine Entity muss getId implementieren, um den Primaerschuessel der
+        * Entity zurueckgeliefert zu bekommen.
+        *
+        * @return Primary-Key der Entity
+        */
+               public abstract String getId();
+
+
+
+       /**
+        * Eine Entity muss setId implementieren, um den Primaerschuessel der
+        * Entity zu setzen
+        *
+        * @param str
+        */
+               public abstract void setId(String str);
+
+
+       /**
+        * Eine Entity muss getValue implementieren, um den Wert eines
+        * Feldes zurueckzugeben
+        *
+        * @param field
+        * @return Wert von Feld field
+        */
+       public abstract String getValue (String field);
+
+
+
+       /**
+        * Einfügen der Entity in StorageObject
+        *
+        * @return Primary-Key der eingefügten Entity
+        * @exception StorageObjectException
+        */
+       public abstract String insert () throws StorageObjectException;
+
+
+
+       /**
+        * Aktualisieren der Entity via StorageObject
+        * @exception StorageObjectException
+        */
+       public abstract void update () throws StorageObjectException;
+
+
+
+       /**
+        * ArrayListe mit Feldern, die einer Sonderbehandlung bedürfen (blobs)
+        * @return Liste der Feldnamen
+        */
+       public abstract ArrayList streamedInput ();
+
+
+       public abstract void setValueForProperty (String theProp, String theValue) throws StorageObjectException;
+
+
+}
+
+
+
+
diff --git a/source/mir/entity/EntityList.java b/source/mir/entity/EntityList.java
new file mode 100755 (executable)
index 0000000..98883c8
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * put your module comment here
+ */
+
+
+package  mir.entity;
+
+import java.lang.*;
+import java.util.*;
+import mir.misc.*;
+
+
+/**
+ *
+ * abstrakte Containerklasse für Listen von Entities.
+ *
+ * @author <RK>
+ * @version    27.6.1999
+ */
+public class EntityList {
+               private static Logfile     theLog;
+               private ArrayList          theEntityArrayList;
+               private String             whereClause;
+               private String             orderClause;
+               private int                count;
+               private int                offset;
+               private int                offsetnext = -1;
+               private int                offsetprev = -1;
+
+       /**
+        * Konstruktor für leere Liste von Entities
+        */
+               public EntityList(){
+                       this.theEntityArrayList = new ArrayList();
+                       if (theLog == null)
+                        this.theLog = Logfile.getInstance(Configuration.getProperty("Home") + Configuration.getProperty("Entity.Logfile"));
+               }
+
+       /**
+        * Setzt die WhereClause, mit der die Entitis dieser Liste geholt wurden.
+        * @param wc
+        */
+               public void setWhere(String wc) {
+                       this.whereClause = wc;
+               }
+
+       /**
+        * Liefert die WhereClause zurueck, mit der die Entities geholt wurden.
+        * @return whereClause
+        */
+               public String getWhere() {
+                       return whereClause;
+               }
+
+       /**
+        * Setzt das Sortierkriterium fest, mit der die Entities in die Liste
+        * gestellt wurden.
+        *
+        * @param oc
+        */
+               public void setOrder(String oc) {
+                       this.orderClause = oc;
+               }
+
+       /**
+        * Liefert das Sortierkriterium der Liste zurueck.
+        * @return orderClause
+        */
+               public String getOrder() {
+                       return orderClause;
+               }
+
+       /**
+        * Setzt die Anzahl der Datensätze fest, die WhereClause erfüllen.
+        * @param i
+        */
+               public void setCount(int i) {
+                       this.count = i;
+               }
+
+       /**
+        * Liefert Anzahle der Datensätze, die WhereClause erfüllen.
+        * @return
+        */
+               public int getCount() {
+                       return count;
+               }
+
+       /**
+        * Setzt den Offset fest.
+        * @param i
+        */
+               public void setOffset(int i) {
+                       offset = i;
+               }
+
+       /**
+        * Liefert den Offset zurueck
+        * @return offset
+        */
+               public int getOffset() {
+                       return offset;
+               }
+
+       /**
+        * Setzt den offset für das naechste Batch von Entities fest.
+        * @param i
+        */
+               public void setNextBatch(int i) {
+                       offsetnext = i;
+               }
+
+       /**
+        * Liefert den offset für das naechste Batch von Entities
+        * @return offset für naechstes Batch
+        */
+               public int getNextBatch() {
+                       return offsetnext;
+               }
+
+       /**
+        * Fragt ab, ob es noch nachfolgendes Batch innerhalb der WhereClause gibt
+        * @return
+        */
+               public boolean hasNextBatch() {
+                       return (offsetnext >= 0);
+               }
+
+       /**
+        * Setzt offset des vorhergehenden Batches fest.
+        * @param i
+        */
+               public void setPrevBatch(int i) {
+                       offsetprev = i;
+               }
+
+       /**
+        * Liefert offset des vorhergehenden Batches zurueck.
+        * @return offset des vorhergehenden Batches.
+        */
+               public int getPrevBatch() {
+                       return offsetprev;
+               }
+
+       /**
+        * Fragt ab, ob es ein vorhergehendes Batch gibt
+        * @return true wenn ja, sont false
+        */
+               public boolean hasPrevBatch() {
+                       return (offsetprev >= 0);
+               }
+
+       /**
+        * Liefert den Startindex des Batches zurueck.
+        * @return
+        */
+               public int getFrom() {
+                       return offset+1;
+               }
+
+       /**
+        * Liefert den Endindex des Batches zurueck.
+        * @return
+        */
+               public int getTo() {
+       if (hasNextBatch())
+                       return offsetnext;
+       else
+                       return count;
+               }
+
+       /**
+        * Fügt eine Entity in die Liste ein
+        * @param anEntity
+        */
+       public void add (Entity anEntity) {
+       if (anEntity!=null)
+                       theEntityArrayList.add(anEntity);
+       else
+                       theLog.printWarning("add (EntityList) mit leerer Entity");
+               }
+
+       /**
+        * @return Anzahl der Entities in der Liste
+        */
+               public int size() {
+       return theEntityArrayList.size();
+               }
+
+
+
+
+
+
+               public Entity elementAt(int i) {
+                       return (Entity)theEntityArrayList.get(i);
+               }
+
+}
diff --git a/source/mir/entity/EntityRelation.java b/source/mir/entity/EntityRelation.java
new file mode 100755 (executable)
index 0000000..8f44ac3
--- /dev/null
@@ -0,0 +1,128 @@
+package mir.entity;
+
+import mir.storage.*;
+import mir.misc.*;
+import freemarker.template.*;
+
+public class EntityRelation {
+
+       public String         fromId;
+       public String         toId;
+       public StorageObject  storage;
+       public int            type;
+
+       public final static int TO_ONE          =  1;
+       public final static int TO_MANY         =  2;
+
+
+       /**
+        *  Kontruktor fuer EntityRelation
+        *  @param fromId ist der Feldname in der ausgehenden Tabelle fuer die Relation
+        *  @param toId ist der Feldname in der Zieltablle
+        *  @param storage ist das StorageObject, ueber das der Zugriff auf die abhaengige
+        *         Tabelle erfolgt.
+        *  @param type ist der Typ der EntityRelation (TO_ONE oder TO_MANY)
+        */
+
+       public EntityRelation(String fromId, String toId, StorageObject storage, int type) {
+                       this.fromId = fromId;
+                       this.toId = toId;
+                       this.storage = storage;
+                       this.type = type;
+       }
+
+       /**
+        *   @return Liefert eine abhaengige Entity mit den verknuepften
+        *           Entities, wenn es sich um eine TO_ONE Beziehung handelt, ansonsten
+        *           null.
+        */
+
+       public Entity getOne(Entity entity) throws StorageObjectException {
+               if (type==TO_ONE) {
+                       return storage.selectById(entity.getValue(fromId));
+               }
+               else return null;
+       }
+
+       /**
+        *   @return Liefert ein freemarker.template.SimpleHash mit den verknuepften
+        *           Entities, wenn es sich um eine TO_ONE Beziehung handelt, ansonsten
+        *           null.
+        */
+
+       public SimpleHash getOneAsSimpleHash(Entity entity) throws StorageObjectException {
+               if (type==TO_ONE) {
+                               Entity returnEntity = getOne(entity);
+                               if (returnEntity!=null) return HTMLTemplateProcessor.makeSimpleHash(returnEntity);
+               }
+               return null;
+       }
+
+       /**
+        *   @return Liefert eine freemarker.template.SimpleList mit den verknuepften
+        *           Entities, wenn es sich um eine TO_MANY Liste handelt, ansonsten
+        *           null.
+        */
+
+       public EntityList getMany(Entity entity) throws StorageObjectException{
+               if (type==TO_MANY) {
+                       return storage.selectByFieldValue(toId, entity.getValue(fromId));
+               }
+               else return null;
+       }
+
+       /**
+        *   @return Liefert eine freemarker.template.SimpleList mit den verknuepften
+        *           Entities, wenn es sich um eine TO_MANY Liste handelt, ansonsten
+        *           null.
+        */
+
+       public EntityList getMany(Entity entity, String order) throws StorageObjectException{
+               if (type==TO_MANY) {
+                       return storage.selectByWhereClause(toId+"="+entity.getValue(fromId), order,-1);
+               }
+               else return null;
+       }
+
+       /**
+        *   @return Liefert eine freemarker.template.SimpleList mit den verknuepften
+        *           Entities, wenn es sich um eine TO_MANY Liste handelt, ansonsten
+        *           null.
+        */
+
+       public SimpleList getManyAsSimpleList(Entity entity)
+               throws StorageObjectException {
+
+               if (type==TO_MANY) {
+                       EntityList returnList = getMany(entity);
+                       if (returnList!=null) return HTMLTemplateProcessor.makeSimpleList(returnList);
+               }
+               return null;
+       }
+
+       /**
+        *   @return Liefert eine freemarker.template.SimpleList mit den verknuepften
+        *           Entities, wenn es sich um eine TO_MANY Liste handelt, ansonsten
+        *           null.
+        */
+
+       public SimpleList getManyAsSimpleList(Entity entity, String order)
+               throws StorageObjectException {
+
+               if (type==TO_MANY) {
+                       EntityList returnList = getMany(entity, order);
+                       if (returnList!=null) return HTMLTemplateProcessor.makeSimpleList(returnList);
+               }
+               return null;
+       }
+
+       /**
+        *   @return Liefert den Referenznamen der abhaengigen Tabelle
+        */
+
+       public String getName() {
+               return "to" + storage.getTableName();
+       }
+
+
+}
\ No newline at end of file
diff --git a/source/mir/entity/GenericEntity.java b/source/mir/entity/GenericEntity.java
new file mode 100755 (executable)
index 0000000..12f3d56
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * GenericEntity
+ */
+package mir.entity;
+
+/**
+ * Standard-Entity-Container. Wenn keine Zusatzfunktionalitaeten für die Kapselung einer
+ * Datenbankzeile nötig sind, d.h. zu einem Database-Objekt keine eigene Entity-Klasse
+ * implementiert wird, so wird dieser Standard-Container verwendet.
+ *
+ * @author /rk
+ * @version 1.2
+ */
+public class GenericEntity extends AbstractEntity
+               implements Entity {}
+
+
+
diff --git a/source/mir/misc/Configuration.java b/source/mir/misc/Configuration.java
new file mode 100755 (executable)
index 0000000..1155bf0
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * put your module comment here
+ */
+
+
+package  mir.misc;
+
+import  java.net.*;
+import  java.io.*;
+import  java.util.*;
+import  java.lang.*;
+import  com.javaexchange.dbConnectionBroker.*;
+
+
+/**
+ * Diese Klasse realisert den Zugriff auf die Konfiguration.
+ *
+ */
+public class Configuration {
+
+  private static HashMap  confs = new HashMap(); // key: conffilename, confHash
+  private static HashMap c = new HashMap();
+  private String          confFilename;
+  private static String   defaultconfFilename;
+  private static int      instances=0;
+  //static ResourceBundle conf = ResourceBundle.getBundle("config");
+  static ResourceBundle conf;
+
+  public static void initConfig(String confName) {
+    conf = ResourceBundle.getBundle(confName);
+    confs.put("confname",confName);
+  }
+
+  public static void addBroker(String driver, String URL){
+
+    System.err.println("--trying to add broker");
+    String username,passwd,min,max,log,reset;
+
+    if(!c.containsKey("Pool.broker")){
+      username=conf.getString("Database.Username");
+      passwd=conf.getString("Database.Password");
+      min=conf.getString("Database.poolMin");
+      max=conf.getString("Database.poolMax");
+      log=conf.getString("Home") + conf.getString("Database.PoolLog");
+      reset=conf.getString("Database.poolResetTime");
+
+      try{
+        System.err.println("-- making Broker for -"
+                            +driver+" - " +URL
+                            + " log " + log + " user "
+                            + username + " pass: " + passwd);
+
+        DbConnectionBroker br = new DbConnectionBroker(driver,URL,username,passwd,(new Integer(min)).intValue(),
+                                                      (new Integer(max)).intValue(),log,(new Float(reset)).floatValue());
+        if (br!=null){
+          instances++;
+          c.put("Pool.broker",br);
+        } else {
+            throw new Exception();
+        }
+      } catch(Exception e){
+        System.err.println("Der ConnectionBroker konnte nicht initializiert werden"+ e.toString());e.printStackTrace();
+      }
+    } // end if
+  }
+
+
+       /**
+        * Fragt ab, ob das Betriebssystem Windows ist.
+        * @return true wenn ja, sonst false.
+        */
+  public static boolean isWindows() {
+    return System.getProperty("os.name").toLowerCase().indexOf("win") >= 0;
+  }
+
+   /**
+        * Liefert Wert einer Property zurueck
+        * @param propName
+        * @return Wert der Property
+        */
+  public static String getProperty(String propName) {  // default
+    return conf.getString(propName);
+  }
+
+  /**
+        * Liest eine Property eines Modules aus der Konfiguration
+        * @param filename
+        * @param theModule
+        * @param propName
+        * @return Wert der Property
+        */
+  public String getProperty(String filename ,String theModule, String propName) {
+    return getProperty(filename, theModule + "." + propName);
+  }
+
+       /**
+        * Liest eine Property aus der Konfiguration
+        * @param filename
+        * @param propName
+        * @return Wert der Property
+        */
+  public static String getProperty(String filename, String propName) {
+    if (filename != null) {
+      String prop = null;
+      HashMap conf = ((HashMap)confs.get("confname"));
+
+      if (conf == null) {
+        System.err.println("Keine Konfiguration fuer " + filename);
+      } else {
+        prop = (String)conf.get(propName);
+      }
+
+      if (prop == null) {
+        System.err.println("Keine Konfiguration fuer " + filename + " " + propName);
+      }
+
+      return prop;
+
+    } else {
+        System.err.println("--- filename null!");
+    }
+
+    return null;
+  }
+
+       /**
+        * Liefert DBConnectionBroker einer Configuration zurueck
+        * @param confFilename
+        * @return DBConnectionBroker
+        */
+  public static DbConnectionBroker getBroker() {
+    DbConnectionBroker broker=null;
+    broker=(DbConnectionBroker)c.get("Pool.broker");
+    if (broker==null) {
+      System.err.println("Konnte kein ConnectionPoolBroker initialisiert werden");
+    }
+    return broker;
+  }
+
+       /**
+        * Liefert Hashtabel mit den Konfigurationen
+        * @return
+        */
+  public static HashMap getConfs(){
+    return confs;
+  }
+
+  public static DbConnectionBroker getBrokerInfo(){
+    return (DbConnectionBroker)c.get("Pool.broker");
+  }
+
+
+       /**
+        * Finalize Methode
+        */
+  public void finalize(){
+    instances --;
+    try {
+      super.finalize();
+    } catch (Throwable t) {}
+  }
+
+  /**
+        * Liefert Anzahl der Instantiierten DBConnectionBroker zurueck
+        * @return
+        */
+  public static int getBrokerInstances() {
+    return instances;
+  }
+} //end of class
diff --git a/source/mir/misc/HTMLParseException.java b/source/mir/misc/HTMLParseException.java
new file mode 100755 (executable)
index 0000000..f82aa73
--- /dev/null
@@ -0,0 +1,20 @@
+package mir.misc;
+
+import java.lang.*;
+
+/*
+ *  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/HTMLTemplateProcessor.java b/source/mir/misc/HTMLTemplateProcessor.java
new file mode 100755 (executable)
index 0000000..70ec150
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * put your module comment here
+ */
+
+
+package mir.misc;
+
+import  java.lang.*;
+import  java.util.*;
+import  java.io.*;
+import  java.net.*;
+import  freemarker.template.*;
+import  mir.entity.*;
+import  mir.storage.*;
+
+
+/**
+ * Hilfsklasse zum Mergen von Template und Daten
+ */
+public final class HTMLTemplateProcessor {
+
+    public static String                templateDir;
+               private static FileTemplateCache    templateCache;
+               private static Logfile                theLog;
+               private static String                 docRoot;
+               private static String                 actionRoot;
+               private static String                 productionHost;
+               private static String               audioHost;
+               private static String               videoHost;
+               private static String               imageHost;
+               private static String                             openAction;
+    protected static String producerDocRoot = Configuration.getProperty("Producer.DocRoot");
+  protected static String producerStorageRoot = Configuration.getProperty("Producer.StorageRoot");
+
+
+               //
+               // Initialisierung
+
+               static {
+      templateDir = Configuration.getProperty("Home") + Configuration.getProperty("HTMLTemplateProcessor.Dir");
+                       templateCache = new FileTemplateCache(templateDir);
+                       templateCache.setLoadingPolicy(templateCache.LOAD_ON_DEMAND);
+                       //templateCache.startAutoUpdate();
+                       theLog = Logfile.getInstance(Configuration.getProperty("Home") + Configuration.getProperty("HTMLTemplateProcessor.Logfile"));
+                       docRoot = Configuration.getProperty("HTMLTemplateProcessor.DocRoot");
+                       actionRoot = Configuration.getProperty("HTMLTemplateProcessor.ActionRoot");
+                       openAction = Configuration.getProperty("Producer.OpenAction");
+                       productionHost = Configuration.getProperty("Producer.ProductionHost");
+                       videoHost = Configuration.getProperty("Producer.VideoHost");
+                       audioHost = Configuration.getProperty("Producer.AudioHost");
+                       imageHost = Configuration.getProperty("Producer.Image.Host");
+      producerDocRoot = Configuration.getProperty("Producer.DocRoot");
+      producerStorageRoot = Configuration.getProperty("Producer.StorageRoot");
+
+
+               }
+
+  /**
+        * Privater Konstruktor, um versehentliche Instantiierung zu verhindern
+        */
+       private HTMLTemplateProcessor () {
+       }
+
+
+               //
+               //  process-Methoden zum Mischen verschiedener Datenstrukturen mit HTML-Templates
+
+
+       /**
+        * Wandelt <code>anEntity</code> in freemarker-Struktur um, mischt die Daten mit
+        * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter
+        * <code>out</code>
+        *
+        * @param templateFilename
+        * @param anEntity
+        * @param out
+        * @exception HTMLParseException
+        */
+
+               public static void process(String templateFilename, Entity anEntity, PrintWriter out)
+                       throws HTMLParseException {
+                               if (anEntity == null)  throw new HTMLParseException("Entity leer!");
+                               else process(templateFilename, anEntity, out);
+               }
+
+
+       /**
+        * Wandelt Liste mit Entities <code>entList</code> in freemarker-Struktur um, mischt die Daten mit
+        * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter
+        * <code>out</code>
+        *
+        * @param templateFilename
+        * @param entList
+        * @param out
+        * @exception HTMLParseException
+        */
+               public static void process(String templateFilename, EntityList entList, PrintWriter out)
+                       throws HTMLParseException {
+                       process( templateFilename,  entList,  (String)null, (TemplateModelRoot)null,  out);
+               }
+
+       /**
+        * Wandelt Entitylist in freemarker-Struktur um, fügt <code>additionalModel</code>
+        * unter dem Namen <code>additionalModelName</code> ein und mischt die Daten mit
+        * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter
+        * <code>out</code>
+        *
+        * @param templateFilename
+        * @param entList
+        * @param additionalModelName
+        * @param additionalModel
+        * @param out
+        * @exception HTMLParseException
+        */
+               public static void process(String templateFilename, EntityList entList, String additionalModelName,
+                                                TemplateModelRoot additionalModel, PrintWriter out)
+                       throws HTMLParseException {
+
+                       SimpleHash modelRoot = new SimpleHash();
+
+                       if (entList == null) {
+                                //theLog.printInfo("Keine Daten! Suche erfolglos.");
+                                process(templateFilename, modelRoot, out);
+                       } else {
+                               try {
+                                       modelRoot = makeSimpleHashWithEntitylistInfos(entList);
+                                       //
+                                       // Hilfskruecke um mal ein Popup mit reinzunhemen ..
+                                       if (additionalModelName != null && additionalModel != null)
+                                                       modelRoot.put(additionalModelName, additionalModel);
+
+                                       process(templateFilename, modelRoot, out);
+                               } catch (StorageObjectException e) {
+                                       throw new HTMLParseException(e.toString());
+                               }
+                       }
+               }
+
+       /**
+        * Wandelt HashMap <code>mergeData</code> in freemarker-Struktur und mischt diese mit
+        * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter
+        * <code>out</code>
+        *
+        * @param templateFilename
+        * @param mergeData
+        * @param out
+        * @exception HTMLParseException
+        */
+               public static void process(String templateFilename, HashMap mergeData, PrintWriter out)
+                       throws HTMLParseException {
+                       process(templateFilename, makeSimpleHash(mergeData), out);
+               }
+
+       /**
+        * Gibt Template <code>templateFilename</code> an den PrintWriter
+        * <code>out</code>
+        *
+        * @param templateFilename
+        * @param mergeData
+        * @param out
+        * @exception HTMLParseException
+        */
+               public static void process(String templateFilename, PrintWriter out)
+                       throws HTMLParseException {
+                       process(templateFilename, (TemplateModelRoot)null, out);
+               }
+
+
+       /**
+        * Mischt die freemarker-Struktur <code>tmr</code> mit
+        * Template <code>templateFilename</code> und gibt das Ergebnis an den PrintWriter
+        * <code>out</code>
+        *
+        * @param templateFilename
+        * @param mergeData
+        * @param out
+        * @exception HTMLParseException
+        */
+               public static void process(String templateFilename, TemplateModelRoot tmr, PrintWriter out)
+                       throws HTMLParseException {
+                       if (out==null) throw new HTMLParseException("KEIN OUTPUTSTREAM");
+                       Template tmpl = getTemplateFor(templateFilename);
+                       if (tmpl == null) throw new HTMLParseException("KEIN TEMPLATE: " + templateFilename);
+                       if (tmr==null) tmr = new SimpleHash();
+
+      //some utilities
+      SimpleHash utilityHash = new SimpleHash();
+      utilityHash.put("htmlEscape",new freemarker.template.utility.HtmlEscape());
+
+      // put standard configuration into tempalteRootmodel
+                       SimpleHash configHash = new SimpleHash();
+                       configHash.put("docroot", new SimpleScalar(producerDocRoot));
+                       configHash.put("storageroot", new SimpleScalar(producerStorageRoot));
+                       configHash.put("productionhost", new SimpleScalar(productionHost));
+                       configHash.put("openaction", new SimpleScalar(openAction));
+
+
+      tmr.put("docRoot", new SimpleScalar(docRoot));
+                       tmr.put("now", new SimpleScalar(StringUtil.date2readableDateTime(new GregorianCalendar())));
+                       tmr.put("actionRoot", new SimpleScalar(actionRoot));
+                       tmr.put("openAction", new SimpleScalar(openAction));
+                       tmr.put("productionHost", new SimpleScalar(productionHost));
+                       tmr.put("videoHost", new SimpleScalar(videoHost));
+                       tmr.put("audioHost", new SimpleScalar(audioHost));
+                       tmr.put("imageHost", new SimpleScalar(imageHost));
+
+      tmr.put("config", configHash);
+      tmr.put("utility",utilityHash);
+                       tmpl.process(tmr, out);
+
+               }
+
+
+  /**
+        *   Wandelt eine Entity-Liste in eine SimpleList von SimpleHashes um.
+        *   @param aList ist eine Liste von Entity
+        *   @return eine freemarker.template.SimpleList von SimpleHashes.
+        */
+       public static SimpleList makeSimpleList(EntityList aList) throws StorageObjectException
+       {
+               SimpleList      simpleList = new SimpleList();
+               if (aList != null) {
+                       for(int i=0;i<aList.size();i++){
+                               simpleList.add(makeSimpleHash(aList.elementAt(i)));
+                       }
+               }
+               return simpleList;
+       }
+
+       /**
+        *  Konvertiert ein EntityList in ein freemarker.template.SimpleHash-Modell. Im Hash
+        *  sind die einzelnen Entities ueber ihre id zu erreichen.
+        *  @param aList ist die EntityList
+        *  @return SimpleHash mit den entsprechenden freemarker Daten
+        *
+        */
+       public static SimpleHash makeSimpleHash(EntityList aList) throws StorageObjectException
+       {
+               SimpleHash      simpleHash = new SimpleHash();
+               Entity          currentEntity;
+
+               if (aList != null) {
+                       for (int i=0;i<aList.size();i++) {
+                                currentEntity = (Entity)aList.elementAt(i);
+                                simpleHash.put(currentEntity.getId(), makeSimpleHash(currentEntity));
+                       }
+               }
+               return simpleHash;
+       }
+
+       /**
+        *  Konvertiert ein Entity in ein freemarker.template.SimpleHash-Modell
+        *  @param entity ist die Entity
+        *  @return SimpleHash mit den entsprechenden freemarker Daten
+        *
+        */
+               public static SimpleHash makeSimpleHash(Entity entity) {
+                       if (entity != null) {
+                               return makeSimpleHash(entity.getValues());
+                       }
+                       else {
+                               //theLog.printWarning("Entity ist <null>");
+                               return null;
+                       }
+               }
+
+       /**
+        *  Konvertiert ein Hashtable mit den keys und values als String
+        *  in ein freemarker.template.SimpleHash-Modell
+        *  @param mergeData der HashMap mit den String / String Daten
+        *  @return SimpleHash mit den entsprechenden freemarker Daten
+        *
+        */
+       public static SimpleHash makeSimpleHash(HashMap mergeData)
+       {
+               SimpleHash modelRoot = new SimpleHash();
+               String aField;
+               if (mergeData != null) {
+                       Set set = mergeData.keySet();
+                       Iterator it =  set.iterator();
+                       for (int i=0; i<set.size();i++)  {
+                               aField = (String)it.next();
+                               modelRoot.put(aField, (String)mergeData.get(aField));
+                       }
+               }
+               return modelRoot;
+       }
+
+
+       /**
+        * Wandelt EntityListe in SimpleHash um, und versieht die Liste mit StandardInfos,
+        * die aus EntityList kommen.
+        *
+        * @param entList
+        * @return SimpleHash mit Entity-Daten und ZusatzInfos.
+        * @exception StorageObjectException
+        */
+               public static SimpleHash makeSimpleHashWithEntitylistInfos(EntityList entList) throws StorageObjectException {
+                       SimpleHash modelRoot = new SimpleHash();
+                       if (entList!=null) {
+                                                               modelRoot.put("contentlist", makeSimpleList(entList));
+                                                               modelRoot.put("count", new SimpleScalar((new Integer(entList.getCount())).toString()));
+                                       if (entList.getWhere()!=null) {
+                                               modelRoot.put("where", new SimpleScalar(entList.getWhere()));
+                                               modelRoot.put("where_encoded", new SimpleScalar(URLEncoder.encode(entList.getWhere())));
+                                       }
+
+                                       if(entList.getOrder()!=null) {
+                                               modelRoot.put("order", new SimpleScalar(entList.getOrder()));
+                                               modelRoot.put("order_encoded", new SimpleScalar(URLEncoder.encode(entList.getOrder())));
+                                       }
+                                       modelRoot.put("from", new SimpleScalar((new Integer(entList.getFrom())).toString()));
+                                       modelRoot.put("to", new SimpleScalar((new Integer(entList.getTo())).toString()));
+
+                                       if (entList.hasNextBatch())
+                                               modelRoot.put("next", new SimpleScalar((new Integer(entList.getNextBatch())).toString()));
+                                       if (entList.hasPrevBatch())
+                                               modelRoot.put("prev", new SimpleScalar((new Integer(entList.getPrevBatch())).toString()));
+                       }
+                       return modelRoot;
+               }
+
+       /**
+        * Private Methode, um für templateFilename das Template zu bekommen.
+        * @param templateFilename
+        * @return Template
+        * @exception HTMLParseException
+        */
+       private static Template getTemplateFor(String templateFilename) throws HTMLParseException
+               {
+                       if (templateFilename!=null) return templateCache.getTemplate(templateFilename);
+                       else {
+                               theLog.printError("CACHE (ERR): Unknown template: " + templateFilename);
+                               throw new HTMLParseException("Templatedatei: "+ templateFilename + " nicht gefunden!");
+                       }
+               }
+
+
+    public static void stopAutoUpdate(){
+      templateCache.stopAutoUpdate();
+      templateCache=null;
+    }
+}
diff --git a/source/mir/misc/Helper.java b/source/mir/misc/Helper.java
new file mode 100755 (executable)
index 0000000..bbfb842
--- /dev/null
@@ -0,0 +1,35 @@
+package mir.misc;
+
+import java.io.IOException;
+
+/**
+ * Title:        Indy
+ * Description:  This class provides some satic help methods
+ * Copyright:    Copyright (c) 2001
+ * Company:      indymedia.de
+ * @author idfx
+ * @version 1.0
+ */
+
+public class Helper {
+
+  /**
+   * rsync the webrepository
+   * needs a rsyncscript
+   * returns the exit-code
+   */
+  public static int rsync(){
+    Process p;
+    int returnValue = -1;
+    try {
+      Runtime run = Runtime.getRuntime();
+      p = run.exec(Configuration.getProperty("Sync.Script.Path"));
+      returnValue = p.waitFor();
+    } catch (IOException e) {
+      return returnValue;
+    } catch (InterruptedException e) {
+      return returnValue;
+    }
+    return returnValue;
+  }
+}
\ No newline at end of file
diff --git a/source/mir/misc/InputSourceResolver.java b/source/mir/misc/InputSourceResolver.java
new file mode 100755 (executable)
index 0000000..0f85d1c
--- /dev/null
@@ -0,0 +1,76 @@
+package mir.misc;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import com.icl.saxon.ExtendedInputSource;
+
+/**
+ * Title:
+ * Description:
+ * Copyright:    Copyright (c) 2001
+ * Company:
+ * @author
+ * @version 1.0
+ */
+
+
+public class InputSourceResolver {
+  private static InputSourceResolver single    = new InputSourceResolver();
+  private String prefix = "";
+
+  /**
+   * InputSourceResolver constructor comment.
+   */
+  private InputSourceResolver() {
+    super();
+  }
+
+  /**
+   * Singleton Constructor
+   * @return de.matetrade.tools.InputSourceResolver
+   */
+  private static InputSourceResolver getInstance() {
+    return single;
+  }
+
+  /**
+   * This method was created in VisualAge.
+   * @return InputStream
+   * @param key java.lang.String
+   */
+  private InputStream getFileInputStream( String key )
+    throws IOException {
+
+    FileInputStream is = null;
+    try {
+      is = new FileInputStream( prefix + key );
+    } catch ( FileNotFoundException ex ) {
+      throw new IOException( "FileNotFoundExcpetion: input for <" + key + "> not found" );
+    }
+
+    return is;
+  }
+
+
+  /**
+   * This method was created in VisualAge.
+   * @return org.xml.sax.InputSource
+   * @param key java.lang.String
+   */
+  public static InputSource resolve( String key )
+    throws IOException {
+
+    InputSource is = new InputSource( single.getFileInputStream( key ) );
+    if ( key.indexOf( ':' ) >= 0 ) {
+      is.setSystemId( "file:///" + key );              // special for win (file:///c:/xxx)
+    } else {
+      is.setSystemId( "file://" + key );
+    }
+
+    return is;
+  }
+}
\ No newline at end of file
diff --git a/source/mir/misc/LineFilterWriter.java b/source/mir/misc/LineFilterWriter.java
new file mode 100755 (executable)
index 0000000..960c29b
--- /dev/null
@@ -0,0 +1,62 @@
+package mir.misc;
+import java.io.*;
+
+/**
+ *  LineFilterWriter schneidet unsinnige \t \r \n ` ` raus
+ *
+ **/
+public final class LineFilterWriter extends PrintWriter{//extends java.io.FilterWriter{
+
+
+  public LineFilterWriter(Writer out) {
+    super(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){;}
+  }
+
+
+}
diff --git a/source/mir/misc/Logfile.java b/source/mir/misc/Logfile.java
new file mode 100755 (executable)
index 0000000..2589e98
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * put your module comment here
+ */
+package  mir.misc;
+
+import  java.util.*;
+import  java.io.*;
+
+
+/**
+ * Hilfs-Klasse, die in Logfiles schreibt.
+ *
+ */
+public final class Logfile {
+               public static final int LOG_INFO = 0;
+               public static final int LOG_WARNING = 1;
+               public static final int LOG_ERROR = 2;
+               public static final int LOG_DEBINFO = 3;
+
+               private static String lineSeparator;
+
+               private static HashMap /* filename / instance */ instanceRepository;
+               private RandomAccessFile raf;
+               private String fileName;
+
+       /**
+        * lineSeparator ermitteln und Repository anlegen
+        */
+               static {
+                       // System.runFinalizersOnExit(true);
+                       lineSeparator = System.getProperty("line.separator");
+                       instanceRepository = new HashMap();
+               }
+
+       /**
+        * Singleton zurueckliefern, anhand des Filenamens,
+        * also pro <code>fileName</code> wird eine Instanz der Logfileklassen
+        * angelegt.
+        *
+        * @param fileName
+        * @return Logfile
+        */
+               public static Logfile getInstance(String fileName) {
+                       Logfile returnLogfile = null;
+                       System.err.println(fileName);
+                       if (fileName != null) {
+                               if (instanceRepository.containsKey(fileName)) {
+                                       returnLogfile = (Logfile) instanceRepository.get(fileName);
+                               } else {
+                                       returnLogfile = new Logfile(fileName);
+                                       instanceRepository.put(fileName, returnLogfile);
+                               }
+                       } else {
+                               System.err.println("Fehler bei Instantiierung von Logfile");
+                       }
+                       return returnLogfile;
+               }
+
+       /**
+        * Privater Konstruktor
+        * @param   String fileName
+        */
+               private Logfile(String fileName){
+                       this.fileName = fileName;
+                       try {
+                               File f = new File(fileName);
+                               File dir = new File(f.getParent());
+                               dir.mkdirs();
+                               raf = new RandomAccessFile(fileName, "rw");
+                       } catch (IOException e) {
+                               System.err.println("Could not open logfile '"+fileName+"'");
+                       }
+               }
+
+       /**
+        * Private Methode, um eine Zeile auszugeben
+        *
+        * @param type  Typ der Logfilezeile (INFO, WARNING, ERROR, DEBUG)
+        * @param text  Lognachricht
+        * @todo an dieser Stelle koennte statt in das File in die Datenbank geloggt werden.
+        */
+               private void print(int type, String text) {
+       if (text == null) text = "null";
+       text = text.replace('\n', ' ');
+
+       String typeText =
+                       type == LOG_DEBINFO ? "DEBINFO " :
+                       type == LOG_INFO    ? "INFO    " :
+                       type == LOG_WARNING ? "WARNING " :
+                       type == LOG_ERROR   ? "ERROR   " :
+                       "?       ";
+
+       String sectionText = text;
+       GregorianCalendar date = new GregorianCalendar();
+
+       String line = StringUtil.pad2(date.get(Calendar.DATE))+"-"+
+                       StringUtil.pad2(date.get(Calendar.MONTH)+1)+"-"+
+                       StringUtil.pad2(date.get(Calendar.YEAR) % 100)+" ";
+       int hour = date.get(Calendar.HOUR);
+       if (date.get(Calendar.AM_PM) == Calendar.PM) hour+=12;
+       line += StringUtil.pad2(hour)+":"+
+                       StringUtil.pad2(date.get(Calendar.MINUTE))+":"+
+                       StringUtil.pad2(date.get(Calendar.SECOND))+" "+
+                       typeText+sectionText;
+
+       print(line);
+               }
+
+       /**
+        *  Interne Ausgabeprozedur.
+        *      Erfordert etwas Handarbeit, da PrintStream nicht mit RandomAcccessFile
+        *      kooperiert. Und ein RandomAccessFile brauchen wir, weil FileOutputStream
+        *      kein "append" zuläßt.
+        *
+        */
+               private void print(String line) {
+       if (raf == null) return;
+       line += lineSeparator;
+       //      byte[] buf = new byte[line.length()];
+       //line.getBytes(0, line.length(), buf, 0);
+
+       byte[] buf = line.getBytes();
+
+       try {
+                       raf.seek(raf.length());
+                       raf.write(buf, 0, line.length());
+       } catch (IOException e) {
+                       System.err.print("Could not write logfile line: "+line);
+       }
+               }
+
+       /**
+        * Schreibt Information <code>text</code> ins Logfil.
+        * @param text
+        */
+       public void printInfo (String text) {
+               print(LOG_INFO, text);
+       }
+
+       /**
+        * Schreibt Warnung <code>text</code> ins Logfile.
+        * @param text
+        */
+       public void printWarning (String text) {
+               print(LOG_WARNING, text);
+       }
+
+       /**
+        * Schreibt Fehlermeldung <code>text</code> ins Logfile.
+        * @param text
+        */
+       public void printError (String text) {
+               print(LOG_ERROR, text);
+       }
+
+       /**
+        * Schreibt Debuginformation <code>text</code> ins Logfile.
+        * @param text
+        */
+       public void printDebugInfo (String text) {
+               print(LOG_DEBINFO, text);
+       }
+
+       /**
+        * Finalize-Methode, die alle offenen Dateien schliesst.
+        */
+       public void finalize () {
+               if (raf != null) {
+                       try {
+                               raf.close();
+                       } catch (IOException e) {}
+                       raf = null;
+               }
+               staticFinalize(fileName);
+               try {
+                       super.finalize();
+               } catch (Throwable t) {
+                       ;
+               }
+       }
+
+       /**
+        * Static-Finalizer
+        * @param fileName
+        */
+       private static synchronized void staticFinalize (String fileName) {
+               instanceRepository.remove(fileName);
+       }
+}
+
+
+
diff --git a/source/mir/misc/StringUtil.java b/source/mir/misc/StringUtil.java
new file mode 100755 (executable)
index 0000000..d5685fe
--- /dev/null
@@ -0,0 +1,899 @@
+/*
+ * put your module comment here
+ */
+
+
+package  mir.misc;
+
+import  java.io.*;
+import  java.lang.*;
+import  java.util.*;
+import  gnu.regexp.*;
+
+/**
+ * Statische Hilfsmethoden zur Stringbehandlung
+ *
+ * @version 29.6.99
+ * @author RK
+ */
+public final class StringUtil {
+
+       /**
+        * 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 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;
+       }
+
+       /**
+        * 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("/").append(webdbDate.substring(6, 8));
+               return  path.toString();
+       }
+
+       /**
+        * wandelt Calendar in dd.mm.yyyy um
+        *
+        * @param theDate
+        * @return String mit  <code>dd.mm.yyyy</code>
+        */
+       public static final String webdbDate2readableDate (String webdbDate) {
+               String date = "";
+               date += webdbDate.substring(6, 8);
+               date += "." + webdbDate.substring(4, 6);
+               date += "." + webdbDate.substring(0, 4);
+               return  date;
+       }
+
+
+  /**
+   * converts string from format: yyyy-mm-dd__hh:mm:ss.d
+   * to dd.mm.yyyy hh:mm
+   */
+       public static String dateToReadableDate(String date) {
+               StringBuffer returnDate = new StringBuffer();
+               if (date!=null) {
+
+                       returnDate.append(date.substring(8,10)).append('.');
+                       returnDate.append(date.substring(5,7)).append('.');
+                       returnDate.append(date.substring(0,4)).append(' ');
+                       returnDate.append(date.substring(11,16));
+               }
+               return returnDate.toString();
+       }
+
+
+       /**
+        * schließt einen String in Anführungsszeichen ein, falls er Leerzeichen o.ä. enthält
+        *
+        * @return gequoteter String
+        */
+        public static String quoteIfNecessary(String s) {
+               for (int i = 0; i < s.length(); i++)
+                       if (!(Character.isLetterOrDigit(s.charAt(i)) || s.charAt(i) == '.'))
+                               return quote(s, '"');
+               return s;
+       }
+
+        /**
+        * schließt <code>s</code> in <code>'</code> ein und setzt Backslashes vor
+        * "gefährliche" Zeichen innerhalb des Strings
+        * Quotes special SQL-characters in <code>s</code>
+        *
+        * @return geqoteter String
+        */
+       public static String quote(String s)
+       {
+    //String s2 = quote(s, '\'');
+
+    //Quickhack
+    //Because of '?-Bug in Postgresql-JDBC-Driver
+    StringBuffer temp = new StringBuffer();
+    for(int i=0;i<s.length();i++){
+      if(s.charAt(i)=='\''){
+        temp.append("&acute;");
+      } else {
+        temp.append(s.charAt(i));
+      }
+    }
+    String s2 = temp.toString();
+    //Quickhack end
+
+    s2 = quote(s2, '\"');
+               return s2;
+       }
+
+       /**
+        * schließt <code>s</code> in <code>'</code> ein und setzt Backslashes vor
+        * "gefährliche" Zeichen innerhalb des Strings
+        *
+        * @param s String, der gequoted werden soll
+        * @param quoteChar zu quotendes Zeichen
+        * @return gequoteter String
+        */
+       public static String quote(String s, char quoteChar)
+       {
+               StringBuffer buf = new StringBuffer(s.length());
+               int pos = 0;
+               while (pos < s.length()) {
+                       int i = s.indexOf(quoteChar, pos);
+                       if (i < 0) i = s.length();
+                       buf.append(s.substring(pos, i));
+                       pos = i;
+                       if (pos < s.length()) {
+                               buf.append('\\');
+             buf.append(quoteChar);
+       pos++;
+                       }
+               }
+               return buf.toString();
+       }
+
+       /**
+        * ersetzt gefährliche zeichen in  <code>s</code>
+        *
+        */
+
+       public static String unquote(String s)
+       {
+               char quoteChar='\'';
+               StringBuffer buf = new StringBuffer(s.length());
+               int pos = 0;
+               String searchString = "\\"+quoteChar;
+               while (pos < s.length()) {
+                       int i = s.indexOf(searchString, pos);
+                       if (i < 0) i = s.length();
+                       buf.append(s.substring(pos, i));
+                       pos = i+1;
+               }
+               return buf.toString();
+       }
+
+       /**
+        * Wandelet String in byte[] um.
+        * @param s
+        * @return byte[] des String
+        */
+
+       public static byte[] stringToBytes(String s) {
+               String crlf = System.getProperty("line.separator");
+               if (!crlf.equals("\n"))
+                       s = replace(s, "\n", crlf);
+    // byte[] buf = new byte[s.length()];
+    byte[] buf = s.getBytes();
+               return buf;
+       }
+
+               /**
+        * Ersetzt in String <code>s</code> das <code>pattern</code> durch <code>substitute</code>
+        * @param s
+        * @param pattern
+        * @param substitute
+        * @return String mit den Ersetzungen
+        */
+       public static String replace(String s, String pattern, String substitute) {
+               int i = 0, pLen = pattern.length(), sLen = substitute.length();
+               StringBuffer buf = new StringBuffer(s.length());
+               while (true) {
+                       int j = s.indexOf(pattern, i);
+                       if (j < 0) {
+                               buf.append(s.substring(i));
+                               break;
+                       } else {
+                               buf.append(s.substring(i, j));
+                               buf.append(substitute);
+                               i = j+pLen;
+                       }
+               }
+               return buf.toString();
+       }
+
+
+       /**
+        * Fügt einen Separator an den Pfad an
+        * @param path
+        * @return Pfad mit Separator am Ende
+        */
+       public static final String addSeparator (String path) {
+               return  path.length() == 0 || path.endsWith(File.separator) ? path : path
+                               + File.separatorChar;
+       }
+
+       /**
+        * Fügt ein <code>/</code> ans ende des Strings and
+        * @param path
+        * @return Pfad mit <code>/</code> am Ende
+        */
+       public static final String addSlash (String path) {
+               return  path.length() == 0 || path.endsWith("/") ? path : path + '/';
+       }
+
+       /**
+        * 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;
+       }
+
+       /**
+        * Löscht Slash am Anfang des Strings
+        * @param path
+        * @return
+        */
+       public static String removeFirstSlash (String path) {
+               return  path.startsWith("/") ? path.substring(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);
+       }
+
+       /**
+        * Konvertiert Unix-Linefeeds in Win-Linefeeds
+        * @param s
+        * @return Konvertierter String
+        */
+       public static String unixLineFeedsToWin(String s) {
+               int i = -1;
+               while (true) {
+                       i = s.indexOf('\n', i+1);
+                       if (i < 0) break;
+                       if ((i == 0 || s.charAt(i-1) != '\r') &&
+                               (i == s.length()-1 || s.charAt(i+1) != '\r')) {
+                               s = s.substring(0, i)+'\r'+s.substring(i);
+                               i++;
+                       }
+               }
+               return s;
+       }
+
+
+       /**
+        * verwandelt einen String in eine gültige Url, konvertiert Sonderzeichen
+        * und Spaces werden zu Underscores
+        *
+        * @return gültige Url
+        */
+       public static String convert2url(String s) {
+               s = toLowerCase(s);
+               StringBuffer buf = new StringBuffer();
+               for(int i = 0; i < s.length(); i++ ) {
+                               switch( s.charAt( i ) ) {
+                               case 'ö':
+                       buf.append( "oe" ); break;
+                               case 'ä':
+                       buf.append( "ae" ); break;
+                               case 'ü':
+                       buf.append( "ue" ); break;
+                               case 'ã':
+                       buf.append( "a" ); break;
+                               case '´':
+                               case '.':
+                       buf.append( "_" ); break;
+                               case ' ':
+                       if( buf.charAt( buf.length() - 1 ) != '_' ) {
+                                       buf.append( "_" );
+                       }
+                       break;
+                               default:
+                       buf.append( s.charAt( i ) );
+                               }
+               }
+               return buf.toString();
+       }
+
+       /**
+        * wandelt Sonderzeichen in Quotes um
+        *
+        * @return Kovertierter String
+        */
+       public static String encodeHtml(String s) {
+               StringBuffer buf = new StringBuffer();
+               for(int i=0;i < s.length(); i++ ) {
+
+                       /** @todo looks inefficient */
+                       if (s.charAt(i)=='&') {
+                               // convert html to xml-parsable representation
+                               if( s.indexOf( "&ouml;", i ) == i ) {
+                                       buf.append( "&#246;" ); i += 5;
+                                       continue;
+                               }
+                               if( s.indexOf( "&auml;", i ) == i ) {
+                                       buf.append( "&#228;" ); i += 5;
+                                       continue;
+                               }
+                               if( s.indexOf( "&uuml;", i ) == i ) {
+                                       buf.append( "&#252;" ); i += 5;
+                                       continue;
+                               }
+                               if( s.indexOf( "&Ouml;", i ) == i ) {
+                                       buf.append( "&#214;" ); i += 5;
+                                       continue;
+                               }
+                               if( s.indexOf( "&Auml;", i ) == i ) {
+                                       buf.append( "&#196;" ); i += 5;
+                                       continue;
+                               }
+                               if( s.indexOf( "&Uuml;", i ) == i ) {
+                                       buf.append( "&#220;" ); i += 5;
+                                       continue;
+                               }
+                               if( s.indexOf( "&szlig;", i ) == i ) {
+                                       buf.append( "&#223;" ); i += 6;
+                                       continue;
+                               }
+
+                               /** @todo should only escape outside of tags */
+
+                               if( s.indexOf( "&quot;", i ) == i ) {
+                                       buf.append( "&#223;" ); i += 5;
+                                       continue;
+        }
+                               if( s.indexOf( "&ndash;", i ) == i ) {
+                                       buf.append( "&#8211;" ); i += 6;
+                                       continue;
+        }
+        if( s.indexOf( "&mdash;", i ) == i ) {
+                                       buf.append( "&#8212;" ); i += 6;
+                                       continue;
+        }
+        if( s.indexOf( "&ldquo;", i ) == i ) {
+                                       buf.append( "&#8220;" ); i += 6;
+                                       continue;
+        }
+        if( s.indexOf( "&rdquo;", i ) == i ) {
+                                       buf.append( "&#8221;" ); i += 6;
+                                       continue;
+        }
+        if( s.indexOf( "&bdquo;", i ) == i ) {
+                                       buf.append( "&#8222;" ); i += 6;
+                                       continue;
+        }
+
+        //looks pretty stupid
+        if( s.indexOf( "&lt;", i ) == i ) {
+                                       buf.append( "&lt;" ); i += 3;
+                                       continue;
+        }
+        if( s.indexOf( "&gt;", i ) == i ) {
+                                       buf.append( "&gt;" ); i += 3;
+                                       continue;
+        }
+        if( s.indexOf( "&acute;", i ) == i ) {
+                                       buf.append( "&acute;" ); i += 6;
+                                       continue;
+        }
+        if( s.indexOf( "&nbsp;", i ) == i ) {
+                                       buf.append( "&nbsp;" ); i += 5;
+                                       continue;
+        }
+        //has to be the last
+        if( s.indexOf( "&", i ) == i ) {
+                                       buf.append( "&#38;" ); i += 0;
+                                       continue;
+        }
+                       }
+                       // convert umlauts an other special charakters
+                       switch( s.charAt(i) ) {
+                               case 'ö': buf.append( "&#246;" ); break;
+                               case 'ä': buf.append( "&#228;" ); break;
+                               case 'ü': buf.append( "&#252;" ); break;
+                               case 'Ö': buf.append( "&#214;" ); break;
+                               case 'Ä': buf.append( "&#196;" ); break;
+                               case 'Ü': buf.append( "&#220;" ); break;
+                               case 'ß': buf.append( "&#223;" ); break;
+                               case 'é': buf.append( "&#233;" ); break;
+                               case 'è': buf.append( "&#232;" ); break;
+                               case 'á': buf.append( "&#225;" ); break;
+                               case 'à': buf.append( "&#224;" ); break;
+                               case 'â': buf.append( "&#226;" ); break;
+                               case 'ã': buf.append( "&#227;" ); break;
+                               case '¬': buf.append( "&#172;" ); break;
+                               case '¹': buf.append( "&#185;" ); break;
+                               case '²': buf.append( "&#178;" ); break;
+                               case '³': buf.append( "&#179;" ); break;
+                               case '¼': buf.append( "&#188;" ); break;
+                               case '½': buf.append( "&#189;" ); break;
+                               case '¾': buf.append( "&#190;" ); break;
+                               case '¶': buf.append( "&#182;" ); break;
+                               case 'æ': buf.append( "&#230;" ); break;
+                               case 'ð': buf.append( "&#240;" ); break;
+                               case '|': buf.append( "&#166;" ); break;
+                               case '·': buf.append( "&#183;" ); break;
+                               case '°': buf.append( "&#176;" ); break;
+                               case '§': buf.append( "&#167;" ); break;
+                               case 'ø': buf.append( "&#248;" ); break;
+                               case 'ç': buf.append( "&#231;" ); break;
+                               case '¤': buf.append( "&#164;" ); break;
+                               case 'ª': buf.append( "&#170;" ); break;
+                               case 'Ç': buf.append( "&#199;" ); break;
+                               case 'Ã': buf.append( "&#195;" ); break;
+                               case 'Â': buf.append( "&#194;" ); break;
+                               case 'Æ': buf.append( "&#198;" ); break;
+                               case '©': buf.append( "&#169;" ); break;
+                               case '®': buf.append( "&#174;" ); break;
+                               case '¥': buf.append( "&#165;" ); break;
+                               case 'Þ': buf.append( "&#254;" ); break;
+                               case '¯': buf.append( "&#175;" ); break;
+                               case 'Ð': buf.append( "&#208;" ); break;
+                               case 'º': buf.append( "&#186;" ); break;
+                               case '¡': buf.append( "&#161;" ); break;
+                               case '£': buf.append( "&#163;" ); break;
+                               case '±': buf.append( "&#177;" ); break;
+                               case '¿': buf.append( "&#191;" ); break;
+                               case 'Ø': buf.append( "&#216;" ); break;
+                               case 'Á': buf.append( "&#192;" ); break;
+                               case 'À': buf.append( "&#193;" ); break;
+                               case 'É': buf.append( "&#200;" ); break;
+                               case 'È': buf.append( "&#201;" ); break;
+                               case 'ù': buf.append( "&#250;" ); break;
+                               case 'ñ': buf.append( "&#241;" ); break;
+                               case 'Ñ': buf.append( "&#209;" ); break;
+                               case 'µ': buf.append( "&#181;" ); break;
+                               case 'Í': buf.append( "&#204;" ); break;
+                               case 'Ì': buf.append( "&#205;" ); break;
+                               case 'í': buf.append( "&#236;" ); break;
+                               case 'ì': buf.append( "&#237;" ); break;
+                               case 'î': buf.append( "&#238;" ); break;
+                               case 'Î': buf.append( "&#206;" ); break;
+                               case 'ó': buf.append( "&#243;" ); break;
+                               case 'Ó': buf.append( "&#210;" ); break;
+                               case 'ò': buf.append( "&#206;" ); break;
+                               case 'Ò': buf.append( "&#211;" ); break;
+                               case 'ô': buf.append( "&#244;" ); break;
+                               case 'Ô': buf.append( "&#212;" ); break;
+                               case 'õ': buf.append( "&#245;" ); break;
+                               case 'Õ': buf.append( "&#213;" ); break;
+                               case 'ý': buf.append( "&#253;" ); break;
+                               case 'Ý': buf.append( "&#221;" ); break;
+                               case 'û': buf.append( "&#251;" ); break;
+                               case 'Û': buf.append( "&#219;" ); break;
+                               case 'ú': buf.append( "&#249;" ); break;
+                               case 'Ú': buf.append( "&#217;" ); break;
+                               case 'Ù': buf.append( "&#218;" ); break;
+                               case 'Ê': buf.append( "&#202;" ); break;
+                               case 'ê': buf.append( "&#234;" ); break;
+                               case 'å': buf.append( "&#229;" ); break;
+                               case 'Å': buf.append( "&#197;" ); break;
+                               case 'ë': buf.append( "&#235;" ); break;
+                               case 'Ë': buf.append( "&#203;" ); break;
+                               case 'ÿ': buf.append( "&#255;" ); break;
+                               case 'ï': buf.append( "&#239;" ); break;
+                               case 'Ï': buf.append( "&#207;" ); break;
+                               case '«': buf.append( "&#171;" ); break;
+        case '»': buf.append( "&#187;" ); break;
+        case '\'': buf.append( "&acute;" ); break;
+        case '\"': buf.append( "&quot;" ); break;
+        //case '\u8211': buf.append( "&#8211;" ); break;
+        //case '\u8212': buf.append( "&#8212;" ); break;
+        //case '\u8220': buf.append( "&#8220;" ); break;
+        //case '\u8221': buf.append( "&#8221;" ); break;
+        //case '\u8222': buf.append( "&#8222;" ); break;
+                               //case '\"': buf.append( "&#34;" ); break;
+                               default: buf.append( s.charAt(i) );
+                       }
+
+               }
+               return buf.toString();
+       }
+
+
+  public static String decodeHTMLinTags(String s){
+    StringBuffer buffer = new StringBuffer();
+    boolean start = false;
+    boolean stop = false;
+    int startIndex = 0;
+    int stopIndex = 0;
+    int temp = 0;
+
+    for(int i=0;i<s.length();i++){
+      if(s.charAt(i)=='<'){
+        start = true;
+        startIndex = i;
+      } else if(s.charAt(i)=='>'){
+        stop = true;
+        stopIndex = i;
+
+        if(start && stop){
+          buffer.append(s.substring(temp,startIndex));
+          buffer.append(replaceQuot(s.substring(startIndex,stopIndex+1)));
+          i= temp= stopIndex+1;
+          start= stop= false;
+        }
+      }
+    }
+    buffer.append(s.substring(stopIndex+1));
+    return buffer.toString();
+  }
+
+  public static String replaceQuot(String s) {
+    StringBuffer buffer = new StringBuffer();
+    for(int j = 0; j < s.length();j++){
+      if(s.charAt(j)=='&'){
+        if(s.indexOf( "&quot;",j) == j) {
+          buffer.append( "\"" );
+          j += 5;
+        }//if
+      } else {
+        buffer.append(s.charAt(j));
+      }//else
+    }//for
+    return buffer.toString();
+  }
+
+       /** wandelt Quotes in Sonderzeichen um
+        */
+       public static String decodeHtml(String s) {
+               StringBuffer buf = new StringBuffer();
+               for(int i=0;i < s.length(); i++ ) {
+                       if( s.indexOf( "&ouml;", i ) == i ) {
+                               buf.append( "ö" ); i += 5;
+                               continue;
+                       }
+                       if( s.indexOf( "&auml;", i ) == i ) {
+                               buf.append( "ä" ); i += 5;
+                               continue;
+                       }
+                       if( s.indexOf( "&uuml;", i ) == i ) {
+                               buf.append( "ü" ); i += 5;
+                               continue;
+                       }
+                       if( s.indexOf( "&Ouml;", i ) == i ) {
+                               buf.append( "Ö" ); i += 5;
+                               continue;
+                       }
+                       if( s.indexOf( "&Auml;", i ) == i ) {
+                               buf.append( "Ä" ); i += 5;
+                               continue;
+                       }
+                       if( s.indexOf( "&Uuml;", i ) == i ) {
+                               buf.append( "Ü" ); i += 5;
+                               continue;
+                       }
+                       if( s.indexOf( "&szlig;", i ) == i ) {
+                               buf.append( "ß" ); i += 6;
+                               continue;
+                       }
+      if( s.indexOf( "&quot;", i ) == i ) {
+                               buf.append( "\"" ); i += 5;
+                               continue;
+                       }
+                       buf.append( s.charAt(i) );
+               }
+               return buf.toString();
+       }
+
+
+       /**
+        * schnellere Variante der String.toLowerCase()-Routine
+        *
+        * @return String in Kleinbuchsten
+        */
+       public static String toLowerCase(String s) {
+               int l = s.length();
+               char[] a = new char[l];
+               for (int i = 0; i < l; i++)
+                       a[i] = Character.toLowerCase(s.charAt(i));
+               return new String(a);
+       }
+
+               /**
+        * Findet <code>element</code> im String-Array <code>array</code>
+        * @param array
+        * @param element
+        * @return Fundstelle als int oder -1
+        */
+       public static int indexOf(String[] array, String element) {
+               if (array != null)
+                       for (int i = 0; i < array.length; i++)
+                               if (array[i].equals(element))
+                                       return i;
+               return -1;
+       }
+
+       /**
+        * Testet auf Vorkommen von <code>element</code> in <code>array</code>
+        * @param array String-Array
+        * @param element
+        * @return true wenn <code>element</code> vorkommt, sonst false
+        */
+       public static boolean contains(String[] array, String element) {
+               return indexOf(array, element) >= 0;
+       }
+
+               /**
+        * Ermittelt CRC-Prüfsumme von String <code>s</code>
+        * @param s
+        * @return CRC-Prüfsumme
+        */
+  public static int getCRC(String s) {
+               int h = 0;
+               char val[] = s.toCharArray();
+               int len = val.length;
+
+               for (int i = 0 ; i < len; i++) {
+                       h &= 0x7fffffff;
+                       h = (((h >> 30) | (h << 1)) ^ (val[i]+i));
+               }
+
+               return (h << 8) | (len & 0xff);
+       }
+
+               /**
+        * 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;
+               }
+       }
+
+       /**
+        * Liefert Defaultwert def zurück, wenn s nicht zu einem float geparsed werden kann.
+        * @param s
+        * @param def
+        * @return geparster float oder def
+        */
+       public static float parseFloat(String s, float def) {
+               if (s == null) return def;
+               try {
+                       return new Float(s).floatValue();
+               } catch (NumberFormatException e) {
+                       return def;
+               }
+       }
+
+               /**
+        * Findet Ende eines Satzes in String <code>text</code>
+        * @param text
+        * @param startIndex
+        * @return index des Satzendes, oder -1
+        */
+       public static int findEndOfSentence(String text, int startIndex) {
+     while (true) {
+       int i = text.indexOf('.', startIndex);
+       if (i < 0) return -1;
+       if (i > 0 && !Character.isDigit(text.charAt(i-1)) &&
+          (i+1 >= text.length()
+          || text.charAt(i+1) == ' '
+          || text.charAt(i+1) == '\n'
+          || text.charAt(i+1) == '\t'))
+          return i+1;
+       startIndex = i+1;
+     }
+  }
+
+       /**
+        * Findet Wortende in String <code>text</code> ab <code>startIndex</code>
+        * @param text
+        * @param startIndex
+        * @return Index des Wortendes, oder -1
+        */
+       public static int findEndOfWord(String text, int startIndex) {
+               int i = text.indexOf(' ', startIndex),
+                       j = text.indexOf('\n', startIndex);
+               if (i < 0) i = text.length();
+               if (j < 0) j = text.length();
+               return Math.min(i, j);
+       }
+
+       /**
+        * Diese Routine macht aus links in reinem text browsbare links
+        * @param text
+        * @return Konvertierter String
+        */
+       public static String makeLinks(String text) {
+               int i = 0;
+               StringBuffer buf = new StringBuffer(text.length());
+               while (true) {
+                       int j = text.indexOf("http://", i);
+                       if (j < 0) {
+                               buf.append(text.substring(i));
+                               break;
+                       } else {
+                               buf.append(text.substring(i, j));
+                               int k = findEndOfWord(text,j+7);
+                               String url="";
+                               if (k<0)        url = text.substring(j);
+                               else            url = text.substring(j,k);
+
+                               buf.append("<a href=\042"+url+"\042>"+url+"</a>");
+                               //System.out.println("url mark: " + url);
+                               i = j+url.length();
+                       }
+               }
+               return buf.toString();
+
+       }
+
+
+       /**
+        *  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) {
+               try {
+                       RE regex = new RE("(<br>\r?\n<br>){1,}");
+                       return regex.substituteAll(haystack,"\n</p><p>");
+               } catch(REException ex){
+                       return null;
+               }
+       }
+
+       /**
+        *  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) {
+               try {
+                       RE regex = new RE("(\r?\n){1}");
+                       return regex.substituteAll(haystack,"$0<br>");
+               } catch(REException ex){
+                       return null;
+               }
+       }
+
+       /**
+        *  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) {
+               try {
+                       RE regex = new RE("([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_-]+).([a-zA-Z0-9_.-]+)");
+                       return regex.substituteAll(haystack,"<a href=\"mailto:$0\">$0</a>");
+               } catch(REException ex){
+                       return null;
+               }
+       }
+
+
+       /**
+        *  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) {
+               try {
+                       RE regex = new RE("([a-zA-Z0-9_.-]+)@([a-zA-Z0-9_-]+).([a-zA-Z0-9_.-]+)");
+                       return regex.substituteAll(haystack,"<img src=\""+imageRoot+"/"+mailImage+"\" border=\"0\"/>&#160;<a href=\"mailto:$0\">$0</a>");
+               } catch(REException ex){
+                       return null;
+               }
+       }
+
+
+       /**
+        *  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) {
+               try {
+                       //dieser Ausdruck brauch dringend fachliche Beratung
+                       RE regex = new RE("((https://)|(http://)|(ftp://))+([a-zA-Z0-9_-]+).([a-zA-Z0-9_.:-]+)/([^ \t\r\n<>]+[^ \t\r\n.,<>])");
+                       return regex.substituteAll(haystack,"<a href=\"$0\">$0</a>");
+               } catch(REException ex){
+                       return null;
+               }
+       }
+
+       /**
+        *  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,String imageRoot,String extImage,String intImage) {
+               try {
+                       //dieser Ausdruck brauch dringend fachliche Beratung
+                       RE regex = new RE("((https://)|(http://)|(ftp://))+([a-zA-Z0-9_-]+).([a-zA-Z0-9_.:-]+)/?([^ \t\r\n<>]+[^ \t\r\n.,<>])");
+                       return regex.substituteAll(haystack,"<img src=\""+imageRoot+"/"+extImage+"\" border=\"0\"/>&#160;<a href=\"$0\">$0</a>");
+               } catch(REException ex){
+                       return null;
+               }
+       }
+
+       /**
+        *  deleteForbiddenTags
+        *  this method deletes all <script>, <body> and <head>-tags
+        */
+       public static String deleteForbiddenTags(String haystack) {
+               try {
+                       RE regex = new RE("<[ \t\r\n](.*?)script(.*?)/script(.*?)>",RE.REG_ICASE);
+                       haystack = regex.substituteAll(haystack,"");
+                       regex = new RE("<head>(.*?)</head>");
+                       haystack = regex.substituteAll(haystack,"");
+                       regex = new RE("<[ \t\r\n/]*body(.*?)>");
+                       haystack = regex.substituteAll(haystack,"");
+                       return haystack;
+               } catch(REException ex){
+                       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,producerDocRoot,extImage,intImage);
+               return content;
+       }
+
+}
\ No newline at end of file
diff --git a/source/mir/misc/WebdbImage.java b/source/mir/misc/WebdbImage.java
new file mode 100755 (executable)
index 0000000..f079948
--- /dev/null
@@ -0,0 +1,155 @@
+package mir.misc;
+
+/**
+ * Title:
+ * Description:
+ * Copyright:    Copyright (c) 2001
+ * Company:      Indymedia
+ * @author
+ * @version 1.0
+ */
+
+import java.io.*;
+import javax.media.jai.*;
+import com.sun.media.jai.codec.*;
+import java.awt.image.renderable.ParameterBlock;
+
+public class WebdbImage
+{
+
+       // imageTypes
+       public final static int        WEBDB_JPG=0;
+       public final static int        WEBDB_GIF=1;
+
+       // default values for scaling
+       private int               maxIconSize=120;
+       private int               maxImageSize=640;
+
+       private byte[]            iconData;
+       private byte[]            imageData;
+       private int               imageType;
+       private int               iconWidth;
+       private int               iconHeight;
+
+       // internal representation of the image
+       private PlanarImage       planarImage;
+
+
+       // constructor
+       public WebdbImage(byte[] image, int type)
+               throws IOException
+       {
+               imageType=type;
+               planarImage = JAI.create("stream",new ByteArraySeekableStream(image));
+               scaleImage();
+       }
+
+       public WebdbImage(byte[] image, int type, int iconMax)
+               throws IOException
+       {
+               imageType=type;
+               maxIconSize=iconMax;
+               planarImage = JAI.create("stream",new ByteArraySeekableStream(image));
+               scaleImage();
+       }
+
+       public WebdbImage(byte[] image, int type, int iconMax, int imageMax)
+               throws IOException
+       {
+               imageType=type;
+               maxIconSize=iconMax;
+               maxImageSize=imageMax;
+               planarImage = JAI.create("stream",new ByteArraySeekableStream(image));
+               scaleImage();
+       }
+
+
+       // acc3ssor-methods
+       public int getIconWidth() throws IOException {
+               if (iconData==null) scaleIcon();
+               return iconWidth;
+       }
+
+       public int getIconHeight() throws IOException {
+               if (iconData==null) scaleIcon();
+               return iconHeight;
+       }
+
+       public int getImageWidth() {
+               return (int)planarImage.getWidth();
+       }
+
+       public int getImageHeight() {
+               return (int)planarImage.getHeight();
+       }
+
+       public byte[] getImage() {
+               if (imageData==null) {
+                       ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+
+                       switch (imageType) {
+                               case WEBDB_JPG:
+                                       JAI.create("encode", planarImage, outStream, "JPEG", null);break;
+                               case WEBDB_GIF:
+                                       JAI.create("encode", planarImage, outStream, "JPEG", null);break;
+                               default:
+                                       System.err.println("unknown image format: " + imageType);
+                       }
+
+                       imageData = outStream.toByteArray();
+               }
+               return imageData;
+       }
+
+       public byte[] getIcon()
+               throws IOException
+       {
+               if (iconData == null) scaleIcon();
+               return iconData;
+       }
+
+       private void scaleImage()
+               throws java.io.IOException
+       {
+               if (maxImageSize>0 && ( getImageHeight()> maxImageSize|| getImageWidth() >maxImageSize))
+               {
+                       float scale;
+                       if (getImageHeight() > getImageWidth())
+                               scale = (float)maxImageSize / (float)getImageHeight();
+                       else
+                               scale = (float)maxImageSize / (float)getImageWidth();
+
+                       InterpolationBilinear interp = new InterpolationBilinear();
+                       planarImage = JAI.create("scale", planarImage, scale, scale, 0.0F, 0.0F, interp);
+               }
+       }
+
+       private void scaleIcon()
+               throws java.io.IOException
+       {
+               if (iconData==null) {
+                       float scale;
+                       if (getImageHeight() > getImageWidth())
+                               scale = (float)maxIconSize / (float)getImageHeight();
+                       else
+                               scale = (float)maxIconSize / (float)getImageWidth();
+
+                       InterpolationBilinear interp = new InterpolationBilinear();
+                       PlanarImage temp = JAI.create("scale", planarImage, scale, scale, 0.0F, 0.0F, interp);
+                       ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+                       /** @todo gif */
+                       switch (imageType) {
+                               case WEBDB_JPG:
+                                       JAI.create("encode", temp, outStream, "JPEG", null);break;
+                               case WEBDB_GIF:
+                                       JAI.create("encode", temp, outStream, "JPEG", null);break;
+                               default:
+                                       System.err.println("unknown image format: " + imageType);
+                       }
+                       iconData = outStream.toByteArray();
+                       iconWidth=temp.getWidth();
+                       iconHeight=temp.getHeight();
+               }
+       }
+
+}
\ No newline at end of file
diff --git a/source/mir/misc/WebdbMultipartRequest.java b/source/mir/misc/WebdbMultipartRequest.java
new file mode 100755 (executable)
index 0000000..0fd0216
--- /dev/null
@@ -0,0 +1,70 @@
+package mir.misc;
+
+import java.util.*;
+import java.io.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import com.oreilly.servlet.multipart.*;
+import com.oreilly.servlet.*;
+
+/**
+ * Title:
+ * Description:
+ * Copyright:    Copyright (c) 2001
+ * Company:      Indymedia
+ * @author
+ * @version 1.0
+ */
+
+public class WebdbMultipartRequest
+{
+       HttpServletRequest    req=null;
+       HashMap               parameters = new HashMap();
+       MultipartParser       mp=null;
+       byte[]                uploadData=null;
+       String                fileName=null;
+
+       public WebdbMultipartRequest(HttpServletRequest theReq) throws IOException
+       {
+               req=theReq;
+               mp = new MultipartParser(req, 1024*8192); // maximum eight megabyte
+               _evaluateRequest();
+       }
+
+
+       public HashMap getParameters(){
+               return parameters;
+       }
+
+       public byte[] getMedia() {
+               return uploadData;
+       }
+
+       public String getFilename() {
+               return fileName;
+       }
+
+       private void _evaluateRequest() throws IOException{
+
+               Part part;
+               while ((part = mp.readNextPart()) != null) {
+                       String name = part.getName();
+                       if (part.isParam()) {
+                               // It's a parameter part, add it to the vector of values
+                               ParamPart paramPart = (ParamPart) part;
+                               String value = paramPart.getStringValue();
+                               parameters.put(name,value);
+                       }
+                       else if (part.isFile()) {
+                               // nur das erste uploadfile beruecksichtigen
+                               FilePart filePart = (FilePart) part;
+                               fileName = filePart.getFileName();
+                               if (fileName != null) {
+                                       ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+                                       filePart.writeTo(byteStream);
+                                       uploadData=byteStream.toByteArray();
+                               }
+                       }
+               } // while */
+       }
+}
diff --git a/source/mir/misc/XmlSaxonStyler.java b/source/mir/misc/XmlSaxonStyler.java
new file mode 100755 (executable)
index 0000000..d5031b4
--- /dev/null
@@ -0,0 +1,43 @@
+package mir.misc;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import org.xml.sax.SAXException;
+import com.icl.saxon.trax.Transformer;
+import com.icl.saxon.trax.Templates;
+import com.icl.saxon.trax.Result;
+import com.icl.saxon.PreparedStyleSheet;
+import org.xml.sax.InputSource;
+
+/**
+ * Title:        XmlSaxonStyler
+ * Description:  Implement XmlStyler
+ * Copyright:    Copyright (c) 2001
+ * Company:      Indymedia
+ * @author       idfx
+ * @version 1.0
+ */
+
+public class XmlSaxonStyler implements XmlStyler{
+
+  private XmlSaxonStyler() {}
+  private static XmlSaxonStyler styler = new XmlSaxonStyler();
+  public static XmlSaxonStyler getInstance(){
+    return styler;
+  }
+
+  public void style( String styleKey, InputStream is, OutputStream os )
+    throws SAXException {
+
+    Templates styleSheet = XslStyleCache.getPreparedStyleSheet( styleKey );
+    Transformer transformer = styleSheet.newTransformer();
+    transformer.transform( new InputSource( is ), new Result( os ) );
+  }
+
+  public void style( Transformer transformer, InputStream is, OutputStream os )
+    throws SAXException {
+
+    transformer.transform( new InputSource( is ), new Result( os ) );
+  }
+}
\ No newline at end of file
diff --git a/source/mir/misc/XmlStyler.java b/source/mir/misc/XmlStyler.java
new file mode 100755 (executable)
index 0000000..719ff4d
--- /dev/null
@@ -0,0 +1,21 @@
+package mir.misc;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import org.xml.sax.SAXException;
+
+/**
+ * Title:        XmLStyler
+ * Description:
+ * Copyright:    Copyright (c) 2001
+ * Company:      Indymedia
+ * @author       idfx
+ * @version 1.0
+ */
+
+public interface XmlStyler {
+
+  void style( String styleKey, InputStream is, OutputStream os )
+    throws SAXException;
+
+}
\ No newline at end of file
diff --git a/source/mir/misc/XslStyleCache.java b/source/mir/misc/XslStyleCache.java
new file mode 100755 (executable)
index 0000000..b0bfa42
--- /dev/null
@@ -0,0 +1,93 @@
+package mir.misc;
+
+import java.io.IOException;
+
+import com.icl.saxon.PreparedStyleSheet;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import com.icl.saxon.trax.Transformer;
+
+import java.util.Hashtable;
+
+/**
+ * Title:
+ * Description:
+ * Copyright:    Copyright (c) 2001
+ * Company:
+ * @author
+ * @version 1.0
+ */
+
+
+public class XslStyleCache {
+
+  private static Hashtable cache;
+  private static XslStyleCache single = new XslStyleCache();
+
+
+  /**
+   * XSLStyleCache constructor comment.
+  */
+  private XslStyleCache() {
+    cache = new Hashtable();
+  }
+
+  /**
+   * singleton constructor
+   */
+  private static synchronized XslStyleCache getInstance() {
+    return single;
+  }
+
+
+  /**
+   * Clear Cache
+   */
+  public static void clear() {
+    cache.clear();
+  }
+
+  /**
+   * This method was created in VisualAge.
+   * @return
+   * @param key java.lang.String
+   */
+  public static PreparedStyleSheet getPreparedStyleSheet( String key )
+    throws SAXException {
+
+    PreparedStyleSheet styleSheet = (PreparedStyleSheet)single.cache.get( key );
+    try {
+      if ( styleSheet == null ) {
+        styleSheet = new PreparedStyleSheet();
+        styleSheet.prepare( InputSourceResolver.resolve( key ) );
+        single.cache.put( key, styleSheet );
+      }
+    } catch ( IOException ex ) {
+      throw new SAXException( "tunneld IOExcpetion:" + ex.getMessage() );
+    }
+
+    return styleSheet;
+  }
+
+  /**
+   * This method was created in VisualAge.
+   * @return
+   * @param key java.lang.String
+   */
+  public static Transformer getTransformer( String key ){
+
+    PreparedStyleSheet styleSheet = (PreparedStyleSheet)single.cache.get( key );
+    try {
+      if ( styleSheet == null ) {
+        styleSheet = new PreparedStyleSheet();
+        styleSheet.prepare( InputSourceResolver.resolve( key ) );
+        single.cache.put( key, styleSheet );
+      }
+    } catch ( IOException ex ) {
+      //throw new SAXException( "tunneld IOExcpetion:" + ex.getMessage() );
+    } catch (SAXException ex) {}
+
+    return styleSheet.newTransformer();
+  }
+
+}
\ No newline at end of file
diff --git a/source/mir/module/AbstractModule.java b/source/mir/module/AbstractModule.java
new file mode 100755 (executable)
index 0000000..f82cc94
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * put your module comment here
+ */
+
+
+package  mir.module;
+
+import  java.util.*;
+import  java.sql.*;
+import  freemarker.template.*;
+import  mir.storage.*;
+import  mir.misc.*;
+import  mir.entity.*;
+
+
+/**
+ * Abstrakte Klasse, von denen die Modules die Basisfunktionalität erben.
+ * Die Moduleschicht dient dazu, Funktionalitaeten zur Verfügung zu stellen,
+ * die von mehreren ServletModulen verwendet werden.
+ */
+public class AbstractModule {
+       protected StorageObject theStorage;
+       protected Logfile theLog;
+
+  public void setStorage(StorageObject storage) {
+        this.theStorage = storage;
+       }
+
+       /**
+        * Liefert das Standard-StorageObject zurück, mit dem das Module assoziiert ist.
+        * @return Standard-StorageObject
+        */
+       public StorageObject getStorageObject () {
+        return theStorage;
+       }
+
+       /**
+        *   Holt eine Entity anhand der Id via StorageObject
+        *   @param String der Entity
+        *   @return Entity
+        */
+       public Entity getById (String id) throws ModuleException {
+               try {
+                       if (theStorage == null)
+                               throw  new ModuleException("Kein StorageObject gesetzt");
+                       Entity entity = (Entity)theStorage.selectById(id);
+                       if (entity == null)
+                                throw new ModuleException("Objekt nicht vorhanden: ID=" + id);
+                       else return entity;
+                       }
+               catch (StorageObjectException e){
+                       throw new ModuleException(e.toString());
+               }
+       }
+
+  /**
+        *   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 ModuleException {
+               try {
+                       if (theStorage == null)
+                               throw  new ModuleException("Kein StorageObject gesetzt");
+                       return theStorage.selectByWhereClause(whereClause, offset);
+               }
+               catch (StorageObjectException e){
+                       throw new ModuleException(e.toString());
+               }
+       }
+
+       /**
+        *   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 ModuleException {
+               try {
+                       if (theStorage==null) throw new ModuleException("Kein StorageObject gesetzt");
+                       return theStorage.selectByWhereClause(where, order, offset);
+               }
+               catch (StorageObjectException e){
+                       throw new ModuleException(e.toString());
+               }
+       }
+       /**
+        *   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 ModuleException
+       {
+               try {
+                       if (theStorage==null) throw new ModuleException("StorageObject not set!");
+                       return theStorage.selectByWhereClause(where, order, offset, limit);
+               }
+               catch (StorageObjectException e){
+                       throw new ModuleException(e.toString());
+               }
+       }
+
+       /**
+        *   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 ModuleException {
+               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
+        * @exception ModuleException
+        */
+       public String add (HashMap theValues) throws ModuleException {
+               try {
+                       Entity theEntity = (Entity)theStorage.getEntityClass().newInstance();
+                       theEntity.setStorage(theStorage);
+                       theEntity.setValues(theValues);
+                       return theEntity.insert();
+               } catch (Exception e) {
+                       throw new ModuleException(e.toString());
+               }
+       }
+
+       /**
+        * Standardfunktion, um einen Datensatz via StorageObject zu aktualisieren
+        * @param theValues Hash mit Spalte/Wert-Paaren
+        * @return Id des eingefügten Objekts
+        * @exception ModuleException
+        */
+       public String set (HashMap theValues) throws ModuleException {
+               try {
+                       Entity theEntity = theStorage.selectById((String)theValues.get("id"));
+                       if (theEntity == null)
+                                throw new ModuleException("Kein Objekt mit id in Datenbank id: " + theValues.get("id"));
+                theEntity.setValues(theValues);
+                theEntity.update();
+                return theEntity.getId();
+               }
+               catch (StorageObjectException e){
+                       e.printStackTrace(System.err);
+                       throw new ModuleException(e.toString());
+               }
+ }
+
+       /**
+        * Löscht einen Datensatz anhand seiner Id
+        * @param idParam
+        * @exception ModuleException
+        */
+       public void deleteById (String idParam) throws ModuleException {
+    try {
+           theStorage.delete(idParam);
+    } catch (StorageObjectException e){
+      throw new ModuleException(e.toString());
+    }
+  }
+
+       /**
+        * Liefert den Lookuptable aller Objekte des StorageObjects
+        * @return freemarker.template.SimpleHash
+        */
+       public SimpleHash getHashData() {
+               return theStorage.getHashData();
+       }
+
+  /**
+   * returns the number of rows
+   */
+  public int getSize(String where)
+    throws SQLException,StorageObjectException {
+    return theStorage.getSize(where);
+  }
+
+}
diff --git a/source/mir/module/ModuleException.java b/source/mir/module/ModuleException.java
new file mode 100755 (executable)
index 0000000..b17e04a
--- /dev/null
@@ -0,0 +1,20 @@
+package mir.module;
+
+import java.lang.*;
+
+/*
+ *  ServletModuleException -
+ *  wird vom ServletModule geschmissen</b>
+ *
+ * 
+ * @version 5.7.199
+ * @author RK
+ */
+
+public final class ModuleException extends Exception
+{
+       public ModuleException(String msg) {
+               super(msg);
+       }
+}
+
diff --git a/source/mir/servlet/AbstractServlet.java b/source/mir/servlet/AbstractServlet.java
new file mode 100755 (executable)
index 0000000..c859872
--- /dev/null
@@ -0,0 +1,75 @@
+package mir.servlet;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.io.File;
+import java.util.Locale;
+
+import mir.misc.HTMLTemplateProcessor;
+import mir.misc.Configuration;
+import mir.misc.Logfile;
+
+/**
+ * Title:        Mir
+ * Description:  Abstract servlet-class
+ * Copyright:    Copyright (c) 2001
+ * Company:      Indymedia
+ * @author       idfx
+ * @version 1.0
+ */
+
+public abstract class AbstractServlet extends HttpServlet {
+  protected static String lang;
+  protected static Logfile theLog;
+
+  /**
+   * get the configration
+   */
+  protected boolean getConfig(HttpServletRequest req) {
+               Configuration.initConfig(getInitParameter("Config"));
+               theLog = Logfile.getInstance(Configuration.getProperty("Home") + Configuration.getProperty("Mir.Logfile"));
+               theLog.printInfo(super.getServletName() + " started.");
+               return true;
+       }
+
+  /**
+   * Bind the language to the session
+   */
+  protected void setLanguage(HttpServletRequest req, String language){
+    HttpSession session = req.getSession();
+    session.setAttribute("Language",language);
+  }
+
+  /**
+   * Get the session-binded language
+   */
+  protected String getLanguage(HttpServletRequest req){
+    HttpSession session = req.getSession();
+    String lang = (String)session.getAttribute("Language");
+    if(lang==null || lang==""){
+      return getAcceptLanguage(req);
+    } else {
+                       return lang;
+               }
+  }
+
+  /**
+   * Checks the Accept-Language of the clients browser.
+   * if this language is available it returns its contry-code,
+   * else it return the standard-language
+   */
+  protected String getAcceptLanguage(HttpServletRequest req){
+    Locale loc = req.getLocale();
+    lang = loc.getLanguage();
+    File f = new File(HTMLTemplateProcessor.templateDir+"/"+lang);
+    //is there an existing template-path?
+    if(!f.isDirectory()){
+      //no there isn't. we use standard-language
+      lang = Configuration.getProperty("StandardLanguage");
+      theLog.printDebugInfo("language not existing");
+    }
+    theLog.printDebugInfo("Language: " + lang);
+    return lang;
+  }
+}
\ No newline at end of file
diff --git a/source/mir/servlet/ServletModule.java b/source/mir/servlet/ServletModule.java
new file mode 100755 (executable)
index 0000000..a81d304
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+ * put your module comment here
+ *
+ */
+
+
+package  mir.servlet;
+
+import  java.io.*;
+import  java.lang.*;
+import  java.util.*;
+import  javax.servlet.http.*;
+import  freemarker.template.*;
+import  mir.storage.*;
+import  mir.servlet.ServletModuleException;
+import  mir.misc.*;
+import  mir.entity.*;
+import  mir.module.*;
+import  mir.misc.*;
+
+
+/**
+ *  Abstrakte Klasse ServletModule stellt die Basisfunktionalitaet der
+ *  abgeleiteten ServletModule zur Verfügung.
+ *
+ * @version 28.6.1999
+ * @author RK
+ */
+
+public abstract class ServletModule {
+
+       public String                 defaultAction;
+       protected Logfile             theLog;
+       protected AbstractModule      mainModule;
+       protected String              templateListString;
+       protected String              templateObjektString;
+       protected String              templateConfirmString;
+
+       /**
+        * Singelton - Methode muss in den abgeleiteten Klassen ueberschrieben werden.
+        * @return ServletModule
+        */
+       public static ServletModule getInstance() { return null; }
+
+  /**
+   * get the session binded language
+   */
+  public String getLanguage(HttpServletRequest req){
+    HttpSession session = req.getSession();
+    String language = (String)session.getAttribute("Language");
+               if(language==null){
+                       language=Configuration.getProperty("StandardLanguage");
+               }
+    return language;
+  }
+
+       // ACHTUNG DEPRECATED::::
+       public void process(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException {}
+
+
+
+       /**
+        *  list(req,res) - generische Listmethode. Wennn die Funktionalitaet
+        *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
+        *  ueberschreiben werden.
+        *
+        * @param req Http-Request, das vom Dispatcher durchgereicht wird
+        * @param res Http-Response, die vom Dispatcher durchgereicht wird
+        */
+       public void list(HttpServletRequest req, HttpServletResponse res)
+               throws ServletModuleException {
+               try {
+                       EntityList   theList;
+                       String       offsetParam = req.getParameter("offset");
+                       int          offset =0;
+                       PrintWriter out = res.getWriter();
+
+                       // hier offsetcode bearbeiten
+                       if (offsetParam != null) offset = Integer.parseInt(offsetParam);
+                       if (req.getParameter("next") != null)
+                                       offset=Integer.parseInt(req.getParameter("nextoffset"));
+                       else
+                                       if (req.getParameter("prev") != null)
+                                               offset = Integer.parseInt(req.getParameter("prevoffset"));
+                       theList = mainModule.getByWhereClause(null, offset);
+                       //theList = mainModule.getByWhereClause((String)null, offset);
+                       if (theList == null || theList.getCount() == 0 || theList.getCount()>1)
+                               HTMLTemplateProcessor.process(getLanguage(req)+"/"+templateListString, theList, out);
+                       else
+                               deliver(req, res, theList.elementAt(0), templateObjektString);
+               }       catch (Exception e) {
+                       throw new ServletModuleException(e.toString());
+               }
+       }
+
+       /**
+        *  add(req,res) - generische Addmethode. Wennn die Funktionalitaet
+        *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
+        *  ueberschreiben werden.
+        * @param req Http-Request, das vom Dispatcher durchgereicht wird
+        * @param res Http-Response, die vom Dispatcher durchgereicht wird
+        */
+       public void add(HttpServletRequest req, HttpServletResponse res)
+       throws ServletModuleException {
+
+               try {
+      SimpleHash mergeData = new SimpleHash();
+      mergeData.put("new", "1");
+      deliver(req, res, mergeData, templateObjektString);
+               } catch (Exception e) {
+      throw new ServletModuleException(e.toString());
+    }
+       }
+
+       /**
+        *  insert(req,res) - generische Insertmethode, folgt auf add.
+        *  Wennn die Funktionalitaet
+        *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
+        *  ueberschreiben werden.
+        *
+        * @param req Http-Request, das vom Dispatcher durchgereicht wird
+        * @param res Http-Response, die vom Dispatcher durchgereicht wird
+        */
+       public void insert(HttpServletRequest req, HttpServletResponse res)
+       throws ServletModuleException {
+       try {
+                       HashMap withValues = getIntersectingValues(req, mainModule.getStorageObject());
+                       String id = mainModule.add(withValues);
+                       // theLog.printDebugInfo("--trying to deliver..."+id);
+                       deliver(req, res, mainModule.getById(id), templateObjektString);
+               }
+               catch (Exception e) { throw new ServletModuleException(e.toString());}
+       }
+
+/**
+        *  delete(req,res) - generische Deletemethode. Wennn die Funktionalitaet
+        *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
+        *  ueberschreiben werden.
+        *
+        * @param req Http-Request, das vom Dispatcher durchgereicht wird
+        * @param res Http-Response, die vom Dispatcher durchgereicht wird
+        */
+
+       public void delete(HttpServletRequest req, HttpServletResponse res)
+       throws ServletModuleException
+       {
+               try {
+                       String idParam = req.getParameter("id");
+                       if (idParam == null) throw new ServletModuleException("Falscher Aufruf: (id) nicht angegeben");
+                       // Hier code zum Loeschen
+                       String confirmParam = req.getParameter("confirm");
+                       String cancelParam = req.getParameter("cancel");
+                       if (confirmParam == null && cancelParam == null) {
+                               // HTML Ausgabe zum Confirmen!
+                               SimpleHash mergeData = new SimpleHash();
+                               String moduleClassName = mainModule.getClass().getName();
+                               int i = moduleClassName.indexOf(".Module");
+                               String moduleName = moduleClassName.substring(i+7);
+                               mergeData.put("module", moduleName);
+                               mergeData.put("infoString", moduleName + ": " + idParam);
+                               mergeData.put("id", idParam);
+                               mergeData.put("where", req.getParameter("where"));
+                               mergeData.put("order", req.getParameter("order"));
+                               mergeData.put("offset", req.getParameter("offset"));
+                               deliver(req, res, mergeData,templateConfirmString);
+                       } else {
+                               if (confirmParam!= null && !confirmParam.equals("")) {
+                                       //theLog.printInfo("delete confirmed!");
+                                       mainModule.deleteById(idParam);
+                                       list(req,res); // back to list
+                               } else {
+                                       if (req.getParameter("where") != null)
+                                                       list(req,res);
+                                       else
+                                               edit(req,res);
+                               }
+                       }
+               } catch (Exception e) {
+      throw new ServletModuleException(e.toString());
+    }
+       }
+
+       /**
+        *  edit(req,res) - generische Editmethode. Wennn die Funktionalitaet
+        *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
+        *  ueberschreiben werden.
+        *
+        * @param req Http-Request, das vom Dispatcher durchgereicht wird
+        * @param res Http-Response, die vom Dispatcher durchgereicht wird
+        */
+  public void edit(HttpServletRequest req, HttpServletResponse res)
+         throws ServletModuleException {
+    try {
+           String idParam = req.getParameter("id");
+                       deliver(req, res, mainModule.getById(idParam), templateObjektString);
+    } catch(ModuleException e) {
+      throw new ServletModuleException(e.toString());
+    }
+  }
+
+/**
+        *  update(req,res) - generische Updatemethode. Wennn die Funktionalitaet
+        *  nicht reicht, muss sie in der abgeleiteten ServletModule-Klasse
+        *  ueberschreiben werden.
+        *
+        * @param req Http-Request, das vom Dispatcher durchgereicht wird
+        * @param res Http-Response, die vom Dispatcher durchgereicht wird
+        */
+
+       public void update(HttpServletRequest req, HttpServletResponse res)
+         throws ServletModuleException {
+               try {
+       String idParam = req.getParameter("id");
+      HashMap withValues = getIntersectingValues(req, mainModule.getStorageObject());
+      String id = mainModule.set(withValues);
+      //theLog.printInfo("Showing Entity with id: " + id);
+      //edit(req,res);
+      String whereParam = req.getParameter("where");
+      String orderParam = req.getParameter("order");
+      if ((whereParam!=null && !whereParam.equals("")) || (orderParam!=null && !orderParam.equals(""))){
+                 //theLog.printDebugInfo("update to list");
+               list(req,res);
+      } else {
+               edit(req, res);
+      }
+      //list(req,res);
+               } catch (Exception e) {
+      throw new ServletModuleException(e.toString());
+    }
+       }
+
+       // Hilfsprozeduren
+  /**
+       public void predeliver(HttpServletResponse res, TemplateModelRoot rtm, String tmpl)
+               throws ServletModuleException   {
+    try {
+      PrintWriter out = new LineFilterWriter(res.getWriter());
+      StringWriter a = new StringWriter();
+      deliver(new PrintWriter(a),rtm,tmpl);
+      out.write(a.toString());
+      out.flush();
+    }  catch (Exception e) {
+      e.printStackTrace();System.err.println(e.toString());
+    }
+       }
+  */
+
+       /**
+        * deliver liefert das Template mit dem Filenamen templateFilename
+        * an den HttpServletResponse res aus, nachdem es mit den Daten aus
+        * TemplateModelRoot rtm gemischt wurde
+        *
+        * @param res Http-Response, die vom Dispatcher durchgereicht wird
+        * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
+        *   Daten, die ins Template gemerged werden sollen.
+        * @param tmpl Name des Templates
+        * @exception ServletModuleException
+        */
+       public void deliver(HttpServletRequest req, HttpServletResponse res, TemplateModelRoot rtm, String templateFilename)
+               throws ServletModuleException   {
+               if (rtm == null) rtm = new SimpleHash();
+               try {
+                       //PrintWriter out =  new LineFilterWriter(res.getWriter());
+                       PrintWriter out =  res.getWriter();
+                       HTMLTemplateProcessor.process(getLanguage(req)+"/"+templateFilename, rtm , out);
+                       out.close();
+               }       catch (HTMLParseException e) {
+                       throw new ServletModuleException(e.toString());
+               } catch (IOException e) {
+                       throw new ServletModuleException(e.toString());
+               }
+       }
+       /**
+        * deliver liefert das Template mit dem Filenamen templateFilename
+        * an den HttpServletResponse res aus, nachdem es mit den Daten aus
+        * TemplateModelRoot rtm gemischt wurde
+        *
+        * @param res Http-Response, die vom Dispatcher durchgereicht wird
+        * @param entity Entity, aus der die Daten, die ins Template gemerged werden sollen.
+        * @param tmpl Name des Templates
+        * @exception ServletModuleException
+        */
+       public void deliver(HttpServletRequest req, HttpServletResponse res, Entity ent, String templateFilename)
+               throws ServletModuleException   {
+               deliver(req, res,HTMLTemplateProcessor.makeSimpleHash(ent), templateFilename);
+       }
+       /**
+        * deliver liefert das Template mit dem Filenamen templateFilename
+        * an den HttpServletResponse res aus, nachdem es mit den Daten aus
+        * TemplateModelRoot rtm gemischt wurde
+        *
+        * @param out ist der OutputStream, in den die gergten Daten geschickt werden sollen.
+        * @param rtm beinahalten das freemarker.template.TempalteModelRoot mit den
+        *   Daten, die ins Template gemerged werden sollen.
+        * @param tmpl Name des Templates
+        * @exception ServletModuleException
+        */
+       private void deliver(HttpServletRequest req, PrintWriter out, TemplateModelRoot rtm, String templateFilename)
+    throws HTMLParseException {
+               HTMLTemplateProcessor.process(getLanguage(req)+"/"+templateFilename, rtm , out);
+       }
+
+       /**
+        *  Wenn die abgeleitete Klasse diese Methode ueberschreibt und einen String mit einem
+        *  Methodennamen zurueckliefert, dann wird diese Methode bei fehlender Angabe des
+        *  doParameters ausgefuehrt.
+        *
+        * @return Name der Default-Action
+        */
+       public String defaultAction() { return defaultAction; }
+
+               /**
+        *  Hier kann vor der Datenaufbereitung schon mal ein response geschickt
+        *  werden (um das subjektive Antwortverhalten bei langsamen Verbindungen
+        *  zu verbessern).
+        */
+       public void predeliver(HttpServletRequest req, HttpServletResponse res) { ; }
+
+       /**
+        * Holt die Felder aus der Metadatenfelderliste des StorageObjects, die
+        * im HttpRequest vorkommen und liefert sie als HashMap zurueck
+        *
+        * @return HashMap mit den Werten
+        */
+       public HashMap getIntersectingValues(HttpServletRequest req, StorageObject theStorage)
+               throws ServletModuleException   {
+               ArrayList theFieldList;
+               try {
+        theFieldList = theStorage.getFields();
+    } catch (StorageObjectException e) {
+                       throw new ServletModuleException("ServletModule.getIntersectingValues: " + e.toString());
+    }
+
+               HashMap withValues = new HashMap();
+               String aField, aValue;
+
+    for(int i=0; i<theFieldList.size();i++) {
+                       aField = (String)theFieldList.get(i);
+                       aValue = req.getParameter(aField);
+                       if (aValue!=null)       withValues.put(aField,aValue);
+               }
+               return withValues;
+       }
+
+}
\ No newline at end of file
diff --git a/source/mir/servlet/ServletModuleDispatch.java b/source/mir/servlet/ServletModuleDispatch.java
new file mode 100755 (executable)
index 0000000..5263fed
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Dispatcher
+ */
+
+package  mir.servlet;
+
+import  java.lang.reflect.*;
+import  javax.servlet.http.*;
+import  mir.servlet.ServletModuleException;
+import  mir.misc.*;
+
+
+/**
+ * Dispatcher, der in einer ServletModule-Klasse, die Methode, die per Http-Post oder Get
+ * Parameter "do" angegeben wurde, ausruft.
+ */
+public final class ServletModuleDispatch {
+
+       static Logfile theLog;
+
+       static {
+               theLog = Logfile.getInstance("/tmp/smod.dispatch");
+       }
+
+       /**
+        * privater Konstruktor, um versehentliche Instantiierung zu verhindern
+        */
+       private ServletModuleDispatch () {
+       }
+
+       /**
+        *  Die Dispatch-Routine ruft das von dem Hauptservlet kommende ServletModule
+        *  mit dem per HttpServletRequest angegebenen Paramter <code>do</code> auf.
+        *  Ist kein Parameter angegeben, so wird versucht, in die <code>defaultAction</code>
+        *  des ServletModules zu springen.
+        *
+        * @param req Http-Request, das vom Dispatcher an die Methode des
+        *    ServletModules durchgereicht wird
+        * @param res Http-Response, die vom Dispatcher an die Methode des
+        *    ServletModules durchgereicht wird
+        * @param sMod ServletModule, an das dispatched wird.
+        * @param mod Name des Modules als String (für Logfile)
+        */
+
+       public static void dispatch(ServletModule sMod, HttpServletRequest req,
+               HttpServletResponse res) throws ServletModuleException
+       {
+                       //sMod.predeliver(req,res);
+
+                       String doParam = req.getParameter("do");
+                       //theLog.printInfo("SerletModuleDispatch: " + sMod.toString() + " with method " + doParam);
+                       if (doParam == null) {
+                               if (sMod.defaultAction() != null) doParam = sMod.defaultAction();
+                               else throw new ServletModuleException("Parameter do nicht angegeben!");
+                       }
+
+                       Class[] params= { HttpServletRequest.class, HttpServletResponse.class};
+
+                       try {
+                               Method method = sMod.getClass().getMethod(doParam,params);
+                               if (method != null) {
+                                       method.invoke(sMod,new Object[] {req,res} );
+                                       return;
+                               }
+                               else theLog.printDebugInfo("method lookup unsuccesful");
+                       }
+                       catch ( NoSuchMethodException e) { throw new ServletModuleException("no such method!" + e.toString());}
+                       catch ( SecurityException e) { throw new ServletModuleException("method not allowed!" + e.toString());}
+                       catch ( InvocationTargetException e) {throw new ServletModuleException("target method exception!" + e.getTargetException().toString());}
+                       catch ( IllegalAccessException e) { throw new ServletModuleException("illegal method not allowed!" + e.toString());}
+//                     catch ( Exception e ) { throw new ServletModuleException(e.toString()); }
+
+                       throw new ServletModuleException("delivery failed! -- ");
+       }
+}
\ No newline at end of file
diff --git a/source/mir/servlet/ServletModuleException.java b/source/mir/servlet/ServletModuleException.java
new file mode 100755 (executable)
index 0000000..6181736
--- /dev/null
@@ -0,0 +1,20 @@
+package mir.servlet;
+
+import java.lang.*;
+
+/*
+ *  ServletModuleException -
+ *  wird vom ServletModule geschmissen</b>
+ *
+ * 
+ * @version 28.6.199
+ * @author RK
+ */
+
+public final class ServletModuleException extends Exception
+{
+       public ServletModuleException(String msg) {
+               super(msg);
+       }
+}
+
diff --git a/source/mir/servlet/ServletModuleMonitor.java b/source/mir/servlet/ServletModuleMonitor.java
new file mode 100755 (executable)
index 0000000..e6a7334
--- /dev/null
@@ -0,0 +1,97 @@
+package mir.servlet;
+
+import java.io.*;
+import java.sql.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+
+import freemarker.template.*;
+
+import mir.servlet.*;
+import mir.module.*;
+import mir.misc.*;
+import mir.storage.*;
+import mir.entity.*;
+
+import com.javaexchange.dbConnectionBroker.*;
+/*
+ *  ServletModuleShow -
+ *  liefert HTML fuer Show
+ *
+ *
+ * @author RK
+ */
+
+public class ServletModuleMonitor extends ServletModule
+{
+  private static ServletModuleMonitor instance = new ServletModuleMonitor();
+  public static ServletModule getInstance() { return instance; }
+
+  public String defaultAction() { return "show"; }
+
+  public void show(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException {
+
+    try {
+      // Hier Ausgabe von
+      // instances in AbstractEntity
+      // eingelesene confs
+      // datenbankverbindungen fuer brokers
+      getSimpleInfo(res.getWriter(),getConfs());
+      PrintWriter out = res.getWriter();
+      out.println(getInstancesInfo());
+      out.println(getInstancesConfInfo());
+
+    }
+    catch (Exception e) {
+      //e.printStackTrace();
+      throw new ServletModuleException(e.toString());
+    }
+  }
+  protected int getInstances(){
+    AbstractEntity ent = new AbstractEntity();
+    return ent.getInstances();
+  }
+  public String getInstancesInfo(){
+    return "<table><tr><td>Momentan instanzierte EntityObjekte = </td><td>" + getInstances()+"</td></tr></table>\n";
+  }
+  public String getInstancesConfInfo(){
+    return "<table><tr><td>Momentan instanzierte BrokerObjekte  = </td><td>" + getConfBrokerCnt()+"</td></tr></table>\n";
+  }
+
+  protected HashMap getConfs(){
+    return Configuration.getConfs();
+  }
+  protected int getBrokerUseCnt(DbConnectionBroker broker){
+    return broker.getUseCount();
+  }
+  protected int getConfBrokerCnt(){
+    return Configuration.getBrokerInstances();
+  }
+  protected int getBrokerSize(DbConnectionBroker broker){
+    return broker.getSize();
+  }
+  public String getBrokerInfo(DbConnectionBroker broker){
+    return "<tr><td>Connections im pool                  = </td><td>"+ broker.getSize() + "</td></tr>\n"+
+           "<tr><td>Connection die gerade benutzt werden = </td><td>" + broker.getUseCount()+"</td></tr>\n";
+  }
+  public void getSimpleInfo(Writer out,HashMap confs) throws IOException{
+    String key;
+    DbConnectionBroker broker = null;
+    out.write(getInstancesInfo());
+    out.write(getInstancesConfInfo());
+    Set set = confs.keySet();
+    Iterator it = set.iterator();
+    for (int i=0;i<set.size();i++){
+      key=(String)it.next();
+      out.write("<table><tr><td>Konfiguration : </td><td>" + confs.get(key)+ "</td></tr>\n" );
+      broker=Configuration.getBrokerInfo();
+      //broker=(DbConnectionBroker) ((HashMap)confs.get(key)).get("Pool.broker");
+      if(broker!=null)  out.write(getBrokerInfo(broker));
+      else
+        out.write("<tr><td>Broker nicht initializiert</td><td></td></tr>\n");
+      out.write("</table>\n");
+    }
+  }
+}
+
diff --git a/source/mir/servlet/ServletModuleShow.java b/source/mir/servlet/ServletModuleShow.java
new file mode 100755 (executable)
index 0000000..6160843
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * put your module comment here
+ */
+
+package  mir.servlet;
+
+import javax.servlet.http.*;
+import freemarker.template.*;
+import mir.storage.*;
+
+
+/**
+ *  Standard ServletModule, dass eine Template anzeigt, und nicht
+ *  mit Daten mischt. Damit ist es moeglich, einfache HTML-Seiten
+ *  als templates zu benutzen. Damit kann auf einfache Weise die
+ *  Funktionalitaet der Freemarker-Bibliothek (beispielsweise Navigationen
+ *  per <code>include</code> einzubauen) benutzt werden. Die Templates
+ *  werden aus dem per Konfiguration angegebenem template-Verzeichnis
+ *  im Ordner "/html" genommen.
+ *
+ * @author RK
+ */
+public class ServletModuleShow extends ServletModule {
+       private static ServletModuleShow instance = new ServletModuleShow();
+
+       /**
+        * Ein ServletModuleShow-Objekt wird über getInstance geliefert. Es gibt zur
+        * Laufzeit nur ein Objekt (Singleton)
+        * @return ServletModuleShow
+        */
+       public static ServletModule getInstance () {
+               return  instance;
+       }
+
+       /**
+        * Initialisierung leer.
+        */
+       private ServletModuleShow () {
+       }
+
+       /**
+        * defaultAction (s.a ServletModule)
+        * @return "show"
+        */
+       public String defaultAction () {
+               return  "show";
+       }
+
+       /**
+        * Standardmethode, die die Funktionalitaet des ServletModules implementiert.
+        *
+        * @param req Http-Request, das vom Dispatcher durchgereicht wird
+        * @param res Http-Response, die vom Dispatcher durchgereicht wird
+        * @return String fuer Logfile
+        * @exception ServletModuleException
+        */
+  public void show(HttpServletRequest req, HttpServletResponse res) throws ServletModuleException {
+    try {
+      String idParam = req.getParameter("tmpl");
+      if (!(idParam==null || idParam.equals(""))) {
+           deliver(req, res, (TemplateModelRoot)null, "html/"+idParam+".template");
+      }
+      else {
+        throw new ServletModuleException("Falsches template: " + idParam);
+      }
+    }
+    catch (Exception e) {
+      throw new ServletModuleException(e.toString());
+    }
+  }
+
+}
+
+
+
+
diff --git a/source/mir/storage/Database.java b/source/mir/storage/Database.java
new file mode 100755 (executable)
index 0000000..4996931
--- /dev/null
@@ -0,0 +1,1082 @@
+/*
+ * put your module comment here
+ */
+package mir.storage;
+
+import  java.sql.*;
+import  java.lang.*;
+import  java.io.*;
+import  java.util.*;
+import  freemarker.template.*;
+import  com.javaexchange.dbConnectionBroker.*;
+import  mir.storage.StorageObject;
+import  mir.entity.*;
+import  mir.misc.*;
+
+
+/**
+ * Diese Klasse implementiert die Zugriffsschicht auf die Datenbank.
+ * Alle Projektspezifischen Datenbankklassen erben von dieser Klasse.
+ * In den Unterklassen wird im Minimalfall nur die Tabelle angegeben.
+ * Im Konfigurationsfile findet sich eine Verweis auf den verwendeten
+ * Treiber, Host, User und Passwort, ueber den der Zugriff auf die
+ * Datenbank erfolgt.
+ *
+ * @author RK
+ * @version 16.7.1999
+ */
+public class Database implements StorageObject {
+
+       protected DbConnectionBroker        myBroker;
+       protected String                    theTable;
+       protected String                    theCoreTable=null;
+       protected String                    thePKeyName="id";
+       protected int                       thePKeyType;
+       protected boolean                   evaluatedMetaData=false;
+       protected ArrayList                 metadataFields,metadataLabels,metadataNotNullFields;
+       protected int[]                     metadataTypes;
+       protected Class                     theEntityClass;
+       protected StorageObject             myselfDatabase;
+       protected HashMap                   cache;
+       protected SimpleList                popupCache=null;
+       protected boolean                                               hasPopupCache = false;
+       protected SimpleHash                hashCache=null;
+       protected boolean                   hasTimestamp=true;
+       private       String                database_driver;
+       private       String                database_url;
+       private int                         defaultLimit;
+       private DatabaseAdaptor             theAdaptor;
+       protected Logfile                   theLog;
+       protected Connection                con;
+
+       /**
+        * 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.
+        *
+        * @param   String confFilename Dateiname der Konfigurationsdatei
+        */
+       public Database() {
+               theLog = Logfile.getInstance(Configuration.getProperty("Home") + Configuration.getProperty("Database.Logfile"));
+               String database_username=Configuration.getProperty("Database.Username");
+               String database_password=Configuration.getProperty("Database.Password");
+               String database_host=Configuration.getProperty("Database.Host");
+               String theAdaptorName=Configuration.getProperty("Database.Adaptor");
+               try {
+                       theEntityClass = Class.forName("mir.entity.GenericEntity");
+                       theAdaptor = (DatabaseAdaptor)Class.forName(theAdaptorName).newInstance();
+                       defaultLimit = Integer.parseInt(Configuration.getProperty("Database.Limit"));
+                       database_driver=theAdaptor.getDriver();
+                       database_url=theAdaptor.getURL(database_username,database_password,database_host);
+                       theLog.printDebugInfo("adding Broker with: " +database_driver+":"+database_url  );
+                       Configuration.addBroker(database_driver,database_url);
+                       myBroker=Configuration.getBroker();
+               }
+               catch (Exception e){
+                       theLog.printError("Bei Konstruktion von Database() with " + theAdaptorName + " -- " +e.toString());
+               }
+       }
+
+       /**
+        * 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  thePKeyName;
+       }
+
+       /**
+        * Liefert den Namen der Tabelle, auf das sich das Datenbankobjekt bezieht.
+        *
+        * @return Name der Tabelle
+        */
+       public String getTableName () {
+               return  theTable;
+       }
+
+       /*
+        *   Dient dazu vererbte Tabellen bei objectrelationalen DBMS
+        *   zu speichern, wenn die id einer Tabelle in der parenttabelle verwaltet wird.
+        *   @return liefert theCoreTabel als String zurueck, wenn gesetzt, sonst
+        *    the Table
+        */
+
+       public String getCoreTable(){
+               if (theCoreTable!=null) return theCoreTable;
+               else return theTable;
+       }
+
+       /**
+        * Liefert Feldtypen der Felder der Tabelle zurueck (s.a. java.sql.Types)
+        * @return int-Array mit den Typen der Felder
+        * @exception StorageObjectException
+        */
+       public int[] getTypes () throws StorageObjectException {
+               if (metadataTypes == null)
+                       get_meta_data();
+               return  metadataTypes;
+       }
+
+       /**
+        * Liefert eine Liste der Labels der Tabellenfelder
+        * @return ArrayListe mit Labeln
+        * @exception StorageObjectException
+        */
+       public ArrayList getLabels () throws StorageObjectException {
+               if (metadataLabels == null)
+                       get_meta_data();
+               return  metadataLabels;
+       }
+
+       /**
+        * Liefert eine Liste der Felder der Tabelle
+        * @return ArrayList mit Feldern
+        * @exception StorageObjectException
+        */
+       public ArrayList getFields () throws StorageObjectException {
+               if (metadataFields == null)
+                       get_meta_data();
+               return  metadataFields;
+       }
+
+
+       /*
+        *   Uebersetzt die Datenbankwerte in einen String.
+        *   @param inValue  Wert aus ResultSet.
+        *   @param aType  Datenbanktyp.
+        *   @return liefert den Wert als String zurueck. Wenn keine Umwandlung moeglich
+        *           dann /unsupported value/
+        */
+       private String getValueAsString (ResultSet rs, int valueIndex, int aType) throws StorageObjectException {
+               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:
+                                               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);
+                                               if (outValue != null)
+                                                       outValue = StringUtil.encodeHtml(StringUtil.unquote(outValue));
+                                               break;
+                                       case java.sql.Types.LONGVARBINARY:
+                                               outValue = rs.getString(valueIndex);
+                                               if (outValue != null)
+                                                       outValue = StringUtil.encodeHtml(StringUtil.unquote(outValue));
+                                               break;
+                                       case java.sql.Types.TIMESTAMP:
+                                               Timestamp timestamp = (rs.getTimestamp(valueIndex));
+                                               if (!rs.wasNull()) {
+                                                       outValue = timestamp.toString();
+                                               }
+                                               break;
+                                       default:
+                                               outValue = "<unsupported value>";
+                                               theLog.printWarning("Unsupported Datatype: at " + valueIndex +
+                                                               " (" + aType + ")");
+                               }
+                       } catch (SQLException e) {
+                               throw  new StorageObjectException("Could not get Value out of Resultset -- "
+                                               + e.toString());
+                       }
+               }
+               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 StorageObjectException {
+
+               if (id==null||id.equals(""))
+      throw new StorageObjectException("id war null");
+               if (cache != null && cache.containsKey(id))
+                       return (Entity)cache.get(id);  // wenn cache gesetzt, evtl. kein roundtrip zur Datenbank
+
+               Statement stmt=null;Connection con=getPooledCon();
+               Entity returnEntity=null;
+               try {
+                       ResultSet rs;
+                       String selectSql = "select * from " + theTable + " where " + thePKeyName + "=" + id;
+                       stmt = con.createStatement();
+                       rs = executeSql(stmt, selectSql);
+                       if (rs != null) {
+                               if (evaluatedMetaData==false) evalMetaData(rs.getMetaData());
+                               if (rs.next())
+                                       returnEntity = makeEntityFromResultSet(rs);
+                               else theLog.printDebugInfo("Keine daten fuer id: " + id + "in Tabelle" + theTable);
+                               rs.close();
+                       }       else {
+        theLog.printDebugInfo("No Data for Id " + id + " in Table " + theTable);
+      }
+               } catch (SQLException sqe){
+      throwSQLException(sqe,"selectById"); return null;
+    } catch (NumberFormatException e) {
+      theLog.printError("ID ist keine Zahl: " + id);
+    } finally {
+      freeConnection(con,stmt);
+    }
+
+               return returnEntity;
+       }
+
+       /**
+        *   select-Operator um Datensaetze zu bekommen, die key = value erfuellen.
+        *   @param key  Datenbankfeld der Bedingung.
+        *   @param value  Wert die der key anehmen muss.
+        *   @return EntityList mit den gematchten Entities
+        */
+
+       public EntityList selectByFieldValue(String aField, String aValue)
+               throws StorageObjectException {
+
+               return selectByFieldValue(aField, aValue, 0);
+       }
+
+       /**
+        *   select-Operator um Datensaetze zu bekommen, die key = value erfuellen.
+        *   @param key  Datenbankfeld der Bedingung.
+        *   @param value  Wert die der key anehmen muss.
+        *   @param offset  Gibt an ab welchem Datensatz angezeigt werden soll.
+        *   @return EntityList mit den gematchten Entities
+        */
+
+       public EntityList selectByFieldValue(String aField, String aValue, int offset)
+               throws StorageObjectException   {
+
+               return selectByWhereClause(aField + "=" + aValue, offset);
+       }
+
+
+       /**
+        * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.
+        * Also offset wird der erste Datensatz genommen.
+        *
+        * @param wc where-Clause
+        * @return EntityList mit den gematchten Entities
+        * @exception StorageObjectException
+        */
+       public EntityList selectByWhereClause(String where)
+               throws StorageObjectException   {
+
+               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 wc where-Clause
+        * @param offset ab welchem Datensatz.
+        * @return EntityList mit den gematchten Entities
+        * @exception StorageObjectException
+        */
+       public EntityList selectByWhereClause(String whereClause, int offset)
+               throws StorageObjectException   {
+
+               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 wc where-Clause
+        * @param ob orderBy-Clause
+        * @return EntityList mit den gematchten Entities
+        * @exception StorageObjectException
+        */
+
+       public EntityList selectByWhereClause(String where, String order)
+               throws StorageObjectException   {
+
+               return selectByWhereClause(where, order, 0);
+       }
+       /**
+        * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.
+        * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.
+        *
+        * @param wc where-Clause
+        * @param ob orderBy-Clause
+        * @param offset ab welchem Datensatz
+        * @return EntityList mit den gematchten Entities
+        * @exception StorageObjectException
+        */
+
+       public EntityList selectByWhereClause(String whereClause, String orderBy, int offset)
+               throws StorageObjectException   {
+
+               return selectByWhereClause(whereClause, orderBy, offset, defaultLimit);
+       }
+
+
+       /**
+        * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.
+        * @param wc where-Clause
+        * @param ob orderBy-Clause
+        * @param offset ab welchem Datensatz
+        * @param limit wieviele Datensätze
+        * @return EntityList mit den gematchten Entities
+        * @exception StorageObjectException
+        */
+
+       public EntityList selectByWhereClause(String wc, String ob, int offset, int limit)
+               throws StorageObjectException   {
+
+               // local
+               EntityList    theReturnList=null;
+               Connection    con=null;
+               Statement     stmt=null;
+               ResultSet     rs;
+               int               offsetCount = 0;
+               int           count=0;
+
+
+               // build sql-statement
+               if (wc != null && wc.length() == 0) {
+                       wc = null;
+               }
+               StringBuffer countSql = new StringBuffer("select count(*) from ").append(theTable);
+               StringBuffer selectSql = new StringBuffer("select * from ").append(theTable);
+               if (wc != null) {
+                       selectSql.append(" where ").append(wc);
+                       countSql.append(" where ").append(wc);
+               }
+               if (ob != null && !(ob.length() == 0)) {
+                       selectSql.append(" order by ").append(ob);
+               }
+               if (theAdaptor.hasLimit()) {
+                       if (limit > -1 && offset > -1) {
+                               selectSql.append(" limit ");
+                               if (theAdaptor.reverseLimit()) {
+                                       selectSql.append(limit).append(",").append(offset);
+                               }
+                               else {
+                                       selectSql.append(offset).append(",").append(limit);
+                               }
+                       }
+               }
+
+                       // execute sql
+               try {
+                       con = getPooledCon();
+                       stmt = con.createStatement();
+                       // counting rows
+                       if (theAdaptor.hasLimit()) {
+                               rs = executeSql(stmt, countSql.toString());
+                               if (rs != null) {
+                                       if (rs.next())
+                                               count = rs.getInt(1);
+                                       rs.close();
+                               }
+                               else
+                                       theLog.printError("Mh. Konnte nicht zaehlen: " + countSql);
+                       }
+                       // hier select
+                       rs = executeSql(stmt, selectSql.toString());
+                       if (rs != null) {
+                               theReturnList = new EntityList();
+                               if (evaluatedMetaData == false) {
+                                       evalMetaData(rs.getMetaData());
+                               }
+                               Entity theResultEntity;
+                               while (rs.next()) {
+                                       theResultEntity = makeEntityFromResultSet(rs);
+                                       theReturnList.add(theResultEntity);
+                                       offsetCount++;
+                               }
+                               rs.close();
+                       }
+                       // making entitylist
+                       if (!(theAdaptor.hasLimit()))
+                               count = offsetCount;
+                       if (theReturnList != null) {
+                               theReturnList.setCount(count);
+                               theReturnList.setOffset(offset);
+                               theReturnList.setWhere(wc);
+                               theReturnList.setOrder(ob);
+                               if (offset >= limit) {
+                                       theReturnList.setPrevBatch(offset - limit);
+                               }
+                               if (offset + offsetCount < count) {
+                                       theReturnList.setNextBatch(offset + limit);
+                               }
+                       }
+               } catch (SQLException sqe) {
+                       throwSQLException(sqe, "selectByWhereClause");
+               } finally {
+                       freeConnection(con, stmt);
+               }
+               return  theReturnList;
+       }
+
+       /**
+        *  Bastelt aus einer Zeile der Datenbank ein EntityObjekt.
+        *
+        *  @param rs Das ResultSetObjekt.
+        *  @return Entity Die Entity.
+        */
+
+       public Entity makeEntityFromResultSet (ResultSet rs) throws StorageObjectException {
+               HashMap theResultHash = new HashMap();
+               String theResult = null;
+               int theType;
+               Entity returnEntity = null;
+               try {
+                       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) {
+                                       InputStream us = rs.getAsciiStream(i + 1);
+                                       if (us != null) {
+                                               InputStreamReader is = new InputStreamReader(us);
+                                               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 (cache != null && theResultHash.containsKey(thePKeyName) && cache.containsKey((String)theResultHash.get(thePKeyName))) {
+                               //theLog.printDebugInfo("CACHE: (out) "+ theResultHash.get(thePKeyName)+ " :"+theTable);
+                               returnEntity = (Entity)cache.get((String)theResultHash.get(thePKeyName));
+                       }
+                       else {
+                               if (theEntityClass != null) {
+                                       returnEntity = (Entity)theEntityClass.newInstance();
+                                       returnEntity.setValues(theResultHash);
+                                       returnEntity.setStorage(myselfDatabase);
+                                       if (cache != null) {
+                                               //theLog.printDebugInfo("CACHE: ( in) " + returnEntity.getId() + " :"+theTable);
+                                               cache.put(returnEntity.getId(), returnEntity);
+                                       }
+                               }
+                               else {
+                                       throwStorageObjectException("Interner Fehler theEntityClass nicht gesetzt!");
+                               }
+                       }
+               }           // try
+               catch (IllegalAccessException e) {
+                       throwStorageObjectException("Kein Zugriff! -- " + e.toString());
+               } catch (IOException e) {
+                       throwStorageObjectException("IOException! -- " + e.toString());
+               } catch (InstantiationException e) {
+                       throwStorageObjectException("Keine Instantiiierung! -- " + e.toString());
+               } catch (SQLException sqe) {
+                       throwSQLException(sqe, "makeEntityFromResultSet");
+                       return  null;
+               }
+               return  returnEntity;
+       }
+
+       /**
+        * insert-Operator: fügt eine Entity in die Tabelle ein. Eine Spalte WEBDB_CREATE
+        * wird automatisch mit dem aktuellen Datum gefuellt.
+        *
+        * @param theEntity
+        * @return der Wert des Primary-keys der eingefügten Entity
+        */
+       public String insert (Entity theEntity) throws StorageObjectException {
+               String returnId = "0";
+               Connection con = null;
+               PreparedStatement pstmt = null;
+               //cache
+               invalidatePopupCache();
+               try {
+                       HashMap theEntityValues = theEntity.getValues();
+                       ArrayList streamedInput = theEntity.streamedInput();
+                       StringBuffer f = new StringBuffer();
+                       StringBuffer v = new StringBuffer();
+                       String aField, aValue;
+                       boolean firstField = true;
+                       // make sql-string
+                       for (int i = 0; i < getFields().size(); i++) {
+                               aField = (String)getFields().get(i);
+                               if (!aField.equals(thePKeyName)) {
+                                       aValue = null;
+                                       // sonderfaelle
+                                       if (aField.equals("webdb_create")) {
+                                               aValue = "NOW()";
+                                       }
+                                       else {
+                                               if (streamedInput != null && streamedInput.contains(aField)) {
+                                                       aValue = "?";
+                                               }
+                                               else {
+                                                       if (theEntityValues.containsKey(aField)) {
+                                                               aValue = "'" + StringUtil.quote((String)theEntityValues.get(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(theTable).append("(").append(f).append(") values (").append(v).append(")");
+                       String sql = sqlBuf.toString();
+                       theLog.printInfo("INSERT: " + sql);
+                       con = getPooledCon();
+                       con.setAutoCommit(false);
+                       pstmt = con.prepareStatement(sql);
+                       if (streamedInput != null) {
+                               for (int i = 0; i < streamedInput.size(); i++) {
+                                       String inputString = (String)theEntityValues.get(streamedInput.get(i));
+                                       pstmt.setBytes(i + 1, inputString.getBytes());
+                               }
+                       }
+                       pstmt.execute();
+                       pstmt = con.prepareStatement(theAdaptor.getLastInsertSQL((Database)myselfDatabase));
+                       ResultSet rs = pstmt.executeQuery();
+                       rs.next();
+                       returnId = rs.getString(1);
+                       theEntity.setId(returnId);
+               } catch (SQLException sqe) {
+                       throwSQLException(sqe, "insert");
+               } finally {
+                       try {
+                               con.setAutoCommit(true);
+                       } catch (Exception e) {
+                               ;
+                       }
+                       freeConnection(con, pstmt);
+               }
+               return  returnId;
+       }
+
+       /**
+        * update-Operator: aktualisiert eine Entity. Eine Spalte WEBDB_LASTCHANGE
+        * wird automatisch mit dem aktuellen Datum gefuellt.
+        *
+        * @param theEntity
+        */
+       public void update (Entity theEntity) throws StorageObjectException {
+               Connection con = null;
+               PreparedStatement pstmt = null;
+               ArrayList streamedInput = theEntity.streamedInput();
+               HashMap theEntityValues = theEntity.getValues();
+               String id = theEntity.getId();
+               String aField;
+               StringBuffer fv = new StringBuffer();
+               boolean firstField = true;
+               //cache
+               invalidatePopupCache();
+               // build sql statement
+               for (int i = 0; i < getFields().size(); i++) {
+                       aField = (String)metadataFields.get(i);
+                       // only normal cases
+                       if (!(aField.equals(thePKeyName) || aField.equals("webdb_create") ||
+                                       aField.equals("webdb_lastchange") || (streamedInput != null && streamedInput.contains(aField)))) {
+                               if (theEntityValues.containsKey(aField)) {
+                                       if (firstField == false) {
+                                               fv.append(", ");
+                                       }
+                                       else {
+                                               firstField = false;
+                                       }
+                                       fv.append(aField).append("='").append(StringUtil.quote((String)theEntityValues.get(aField))).append("'");
+                               }
+                       }
+               }
+               StringBuffer sql = new StringBuffer("update ").append(theTable).append(" set ").append(fv);
+               // exceptions
+               if (metadataFields.contains("webdb_lastchange")) {
+                       sql.append(",webdb_lastchange=NOW()");
+               }
+               if (streamedInput != null) {
+                       for (int i = 0; i < streamedInput.size(); i++) {
+                               sql.append(",").append(streamedInput.get(i)).append("=?");
+                       }
+               }
+               sql.append(" where id=").append(id);
+               theLog.printInfo("UPDATE: " + sql);
+               // execute sql
+               try {
+                       con = getPooledCon();
+                       con.setAutoCommit(false);
+                       pstmt = con.prepareStatement(sql.toString());
+                       if (streamedInput != null) {
+                               for (int i = 0; i < streamedInput.size(); i++) {
+                                       String inputString = (String)theEntityValues.get(streamedInput.get(i));
+                                       pstmt.setBytes(i + 1, inputString.getBytes());
+                               }
+                       }
+                       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 StorageObjectException {
+               Statement stmt = null;
+               Connection con = null;
+               String sql;
+               int res = 0;
+               // loeschen des caches
+               invalidatePopupCache();
+               sql = "delete from " + theTable + " where " + thePKeyName + "='" + id +
+                               "'";
+               theLog.printInfo("DELETE " + sql);
+               try {
+                       con = getPooledCon();
+                       stmt = con.createStatement();
+                       res = stmt.executeUpdate(sql);
+               } catch (SQLException sqe) {
+                       throwSQLException(sqe, "delete");
+               } finally {
+                       freeConnection(con, stmt);
+               }
+               if (cache != null) {
+                       theLog.printInfo("CACHE: deleted " + id);
+                       cache.remove(id);
+               }
+               return  (res > 0) ? true : false;
+       }
+
+       /* noch nicht implementiert.
+        * @return immer false
+        */
+       public boolean delete (EntityList theEntityList) {
+               invalidatePopupCache();
+               return  false;
+       }
+
+       /**
+        * Diese Methode sollte ueberschrieben werden, wenn fuer die abgeleitete Database-Klasse
+        * eine SimpleList mit Standard-Popupdaten erzeugt werden koennen soll.
+        * @return null
+        */
+       public SimpleList getPopupData () {
+               return  null;
+       }
+
+       /**
+        *  Holt Daten fuer Popups.
+        *  @param name  Name des Feldes.
+        *  @param hasNullValue  Wenn true wird eine leerer  Eintrag fuer die Popups erzeugt.
+        *  @return SimpleList Gibt freemarker.template.SimpleList zurueck.
+        */
+       public SimpleList getPopupData (String name, boolean hasNullValue) {
+               return  getPopupData(name, hasNullValue, null);
+       }
+
+       /**
+        *  Holt Daten fuer Popups.
+        *  @param name  Name des Feldes.
+        *  @param hasNullValue  Wenn true wird eine leerer  Eintrag fuer die Popups erzeugt.
+        *  @param where  Schraenkt die Selektion der Datensaetze ein.
+        *  @return SimpleList Gibt freemarker.template.SimpleList zurueck.
+        */
+       public SimpleList getPopupData (String name, boolean hasNullValue, String where) {
+               return  getPopupData(name, hasNullValue, where, null);
+       }
+
+       /**
+        *  Holt Daten fuer Popups.
+        *  @param name  Name des Feldes.
+        *  @param hasNullValue  Wenn true wird eine leerer  Eintrag fuer die Popups erzeugt.
+        *  @param where  Schraenkt die Selektion der Datensaetze ein.
+        *  @param order  Gibt ein Feld als Sortierkriterium an.
+        *  @return SimpleList Gibt freemarker.template.SimpleList zurueck.
+        */
+       public SimpleList getPopupData (String name, boolean hasNullValue, String where,
+                       String order) {
+               // caching
+               if (hasPopupCache && popupCache != null)
+                       return  popupCache;
+               SimpleList simpleList = null;
+               Connection con = null;
+               Statement stmt = null;
+               // build sql
+               StringBuffer sql = new StringBuffer("select ").append(thePKeyName).append(",").append(name).append(" from ").append(theTable);
+               if (where != null && !(where.length() == 0))
+                       sql.append(" where ").append(where);
+               sql.append(" order by ");
+               if (order != null && !(order.length() == 0))
+                       sql.append(order);
+               else
+                       sql.append(name);
+               // execute sql
+               try {
+                       con = getPooledCon();
+                       stmt = con.createStatement();
+                       ResultSet rs = executeSql(stmt, sql.toString());
+                       if (rs != null) {
+                               if (evaluatedMetaData == false)
+                                       get_meta_data();
+                               simpleList = new SimpleList();
+                               SimpleHash popupDict;
+                               if (hasNullValue) {
+                                       popupDict = new SimpleHash();
+                                       popupDict.put("key", "");
+                                       popupDict.put("value", "--");
+                                       simpleList.add(popupDict);
+                               }
+                               while (rs.next()) {
+                                       popupDict = new SimpleHash();
+                                       popupDict.put("key", getValueAsString(rs, 1, thePKeyType));
+                                       popupDict.put("value", rs.getString(2));
+                                       simpleList.add(popupDict);
+                               }
+                               rs.close();
+                       }
+               } catch (Exception e) {
+                       theLog.printDebugInfo(e.toString());
+               } finally {
+                       freeConnection(con, stmt);
+               }
+               if (hasPopupCache) {
+                       popupCache = simpleList;
+               }
+               return  simpleList;
+       }
+
+       /**
+        * Liefert alle Daten der Tabelle als SimpleHash zurueck. Dies wird verwandt,
+        * wenn in den Templates ein Lookup-Table benoetigt wird. Sollte nur bei kleinen
+        * Tabellen Verwendung finden.
+        * @return SimpleHash mit den Tabellezeilen.
+        */
+       public SimpleHash getHashData () {
+               if (hashCache == null) {
+                       try {
+                               hashCache = HTMLTemplateProcessor.makeSimpleHash(selectByWhereClause("",
+                                               -1));
+                       } catch (StorageObjectException e) {
+                               theLog.printDebugInfo(e.toString());
+                       }
+               }
+               return  hashCache;
+       }
+
+       /* invalidates the popupCache
+        */
+       private void invalidatePopupCache () {
+
+               /** @todo  invalidates toooo much */
+               popupCache = null;
+               hashCache = null;
+       }
+
+       /**
+        * Diese Methode fuehrt den Sqlstring <i>sql</i> aus und timed im Logfile.
+        * @param stmt Statemnt
+        * @param sql Sql-String
+        * @return ResultSet
+        * @exception StorageObjectException, SQLException
+        */
+       public ResultSet executeSql (Statement stmt, String sql) throws StorageObjectException,
+                       SQLException {
+               long startTime = (new java.util.Date()).getTime();
+               ResultSet rs = stmt.executeQuery(sql);
+               theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms. for: "
+                               + sql);
+               return  rs;
+       }
+
+       /**
+        * Fuehrt Statement stmt aus und liefert Resultset zurueck. Das SQL-Statment wird
+        * getimed und geloggt.
+        * @param stmt PreparedStatement mit der SQL-Anweisung
+        * @return Liefert ResultSet des Statements zurueck.
+        * @exception StorageObjectException, SQLException
+        */
+       public ResultSet executeSql (PreparedStatement stmt) throws StorageObjectException,
+                       SQLException {
+               long startTime = (new java.util.Date()).getTime();
+               ResultSet rs = stmt.executeQuery();
+               theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms.");
+               return  rs;
+       }
+
+       /**
+        * returns the number of rows in the table
+        */
+       public int getSize(String where)
+               throws SQLException,StorageObjectException
+       {
+               long  startTime = (new java.util.Date()).getTime();
+               String sql = "SELECT count(*) FROM "+ theTable + " where " + where;
+               //theLog.printDebugInfo("trying: "+ sql);
+               Connection con = null;
+               Statement stmt = null;
+               int result = 0;
+
+               try {
+                       con = getPooledCon();
+                       stmt = con.createStatement();
+                       ResultSet rs = executeSql(stmt,sql);
+                       while(rs.next()){
+                               result = rs.getInt(1);
+                       }
+               } catch (SQLException e) {
+                       theLog.printError(e.toString());
+               } finally {
+                       freeConnection(con,stmt);
+               }
+               theLog.printInfo(theTable + " has "+ result +" rows where " + where);
+               theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms. for: " + sql);
+               return result;
+       }
+
+       public int executeUpdate(Statement stmt, String sql)
+               throws StorageObjectException, SQLException
+       {
+               long  startTime = (new java.util.Date()).getTime();
+               //theLog.printDebugInfo("trying: "+ sql);
+               int rs = stmt.executeUpdate(sql);
+               theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms. for: " + sql);
+               return rs;
+       }
+
+       public int executeUpdate(String sql)
+               throws StorageObjectException, SQLException
+       {
+               int result=-1;
+               long  startTime = (new java.util.Date()).getTime();
+               Connection con=null;PreparedStatement pstmt=null;
+               try {
+                       con=getPooledCon();
+                       pstmt = con.prepareStatement(sql);
+                       result = pstmt.executeUpdate();
+               }
+               catch (Exception e) {theLog.printDebugInfo("settimage :: setImage gescheitert: "+e.toString());}
+               finally {       freeConnection(con,pstmt); }
+               theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms. for: " + sql);
+               return result;
+       }
+
+       /**
+        * Wertet ResultSetMetaData aus und setzt interne Daten entsprechend
+        * @param md ResultSetMetaData
+        * @exception StorageObjectException
+        */
+       private void evalMetaData (ResultSetMetaData md) throws StorageObjectException {
+               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(thePKeyName)) {
+                                       thePKeyType = aType;
+                               }
+                               if (md.isNullable(i) == md.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 StorageObjectException {
+               Connection con = null;
+               PreparedStatement pstmt = null;
+               String sql = "select * from " + theTable + " where 0=1";
+               try {
+                       con = getPooledCon();
+                       pstmt = con.prepareStatement(sql);
+                       theLog.printInfo("METADATA: " + sql);
+                       ResultSet rs = pstmt.executeQuery();
+                       evalMetaData(rs.getMetaData());
+                       rs.close();
+               } catch (SQLException e) {
+                       throwSQLException(e, "get_meta_data");
+               } finally {
+                       freeConnection(con, pstmt);
+               }
+       }
+
+       /**
+        * Datenbankverbindung wird geschlossen
+        */
+       public void disconnectPool () {
+               try {
+                       myBroker.destroy(100);
+               } catch (SQLException sqe) {
+                       ;
+               }
+       }
+
+       /**
+        * Liefert ein Connection-Objekt aus dem ConnectionPool.
+        * @return Connection Objekt.
+        */
+       public Connection getPooledCon () throws StorageObjectException {
+               if (myBroker != null) {
+                       Connection con = myBroker.getConnection();
+                       if (con != null)
+                               return  con;
+               }
+               throw  new StorageObjectException("KEINE VERBINDUNG ZUR DATENBANK");
+       }
+
+       /**
+        * Connection und StatementObjekt werden geschlossen und an den Connectionpool
+        * zurückgeben
+        * @param con Connection zur Datenbank
+        * @param stmt Statement-Objekt
+        */
+       public void freeConnection (Connection con, Statement stmt) {
+               try {
+                       if (stmt != null)
+                               stmt.close();
+               } catch (SQLException e1) {
+                       theLog.printDebugInfo(e1.toString());
+               }
+               if (con != null)
+                       myBroker.freeConnection(con);
+               else
+                       theLog.printDebugInfo("Con was null!");
+       }
+
+       /**
+        * Wertet SQLException aus und wirft dannach eine StorageObjectException
+        * @param sqe SQLException
+        * @param wo Funktonsname, in der die SQLException geworfen wurde
+        * @exception StorageObjectException
+        */
+       void throwSQLException (SQLException sqe, String wo) throws StorageObjectException {
+               String state = "";
+               String message = "";
+               int vendor = 0;
+               if (sqe != null) {
+                       state = sqe.getSQLState();
+                       message = sqe.getMessage();
+                       vendor = sqe.getErrorCode();
+               }
+               theLog.printError(state + ": " + vendor + " : " + message + " Funktion: "
+                               + wo);
+               throw  new StorageObjectException((sqe == null) ? "undefined sql exception" :
+                               sqe.toString());
+       }
+
+       /**
+        * Loggt Fehlermeldung mit dem Parameter Message und wirft dannach eine StorageObjectException
+        * @param message Nachricht mit dem Fehler
+        * @exception StorageObjectException
+        */
+       void throwStorageObjectException (String message) throws StorageObjectException {
+               theLog.printError(message);
+               throw  new StorageObjectException(message);
+       }
+}
+
+
+
diff --git a/source/mir/storage/DatabaseAdaptor.java b/source/mir/storage/DatabaseAdaptor.java
new file mode 100755 (executable)
index 0000000..46c606d
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * put your module comment here
+ */
+
+
+package  mir.storage;
+
+import java.util.*;
+
+
+/**
+ * Interfacedefinition für Datenbank-Adpatoren. Die Adaptoren legen
+ * jeweils das Verhalten und die Befehlsmächtigkeit der Datenbank
+ * fest.
+ *
+ * @author <RK>
+ * @version 27.6.1999
+ */
+
+public interface  DatabaseAdaptor{
+
+        /* Liefert den Namen der Adaptorklasse
+        * @return Adaptorklasse als String
+        */
+       public abstract String getDriver ();
+
+
+       /**
+        * Liefert die URL für JDBC zurück, in den die Parameter user, pass und host
+        * eingefügt werden. Die URL wird aus der Konfiguration geholt.
+        *
+        * @param user user als String
+        * @param pass passwort als String
+        * @param host host als String
+        * @return url als String
+        */
+       public abstract String getURL (String user, String pass, String host);
+
+
+       /**
+        * Gibt zurück, ob das SQL der Datenbank den <code>limit</code>-Befehl beherrscht.
+        * @return true wenn ja, sonst false
+        */
+       public abstract boolean hasLimit ();
+
+
+       /**
+        * Liefert zurück, ob der <code>limit</code>-Befehl erst start und dann offset
+        * hat (true), oder umgekehrt. Nur Relevant, wenn hasLimit true zurückliefert.
+        *
+        * @return true wenn erstes, sonst false
+        */
+       public abstract boolean reverseLimit ();
+
+
+       /**
+        * Liefert ein Properties-Objekt zurueck mit user und password.
+        * @param user
+        * @param password
+        * @return Properties
+        */
+       public abstract Properties getProperties (String user, String password);
+
+
+       /**
+        * Gibt SQL-Stringfragment zurück, mit dem nach einem insert-Befehl ermittelt
+        * werden kann, wie man den primary-Key des eingefügten Datensatzes bekommt.
+        *
+        * @param theDB Database-Objekt, aus dem ggf. noetige Informationen geholt
+        * werden können, wie z.B. der Tabellenname
+        * @return SQL-Statement als String
+        */
+       public abstract String getLastInsertSQL (Database theDB);
+}
+
+
diff --git a/source/mir/storage/DatabaseAdaptorMySQL.java b/source/mir/storage/DatabaseAdaptorMySQL.java
new file mode 100755 (executable)
index 0000000..c917f82
--- /dev/null
@@ -0,0 +1,40 @@
+package mir.storage;
+
+import java.util.*;
+import mir.misc.*;
+
+/**
+ * <b>Diese Klasse implementiert die abstrakte Klasse DatabaseAdaptor
+ *
+ * @author <RK>
+ * @version 27.6.1999
+ */
+
+public final class DatabaseAdaptorMySQL implements DatabaseAdaptor{
+
+    public String getDriver() {
+       return Configuration.getProperty("Adaptor.MySQL.Driver");
+    }
+
+    public String getURL(String user, String pass, String host) {
+           return Configuration.getProperty("Adaptor.MySQL.URL");
+    }
+
+    public  boolean hasLimit() {
+      return true;
+    }
+
+    public boolean reverseLimit() {
+      return false;
+    }
+
+    public Properties getProperties(String user, String password) {
+      return null;
+    }
+
+    public String getLastInsertSQL(Database theDB) {
+           return "select last_insert_id()";
+    }
+}
+
+
diff --git a/source/mir/storage/DatabaseAdaptorOracle.java b/source/mir/storage/DatabaseAdaptorOracle.java
new file mode 100755 (executable)
index 0000000..44b85b4
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * put your module comment here
+ */
+
+
+package  mir.storage;
+
+import java.util.*;
+import  mir.misc.*;
+
+
+/**
+ * Diese Klasse implementiert Interface DatabaseAdaptor fuer Oracle
+ *
+ * @author <RK>
+ * @version 15.05.2000
+ */
+public final class DatabaseAdaptorOracle
+               implements DatabaseAdaptor {
+
+       /**
+        * Liefert den Namen der Adaptorklasse <code>Adaptor.Oracle.Driver</code>
+        * für Oracle zurück.
+        * @return Adaptorklasse als String
+        */
+    public String getDriver() {
+           return Configuration.getProperty("Adaptor.Oracle.Driver");
+    }
+
+       /**
+        * Liefert die URL für JDBC zurück, in den die Parameter user, pass und host
+        * eingefügt werden. Die URL wird aus der Konfiguration geholt.
+        *
+        * @param user user als String
+        * @param pass passwort als String
+        * @param host host als String
+        * @return url als String
+        */
+    public String getURL(String user, String pass, String host) {
+           return Configuration.getProperty("Adaptor.Oracle.URL");
+               /** @todo   hier muesste bessererweise $HOST durch HOST ersetzt, etc. werden */
+
+    }
+
+       /**
+        * Gibt zurück, ob das SQL der Datenbank den <code>limit</code>-Befehl beherrscht.
+        * @return false
+        */
+     public  boolean hasLimit() {
+      return false;
+    }
+
+       /**
+        * Liefert zurück, ob der <code>limit</code>-Befehl erst start und dann offset
+        * hat (true), oder umgekehrt. Nur Relevant, wenn hasLimit true zurückliefert.
+        *
+        * @return false
+        */
+    public boolean reverseLimit() {
+      return false;
+    }
+
+       /**
+        * Liefert ein Properties-Objekt zurueck mit user und password.
+        * @param user
+        * @param password
+        * @return Properties
+        */
+    public Properties getProperties(String user, String password) {
+      return null;
+    }
+
+
+
+
+
+
+
+
+     public String getLastInsertSQL(Database theDB) {
+           return "select currval('"+theDB.getCoreTable()+"_id_seq')";
+    }
+}
diff --git a/source/mir/storage/DatabaseAdaptorPostgresql.java b/source/mir/storage/DatabaseAdaptorPostgresql.java
new file mode 100755 (executable)
index 0000000..56d329e
--- /dev/null
@@ -0,0 +1,40 @@
+package mir.storage;
+
+import java.util.*;
+import mir.misc.*;
+
+/**
+ * <b>Diese Klasse implementiert die abstrakte Klasse DatabaseAdaptor für Postgresql-Datenbanken
+ *
+ * @author <RK>
+ * @version 30.12.2000
+ */
+
+public final class DatabaseAdaptorPostgresql implements DatabaseAdaptor{
+
+    public String getDriver() {
+       return Configuration.getProperty("Adaptor.PostgreSQL.Driver");
+    }
+
+    public String getURL(String user, String pass, String host) {
+           return Configuration.getProperty("Adaptor.PostgreSQL.URL");
+    }
+
+    public  boolean hasLimit() {
+      return true;
+    }
+
+    public boolean reverseLimit() {
+      return true;
+    }
+
+    public Properties getProperties(String user, String password) {
+      return null;
+    }
+
+    public String getLastInsertSQL(Database theDB) {
+           return "select currval('"+theDB.getCoreTable()+"_id_seq')";
+    }
+}
+
+
diff --git a/source/mir/storage/DatabaseAdaptorSybase.java b/source/mir/storage/DatabaseAdaptorSybase.java
new file mode 100755 (executable)
index 0000000..2bd9643
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Implementiert DatabaseAdaptor Interface für Sybase.
+ */
+
+
+package  mir.storage;
+
+import java.util.*;
+import  mir.misc.*;
+
+
+/**
+ * Diese Klasse implementiert Interface DatabaseAdaptor fuer Sybase
+ *
+ * @author <RK>
+ * @version 15.05.2000
+ */
+public final class DatabaseAdaptorSybase
+               implements DatabaseAdaptor {
+
+       /**
+        * Liefert den Namen der Adaptorklasse <code>Adaptor.Sybase.Driver</code>
+        * für Sybase zurück.
+        * @return Adaptorklasse als String
+        */
+    public String getDriver() {
+           return Configuration.getProperty("Adaptor.Sybase.Driver");
+    }
+
+       /**
+        * Liefert die URL für JDBC zurück, in den die Parameter user, pass und host
+        * eingefügt werden. Die URL wird aus der Konfiguration geholt.
+        *
+        * @param user user als String
+        * @param pass passwort als String
+        * @param host host als String
+        * @return url als String
+        */
+    public String getURL(String user, String pass, String host) {
+           return Configuration.getProperty("Adaptor.Sybase.URL");
+               /** @todo  hier muesste bessererweise $HOST durch HOST ersetzt, etc. werden */
+    }
+
+       /**
+        * Gibt zurück, ob das SQL der Datenbank den <code>limit</code>-Befehl beherrscht.
+        * @return false
+        */
+       public boolean hasLimit () {
+               return  false;
+       }
+
+       /**
+        * Liefert zurück, ob der <code>limit</code>-Befehl erst start und dann offset
+        * hat (true), oder umgekehrt. Nur Relevant, wenn hasLimit true zurückliefert.
+        *
+        * @return false
+        */
+    public boolean reverseLimit() {
+      return false;
+    }
+
+       /**
+        * Liefert ein Properties-Objekt zurueck mit user und password.
+        * @param user
+        * @param password
+        * @return Properties
+        */
+    public Properties getProperties(String user, String password) {
+      Properties props = new Properties();
+      props.put("user", user);
+      props.put("password", password);
+      return props;
+    }
+
+
+
+
+
+
+
+
+    public String getLastInsertSQL(Database theDB) {
+           return "select currval('"+theDB.getCoreTable()+"_id_seq')";
+    }
+}
diff --git a/source/mir/storage/StorageObject.java b/source/mir/storage/StorageObject.java
new file mode 100755 (executable)
index 0000000..1677903
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Implementiert Interface für die Speicherschicht.
+ * Bislang gibt es in der Bibliothek nur die Möglichkeit
+ * in einer Datenbank zu speichern.
+ */
+package mir.storage;
+
+import java.lang.*;
+import java.util.*;
+import java.sql.*;
+import freemarker.template.*;
+import mir.entity.*;
+
+
+/**
+ * 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
+ */
+public interface StorageObject {
+
+       /**
+        * Dokumentation siehe Database.java
+        * @param id
+        * @return Entity
+        * @exception StorageObjectException
+        */
+       abstract public Entity selectById (String id) throws StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @param aField
+        * @param aValue
+        * @return EntityList
+        * @exception StorageObjectException
+        */
+       abstract public EntityList selectByFieldValue (String aField, String aValue) throws StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @param whereClause
+        * @return EntityList
+        * @exception StorageObjectException
+        */
+       abstract public EntityList selectByWhereClause (String whereClause) throws StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @param whereClause
+        * @param offset
+        * @return EntityList
+        * @exception StorageObjectException
+        */
+       abstract public EntityList selectByWhereClause (String whereClause, int offset) throws StorageObjectException;
+
+
+
+       /**
+        * 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 StorageObjectException;
+
+
+
+       /**
+        * 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 StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @param id
+        * @return boolen
+        * @exception StorageObjectException
+        */
+       abstract public boolean delete (String id) throws StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @return ArrayList
+        * @exception StorageObjectException
+        */
+       abstract public ArrayList getFields () throws StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @return int[]
+        * @exception StorageObjectException
+        */
+       abstract public int[] getTypes () throws StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @return ArrayList
+        * @exception StorageObjectException
+        */
+       abstract public ArrayList getLabels () throws StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @param a
+        * @exception StorageObjectException
+        */
+       abstract public void update (Entity a) throws StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @param a
+        * @return String id
+        * @exception StorageObjectException
+        */
+       abstract public String insert (Entity a) throws StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @return Class Klasse der Entity
+        */
+               abstract public Class getEntityClass();
+
+
+
+       /**
+        * put your documentation comment here
+        * @return
+        */
+               abstract public String getIdName();
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @return String
+        */
+               abstract public String getTableName();
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @return SimpleHash
+        */
+               abstract public SimpleHash getHashData();
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @return Connection
+        * @exception StorageObjectException
+        */
+       abstract public Connection getPooledCon () throws StorageObjectException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @param a
+        * @param sql
+        * @return ResultSet
+        * @exception StorageObjectException, SQLException
+        */
+       abstract public ResultSet executeSql (Statement a, String sql) throws StorageObjectException,
+                       SQLException;
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @param con
+        * @param stmt
+        */
+               abstract public void freeConnection(Connection con,  Statement stmt);
+
+
+
+       /**
+        * Dokumentation siehe Database.java
+        * @return
+        */
+       abstract public SimpleList getPopupData ();
+
+       abstract public int executeUpdate(Statement a, String sql) throws StorageObjectException, SQLException ;
+       abstract public int executeUpdate(String sql) throws StorageObjectException, SQLException ;
+       abstract public int getSize(String where) throws SQLException,StorageObjectException;
+
+}
+
+
+
diff --git a/source/mir/storage/StorageObjectException.java b/source/mir/storage/StorageObjectException.java
new file mode 100755 (executable)
index 0000000..6237217
--- /dev/null
@@ -0,0 +1,40 @@
+/**
+ * <b>Exception fuer StorageObject</b><p>
+ *
+ * @author RK
+ * @version    30.6.1999
+ *
+ *
+ */
+
+
+package  mir.storage;
+
+import java.lang.*;
+
+
+/**
+ *  Expception Objekt fuer alle Fehler, die in der Speicherzugriffsschicht
+ *  (mir.storage) auftauchen
+ */
+public class StorageObjectException extends Exception {
+
+       /**
+        * Leerer Konstruktor
+        */
+       public StorageObjectException () {
+               super();
+       }
+
+       /**
+        * Konstruktor mit Nachricht
+        * @param   String msg
+        */
+       public StorageObjectException (String msg) {
+         super(msg);
+  }
+}
+
+
+
+