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ülcü
</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 "<b>"
element nested with a "<a>" element but not a "<c>"
element even if nested within "<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 <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ülcü
*
*/
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]