ceki        2003/08/25 08:37:19

  Added:       src/java/org/apache/joran JoranParser.java RuleStore.java
                        joran-specs.html Context.java SimpleRuleStore.java
                        Rule.java Action.java Pattern.java
  Log:
  
  Initial commit for joran configurator.
  
  JoranConfigurator is similar to digester in design. It behaves like 
   DOMConfigurator except that it can learn new tricks.
  
  Revision  Changes    Path
  1.1                  jakarta-log4j/src/java/org/apache/joran/JoranParser.java
  
  Index: JoranParser.java
  ===================================================================
  package org.apache.joran;
  
  import java.util.Iterator;
  import java.util.List;
  
  import org.w3c.dom.Document;
  import org.w3c.dom.Element;
  import org.w3c.dom.Node;
  
  public class JoranParser {
  
        private RuleStore ruleStore;
  
        JoranParser(RuleStore rs) {
                ruleStore = rs;
        }
  
        public void parse(Document document) {
  
                Pattern pattern = new Pattern();
                Element e = document.getDocumentElement();
                loop(e, pattern);
        }
  
        void loop(Node n, Pattern pattern) {
                if (n == null) {
                        return;
                }
  
                try {
                        pattern.push(n.getNodeName());
                        if (n instanceof Element) {
                                System.out.println("pattern is " + pattern);
                        }
  
                        List applicableActionList = ruleStore.matchActions(pattern);
  
                        if(applicableActionList != null) {
                         callBeginAction(applicableActionList, n);
                        }
                        
                        if (n.hasChildNodes()) {
                                for (Node c = n.getFirstChild();
                                        c != null;
                                        c = c.getNextSibling()) {
                                        loop(c, pattern);
                                }
                        }
                        if(applicableActionList != null) {
                          callEndAction(n);
                        }
                } finally {
                        pattern.pop();
                }
        }
  
        void callBeginAction(List applicableActionList, Node n) {
                if(applicableActionList == null) {
                  return;
                }
                
                short type = n.getNodeType();
  
                if(type != Node.ELEMENT_NODE) {
                        return;
                }
  
                Element e = (Element) n;
                String localName = n.getNodeName();
        System.out.println("New node: <" + localName + ">");
                System.out.println("  node is an element");
                System.out.println(
                                "  element attribs: " + e.getAttributes());
      
                Iterator i = applicableActionList.iterator();
  
                while (i.hasNext()) {
                        Action action = (Action) i.next();
                        action.begin(e);
                }
        }
  
        void callEndAction(Node n) {
        }
  
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/joran/RuleStore.java
  
  Index: RuleStore.java
  ===================================================================
  package org.apache.joran;
  
  import java.util.List;
  
  public interface RuleStore {
  
    public void addRule(Pattern pattern, Action action);
    
    public List matchActions(Pattern pattern);
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/joran/joran-specs.html
  
  Index: joran-specs.html
  ===================================================================
  
  <html>
  
    <head>
      <title>Project specifications</title>
    </head>
    
    <body>
      
      <center>
        <h1>Project specifications</h1>
        Ceki G&uuml;lc&uuml;
      </center>
      
      <p>The projects takes its name from a cold north-west wind that
        occasionally but forcefully blows on the Leman lake.
      </p>
      
        
      <p>The joran project will implement a generic XML-based
      configuration tool for the Java platform. 
      </p>
  
      <h2>Introduction</h2>
  
      <p>One of the most powerful features of the Java language is
        reflection. Using reflection makes it possible to configure
        software systems declaratively. For example, many important
        properfies of a EJB are configured with the ejb.xml file. While
        EJBs are written in Java many of their properties are specified
        within the ejb.xml file. Similarly, the log4j logging settings
        are specified in a configuration file which can be expressed in
        key=properties format or in XML.
      </p>
  
      <p>The DOMConfigurator that ships with log4j can parse
        configuration files written in XML. The DOMConfigurator is
        written in Java such that each time the structure of the
        configuration file changes the DOMConfigurator must be tweaked
        accordingly and the resulting code must be recompiled and
        redeployed. Just as importantly, the code of the DOMConfigurator
        consists of a bunch of loops on children of elements with many
        interspread if/else statemets. One can't help but notice that
        the code reeks of redundancy.
      </p>
  
      <p>The <a
        href="http://jakarta.apache.org/commons/digester.html";>digester
        project</a> has shown that it is possible to parse XML files
        using pattern matching rules. At parse time, digester will apply
        the rules that match previously stated patterns. Rule classes
        are usually quite small and specialized. Consequently, they are
        easy to understand and maintain.
      </p>
  
      <p>I find the the commons-digester terminology somewhat
       confusing. In commons-digester a rule can be seen as consisting
       of a pattern and a rule, as shown by the <a
       
href="http://jakarta.apache.org/commons/digester/api/org/apache/commons/digester/Digester.html#addRule(java.lang.String,%20org.apache.commons.digester.Rule)">Digester.addRule(java.lang.String
       pattern, Rule rule)</a> method. In commons-joran, a rule consists
       of a pattern and an action. An action is invoked when a match
       occurs for the corresponding pattern.
      </p>
  
      <p>Quite remarkably, one can deal with quite complex situations by
        using simple patterns, that is exact matches and wilcard
        matches. For example, the pattern a/b will match a "&lt;b>"
        element nested with a "&lt;a>" element but not a "&lt;c>"
        element even if nested within "&lt;b>". It is also possible to
        match a particular XML element, regardless of its nesting, by
        using the "*" wildcard character. For example, an element
        matching pattern of "*/a" will match an &lt;a> element at any
        nesting position within the document. Other types of patterns,
        for example, "a/*" were not supported by earlier versions of
        commons-digester.
      </p>
  
      <h3>Relations between elements</h3>
  
      <p>Due to the event-based artchitecture of the SAX API, a tool
        based on SAX cannot easily deal with forward references, that is
        references to elements which are defined later than the current
        element being processed. Elements with cyclical references are
        equally problematic. Another restriction of the SAX API is that
        the element being processed cannot directly access its children
        (elements nested within itself). This precludes actions that
        process nested elements using implicit rules. For example,
        jakarta-ant will process nested elements within a task by
        studying addXXX methods of the task class. This type of implicit
        processing cannot be performed using the SAX API.
      </p>
      
      <h2>Goals</h2>
      
      <p>A <em>flexible</em> XML processing API based on possibly
      dynamic rules. Support for implicit rules, similar to the addXXX
      methods of jakarta-ant, will also be seriously considered.
      </p>
  
      <h2>Non goals</h2>
      
      <p>The Joran API is not intended to be used to parse documents
        with thousands of elements.
      </p>
  
    </body> 
  </html>
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/joran/Context.java
  
  Index: Context.java
  ===================================================================
  /*
   * Created on Aug 23, 2003
   *
   * To change the template for this generated file go to
   * Window>Preferences>Java>Code Generation>Code and Comments
   */
  package org.apache.joran;
  
  import java.util.Stack;
  
  
  /**
   * 
   * Joran is designed to parse DOM trees
   * 
   */
  public class Context {
  
        Stack objectStack;
    Stack ipStack;
  
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/joran/SimpleRuleStore.java
  
  Index: SimpleRuleStore.java
  ===================================================================
  package org.apache.joran;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  
  public class SimpleRuleStore implements RuleStore {
  
    HashMap rules = new HashMap();
    
        public void addRule(Pattern pattern, Action action) {
  
                //System.out.println("pattern to add is:" + pattern + "hashcode:" + 
pattern.hashCode());
       List a4p = (List) rules.get(pattern);
       
       if(a4p == null) {
        a4p = new ArrayList();
                  rules.put(pattern, a4p);
       }
       a4p.add(action);
        }
  
        public List matchActions(Pattern pattern) {
        
                //System.out.println("pattern to search for:" + pattern + ", hashcode: 
" + pattern.hashCode());
                //System.out.println("rules:" + rules);
                
                ArrayList a4p = (ArrayList) rules.get(pattern);
         
          if(a4p != null) {
                return  a4p;
          } else {
                
                  Iterator patternsIterator = rules.keySet().iterator();
                  int max = 0;
                  Pattern longestMatch = null;
                  while(patternsIterator.hasNext()) {
                        Pattern p = (Pattern)  patternsIterator.next();
                        if((p.size() > 1) && p.get(0).equals("*")) {
                          int r = pattern.tailMatch(p);
                          //System.out.println("tailMatch " +r);
                          if(r > max) {
                                //System.out.println("New longest match "+p);
                                max = r;
                                longestMatch = p;
                          }
                        }
                  }
                  
                  if(longestMatch != null) {
                    return (ArrayList) rules.get(longestMatch);
                  } else {
                        return null;
                  }
          }
        
        }
  
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/joran/Rule.java
  
  Index: Rule.java
  ===================================================================
  /*
   * Created on Aug 23, 2003
   *
   * To change the template for this generated file go to
   * Window>Preferences>Java>Code Generation>Code and Comments
   */
  package org.apache.joran;
  
  /**
   * @author ceki
   *
   * To change the template for this generated type comment go to
   * Window>Preferences>Java>Code Generation>Code and Comments
   */
  public class Rule {
  
    Pattern pattern;
    Action action;
    
    Rule(Pattern p, Action a) {
        pattern = p;
        action = a;
    }
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/joran/Action.java
  
  Index: Action.java
  ===================================================================
  /*
   * ============================================================================
   *                   The Apache Software License, Version 1.1
   * ============================================================================
   *
   *    Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modifica-
   * tion, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of  source code must  retain the above copyright  notice,
   *    this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   *
   * 3. The end-user documentation included with the redistribution, if any, must
   *    include  the following  acknowledgment:  "This product includes  software
   *    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
   *    Alternately, this  acknowledgment may  appear in the software itself,  if
   *    and wherever such third-party acknowledgments normally appear.
   *
   * 4. The names "log4j" and  "Apache Software Foundation"  must not be used to
   *    endorse  or promote  products derived  from this  software without  prior
   *    written permission. For written permission, please contact
   *    [EMAIL PROTECTED]
   *
   * 5. Products  derived from this software may not  be called "Apache", nor may
   *    "Apache" appear  in their name,  without prior written permission  of the
   *    Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   * FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   * APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   * DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   * OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   * ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   * (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * This software  consists of voluntary contributions made  by many individuals
   * on  behalf of the Apache Software  Foundation.  For more  information on the
   * Apache Software Foundation, please see <http://www.apache.org/>.
   *
   */
  
  package org.apache.joran;
  
  import org.w3c.dom.Element;
  
  
  /**
   *
   * Most of the work for configuring log4j is done by Actions.
   *
   * Methods of an Action are invoked while an XML file is parsed through.
   *
   * This class is largely copied from the relevant class in the commons-digester
   * project of the Apache Software Foundation.
   *
   * @author Craig McClanahan
   * @authro Christopher Lenz 
   * @author Ceki G&uuml;lc&uuml;
   *
   */
  public abstract class Action {
        
        
    public abstract void begin(Element e);
    public abstract void end(Element e);
    public abstract void finish();
  }
  
  
  
  1.1                  jakarta-log4j/src/java/org/apache/joran/Pattern.java
  
  Index: Pattern.java
  ===================================================================
  package org.apache.joran;
  
  import java.util.ArrayList;
  
  public class Pattern {
  
        //String patternStr;
        ArrayList components;
        
        public Pattern() {
                components = new ArrayList();
        }
  
        Pattern(String p) {
                this();
        
          if(p == null) {
            return;
          }     
                
                int lastIndex = 0;
                //System.out.println("p is "+ p);
                while(true) {
                        int k = p.indexOf('/', lastIndex);
                        //System.out.println("k is "+ k);
                        if(k == -1) {
                          components.add(p.substring(lastIndex));
                          break;
                        } else {
                                String c = p.substring(lastIndex, k);
                                if(c.length() > 0) {
                                 components.add(c);
                                }
                                lastIndex = k+1;
                        }
                }
                
                //System.out.println(components);
        }
  
        void push(String s) {
                components.add(s);
        }
  
    public int size() {
      return components.size(); 
    }
  
    public String get(int i) {
          return (String) components.get(i);    
    }
  
        void pop() {
                if (!components.isEmpty()) {
                        components.remove(components.size() - 1);
                }
        }
  
    /**
     * Returns the number of "tail" components that this pattern has in common 
     * with the pattern p passed as parameter. By "tail" components we mean the
     * components at the end of the pattern.
     */
    public int tailMatch(Pattern p) {
        if(p == null) {
                return 0;
      }
      
        int lSize = this.components.size();
        int rSize = p.components.size();
  
      // no match possible for empty sets
        if(lSize == 0 || rSize == 0) {
                return 0;
        }
        
        int minLen = lSize <= rSize ? lSize : rSize;
        int match = 0;
        // loop from the end to the front
        for(int i = 1; i <= minLen; i++) {
                String l = (String) this.components.get(lSize-i);
                String r = (String) p.components.get(rSize-i);
                if(l.equals(r)) {
                  match++;
                } else {
                        break;
                }
        }
        return match;
    }
    
    public boolean equals(Object o) {
          //System.out.println("in equals:" +this+ " vs. " + o);
        if((o == null) || !(o instanceof Pattern)) {
          return false;
        }
        
          //System.out.println("both are Patterns");
        Pattern r = (Pattern) o;
        
        if(r.size() != size()) {
          return false;
        }
        
          //System.out.println("both are size compatible");
        int len = size();
        
        for(int i = 0; i <len; i++) {
          if(!(get(i).equals(r.get(i)))) {
            return false;
          }
        }
        
        // if everything matches, then the twp patterns are equal
        return true;
    }
    
    public int hashCode() {
        int hc = 0;
        int len = size();
        for(int i = 0; i < len; i++) {
          hc ^=  get(i).hashCode();
            //System.out.println("i = "+i+", hc="+hc);
        }
        return hc;
    }
    
    
    public String toString() {
        return components.toString();
    }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to