yet another rewrite of the producers...
authorzapata <zapata>
Mon, 13 May 2002 20:53:54 +0000 (20:53 +0000)
committerzapata <zapata>
Mon, 13 May 2002 20:53:54 +0000 (20:53 +0000)
47 files changed:
source/Mir.java
source/mir/entity/EntityBrowser.java
source/mir/entity/adapter/EntityAdapter.java [new file with mode: 0755]
source/mir/entity/adapter/EntityAdapterDefinition.java [new file with mode: 0755]
source/mir/entity/adapter/EntityIteratorAdapter.java [new file with mode: 0755]
source/mir/entity/adapter/EntityListAdapter.java [new file with mode: 0755]
source/mir/generator/FreemarkerGenerator.java
source/mir/producer/CompositeProducerNode.java [new file with mode: 0755]
source/mir/producer/EntityEnumeratingProducerNode.java [new file with mode: 0755]
source/mir/producer/EntityListProducerNode.java [new file with mode: 0755]
source/mir/producer/NodedProducer.java [new file with mode: 0755]
source/mir/producer/ProducerNode.java [new file with mode: 0755]
source/mir/producer/ProducerNodeDecorator.java [new file with mode: 0755]
source/mir/producer/ProducerQueue.java [deleted file]
source/mir/producer/ResourceBundleProducerNode.java [new file with mode: 0755]
source/mir/producer/ValuesMapProducerNode.java [new file with mode: 0755]
source/mir/util/RewindableIterator.java [new file with mode: 0755]
source/mircoders/entity/adapter/AudioAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/BreakingAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/CommentAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/ContentAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/FeatureAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/ImagesAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/LanguageAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/LinksImcsAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/MediaAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/OtherAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/TopicsAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/UploadedMediaAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/UsersAdapterDefinition.java [new file with mode: 0755]
source/mircoders/entity/adapter/VideoAdapterDefinition.java [new file with mode: 0755]
source/mircoders/global/MirGlobal.java
source/mircoders/localizer/MirProducerToolLocalizer.java
source/mircoders/localizer/basic/MirBasicProducerLocalizer.java
source/mircoders/localizer/basic/MirBasicProducerToolLocalizer.java
source/mircoders/producer/ContentProducer.java
source/mircoders/producer/GeneratingProducerNode.java [new file with mode: 0755]
source/mircoders/producer/NodedProducerFactory.java [new file with mode: 0755]
source/mircoders/producer/StaticProducerFactory.java
source/mircoders/producer/TopicStartPageProducerFactory.java
source/mirlocal/bolivia.indymedia.org/BoliviaLocalizer.java [new file with mode: 0755]
source/mirlocal/bolivia.indymedia.org/BoliviaOpenPostingLocalizer.java [new file with mode: 0755]
source/mirlocal/bolivia.indymedia.org/BoliviaProducerLocalizer.java [new file with mode: 0755]
source/mirlocal/bolivia.indymedia.org/BoliviaProducerToolLocalizer.java [new file with mode: 0755]
source/mirlocal/indymedia.nl/IndyNLLocalizer.java [new file with mode: 0755]
source/mirlocal/indymedia.nl/IndyNLOpenPostingLocalizer.java [new file with mode: 0755]
source/mirlocal/indymedia.nl/IndyNLProducerLocalizer.java [new file with mode: 0755]

index 77412c0..c70f42a 100755 (executable)
@@ -327,6 +327,7 @@ public class Mir extends AbstractServlet {
             HTMLTemplateProcessor.process(res, startTemplate, mergeData, out, getLocale(req));
         }
         catch (Exception e) {
+            e.printStackTrace(System.out);
             handleError(req, res, out, "error while trying to send startpage. " + e.toString());
         }
     }
index aa3f3cc..5a05e18 100755 (executable)
@@ -1,9 +1,11 @@
 package mir.entity;\r
 \r
+import java.util.*;\r
+import mir.util.*;\r
 import mir.storage.*;\r
 import mir.entity.*;\r
 \r
