1.1 restoration
[mir.git] / source / mir / generator / tal / template / MacroTemplateNodeLibrary.java
diff --git a/source/mir/generator/tal/template/MacroTemplateNodeLibrary.java b/source/mir/generator/tal/template/MacroTemplateNodeLibrary.java
new file mode 100755 (executable)
index 0000000..1310c7b
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2001, 2002 The Mir-coders group
+ *
+ * This file is part of Mir.
+ *
+ * Mir is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Mir is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mir; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * In addition, as a special exception, The Mir-coders gives permission to link
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * and distribute linked combinations including the two.  You must obey the
+ * GNU General Public License in all respects for all of the code used other than
+ * the above mentioned libraries.  If you modify this file, you may extend this
+ * exception to your version of the file, but you are not obligated to do so.
+ * If you do not wish to do so, delete this exception statement from your version.
+ */
+package mir.generator.tal.template;
+
+import java.util.Map;
+import java.util.Iterator;
+import java.util.List;
+import java.util.HashMap;
+
+import mir.generator.tal.interfaces.TALExpressionParser;
+import mir.generator.tal.interfaces.TALLogger;
+import mir.util.xml.XMLName;
+import mir.util.xml.XMLParserExc;
+import mir.util.xml.XMLReaderTool;
+import mir.util.StringRoutines;
+import mir.util.HTMLRoutines;
+
+public class MacroTemplateNodeLibrary implements TemplateNodeLibrary {
+  /** {@inheritDoc} */
+  private static final String DEFINE_MACRO_ATTRIBUTE = "define-macro";
+  private static final String USE_MACRO_ATTRIBUTE = "use-macro";
+  private static final String DEFINE_SLOT_ATTRIBUTE = "define-slot";
+  private static final String FILL_SLOT_ATTRIBUTE = "fill-macro";
+
+  public static final String MACRO_DEFINITIONS_KEY = "$" + MacroTemplateNodeLibrary.class.getName() + "$macro_definitions";
+  public static final String ORPHANED_SLOTS_KEY = "$" + MacroTemplateNodeLibrary.class.getName() + "$macro_definitions";
+
+  private String prefix;
+  private String uri;
+
+
+  private boolean isOurTag(XMLName aName) {
+    return prefix.equals(aName.getPrefix()) || uri.equals(aName.getNamespaceURI());
+  }
+
+  public MacroTemplateNodeLibrary(String aPrefix, String aUri) {
+    prefix = aPrefix;
+    uri = aUri;
+  }
+
+  public TemplateNode constructTemplateNode(TALExpressionParser anExpressionParser, XMLName aTag, Map anAttributes,
+      TemplateNode aChildTemplateNode, Map aTemplateContext) throws XMLParserExc {
+
+    StringBuffer prefix = new StringBuffer();
+    boolean useSurroundingTag = !(isOurTag(aTag));
+
+    prefix.append("<").append(XMLReaderTool.normalizeXMLName(aTag));
+    String suffix = "</"+XMLReaderTool.normalizeXMLName(aTag)+">";
+
+    String macroDefinition = null;
+    String slotDefinition = null;
+    String slotFill = null;
+    Object macroCallExpression = null;
+
+    Iterator i = anAttributes.entrySet().iterator();
+
+    while (i.hasNext()) {
+      Map.Entry entry = (Map.Entry) i.next();
+      XMLName name = (XMLName) entry.getKey();
+
+      if (!isOurTag(name)) {
+        prefix.append(" ").append(XMLReaderTool.normalizeXMLName(name));
+        prefix.append("=\"").append(HTMLRoutines.encodeHTML( (String) entry.getValue())).append('"');
+      }
+      else {
+        if (name.getLocalName().equalsIgnoreCase(DEFINE_MACRO_ATTRIBUTE)) {
+          macroDefinition = (String) entry.getValue();
+        }
+        else if (name.getLocalName().equalsIgnoreCase(USE_MACRO_ATTRIBUTE)) {
+          macroCallExpression = anExpressionParser.preparseStringExpression((String) entry.getValue());
+        }
+        else if (name.getLocalName().equalsIgnoreCase(DEFINE_SLOT_ATTRIBUTE)) {
+          slotDefinition = (String) entry.getValue();
+        }
+        else if (name.getLocalName().equalsIgnoreCase(FILL_SLOT_ATTRIBUTE)) {
+          slotFill = (String) entry.getValue();
+        }
+      }
+    }
+    prefix.append(">");
+
+    MacroTemplateNode result;
+    if (useSurroundingTag) {
+      result = new MacroTemplateNode(aChildTemplateNode, prefix.toString(), suffix, slotDefinition, slotFill);
+    }
+    else {
+      result = new MacroTemplateNode(aChildTemplateNode, "", "", slotDefinition, slotFill);
+    }
+
+    if (macroCallExpression!=null) {
+      result.setMacroCall(macroCallExpression);
+    }
+
+    if (macroDefinition!=null) {
+      macroDefinition = macroDefinition.trim();
+      if (macroDefinition.length()==0) {
+        throw new XMLParserExc("Empty macro name");
+      }
+
+      Map definitions = (Map) aTemplateContext.get(MACRO_DEFINITIONS_KEY);
+      if (definitions==null) {
+        definitions=new HashMap();
+        aTemplateContext.put(MACRO_DEFINITIONS_KEY, definitions);
+      }
+
+      if (definitions.containsKey(macroDefinition)) {
+        throw new XMLParserExc("Duplicate macro name: " + macroDefinition);
+      }
+
+      definitions.put(macroDefinition, result);
+
+      Map slots = (Map) aTemplateContext.get(ORPHANED_SLOTS_KEY);
+      if (slots!=null) {
+      }
+    }
+
+    return result;
+  }
+
+  private class MacroTemplateNode implements TemplateNode {
+    private TemplateNode childNode;
+    private String prefix;
+    private String suffix;
+
+    private Object macroCallTemplateExpression = null;
+
+    private String slotDefinition;
+    private String slotFill;
+
+    public MacroTemplateNode(TemplateNode aChildNode, String aPrefix, String aSuffix,
+        String aSlotDefinition, String aSlotFill) {
+      childNode = aChildNode;
+      prefix = aPrefix;
+      suffix = aSuffix;
+
+      slotDefinition = aSlotDefinition;
+      slotFill = aSlotFill;
+    }
+
+    public void setMacroCall(Object anExpression) {
+      macroCallTemplateExpression = anExpression;
+    }
+
+    /** {@inheritDoc} */
+    public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination,
+        TALLogger aLogger, Map aTemplateContext, TemplateLibrary aLibrary) throws TemplateProcessingException {
+
+      if (macroCallTemplateExpression!=null) {
+        String macroPath = aParser.evaluateStringExpression(aContext, macroCallTemplateExpression);
+        List parts = StringRoutines.separateString(macroPath, "#");
+        if (parts.size()!=2) {
+          throw new TemplateProcessingException("Invalid macro path '" + macroPath + "'");
+        }
+
+        Template template = aLibrary.lookupTemplate((String) parts.get(0));
+        Map definitions = (Map) template.getContext().get(MACRO_DEFINITIONS_KEY);
+        if (template==null) {
+          throw new TemplateProcessingException("Cannot find template '" + (String) parts.get(0) + "'");
+        }
+        if (definitions==null || !definitions.containsKey(parts.get(1))) {
+          throw new TemplateProcessingException("No macro '"+(String) parts.get(1)+"' found in template '" + (String) parts.get(0) + "'");
+        }
+
+        MacroTemplateNode macro = (MacroTemplateNode) definitions.get(parts.get(1));
+
+        macro.process(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
+      }
+      else {
+        aDestination.append(prefix);
+
+        childNode.process(aParser, aContext, aDestination, aLogger, aTemplateContext, aLibrary);
+        aDestination.append(suffix);
+      }
+    }
+
+    public String getPlainText() {
+      return childNode.getPlainText();
+    }
+  }
+}