-public class EntityBrowser {\r
+public class EntityBrowser implements RewindableIterator {\r
 \r
   private StorageObject storage;\r
   private String whereClause;\r
@@ -25,11 +27,14 @@ public class EntityBrowser {
     rewind();\r
   }\r
 \r
-  private void rewind() throws StorageObjectException {\r
-    currentBatch = storage.selectByWhereClause(whereClause, orderByClause,\r
-            0, batchSize);\r
-\r
-    position=0;\r
+  public void rewind() {\r
+    try {\r
+      currentBatch = storage.selectByWhereClause(whereClause, orderByClause, 0, batchSize);\r
+      position=0;\r
+    }\r
+    catch (Throwable t) {\r
+      throw new RuntimeException(t.getMessage());\r
+    }\r
   }\r
 \r
   private void readNextBatch() throws StorageObjectException  {\r
@@ -40,23 +45,37 @@ public class EntityBrowser {
     }\r
   }\r
 \r
-  public boolean hasNext() throws StorageObjectException {\r
-    if (position>=currentBatch.size() && currentBatch.hasNextBatch()) {\r
-      readNextBatch();\r
-    }\r
+  public boolean hasNext() {\r
+    try {\r
+      if (position>=currentBatch.size() && currentBatch.hasNextBatch()) {\r
+        readNextBatch();\r
+      }\r
 \r
-    return (position<currentBatch.size());\r
+      return (position<currentBatch.size());\r
+    }\r
+    catch (Throwable t) {\r
+      throw new RuntimeException(t.getMessage());\r
+    }\r
   }\r
 \r
-  public Entity next() throws StorageObjectException {\r
-    if (hasNext()) {\r
-      Entity result = currentBatch.elementAt(position);\r
-      position=position+1;\r
+  public Object next() {\r
+    try {\r
+      if (hasNext()) {\r
+        Entity result = currentBatch.elementAt(position);\r
+        position=position+1;\r
 \r
-      return result;\r
+        return result;\r
+      }\r
+      else {\r
+        return null;\r
+      }\r
     }\r
-    else {\r
-      return null;\r
+    catch (Throwable t) {\r
+      throw new RuntimeException(t.getMessage());\r
     }\r
   }\r
+\r
+  public void remove() {\r
+    throw new UnsupportedOperationException();\r
+  }\r
 }
\ No newline at end of file
diff --git a/source/mir/entity/adapter/EntityAdapter.java b/source/mir/entity/adapter/EntityAdapter.java
new file mode 100755 (executable)
index 0000000..dd63f81
--- /dev/null
@@ -0,0 +1,97 @@
+package mir.entity.adapter;
+
+import java.util.*;
+import mir.entity.*;
+
+public class EntityAdapter implements Map {
+  private Entity entity;
+  private EntityAdapterDefinition definition;
+  private Map calculatedFieldsCache;
+
+  public EntityAdapter(Entity anEntity, EntityAdapterDefinition aDefinition) {
+    entity = anEntity;
+    definition = aDefinition;
+    calculatedFieldsCache = new HashMap();
+  }
+
+  public boolean containsKey(Object aKey) {
+    if (aKey instanceof String)
+      return      entity.hasValueForField((String) aKey)
+              || definition.hasCalculatedField((String) aKey);
+    else
+      return false;
+  }
+
+  public boolean equals(Object anObject) {
+    return        anObject instanceof EntityAdapter
+           && ((EntityAdapter) anObject).entity.equals(entity);
+  }
+
+  public int hashCode() {
+    return entity.hashCode();
+  }
+
+  protected Entity getEntity() {
+    return entity;
+  }
+
+  public Object get(Object aKey) {
+    Object result;
+
+    if (calculatedFieldsCache.containsKey(aKey)) {
+      return calculatedFieldsCache.get(aKey);
+    }
+    else if (aKey instanceof String && definition.hasCalculatedField((String) aKey)) {
+      result = definition.getCalculatedField((String) aKey).getValue(this);
+      calculatedFieldsCache.put(aKey, result);
+
+      return result;
+    }
+    else if (aKey instanceof String) {
+      return entity.getValue((String) aKey);
+    }
+    else {
+      return null;
+    }
+  }
+
+  public boolean isEmpty() {
+    throw new UnsupportedOperationException("EntityAdapter.isEmpty()");
+  }
+
+  public Set keySet() {
+    throw new UnsupportedOperationException("EntityAdapter.keySet()");
+  }
+
+  public Object put(Object aKey, Object value) {
+    throw new UnsupportedOperationException("EntityAdapter.put()");
+  }
+
+  public void putAll(Map t) {
+    throw new UnsupportedOperationException("EntityAdapter.putAll()");
+  }
+
+  public Object remove(Object aKey) {
+    throw new UnsupportedOperationException("EntityAdapter.remove()");
+  }
+
+  public int size() {
+    throw new UnsupportedOperationException("EntityAdapter.size()");
+  }
+
+  public Collection values() {
+    throw new UnsupportedOperationException("EntityAdapter.values()");
+  }
+
+  public void clear() {
+    throw new UnsupportedOperationException("EntityAdapter.clear()");
+  }
+
+  public boolean containsValue(Object value) {
+    throw new UnsupportedOperationException("EntityAdapter.containsValue()");
+  }
+
+  public Set entrySet() {
+    throw new UnsupportedOperationException("EntityAdapter.entrySet()");
+  }
+}
\ No newline at end of file
diff --git a/source/mir/entity/adapter/EntityAdapterDefinition.java b/source/mir/entity/adapter/EntityAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..1d96922
--- /dev/null
@@ -0,0 +1,91 @@
+package mir.entity.adapter;
+
+import java.util.*;
+import mir.entity.*;
+import mir.storage.*;
+
+public class EntityAdapterDefinition {
+  Map calculatedFields;
+
+  public EntityAdapterDefinition() {
+    calculatedFields = new HashMap();
+  }
+
+  public EntityAdapter makeEntityAdapter(Entity anEntity) {
+    return new EntityAdapter(anEntity, this);
+  }
+
+  public CalculatedField getCalculatedField(String aFieldName) {
+    return (CalculatedField) calculatedFields.get(aFieldName);
+  }
+
+  public boolean hasCalculatedField(String aFieldName) {
+    return calculatedFields.containsKey(aFieldName);
+  }
+
+  public void addCalculatedField(String aFieldName, CalculatedField aField) {
+    calculatedFields.put(aFieldName, aField);
+  }
+
+  public void addDateField(String aDestinationFieldName, String aSourceFieldName) {
+    addCalculatedField(aDestinationFieldName, new DateField(aSourceFieldName));
+  }
+
+  public interface CalculatedField {
+    public Object getValue(EntityAdapter anEntityAdapter);
+  }
+
+  private class DateField implements CalculatedField {
+    private String fieldName;
+
+    public DateField(String aFieldName) {
+      fieldName = aFieldName;
+    }
+
+    public Object getValue(EntityAdapter anEntityAdapter) {
+      Map result = new HashMap();
+      String textValue = anEntityAdapter.getEntity().getValue(fieldName);
+      Calendar calendar = GregorianCalendar.getInstance();
+      int year;
+      int month;
+      int day;
+      Date date;
+
+      if (textValue!=null) {
+        try {
+          year = Integer.parseInt(textValue.substring(0,4));
+          month = Integer.parseInt(textValue.substring(4,6));
+          day = Integer.parseInt(textValue.substring(6,8));
+
+          calendar.set(year, month, day);
+          date = calendar.getTime();
+
+          result.put("date", date);
+          result.put("year", textValue.substring(0,4));
+          result.put("month", textValue.substring(4,6));
+          result.put("day", textValue.substring(6,8));
+        }
+        catch (Throwable t) {
+          result.put("date", null);
+          result.put("year", null);
+          result.put("month", null);
+          result.put("day", null);
+        }
+      }
+
+      return result;
+    }
+  }
+
+  static protected Object getRelation(StorageObject aStorageObject, String aWhereClause, String anOrderByClause, EntityAdapterDefinition aDefinition) {
+    try {
+      return
+          new EntityIteratorAdapter(
+              new EntityBrowser( aStorageObject, aWhereClause, anOrderByClause, -1),
+              aDefinition);
+    }
+    catch (Throwable t) {
+      throw new RuntimeException(t.getMessage());
+    }
+  }
+}
diff --git a/source/mir/entity/adapter/EntityIteratorAdapter.java b/source/mir/entity/adapter/EntityIteratorAdapter.java
new file mode 100755 (executable)
index 0000000..8531625
--- /dev/null
@@ -0,0 +1,36 @@
+package mir.entity.adapter;
+
+import java.util.*;
+import mir.storage.*;
+import mir.util.*;
+import mir.entity.*;
+
+public class EntityIteratorAdapter implements RewindableIterator {
+  private EntityAdapterDefinition definition;
+  private RewindableIterator iterator;
+
+  public EntityIteratorAdapter(RewindableIterator anIterator, EntityAdapterDefinition aDefinition) {
+    iterator = anIterator;
+    definition = aDefinition;
+  }
+
+  public EntityIteratorAdapter(StorageObject aStorage, String aWhereClause, String anOrderByClause, int aBatchSize, EntityAdapterDefinition aDefinition) throws StorageObjectException {
+    this(new EntityBrowser(aStorage, aWhereClause, anOrderByClause, aBatchSize), aDefinition);
+  }
+
+  public boolean hasNext() {
+    return iterator.hasNext();
+  }
+
+  public Object next() {
+    return definition.makeEntityAdapter((Entity) iterator.next());
+  }
+
+  public void remove() {
+    iterator.remove();
+  }
+
+  public void rewind() {
+    iterator.rewind();
+  };
+}
\ No newline at end of file
diff --git a/source/mir/entity/adapter/EntityListAdapter.java b/source/mir/entity/adapter/EntityListAdapter.java
new file mode 100755 (executable)
index 0000000..ceedf47
--- /dev/null
@@ -0,0 +1,85 @@
+package mir.entity.adapter;
+
+import java.util.*;
+import mir.entity.*;
+
+public class EntityListAdapter extends AbstractList {
+  private int skip;
+  private int maximumLength;
+  private EntityBrowser browser;
+  private boolean exhausted = false;
+  private boolean skipped = false;
+
+  private List cache;
+
+  protected EntityListAdapter(EntityBrowser aBrowser, int aSkip, int aMaximumLength) {
+    browser = aBrowser;
+    skip = aSkip;
+    maximumLength = aMaximumLength;
+    cache = new Vector();
+  }
+
+  protected EntityListAdapter(EntityBrowser aBrowser, int aMaximumLength) {
+    this(aBrowser, 0, aMaximumLength);
+  }
+
+  protected EntityListAdapter(EntityBrowser aBrowser) {
+    this(aBrowser, 0, -1);
+  }
+
+  private void skip() {
+    int i;
+
+    try {
+      if (!skipped) {
+        for(i=0; i<skip; i++)
+          if (browser.hasNext())
+            browser.next();
+      }
+      skipped=true;
+    }
+    catch (Throwable t) {
+      throw new RuntimeException(t.getMessage());
+    }
+  }
+
+  private void fetchNext() {
+    try {
+      if (!exhausted) {
+        if (browser.hasNext())
+          cache.add(browser.next());
+
+        exhausted = !browser.hasNext() || (maximumLength>0 && cache.size()>=maximumLength) ;
+      }
+    }
+    catch (Throwable t) {
+      throw new RuntimeException(t.getMessage());
+    }
+
+  }
+
+  private void exhaust() {
+    skip();
+
+    while (!exhausted)
+      fetchNext();
+  }
+
+  private void fetchUntil(int anIndex) {
+    skip();
+
+    while (!exhausted && anIndex>=cache.size())
+      fetchNext();
+  }
+
+  public int size() {
+    exhaust();
+
+    return cache.size();
+  }
+
+  public Object get(int anIndex) {
+    fetchUntil(anIndex);
+    return cache.get(anIndex);
+  }
+}
\ No newline at end of file
index aeab524..da383aa 100755 (executable)
@@ -1,9 +1,10 @@
 package mir.generator;
 
-import freemarker.template.*;
-import mir.entity.*;
 import java.util.*;
 import java.io.*;
+import freemarker.template.*;
+import mir.entity.*;
+import mir.util.*;
 
 public class FreemarkerGenerator implements Generator {
   private Template template;
@@ -26,11 +27,11 @@ public class FreemarkerGenerator implements Generator {
     return new MapAdapter(aMap);
   }
 
-  private static TemplateListModel makeListAdapter(List aList) {
-    return new ListAdapter(aList);
+  private static TemplateListModel makeIteratorAdapter(Iterator anIterator) {
+    return new IteratorAdapter(anIterator);
   }
 
-       private static TemplateModel makeAdapter(Object anObject) {
+       private static TemplateModel makeAdapter(Object anObject) throws TemplateModelException {
          if (anObject == null)
            return null;
          if (anObject instanceof TemplateModel)
@@ -39,10 +40,10 @@ public class FreemarkerGenerator implements Generator {
            return makeStringAdapter((String) anObject);
          else if (anObject instanceof Map)
            return makeMapAdapter((Map) anObject);
-         else if (anObject instanceof List)
-           return makeListAdapter((List) anObject);
+         else if (anObject instanceof Iterator)
+           return makeIteratorAdapter((Iterator) anObject);
          else
-           return null;
+           throw new TemplateModelException("Unadaptable class: " + anObject.getClass().getName());
        }
 
        private static class MapAdapter implements TemplateModelRoot {
@@ -80,6 +81,75 @@ public class FreemarkerGenerator implements Generator {
          }
        }
 
+       private static class IteratorAdapter implements TemplateListModel {
+         Iterator iterator;
+         List valuesCache;
+         int position;
+
+         private IteratorAdapter(Iterator anIterator) {
+           iterator = anIterator;
+
+           valuesCache = new Vector();
+           position=0;
+
+
+           if (iterator instanceof RewindableIterator) {
+             ((RewindableIterator) iterator).rewind();
+           }
+         }
+
+         public boolean isEmpty() {
+           return valuesCache.isEmpty() && !iterator.hasNext();
+         }
+
+         private void getUntil(int anIndex) throws TemplateModelException {
+           while (valuesCache.size()<=anIndex && iterator.hasNext())
+           {
+             valuesCache.add(makeAdapter(iterator.next()));
+           }
+         };
+
+         public TemplateModel get(int anIndex) throws TemplateModelException {
+           TemplateModel result;
+
+           getUntil(anIndex);
+
+           if (anIndex<valuesCache.size())
+           {
+             result = (TemplateModel) valuesCache.get(anIndex);
+
+             return result;
+           }
+           else
+             throw new TemplateModelException( "Iterator out of bounds" );
+         }
+
+    public boolean hasNext() {
+      return position<valuesCache.size() || iterator.hasNext();
+    }
+
+    public boolean isRewound() {
+      return position==0;
+    }
+
+    public TemplateModel next() throws TemplateModelException {
+      TemplateModel result;
+
+      if (hasNext()) {
+        result = get(position);
+        position++;
+      }
+      else
+             throw new TemplateModelException( "Iterator out of bounds" );
+
+      return result;
+    }
+
+    public void rewind() {
+      position=0;
+    }
+       }
+
        private static class ListAdapter implements TemplateListModel {
          List list;
          List valuesCache;
@@ -95,7 +165,7 @@ public class FreemarkerGenerator implements Generator {
            return list.isEmpty();
          }
 
-         public TemplateModel get(int i) {
+         public TemplateModel get(int i) throws TemplateModelException {
 
            if (i>=valuesCache.size() && i<list.size()) {
              for(int j=valuesCache.size(); j<=i; j++) {
@@ -106,7 +176,7 @@ public class FreemarkerGenerator implements Generator {
            if (i<valuesCache.size())
              return (TemplateModel) valuesCache.get(i);
            else
-             return null;
+             throw new TemplateModelException( "Iterator out of bounds" );
          }
 
     public boolean hasNext() {
@@ -117,13 +187,15 @@ public class FreemarkerGenerator implements Generator {
       return position==0;
     }
 
-    public TemplateModel next() {
-      TemplateModel result = null;
+    public TemplateModel next() throws TemplateModelException {
+      TemplateModel result;
 
       if (hasNext()) {
         result = get(position);
         position++;
       }
+           else
+             throw new TemplateModelException( "Iterator out of bounds" );
 
       return result;
     }
diff --git a/source/mir/producer/CompositeProducerNode.java b/source/mir/producer/CompositeProducerNode.java
new file mode 100755 (executable)
index 0000000..4154d33
--- /dev/null
@@ -0,0 +1,43 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+
+public class CompositeProducerNode implements ProducerNode {
+  private List subNodes;
+
+  public CompositeProducerNode() {
+    subNodes = new Vector();
+  }
+
+  public CompositeProducerNode(ProducerNode[] aSubNodes) {
+    this();
+
+    int i;
+
+    for (i=0; i<aSubNodes.length; i++) {
+      addSubNode(aSubNodes[i]);
+    }
+  }
+
+  public void addSubNode(ProducerNode aSubNode) {
+    subNodes.add(aSubNode);
+  }
+
+  public void produce(Map aValueSet, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    Iterator i = subNodes.iterator();
+
+    while (i.hasNext())
+      ((ProducerNode) i.next()).produce(aValueSet, aVerb, aLogger);
+  }
+
+  public Set buildVerbSet() {
+    Iterator i = subNodes.iterator();
+    Set result = new HashSet();
+
+    while (i.hasNext())
+      result.addAll(((ProducerNode) i.next()).buildVerbSet());
+
+    return result;
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/EntityEnumeratingProducerNode.java b/source/mir/producer/EntityEnumeratingProducerNode.java
new file mode 100755 (executable)
index 0000000..7bc5caa
--- /dev/null
@@ -0,0 +1,87 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.entity.adapter.*;
+import mir.entity.*;
+import mir.storage.*;
+import mir.util.*;
+
+public class EntityEnumeratingProducerNode extends ProducerNodeDecorator {
+  private Map verbs;
+  private EntityEnumeratingProducerNodeVerb defaultVerb;
+  private String key;
+  private EntityAdapterDefinition definition;
+  private StorageObject storage;
+
+  public EntityEnumeratingProducerNode(String aKey, StorageObject aStorage, EntityAdapterDefinition aDefinition, ProducerNode aSubNode) {
+    super(aSubNode);
+
+    defaultVerb = null;
+    verbs = new HashMap();
+    storage = aStorage;
+    definition = aDefinition;
+    key = aKey;
+  }
+
+  public EntityEnumeratingProducerNode(String aKey, StorageObject aStorage, EntityAdapterDefinition aDefinition,
+          String aDefaultWhereClause, String aDefaultOrderByClause, ProducerNode aSubNode) {
+    this(aKey, aStorage, aDefinition, aSubNode);
+
+    defaultVerb = new EntityEnumeratingProducerNodeVerb(aDefaultWhereClause, aDefaultOrderByClause);
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    EntityEnumeratingProducerNodeVerb verb = (EntityEnumeratingProducerNodeVerb) verbs.get(aVerb);
+    Iterator browser;
+
+    if (verb==null)
+      verb = defaultVerb;
+
+    if (verb==null)
+      throw new ProducerFailure("EntityEnumeratingProducerNode: unknown verb '"+aVerb+"'", null);
+
+    try {
+      browser = new EntityIteratorAdapter(
+          storage,
+          ParameterExpander.expandExpression( aValueMap, verb.whereClause ),
+          ParameterExpander.expandExpression( aValueMap, verb.orderByClause ),
+          -1,
+          definition );
+
+      while (browser.hasNext()) {
+        aLogger.println( verb.whereClause + ": next... ");
+        aValueMap.put(key, browser.next());
+        super.produce(aValueMap, aVerb, aLogger);
+      }
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+  public Set buildVerbSet() {
+    Set set;
+
+    set = super.buildVerbSet();
+    set.addAll(verbs.keySet());
+
+    return set;
+  };
+
+  public void addVerb(String aVerb, String aWhereClause, String anOrderByClause) {
+    verbs.put(aVerb, new EntityEnumeratingProducerNodeVerb(aWhereClause, anOrderByClause));
+  }
+
+  private class EntityEnumeratingProducerNodeVerb {
+    StorageObject database;
+
+    String whereClause;
+    String orderByClause;
+
+    EntityEnumeratingProducerNodeVerb(String aWhereClause, String anOrderByClause) {
+      whereClause = aWhereClause;
+      orderByClause = anOrderByClause;
+    }
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/EntityListProducerNode.java b/source/mir/producer/EntityListProducerNode.java
new file mode 100755 (executable)
index 0000000..d2aeec6
--- /dev/null
@@ -0,0 +1,48 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.entity.adapter.*;
+import mir.entity.*;
+import mir.storage.*;
+import mir.util.*;
+
+public class EntityListProducerNode extends ProducerNodeDecorator {
+  private String key;
+  private String whereClause;
+  private String orderByClause;
+  private int batchSize;
+  private EntityAdapterDefinition definition;
+  private StorageObject storage;
+
+  public EntityListProducerNode(String aKey, StorageObject aStorage,
+      EntityAdapterDefinition aDefinition, String aWhereClause, String anOrderByClause,
+      int aBatchSize, ProducerNode aSubNode) {
+    super(aSubNode);
+
+    storage = aStorage;
+    definition = aDefinition;
+    key = aKey;
+    whereClause = aWhereClause;
+    orderByClause = anOrderByClause;
+    batchSize = aBatchSize;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    try {
+      aValueMap.put(key,
+        new EntityIteratorAdapter(
+          storage,
+          ParameterExpander.expandExpression( aValueMap, whereClause ),
+          ParameterExpander.expandExpression( aValueMap, orderByClause ),
+          batchSize,
+          definition )
+      );
+      super.produce(aValueMap, aVerb, aLogger);
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+}
\ No newline at end of file
diff --git a/source/mir/producer/NodedProducer.java b/source/mir/producer/NodedProducer.java
new file mode 100755 (executable)
index 0000000..11b7b02
--- /dev/null
@@ -0,0 +1,25 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+
+public class NodedProducer implements Producer {
+  ProducerNode rootNode;
+  String verb;
+  Map baseValues;
+
+  public NodedProducer( ProducerNode aRootNode, String aVerb, Map aBaseValues) {
+    rootNode = aRootNode;
+    verb = aVerb;
+    baseValues = aBaseValues;
+  }
+
+  public void produce( PrintWriter aLogger ) throws ProducerFailure {
+    Map valueMap;
+
+    valueMap = new HashMap();
+    valueMap.putAll(baseValues);
+
+    rootNode.produce(valueMap, verb, aLogger);
+  };
+}
diff --git a/source/mir/producer/ProducerNode.java b/source/mir/producer/ProducerNode.java
new file mode 100755 (executable)
index 0000000..886a886
--- /dev/null
@@ -0,0 +1,9 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+
+public interface ProducerNode {
+  public void produce(Map aValueSet, String aVerb, PrintWriter aLogger);
+  public Set buildVerbSet();
+}
\ No newline at end of file
diff --git a/source/mir/producer/ProducerNodeDecorator.java b/source/mir/producer/ProducerNodeDecorator.java
new file mode 100755 (executable)
index 0000000..e93423d
--- /dev/null
@@ -0,0 +1,20 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+
+public class ProducerNodeDecorator implements ProducerNode {
+  private ProducerNode slave;
+
+  protected ProducerNodeDecorator(ProducerNode aSlave) {
+    slave = aSlave;
+  }
+
+  public void produce(Map aValueSet, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    slave.produce(aValueSet, aVerb, aLogger);
+  }
+
+  public Set buildVerbSet() {
+    return slave.buildVerbSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mir/producer/ProducerQueue.java b/source/mir/producer/ProducerQueue.java
deleted file mode 100755 (executable)
index e69de29..0000000
diff --git a/source/mir/producer/ResourceBundleProducerNode.java b/source/mir/producer/ResourceBundleProducerNode.java
new file mode 100755 (executable)
index 0000000..b7767cc
--- /dev/null
@@ -0,0 +1,34 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import org.apache.struts.util.MessageResources;
+import mir.util.*;
+
+public class ResourceBundleProducerNode extends ProducerNodeDecorator {
+  private String key;
+  private String bundleIdentifier;
+
+  public ResourceBundleProducerNode(String aKey, String aBundleIdentifier, ProducerNode aSubNode) {
+    super(aSubNode);
+
+    bundleIdentifier = aBundleIdentifier;
+    key = aKey;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    try {
+      aValueMap.put(
+          key,
+          MessageResources.getMessageResources(
+              ParameterExpander.expandExpression( aValueMap, bundleIdentifier ))
+      );
+
+      super.produce(aValueMap, aVerb, aLogger);
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+}
\ No newline at end of file
diff --git a/source/mir/producer/ValuesMapProducerNode.java b/source/mir/producer/ValuesMapProducerNode.java
new file mode 100755 (executable)
index 0000000..45d4790
--- /dev/null
@@ -0,0 +1,28 @@
+package mir.producer;
+
+import java.util.*;
+import java.io.*;
+import org.apache.struts.util.MessageResources;
+import mir.util.*;
+
+public class ValuesMapProducerNode extends ProducerNodeDecorator {
+  private String key;
+  private String bundleIdentifier;
+  private Map map;
+
+  public ValuesMapProducerNode(Map aMap, ProducerNode aSubNode) {
+    super(aSubNode);
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    try {
+      aValueMap.putAll(map);
+
+      super.produce(aValueMap, aVerb, aLogger);
+    }
+    catch (Throwable t) {
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+  };
+
+}
\ No newline at end of file
diff --git a/source/mir/util/RewindableIterator.java b/source/mir/util/RewindableIterator.java
new file mode 100755 (executable)
index 0000000..23f8e55
--- /dev/null
@@ -0,0 +1,7 @@
+package mir.util;
+
+import java.util.*;
+
+public interface RewindableIterator extends Iterator {
+  public void rewind();
+}
\ No newline at end of file
diff --git a/source/mircoders/entity/adapter/AudioAdapterDefinition.java b/source/mircoders/entity/adapter/AudioAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..f2cb7f9
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class AudioAdapterDefinition extends EntityAdapterDefinition {
+  private static AudioAdapterDefinition instance;
+
+  public static AudioAdapterDefinition getInstance() {
+    synchronized (AudioAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new AudioAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public AudioAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/BreakingAdapterDefinition.java b/source/mircoders/entity/adapter/BreakingAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..8a843b2
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class BreakingAdapterDefinition extends EntityAdapterDefinition {
+  private static BreakingAdapterDefinition instance;
+
+  public static BreakingAdapterDefinition getInstance() {
+    synchronized (BreakingAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new BreakingAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public BreakingAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/CommentAdapterDefinition.java b/source/mircoders/entity/adapter/CommentAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..e7eac3c
--- /dev/null
@@ -0,0 +1,293 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class CommentAdapterDefinition extends EntityAdapterDefinition {
+  private static CommentAdapterDefinition instance;
+
+  public static CommentAdapterDefinition getInstance() {
+    synchronized (CommentAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new CommentAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public CommentAdapterDefinition() {
+    super();
+  }
+}
+
+
+//  String mirconf_extLinkName  = MirConfig.getProp("Producer.ExtLinkName");
+//  String mirconf_intLinkName  = MirConfig.getProp("Producer.IntLinkName");
+//  String mirconf_mailLinkName = MirConfig.getProp("Producer.MailLinkName");
+//  String mirconf_imageRoot    = MirConfig.getProp("Producer.ImageRoot");
+
+
+//      if (field.equals("date_formatted"))
+//      {
+//               if (hasValueForField("date"))
+//             returnField = StringUtil.webdbDate2readableDate(getValue("date"));
+//             }
+//      else if (field.equals("description_parsed"))
+//        returnField = getDescriptionParsed();
+//      else if (field.equals("description_sentence"))
+//        returnField = getDescriptionSentence();
+//      else if (field.equals("content_data_parsed"))
+//        returnField = getContentDataParsed();
+
+
+//      if (key.equals("to_comments")) {
+//        try {
+//          _entCache.put(key, getComments());
+//          return (TemplateModel)_entCache.get(key);
+//        } catch (Exception ex) {
+//          theLog.printWarning("-- getComments: could not fetch data " + ex.toString());
+//          throw new TemplateModelException(ex.toString());
+//        }
+//      }
+//      if (key.equals("to_media_images")) {
+//        try {
+//          _entCache.put(key, getImagesForContent());
+//          return (TemplateModel)_entCache.get(key);
+//        }
+//        catch (Exception ex) {
+//          theLog.printWarning("-- getImagesForContent: could not fetch data " + ex.toString());
+//          throw new TemplateModelException(ex.toString());
+//        }
+//      }
+//      if (key.equals("to_media_audio")) {
+//        try {
+////          _entCache.put(key, getAudioForContent());
+//          return (TemplateModel)_entCache.get(key);
+//        }
+//        catch (Exception ex) {
+//          theLog.printWarning("-- getAudioForContent: could not fetch data " + ex.toString());
+//          throw new TemplateModelException(ex.toString());
+//        }
+//      }
+//      if (key.equals("to_media_video")) {
+//        try {
+//          _entCache.put(key, getVideoForContent());
+/*          return (TemplateModel)_entCache.get(key);
+        }
+        catch (Exception ex) {
+          theLog.printWarning("-- getVideoForContent: could not fetch data " + ex.toString());
+          throw new TemplateModelException(ex.toString());
+        }
+      }
+      if (key.equals("to_media_other")) {
+        try {
+          _entCache.put(key, getOtherMediaForContent());
+          return (TemplateModel)_entCache.get(key);
+        }
+        catch (Exception ex) {
+          theLog.printWarning("-- getOtherMediaForContent: could not fetch data " + ex.toString());
+          throw new TemplateModelException(ex.toString());
+        }
+      }
+      else if (key.equals("to_media_icon")) {
+        try {
+          _entCache.put(key, getUploadedMediaForNewswire());
+          return (TemplateModel)_entCache.get(key);
+        }
+        catch (Exception ex) {
+          theLog.printWarning("-- getUploadedMediaForNewswire: could not fetch data " + ex.toString());
+          throw new TemplateModelException(ex.toString());
+        }
+      }
+      else if (key.equals("to_topics")) {
+        try {
+          _entCache.put(key,
+                        DatabaseContentToTopics.getInstance().getTopics(this));
+          return (TemplateModel)_entCache.get(key);
+        }
+        catch (Exception ex) {
+          theLog.printWarning("-- getTopics: could not fetch data " + ex.toString());
+          throw new TemplateModelException(ex.toString());
+        }
+      }
+*/
+
+
+
+
+/*
+  private String getContentDataParsed() {
+    String returnField = getValue("content_data");
+    if (returnField!=null & returnField.length()>0 ) {
+      returnField=StringUtil.deleteForbiddenTags(returnField);
+      //create http-links and email-links
+      if (getValue("is_html").equals("0")) {
+        returnField = StringUtil.createHTML(returnField,mirconf_imageRoot,
+                                            mirconf_mailLinkName,mirconf_extLinkName,
+                                            mirconf_intLinkName);
+      }
+      returnField = StringUtil.decodeHTMLinTags(returnField);
+    }
+    return returnField;
+  }
+
+  private String getDescriptionSentence() {
+    String returnField = getValue("description");
+    if (returnField != null && returnField.length()>0) {
+       returnField = StringUtil.removeHTMLTags(returnField);
+       int endOfFirstSentence=StringUtil.findEndOfSentence(returnField,0);
+       if (endOfFirstSentence > 0){
+        returnField = returnField.substring(0,endOfFirstSentence);
+       }
+    }
+    return returnField;
+  }
+
+  private String getDescriptionParsed() {
+    String returnField = getValue("description");
+    if (returnField != null && returnField.length()>0) {
+      returnField = StringUtil.deleteForbiddenTags(returnField);
+      if (getValue("is_html").equals("0")) {
+        returnField = StringUtil.createHTML(returnField,mirconf_imageRoot,
+                                            mirconf_mailLinkName,mirconf_extLinkName,
+                                            mirconf_intLinkName);
+      }
+      returnField = StringUtil.decodeHTMLinTags(returnField);
+    }
+    return returnField;
+  }
+
+
+       private EntityList getComments() throws StorageObjectException {
+               return ((DatabaseContent)theStorageObject).getComments(this);
+       }
+
+  // @todo this needs to optimized. expensive SQL
+  private SimpleHash getUploadedMediaForNewswire()
+    throws StorageObjectException, TemplateModelException
+  {
+    // fetching/setting the images
+    // return to_media_icons
+    String        tinyIcon = null, iconAlt = null;
+    MirMedia      mediaHandler = null;
+    EntityUploadedMedia uploadedMedia;
+    Entity        mediaType;
+    SimpleHash    returnHash = new SimpleHash();
+
+    EntityList upMediaEntityList =
+                    DatabaseContentToMedia.getInstance().getUploadedMedia(this);
+    if (upMediaEntityList!=null && upMediaEntityList.getCount()>=1) {
+
+      for (int n=0; n < upMediaEntityList.size();n++) {
+        uploadedMedia = (EntityUploadedMedia)upMediaEntityList.elementAt(n);
+        mediaType = uploadedMedia.getMediaType();
+        try {
+          mediaHandler = MediaHelper.getHandler( mediaType );
+        } catch (MirMediaException ex) {
+          throw new TemplateModelException(ex.toString());
+        }
+        //the "best" media type to show
+        if (mediaHandler.isVideo()) {
+          tinyIcon = MirConfig.getProp("Producer.Icon.TinyVideo");
+          iconAlt = "Video";
+          break;
+        } else if (mediaHandler.isAudio()) {
+          tinyIcon = MirConfig.getProp("Producer.Icon.TinyAudio");
+          iconAlt = "Audio";
+        } else if (tinyIcon == null && !mediaHandler.isImage()) {
+          tinyIcon = mediaHandler.getTinyIcon();
+          iconAlt = mediaHandler.getIconAlt();
+        }
+
+      }
+      //it only has image(s)
+      if (tinyIcon == null) {
+        tinyIcon = MirConfig.getProp("Producer.Icon.TinyImage");
+        iconAlt = "Image";
+      }
+    // uploadedMedia Entity list is empty.
+    // we only have text
+    } else {
+      tinyIcon = MirConfig.getProp("Producer.Icon.TinyText");
+      iconAlt = "Text";
+    }
+    returnHash.put("tiny_icon", mirconf_imageRoot+"/"+tinyIcon);
+    returnHash.put("icon_alt", iconAlt);
+    return returnHash;
+  }
+
+  private boolean hasMedia() throws StorageObjectException
+  {
+    if (_hasMedia == null) {
+      _hasMedia =
+        new Boolean(DatabaseContentToMedia.getInstance().hasMedia(this));
+    }
+    return _hasMedia.booleanValue();
+  }
+
+  //######## @todo all of the following getBlahForContent should have
+  // and optimized version where LIMIT=1 sql for list view.
+  private EntityList getImagesForContent()
+    throws StorageObjectException, TemplateModelException
+  {
+    if (hasMedia())
+      return DatabaseContentToMedia.getInstance().getImages(this);
+    else
+      return null;
+  }
+
+  private EntityList getAudioForContent()
+    throws StorageObjectException, TemplateModelException
+  {
+    if (hasMedia())
+      return DatabaseContentToMedia.getInstance().getAudio(this) ;
+    else
+      return null;
+  }
+
+  private EntityList getVideoForContent()
+    throws StorageObjectException, TemplateModelException
+  {
+    if (hasMedia())
+      return DatabaseContentToMedia.getInstance().getVideo(this) ;
+    else
+      return null;
+  }
+
+  private EntityList getOtherMediaForContent()
+    throws StorageObjectException, TemplateModelException
+  {
+    if (hasMedia())
+      return DatabaseContentToMedia.getInstance().getOther(this);
+    else
+      return null;
+  }
+
+}
+*/
+
+
+
+
+
+
+
+
+
+
+
+
+//      if (field.equals("date_formatted"))
+//      {
+//               if (hasValueForField("webdb_create"))
+//               returnField = StringUtil.dateToReadableDate(getValue("webdb_create"));
+
+
+//      else if (field.equals("description_parsed")) {
+//        /** @todo the config stuff should be moved to StringUtil */
+//        String extLinkName = MirConfig.getProp("Producer.ExtLinkName");
+//        String intLinkName = MirConfig.getProp("Producer.IntLinkName");
+//        String mailLinkName = MirConfig.getProp("Producer.MailLinkName");
+//        String imageRoot = MirConfig.getProp("Producer.ImageRoot");
+//        returnField = StringUtil.createHTML(getValue("description"),imageRoot,mailLinkName,extLinkName,intLinkName);
diff --git a/source/mircoders/entity/adapter/ContentAdapterDefinition.java b/source/mircoders/entity/adapter/ContentAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..d5062e0
--- /dev/null
@@ -0,0 +1,320 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+
+public class ContentAdapterDefinition extends EntityAdapterDefinition {
+  private static ContentAdapterDefinition instance;
+
+  public static ContentAdapterDefinition getInstance() {
+    synchronized (ContentAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new ContentAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public ContentAdapterDefinition() {
+    super();
+
+    addDateField("date", "date");
+    addCalculatedField("to_topics", new ContentToTopicsField());
+    addCalculatedField("to_comments", new ContentToCommentsField());
+    addCalculatedField("description_parsed", new FilteredField("description"));
+    addCalculatedField("content_data_parsed", new FilteredField("content_data"));
+//      else if (field.equals(""))
+//        returnField = getDescriptionParsed();
+//      else if (field.equals("description_sentence"))
+//        returnField = getDescriptionSentence();
+//      else if (field.equals("content_data_parsed"))
+//        returnField = getContentDataParsed();
+  }
+
+  private class FilteredField implements CalculatedField {
+    String fieldName;
+
+    public FilteredField(String aFieldName) {
+      fieldName = aFieldName;
+    }
+
+    public Object getValue(EntityAdapter anEntityAdapter) {
+      if (anEntityAdapter.get("is_html").equals("0")) {
+        return MirGlobal.localizer().producerTool().filterText((String) anEntityAdapter.get(fieldName));
+      }
+      else {
+        return anEntityAdapter.get(fieldName);
+      }
+    }
+  }
+
+  private class ContentToCommentsField implements CalculatedField {
+    public Object getValue(EntityAdapter anEntityAdapter) {
+      try {
+        return getRelation(
+                    DatabaseComment.getInstance(),
+                    "to_media="+anEntityAdapter.get("id"),
+                    "title",
+                    CommentAdapterDefinition.getInstance());
+      }
+      catch (Throwable t) {
+        throw new RuntimeException(t.getMessage());
+      }
+    }
+  }
+
+  private class ContentToTopicsField implements CalculatedField {
+    public Object getValue(EntityAdapter anEntityAdapter) {
+      try {
+        return getRelation(
+                    DatabaseTopics.getInstance(),
+                    "exists (select * from content_x_topic where content_id="+anEntityAdapter.get("id")+" and topic_id=id)",
+                    "title",
+                    TopicsAdapterDefinition.getInstance());
+      }
+      catch (Throwable t) {
+        throw new RuntimeException(t.getMessage());
+      }
+    }
+  }
+}
+
+
+//  String mirconf_extLinkName  = MirConfig.getProp("Producer.ExtLinkName");
+//  String mirconf_intLinkName  = MirConfig.getProp("Producer.IntLinkName");
+//  String mirconf_mailLinkName = MirConfig.getProp("Producer.MailLinkName");
+//  String mirconf_imageRoot    = MirConfig.getProp("Producer.ImageRoot");
+
+
+//      if (field.equals("date_formatted"))
+//      {
+//               if (hasValueForField("date"))
+//             returnField = StringUtil.webdbDate2readableDate(getValue("date"));
+//             }
+//      else if (field.equals("description_parsed"))
+//        returnField = getDescriptionParsed();
+//      else if (field.equals("description_sentence"))
+//        returnField = getDescriptionSentence();
+//      else if (field.equals("content_data_parsed"))
+//        returnField = getContentDataParsed();
+
+
+//      if (key.equals("to_media_images")) {
+//        try {
+//          _entCache.put(key, getImagesForContent());
+//          return (TemplateModel)_entCache.get(key);
+//        }
+//        catch (Exception ex) {
+//          theLog.printWarning("-- getImagesForContent: could not fetch data " + ex.toString());
+//          throw new TemplateModelException(ex.toString());
+//        }
+//      }
+//      if (key.equals("to_media_audio")) {
+//        try {
+////          _entCache.put(key, getAudioForContent());
+//          return (TemplateModel)_entCache.get(key);
+//        }
+//        catch (Exception ex) {
+//          theLog.printWarning("-- getAudioForContent: could not fetch data " + ex.toString());
+//          throw new TemplateModelException(ex.toString());
+//        }
+//      }
+//      if (key.equals("to_media_video")) {
+//        try {
+//          _entCache.put(key, getVideoForContent());
+/*          return (TemplateModel)_entCache.get(key);
+        }
+        catch (Exception ex) {
+          theLog.printWarning("-- getVideoForContent: could not fetch data " + ex.toString());
+          throw new TemplateModelException(ex.toString());
+        }
+      }
+      if (key.equals("to_media_other")) {
+        try {
+          _entCache.put(key, getOtherMediaForContent());
+          return (TemplateModel)_entCache.get(key);
+        }
+        catch (Exception ex) {
+          theLog.printWarning("-- getOtherMediaForContent: could not fetch data " + ex.toString());
+          throw new TemplateModelException(ex.toString());
+        }
+      }
+      else if (key.equals("to_media_icon")) {
+        try {
+          _entCache.put(key, getUploadedMediaForNewswire());
+          return (TemplateModel)_entCache.get(key);
+        }
+        catch (Exception ex) {
+          theLog.printWarning("-- getUploadedMediaForNewswire: could not fetch data " + ex.toString());
+          throw new TemplateModelException(ex.toString());
+        }
+      }
+      else if (key.equals("to_topics")) {
+        try {
+          _entCache.put(key,
+                        DatabaseContentToTopics.getInstance().getTopics(this));
+          return (TemplateModel)_entCache.get(key);
+        }
+        catch (Exception ex) {
+          theLog.printWarning("-- getTopics: could not fetch data " + ex.toString());
+          throw new TemplateModelException(ex.toString());
+        }
+      }
+*/
+
+
+
+
+/*
+  private String getContentDataParsed() {
+    String returnField = getValue("content_data");
+    if (returnField!=null & returnField.length()>0 ) {
+      returnField=StringUtil.deleteForbiddenTags(returnField);
+      //create http-links and email-links
+      if (getValue("is_html").equals("0")) {
+        returnField = StringUtil.createHTML(returnField,mirconf_imageRoot,
+                                            mirconf_mailLinkName,mirconf_extLinkName,
+                                            mirconf_intLinkName);
+      }
+      returnField = StringUtil.decodeHTMLinTags(returnField);
+    }
+    return returnField;
+  }
+
+  private String getDescriptionSentence() {
+    String returnField = getValue("description");
+    if (returnField != null && returnField.length()>0) {
+       returnField = StringUtil.removeHTMLTags(returnField);
+       int endOfFirstSentence=StringUtil.findEndOfSentence(returnField,0);
+       if (endOfFirstSentence > 0){
+        returnField = returnField.substring(0,endOfFirstSentence);
+       }
+    }
+    return returnField;
+  }
+
+  private String getDescriptionParsed() {
+    String returnField = getValue("description");
+    if (returnField != null && returnField.length()>0) {
+      returnField = StringUtil.deleteForbiddenTags(returnField);
+      if (getValue("is_html").equals("0")) {
+        returnField = StringUtil.createHTML(returnField,mirconf_imageRoot,
+                                            mirconf_mailLinkName,mirconf_extLinkName,
+                                            mirconf_intLinkName);
+      }
+      returnField = StringUtil.decodeHTMLinTags(returnField);
+    }
+    return returnField;
+  }
+
+
+       private EntityList getComments() throws StorageObjectException {
+               return ((DatabaseContent)theStorageObject).getComments(this);
+       }
+
+  // @todo this needs to optimized. expensive SQL
+  private SimpleHash getUploadedMediaForNewswire()
+    throws StorageObjectException, TemplateModelException
+  {
+    // fetching/setting the images
+    // return to_media_icons
+    String        tinyIcon = null, iconAlt = null;
+    MirMedia      mediaHandler = null;
+    EntityUploadedMedia uploadedMedia;
+    Entity        mediaType;
+    SimpleHash    returnHash = new SimpleHash();
+
+    EntityList upMediaEntityList =
+                    DatabaseContentToMedia.getInstance().getUploadedMedia(this);
+    if (upMediaEntityList!=null && upMediaEntityList.getCount()>=1) {
+
+      for (int n=0; n < upMediaEntityList.size();n++) {
+        uploadedMedia = (EntityUploadedMedia)upMediaEntityList.elementAt(n);
+        mediaType = uploadedMedia.getMediaType();
+        try {
+          mediaHandler = MediaHelper.getHandler( mediaType );
+        } catch (MirMediaException ex) {
+          throw new TemplateModelException(ex.toString());
+        }
+        //the "best" media type to show
+        if (mediaHandler.isVideo()) {
+          tinyIcon = MirConfig.getProp("Producer.Icon.TinyVideo");
+          iconAlt = "Video";
+          break;
+        } else if (mediaHandler.isAudio()) {
+          tinyIcon = MirConfig.getProp("Producer.Icon.TinyAudio");
+          iconAlt = "Audio";
+        } else if (tinyIcon == null && !mediaHandler.isImage()) {
+          tinyIcon = mediaHandler.getTinyIcon();
+          iconAlt = mediaHandler.getIconAlt();
+        }
+
+      }
+      //it only has image(s)
+      if (tinyIcon == null) {
+        tinyIcon = MirConfig.getProp("Producer.Icon.TinyImage");
+        iconAlt = "Image";
+      }
+    // uploadedMedia Entity list is empty.
+    // we only have text
+    } else {
+      tinyIcon = MirConfig.getProp("Producer.Icon.TinyText");
+      iconAlt = "Text";
+    }
+    returnHash.put("tiny_icon", mirconf_imageRoot+"/"+tinyIcon);
+    returnHash.put("icon_alt", iconAlt);
+    return returnHash;
+  }
+
+  private boolean hasMedia() throws StorageObjectException
+  {
+    if (_hasMedia == null) {
+      _hasMedia =
+        new Boolean(DatabaseContentToMedia.getInstance().hasMedia(this));
+    }
+    return _hasMedia.booleanValue();
+  }
+
+  //######## @todo all of the following getBlahForContent should have
+  // and optimized version where LIMIT=1 sql for list view.
+  private EntityList getImagesForContent()
+    throws StorageObjectException, TemplateModelException
+  {
+    if (hasMedia())
+      return DatabaseContentToMedia.getInstance().getImages(this);
+    else
+      return null;
+  }
+
+  private EntityList getAudioForContent()
+    throws StorageObjectException, TemplateModelException
+  {
+    if (hasMedia())
+      return DatabaseContentToMedia.getInstance().getAudio(this) ;
+    else
+      return null;
+  }
+
+  private EntityList getVideoForContent()
+    throws StorageObjectException, TemplateModelException
+  {
+    if (hasMedia())
+      return DatabaseContentToMedia.getInstance().getVideo(this) ;
+    else
+      return null;
+  }
+
+  private EntityList getOtherMediaForContent()
+    throws StorageObjectException, TemplateModelException
+  {
+    if (hasMedia())
+      return DatabaseContentToMedia.getInstance().getOther(this);
+    else
+      return null;
+  }
+
+}
+*/
\ No newline at end of file
diff --git a/source/mircoders/entity/adapter/FeatureAdapterDefinition.java b/source/mircoders/entity/adapter/FeatureAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..0e98f58
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class FeatureAdapterDefinition extends EntityAdapterDefinition {
+  private static FeatureAdapterDefinition instance;
+
+  public static FeatureAdapterDefinition getInstance() {
+    synchronized (FeatureAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new FeatureAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public FeatureAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/ImagesAdapterDefinition.java b/source/mircoders/entity/adapter/ImagesAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..c8a4c9c
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class ImagesAdapterDefinition extends EntityAdapterDefinition {
+  private static ImagesAdapterDefinition instance;
+
+  public static ImagesAdapterDefinition getInstance() {
+    synchronized (ImagesAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new ImagesAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public ImagesAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/LanguageAdapterDefinition.java b/source/mircoders/entity/adapter/LanguageAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..7a49217
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class LanguageAdapterDefinition extends EntityAdapterDefinition {
+  private static LanguageAdapterDefinition instance;
+
+  public static LanguageAdapterDefinition getInstance() {
+    synchronized (LanguageAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new LanguageAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public LanguageAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/LinksImcsAdapterDefinition.java b/source/mircoders/entity/adapter/LinksImcsAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..9c66c62
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class LinksImcsAdapterDefinition extends EntityAdapterDefinition {
+  private static LinksImcsAdapterDefinition instance;
+
+  public static LinksImcsAdapterDefinition getInstance() {
+    synchronized (LinksImcsAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new LinksImcsAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public LinksImcsAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/MediaAdapterDefinition.java b/source/mircoders/entity/adapter/MediaAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..70d078e
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class MediaAdapterDefinition extends EntityAdapterDefinition {
+  private static MediaAdapterDefinition instance;
+
+  public static MediaAdapterDefinition getInstance() {
+    synchronized (MediaAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new MediaAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public MediaAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/OtherAdapterDefinition.java b/source/mircoders/entity/adapter/OtherAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..33ab0ec
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class OtherAdapterDefinition extends EntityAdapterDefinition {
+  private static OtherAdapterDefinition instance;
+
+  public static OtherAdapterDefinition getInstance() {
+    synchronized (OtherAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new OtherAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public OtherAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/TopicsAdapterDefinition.java b/source/mircoders/entity/adapter/TopicsAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..7114700
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class TopicsAdapterDefinition extends EntityAdapterDefinition {
+  private static TopicsAdapterDefinition instance;
+
+  public static TopicsAdapterDefinition getInstance() {
+    synchronized (TopicsAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new TopicsAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public TopicsAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/UploadedMediaAdapterDefinition.java b/source/mircoders/entity/adapter/UploadedMediaAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..4a2d3a1
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class UploadedMediaAdapterDefinition extends EntityAdapterDefinition {
+  private static UploadedMediaAdapterDefinition instance;
+
+  public static UploadedMediaAdapterDefinition getInstance() {
+    synchronized (UploadedMediaAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new UploadedMediaAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public UploadedMediaAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/UsersAdapterDefinition.java b/source/mircoders/entity/adapter/UsersAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..b54ca73
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class UsersAdapterDefinition extends EntityAdapterDefinition {
+  private static UsersAdapterDefinition instance;
+
+  public static UsersAdapterDefinition getInstance() {
+    synchronized (UsersAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new UsersAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public UsersAdapterDefinition() {
+    super();
+  }
+}
diff --git a/source/mircoders/entity/adapter/VideoAdapterDefinition.java b/source/mircoders/entity/adapter/VideoAdapterDefinition.java
new file mode 100755 (executable)
index 0000000..1435b38
--- /dev/null
@@ -0,0 +1,22 @@
+package mircoders.entity.adapter;
+
+import mir.entity.*;
+import mir.entity.adapter.*;
+import mircoders.storage.*;
+
+public class VideoAdapterDefinition extends EntityAdapterDefinition {
+  private static VideoAdapterDefinition instance;
+
+  public static VideoAdapterDefinition getInstance() {
+    synchronized (VideoAdapterDefinition.class) {
+      if (instance == null) {
+        instance = new VideoAdapterDefinition();
+      }
+      return instance;
+    }
+  }
+
+  public VideoAdapterDefinition() {
+    super();
+  }
+}
index cbbea02..28a4a3b 100755 (executable)
@@ -3,21 +3,42 @@ package mircoders.global;
 import mir.misc.*;
 import mircoders.localizer.*;
 
-import mircoders.localizer.basic.*;
-
-
 public class MirGlobal {
   static private MirConfig configuration;
   static private MirLocalizer localizer;
   static private ProducerEngine producerEngine;
 
   public static MirLocalizer localizer() {
+    String localizerClassName;
+    Class localizerClass;
+
     if (localizer == null ) {
-      localizer = new MirCachingLocalizerDecorator(new MirBasicLocalizer());
+      synchronized(MirGlobal.class) {
+        if (localizer == null ) {
+          localizerClassName = getConfigPropertyWithDefault("Mir.Localizer", "mirlocal.loaclizer.basic.MirBasicLocalizer");
+
+          try {
+            localizerClass = Class.forName(localizerClassName);
+          }
+          catch (Throwable t) {
+            throw new ConfigException("localizer class '" + localizerClassName + "' not found: " + t.toString());
+          }
+
+          if (!(MirLocalizer.class.isAssignableFrom(localizerClass)))
+            throw new ConfigException("localizer class '" + localizerClassName + "' is not assignable from MirLocalizer");
+
+          try {
+            localizer = new MirCachingLocalizerDecorator((MirLocalizer) localizerClass.newInstance());
+          }
+          catch (Throwable t) {
+            throw new ConfigException("localizer class '" + localizerClassName + "' cannot be instantiated: " + t.toString());
+          }
+        }
+      }
     }
 
     return localizer;
-  };
+  }
 
   public static MirConfig config() {
     if (configuration == null) {
@@ -25,7 +46,7 @@ public class MirGlobal {
     }
 
     return configuration;
-  };
+  }
 
   public static ProducerEngine producerEngine() {
     if (producerEngine == null) {
@@ -35,6 +56,17 @@ public class MirGlobal {
     return producerEngine;
   }
 
+  public static String getConfigPropertyWithDefault(String aPropertyName, String aDefault) {
+    String result;
+
+    result = config().getProp(aPropertyName);
+
+    if (result==null)
+      result = aDefault;
+
+    return result;
+  }
+
   public static String getConfigProperty(String aPropertyName) {
     String result;
 
index a9bf823..6b2af6c 100755 (executable)
@@ -7,4 +7,5 @@ public interface MirProducerToolLocalizer {
   public void initializeGenerationValueSet(Map aValueSet);
   public PrintWriter openWriter(String anIdentifier) throws MirLocalizerFailure;
   public void closeWriter(PrintWriter aWriter);
+  public String filterText(String aText);
 }
index 9f2876d..9e3dc96 100755 (executable)
@@ -36,15 +36,6 @@ public class MirBasicProducerLocalizer implements MirProducerLocalizer {
           MirGlobal.getConfigProperty("Producer.StorageRoot") + "/index.shtml",
           MirGlobal.getConfigIntegerProperty("Producer.StartPage.Items"),
           MirGlobal.getConfigIntegerProperty("Producer.StartPage.Newswire")));
-
-
-    aStartPageFactory.addFactory(
-      new TopicStartPageProducerFactory(
-          MirGlobal.getConfigProperty("Producer.StartPage.Template"),
-          "bundles.admin",
-          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/${filename}index.shtml",
-          MirGlobal.getConfigIntegerProperty("Producer.StartPage.Items"),
-          MirGlobal.getConfigIntegerProperty("Producer.StartPage.Newswire")));
   }
 
   protected void setupSynchronizationFactory(CompositeProducerFactory aSynchronizationFactory) {
index 406f031..c1f9db2 100755 (executable)
@@ -17,7 +17,7 @@ public class MirBasicProducerToolLocalizer implements MirProducerToolLocalizer {
 
     Map configMap = new HashMap();
 
-               configMap.put("producerDocRoot", MirGlobal.getConfigProperty("Producer.DocRoot"));
+               configMap.put("producerDocRoot", "");//MirGlobal.getConfigProperty("Producer.DocRoot"));
                configMap.put("storageRoot", MirGlobal.getConfigProperty("Producer.StorageRoot"));
     configMap.put("productionHost", MirGlobal.getConfigProperty("Producer.ProductionHost"));
                configMap.put("openAction", MirGlobal.getConfigProperty("Producer.OpenAction"));
@@ -36,15 +36,17 @@ public class MirBasicProducerToolLocalizer implements MirProducerToolLocalizer {
     EntityList topicList=null;
     EntityList entityList=null;
     EntityList parentList=null;
+    EntityList languageList=null;
 
     try {
       ModuleLinksImcs linksImcsModule = new ModuleLinksImcs(DatabaseLinksImcs.getInstance());
       ModuleTopics topicsModule = new ModuleTopics(DatabaseTopics.getInstance());
+      ModuleLanguage languageModule = new ModuleLanguage(DatabaseLanguage.getInstance());
 
       topicList = topicsModule.getTopicsList();
       entityList = linksImcsModule.getByWhereClause("", "sortpriority, title", -1);
       parentList = linksImcsModule.getByWhereClause("to_parent_id=NULL", "sortpriority, title", -1);
-
+      languageList = languageModule.getByWhereClause("", "id", -1);
     }
     catch (Throwable t) {
       System.out.println("initializeGenerationValueSet: Exception "+t.getMessage());
@@ -81,4 +83,14 @@ public class MirBasicProducerToolLocalizer implements MirProducerToolLocalizer {
   public void closeWriter(PrintWriter aWriter) {
     aWriter.close();
   };
+
+  public String filterText(String aText) {
+    return StringUtil.createHTML(
+        StringUtil.deleteForbiddenTags(aText),
+        MirGlobal.getConfigProperty("Producer.ImageRoot"),
+        MirGlobal.getConfigProperty("Producer.MailLinkName"),
+        MirGlobal.getConfigProperty("Producer.ExtLinkName"),
+        MirGlobal.getConfigProperty("Producer.IntLinkName")
+    );
+  }
 }
index 09fbfa6..99902a5 100755 (executable)
@@ -12,11 +12,10 @@ import mir.generator.*;
 import mircoders.localizer.*;
 import mircoders.global.*;
 import mircoders.entity.*;
+import mircoders.entity.adapter.*;
 
 import org.apache.struts.util.MessageResources;
 
-// @todo ML: the file that gets generated should be better configurable
-
 public class ContentProducer implements mir.producer.Producer {
 
   private String generatorIdentifier;
@@ -60,7 +59,7 @@ public class ContentProducer implements mir.producer.Producer {
 
       while (browser.hasNext()) {
         content = (EntityContent) browser.next();
-        dataMap.put("content", content);
+        dataMap.put("content", ContentAdapterDefinition.getInstance().makeEntityAdapter(content));
 
         String date = content.getValue("date");
 
diff --git a/source/mircoders/producer/GeneratingProducerNode.java b/source/mircoders/producer/GeneratingProducerNode.java
new file mode 100755 (executable)
index 0000000..0e25977
--- /dev/null
@@ -0,0 +1,49 @@
+package mircoders.producer;
+
+import java.util.*;
+import java.io.*;
+import mir.util.*;
+import mir.producer.*;
+import mir.generator.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+
+public class GeneratingProducerNode implements ProducerNode {
+  private String generatorExpression;
+  private String destinationExpression;
+
+  public GeneratingProducerNode(String aGenerator, String aDestination) {
+    generatorExpression=aGenerator;
+    destinationExpression=aDestination;
+  }
+
+  public void produce(Map aValueMap, String aVerb, PrintWriter aLogger) throws ProducerFailure {
+    Generator generator;
+    PrintWriter printWriter;
+    String generatorIdentifier;
+    String destinationIdentifier;
+
+    try {
+      destinationIdentifier = ParameterExpander.expandExpression( aValueMap, destinationExpression );
+      generatorIdentifier = ParameterExpander.expandExpression( aValueMap, generatorExpression );
+
+      aLogger.println("Generating " + generatorIdentifier + " into " + destinationIdentifier);
+      printWriter = MirGlobal.localizer().producerTool().openWriter( destinationIdentifier );
+      generator = MirGlobal.localizer().generators().makeGenerator( generatorIdentifier );
+      generator.generate(printWriter, aValueMap, aLogger);
+      MirGlobal.localizer().producerTool().closeWriter( printWriter );
+      aLogger.println("Done generating");
+    }
+    catch (Throwable t) {
+      aLogger.println("Error while generating: " + t.getMessage());
+      t.printStackTrace(aLogger);
+
+      throw new ProducerFailure(t.getMessage(), t);
+    }
+
+  }
+
+  public Set buildVerbSet() {
+    return new HashSet();
+  }
+}
\ No newline at end of file
diff --git a/source/mircoders/producer/NodedProducerFactory.java b/source/mircoders/producer/NodedProducerFactory.java
new file mode 100755 (executable)
index 0000000..ca547de
--- /dev/null
@@ -0,0 +1,36 @@
+package mircoders.producer;
+
+import java.util.*;
+import mir.producer.*;
+import mircoders.global.*;
+
+public class NodedProducerFactory implements ProducerFactory {
+  private ProducerNode rootNode;
+
+  public NodedProducerFactory(ProducerNode aRootNode) {
+    rootNode = aRootNode;
+  }
+
+  public mir.producer.Producer makeProducer(String aVerb) throws ProducerFailure {
+    Map baseValues;
+
+    baseValues = new HashMap();
+
+    MirGlobal.localizer().producerTool().initializeGenerationValueSet(baseValues);
+
+    return new NodedProducer(rootNode, aVerb, baseValues);
+  };
+
+  public Iterator verbs() {
+    Set verbSet = rootNode.buildVerbSet();
+
+    if (verbSet.isEmpty()) {
+      verbSet = new HashSet();
+
+      verbSet.add("(default)");
+    }
+
+    return verbSet.iterator();
+  };
+}
+
index f5024cd..4413ff4 100755 (executable)
@@ -18,7 +18,6 @@ public class StaticProducerFactory implements ProducerFactory {
     outputFile = anOutputFile;
   }
 
-
   public mir.producer.Producer makeProducer(String aVerb) throws ProducerFailure {
     try {
       return new StaticProducer( generatorIdentifier, resourceBundle, outputFile );
index aee7267..5b3f29a 100755 (executable)
@@ -7,6 +7,8 @@ import mir.util.*;
 import mircoders.storage.*;
 import mircoders.module.*;
 import mircoders.entity.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
 
 
 public class TopicStartPageProducerFactory implements ProducerFactory {
@@ -35,7 +37,10 @@ public class TopicStartPageProducerFactory implements ProducerFactory {
     CompositeProducer result = new CompositeProducer();
     Map values = new HashMap();
 
+
     try {
+      MirGlobal.localizer().producerTool().initializeGenerationValueSet(values);
+
       ModuleContent contentModule = new ModuleContent(DatabaseContent.getInstance());
       ModuleTopics topicsModule = new ModuleTopics(DatabaseTopics.getInstance());
       ModuleBreaking breakingModule = new ModuleBreaking(DatabaseBreaking.getInstance());
@@ -54,7 +59,8 @@ public class TopicStartPageProducerFactory implements ProducerFactory {
         values.put("archiv_url", topic.getValue("archiv_url"));
 
 
-        // ML: ok, this is way to low-level for this place:
+
+        // ML: ok, this is way too low-level for this place:
         String orderBy = "webdb_create desc";
         String topicSelection = "exists (select * from content_x_topic where content_id=content.id and topic_id='"+topic.getValue("id")+"')";
         String featureWhereClause = "is_published='1' and to_article_type='2' and "+topicSelection;
diff --git a/source/mirlocal/bolivia.indymedia.org/BoliviaLocalizer.java b/source/mirlocal/bolivia.indymedia.org/BoliviaLocalizer.java
new file mode 100755 (executable)
index 0000000..68663f5
--- /dev/null
@@ -0,0 +1,21 @@
+package mirlocal.bolivia.indymedia.org;
+
+import mircoders.localizer.*;
+import mircoders.global.*;
+import mircoders.localizer.basic.*;
+
+public class BoliviaLocalizer extends MirBasicLocalizer {
+
+  public MirProducerLocalizer producers() {
+    return new BoliviaProducerLocalizer();
+  }
+
+  public MirOpenPostingLocalizer openPostings() {
+    return new BoliviaOpenPostingLocalizer();
+  }
+
+  public MirProducerToolLocalizer producerTool() {
+    return new BoliviaProducerToolLocalizer();
+  }
+
+}
\ No newline at end of file
diff --git a/source/mirlocal/bolivia.indymedia.org/BoliviaOpenPostingLocalizer.java b/source/mirlocal/bolivia.indymedia.org/BoliviaOpenPostingLocalizer.java
new file mode 100755 (executable)
index 0000000..f546193
--- /dev/null
@@ -0,0 +1,16 @@
+package mirlocal.bolivia.indymedia.org;
+
+import mircoders.localizer.*;
+import mircoders.global.*;
+import mircoders.localizer.basic.*;
+
+public class BoliviaOpenPostingLocalizer extends MirBasicOpenPostingLocalizer {
+
+  public void afterContentPosting() {
+    super.afterContentPosting();
+  }
+
+  public void afterCommentPosting() {
+    super.afterCommentPosting();
+  }
+}
diff --git a/source/mirlocal/bolivia.indymedia.org/BoliviaProducerLocalizer.java b/source/mirlocal/bolivia.indymedia.org/BoliviaProducerLocalizer.java
new file mode 100755 (executable)
index 0000000..132c98a
--- /dev/null
@@ -0,0 +1,167 @@
+package mirlocal.bolivia.indymedia.org;
+
+import java.util.*;
+import mir.producer.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+import mircoders.localizer.basic.*;
+import mircoders.producer.*;
+import mircoders.storage.*;
+import mircoders.entity.adapter.*;
+
+public class BoliviaProducerLocalizer extends MirBasicProducerLocalizer {
+
+  protected void setupContentFactory(CompositeProducerFactory aContentFactory) {
+
+    EntityEnumeratingProducerNode contentNode = null;
+
+    try {
+      contentNode =
+          new EntityEnumeratingProducerNode( "content", DatabaseContent.getInstance(), ContentAdapterDefinition.getInstance(),
+            new CompositeProducerNode( new ProducerNode[] {
+              new EntityEnumeratingProducerNode( "language", DatabaseLanguage.getInstance(), LanguageAdapterDefinition.getInstance(), "", "",
+                new ResourceBundleProducerNode("lang", "producer_${language.code}",
+                  new GeneratingProducerNode(
+                      "/producer/bolivia.indymedia.org/article.template",
+                      "${config.storageRoot}/${language.code}/articles/${content.date.year}/${content.date.month}/${content.id}.shtml"
+                  )
+                )
+              )
+            } )
+          );
+    }
+    catch (Throwable t) {
+    }
+
+    contentNode.addVerb( "all", "is_published='1'", "" );
+    contentNode.addVerb( "all", "is_published='1' and is_produced='f'", "" );
+
+    aContentFactory.addFactory( new NodedProducerFactory( contentNode ) );
+
+
+//  public EntityEnumeratingProducerNode(String aKey, StorageObject aStorage, EntityAdapterDefinition aDefinition, ProducerNode aSubNode) {
+
+//    aContentFactory.addFactory(
+//      new ContentProducerFactory(
+//      "producer/content.template",
+//      "bundles.admin",
+//      MirGlobal.getConfigProperty("Producer.StorageRoot") + "/content/${contentyear}/${contentmonth}/${contentid}.inc",
+//      Integer.parseInt(MirGlobal.getConfigProperty("Producer.Content.Batchsize"))));
+
+//    aContentFactory.addFactory(
+//      new ContentProducerFactory(
+//      "producer/article.template",
+//      "bundles.admin",
+//      MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/${contentyear}/${contentmonth}/${contentid}.shtml",
+//      Integer.parseInt(MirGlobal.getConfigProperty("Producer.Content.Batchsize"))));
+  }
+
+  protected void setupStartPageFactory(CompositeProducerFactory aStartPageFactory) {
+    ProducerNode startPageNode = null;
+
+    try {
+      startPageNode =
+          new EntityListProducerNode("features", DatabaseContent.getInstance(), ContentAdapterDefinition.getInstance(),
+                  "is_published='1' and to_article_type = 2", "date desc, webdb_create desc", 10,
+            new EntityListProducerNode("newswire", DatabaseContent.getInstance(), ContentAdapterDefinition.getInstance(),
+                    "is_published='1' and to_article_type = 1", "date desc, webdb_create desc", 10,
+              new EntityListProducerNode("breaking", DatabaseBreaking.getInstance(), BreakingAdapterDefinition.getInstance(),
+                      "", "webdb_create desc", 5,
+                new EntityListProducerNode("languages", DatabaseLanguage.getInstance(), LanguageAdapterDefinition.getInstance(),
+                        "", "code", 10,
+                  new CompositeProducerNode( new ProducerNode[] {
+                    new EntityEnumeratingProducerNode( "language", DatabaseLanguage.getInstance(), LanguageAdapterDefinition.getInstance(), "", "",
+                      new ResourceBundleProducerNode("lang", "producer_${language.code}",
+                        new GeneratingProducerNode(
+                            "/producer/bolivia.indymedia.org/startpage.template",
+                            "${config.storageRoot}/${language.code}/index.shtml"
+                        )
+                      )
+                    )
+                  } )
+                )
+              )
+            )
+          );
+    }
+    catch (Throwable t) {
+    }
+
+    aStartPageFactory.addFactory( new NodedProducerFactory( startPageNode ) );
+
+
+/*
+    aStartPageFactory.addFactory(
+      new TopicStartPageProducerFactory(
+          "producer/citystart.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/start${filename}.shtml",
+          MirGlobal.getConfigIntegerProperty("Producer.StartPage.Items"),
+          0));
+
+    aStartPageFactory.addFactory(
+      new TopicStartPageProducerFactory(
+          "producer/newswire.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/newswire${filename}.inc",
+          0,
+          MirGlobal.getConfigIntegerProperty("Producer.StartPage.Newswire")));
+
+    aStartPageFactory.addFactory(
+      new StartPageProducerFactory(
+          "producer/start.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/start.shtml",
+          MirGlobal.getConfigIntegerProperty("Producer.StartPage.Items"),
+          0));
+
+    aStartPageFactory.addFactory(
+      new StartPageProducerFactory(
+          "producer/newswire.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/newswire.inc",
+          0,
+          MirGlobal.getConfigIntegerProperty("Producer.StartPage.Newswire")));
+
+*/
+  }
+
+  protected void setupStaticFactory(CompositeProducerFactory aStaticFactory) {
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/nav.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/nav.inc"));
+
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/top.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/top.inc"));
+
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/bottom.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/bottom.inc"));
+
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/style.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/style.css"));
+
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/articlepre.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/articlepre.shtml"));
+
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/articlepost.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/articlepost.shtml"));
+  }
+
+}
diff --git a/source/mirlocal/bolivia.indymedia.org/BoliviaProducerToolLocalizer.java b/source/mirlocal/bolivia.indymedia.org/BoliviaProducerToolLocalizer.java
new file mode 100755 (executable)
index 0000000..569825b
--- /dev/null
@@ -0,0 +1,36 @@
+package mirlocal.bolivia.indymedia.org;
+
+import java.util.*;
+import java.io.*;
+import freemarker.template.utility.*;
+import mir.misc.*;
+import mir.entity.*;
+import mircoders.module.*;
+import mircoders.storage.*;
+import mircoders.localizer.*;
+import mircoders.localizer.basic.*;
+import mircoders.global.*;
+
+public class BoliviaProducerToolLocalizer extends MirBasicProducerToolLocalizer {
+
+  public void initializeGenerationValueSet(Map aValueSet) {
+    super.initializeGenerationValueSet(aValueSet);
+
+    EntityList topicList=null;
+    EntityList cityList=null;
+
+
+    try {
+      ModuleTopics topicsModule = new ModuleTopics(DatabaseTopics.getInstance());
+
+      cityList = topicsModule.getByWhereClause("main_url<>'c'", "title", -1);
+      topicList = topicsModule.getByWhereClause("main_url<>'c'", "title", -1);
+    }
+    catch (Throwable t) {
+      throw new RuntimeException("initializeGenerationValueSet: Exception "+t.getMessage());
+    }
+
+    aValueSet.put("topics", topicList);
+    aValueSet.put("cities", topicList);
+  }
+}
diff --git a/source/mirlocal/indymedia.nl/IndyNLLocalizer.java b/source/mirlocal/indymedia.nl/IndyNLLocalizer.java
new file mode 100755 (executable)
index 0000000..464e4ed
--- /dev/null
@@ -0,0 +1,21 @@
+package mirlocal.indymedia.nl;
+
+import mircoders.localizer.*;
+import mircoders.global.*;
+import mircoders.localizer.basic.*;
+
+public class IndyNLLocalizer extends MirBasicLocalizer {
+
+  public MirProducerLocalizer producers() {
+    return new IndyNLProducerLocalizer();
+  }
+
+  public MirOpenPostingLocalizer openPostings() {
+    return new IndyNLOpenPostingLocalizer();
+  }
+
+  public MirProducerToolLocalizer producerTool() {
+    return new MirBasicProducerToolLocalizer();
+  }
+
+}
\ No newline at end of file
diff --git a/source/mirlocal/indymedia.nl/IndyNLOpenPostingLocalizer.java b/source/mirlocal/indymedia.nl/IndyNLOpenPostingLocalizer.java
new file mode 100755 (executable)
index 0000000..4c5fd18
--- /dev/null
@@ -0,0 +1,17 @@
+package mirlocal.indymedia.nl;
+
+import mircoders.localizer.*;
+import mircoders.global.*;
+import mircoders.localizer.basic.*;
+
+public class IndyNLOpenPostingLocalizer extends MirBasicOpenPostingLocalizer {
+
+  public void afterContentPosting() {
+    super.afterContentPosting();
+  }
+
+  public void afterCommentPosting() {
+    MirGlobal.producerEngine().addJob("startpage", "all");
+    super.afterCommentPosting();
+  }
+}
diff --git a/source/mirlocal/indymedia.nl/IndyNLProducerLocalizer.java b/source/mirlocal/indymedia.nl/IndyNLProducerLocalizer.java
new file mode 100755 (executable)
index 0000000..c7562f9
--- /dev/null
@@ -0,0 +1,216 @@
+package mirlocal.indymedia.nl;
+
+import java.util.*;
+import mir.producer.*;
+import mircoders.global.*;
+import mircoders.localizer.*;
+import mircoders.localizer.basic.*;
+import mircoders.producer.*;
+import mircoders.storage.*;
+import mircoders.entity.adapter.*;
+
+public class IndyNLProducerLocalizer extends MirBasicProducerLocalizer {
+
+  protected void setupContentFactory(CompositeProducerFactory aContentFactory) {
+    EntityEnumeratingProducerNode contentNode = null;
+
+    try {
+      contentNode =
+          new EntityEnumeratingProducerNode( "content", DatabaseContent.getInstance(), ContentAdapterDefinition.getInstance(),
+            new CompositeProducerNode( new ProducerNode[] {
+              new GeneratingProducerNode(
+                  "/producer/indymedia.nl/content.template",
+                  "${config.storageRoot}/content/${content.date.year}/${content.date.month}/${content.id}.inc"
+              ),
+              new EntityEnumeratingProducerNode( "language", DatabaseLanguage.getInstance(), LanguageAdapterDefinition.getInstance(), "", "",
+                new ResourceBundleProducerNode("lang", "producer_${language.code}",
+                    new GeneratingProducerNode(
+                        "/producer/indymedia.nl/article.template",
+                        "${config.storageRoot}/${language.code}/${content.date.year}/${content.date.month}/${content.id}.shtml"
+                    )
+                )
+              )
+            } )
+          );
+    }
+    catch (Throwable t) {
+    }
+
+    contentNode.addVerb( "all", "is_published='1'", "" );
+    contentNode.addVerb( "all", "is_published='1' and is_produced='f'", "" );
+
+    aContentFactory.addFactory( new NodedProducerFactory( contentNode ) );
+
+
+/*
+    aContentFactory.addFactory(
+      new ContentProducerFactory(
+      "producer/content.template",
+      "bundles.admin",
+      MirGlobal.getConfigProperty("Producer.StorageRoot") + "/content/${contentyear}/${contentmonth}/${contentid}.inc",
+      Integer.parseInt(MirGlobal.getConfigProperty("Producer.Content.Batchsize"))));
+
+    aContentFactory.addFactory(
+      new ContentProducerFactory(
+      "producer/article.template",
+      "bundles.admin",
+      MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/${contentyear}/${contentmonth}/${contentid}.shtml",
+      Integer.parseInt(MirGlobal.getConfigProperty("Producer.Content.Batchsize"))));
+ */
+  }
+
+  protected void setupStartPageFactory(CompositeProducerFactory aStartPageFactory) {
+    ProducerNode startPageNode = null;
+
+    try {
+      startPageNode =
+          new EntityListProducerNode("features", DatabaseContent.getInstance(), ContentAdapterDefinition.getInstance(),
+                  "is_published='1' and to_article_type = 2", "date desc, webdb_create desc", 10,
+            new EntityListProducerNode("newswire", DatabaseContent.getInstance(), ContentAdapterDefinition.getInstance(),
+                    "is_published='1' and to_article_type = 1", "date desc, webdb_create desc", 10,
+              new EntityListProducerNode("breaking", DatabaseBreaking.getInstance(), BreakingAdapterDefinition.getInstance(),
+                      "", "webdb_create desc", 5,
+                new EntityListProducerNode("languages", DatabaseLanguage.getInstance(), LanguageAdapterDefinition.getInstance(),
+                        "", "code", 10,
+                    new EntityEnumeratingProducerNode( "language", DatabaseLanguage.getInstance(), LanguageAdapterDefinition.getInstance(), "", "",
+                      new ResourceBundleProducerNode("lang", "producer_${language.code}",
+                        new CompositeProducerNode( new ProducerNode[] {
+                          new GeneratingProducerNode(
+                              "/producer/indymedia.nl/start.template",
+                              "${config.storageRoot}/${language.code}/start.shtml"
+                          ),
+                          new GeneratingProducerNode(
+                              "/producer/indymedia.nl/newswire.template",
+                              "${config.storageRoot}/${language.code}/newswire.inc"
+                          )
+                        } )
+                      )
+                    )
+                )
+              )
+            )
+          );
+    }
+    catch (Throwable t) {
+    }
+
+    aStartPageFactory.addFactory( new NodedProducerFactory( startPageNode ) );
+/*
+    aStartPageFactory.addFactory(
+      new StartPageProducerFactory(
+          "producer/start.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/start.shtml",
+          MirGlobal.getConfigIntegerProperty("Producer.StartPage.Items"),
+          0));
+
+    aStartPageFactory.addFactory(
+      new StartPageProducerFactory(
+          "producer/newswire.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/newswire.inc",
+          0,
+          MirGlobal.getConfigIntegerProperty("Producer.StartPage.Newswire")));
+*/
+  }
+
+  protected void setupSynchronizationFactory(CompositeProducerFactory aSynchronizationFactory) {
+    if(MirGlobal.getConfigBooleanProperty("Rsync")){
+      aSynchronizationFactory.addFactory(
+        new ScriptCallProducerFactory(MirGlobal.getConfigProperty("Rsync.Script.Path")));
+    }
+    else {
+      NullProducerFactory nullFactory = new NullProducerFactory();
+      nullFactory.addVerb("run");
+      aSynchronizationFactory.addFactory(nullFactory);
+    }
+  }
+
+  protected void setupStaticFactory(CompositeProducerFactory aStaticFactory) {
+    ProducerNode staticNode = null;
+
+    try {
+      staticNode =
+          new EntityListProducerNode("languages", DatabaseLanguage.getInstance(), LanguageAdapterDefinition.getInstance(),
+                  "", "code", 10,
+              new EntityEnumeratingProducerNode( "language", DatabaseLanguage.getInstance(), LanguageAdapterDefinition.getInstance(), "", "",
+                new ResourceBundleProducerNode("lang", "producer_${language.code}",
+                  new CompositeProducerNode( new ProducerNode[] {
+                    new GeneratingProducerNode(
+                        "/producer/indymedia.nl/nav.template",
+                        "${config.storageRoot}/${language.code}/nav.inc"
+                    ),
+                    new GeneratingProducerNode(
+                        "/producer/indymedia.nl/top.template",
+                        "${config.storageRoot}/${language.code}/top.inc"
+                    ),
+                    new GeneratingProducerNode(
+                        "/producer/indymedia.nl/bottom.template",
+                        "${config.storageRoot}/${language.code}/bottom.inc"
+                    ),
+                    new GeneratingProducerNode(
+                        "/producer/indymedia.nl/style.template",
+                        "${config.storageRoot}/${language.code}/style.css"
+                    ),
+                    new GeneratingProducerNode(
+                        "/producer/indymedia.nl/top.template",
+                        "${config.storageRoot}/${language.code}/top.inc"
+                    ),
+                    new GeneratingProducerNode(
+                        "/producer/indymedia.nl/articlepre.template",
+                        "${config.storageRoot}/${language.code}/articlepre.inc"
+                    ),
+                    new GeneratingProducerNode(
+                        "/producer/indymedia.nl/articlepost.template",
+                        "${config.storageRoot}/${language.code}/articlepost.inc"
+                    ),
+                  } )
+                )
+              )
+          );
+    }
+    catch (Throwable t) {
+    }
+
+    aStaticFactory.addFactory( new NodedProducerFactory( staticNode ) );
+
+
+/*
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/nav.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/nav.inc"));
+
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/top.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/top.inc"));
+
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/bottom.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/bottom.inc"));
+
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/style.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/style.css"));
+
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/articlepre.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/articlepre.shtml"));
+
+    aStaticFactory.addFactory(
+      new StaticProducerFactory(
+          "producer/articlepost.template",
+          "bundles.admin",
+          MirGlobal.getConfigProperty("Producer.StorageRoot") + "/nl/articlepost.shtml"));
+*/
+  }
+}