You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sk...@apache.org on 2005/02/04 02:51:54 UTC
svn commit: r151287 [2/7] - in
jakarta/commons/proper/digester/branches/digester2: ./ src/ src/conf/
src/examples/ src/examples/api/ src/examples/api/addressbook/ src/java/
src/java/org/ src/java/org/apache/ src/java/org/apache/commons/
src/java/org/apache/commons/digester2/
src/java/org/apache/commons/digester2/actions/
src/java/org/apache/commons/digester2/factory/ src/media/ src/test/
src/test/org/ src/test/org/apache/ src/test/org/apache/commons/
src/test/org/apache/commons/digester2/ xdocs/ xdocs/dtds/ xdocs/images/
xdocs/style/
Added: jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/build.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/build.xml?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/build.xml (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/build.xml Thu Feb 3 17:51:43 2005
@@ -0,0 +1,127 @@
+<!--
+ Copyright 2004 The Apache Software Foundation.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<project name="Example-AddressBook" default="compile" basedir=".">
+
+
+<!-- ========== Initialize Properties ===================================== -->
+
+
+ <property file="build.properties"/> <!-- Component local -->
+ <property file="../build.properties"/> <!-- examples/api local-->
+ <property file="../../../../build.properties"/> <!-- Digester local -->
+ <property file="../../../../../build.properties"/> <!-- Commons local -->
+ <property file="${user.home}/build.properties"/> <!-- User local -->
+
+
+<!-- ========== External Dependencies ===================================== -->
+
+
+ <!-- The directories corresponding to your necessary dependencies -->
+ <property name="jaxp.home" value="/usr/local/jaxp1.1"/>
+ <property name="commons.home" value="../../../../.."/>
+ <property name="beanutils.home" value="${commons.home}/beanutils"/>
+ <property name="collections.home" value="${commons.home}/collections"/>
+ <property name="logging.home" value="${commons.home}/logging"/>
+ <property name="digester.home" value="${commons.home}/digester"/>
+
+
+<!-- ========== Derived Values ============================================ -->
+
+
+ <!-- The locations of necessary jar files -->
+ <property name="jaxp.jaxp.jar" value="${jaxp.home}/jaxp.jar"/>
+ <property name="jaxp.parser.jar" value="${jaxp.home}/crimson.jar"/>
+ <property name="commons-beanutils.jar" value="${beanutils.home}/dist/commons-beanutils.jar"/>
+ <property name="commons-collections.jar" value="${collections.home}/dist/commons-collections.jar"/>
+ <property name="commons-logging.jar" value="${logging.home}/dist/commons-logging.jar"/>
+ <property name="commons-digester.jar" value="${digester.home}/dist/commons-digester.jar"/>
+
+
+<!-- ========== Component Declarations ==================================== -->
+
+ <!-- The name of this component -->
+ <property name="component.name" value="addressbook"/>
+
+
+<!-- ========== Compiler Defaults ========================================= -->
+
+ <!-- Should Java compilations set the 'debug' compiler option? -->
+ <property name="compile.debug" value="true"/>
+
+ <!-- Should Java compilations set the 'deprecation' compiler option? -->
+ <property name="compile.deprecation" value="false"/>
+
+ <!-- Should Java compilations set the 'optimize' compiler option? -->
+ <property name="compile.optimize" value="true"/>
+
+ <!-- Construct compile classpath -->
+ <path id="compile.classpath">
+ <pathelement location="."/>
+ <pathelement location="${jaxp.jaxp.jar}"/>
+ <pathelement location="${jaxp.parser.jar}"/>
+ <pathelement location="${commons-beanutils.jar}"/>
+ <pathelement location="${commons-collections.jar}"/>
+ <pathelement location="${commons-logging.jar}"/>
+ <pathelement location="${commons-digester.jar}"/>
+ <pathelement location="${log4j.jar}"/>
+ </path>
+
+
+<!-- ========== Executable Targets ======================================== -->
+
+
+ <target name="compile">
+ <javac srcdir="."
+ destdir="."
+ debug="${compile.debug}"
+ deprecation="${compile.deprecation}"
+ optimize="${compile.optimize}">
+ <classpath refid="compile.classpath"/>
+ </javac>
+ </target>
+
+
+ <target name="clean">
+ <delete>
+ <fileset dir="." includes="*.class"/>
+ </delete>
+ <delete dir="docs"/>
+ </target>
+
+ <target name="all" depends="clean,compile"/>
+
+ <target name="javadoc" depends="compile">
+ <mkdir dir="docs"/>
+ <javadoc destdir="docs"
+ author="true"
+ private="true"
+ version="true">
+ <classpath refid="compile.classpath"/>
+ <fileset dir="." includes="*.java"/>
+ </javadoc>
+ </target>
+
+ <target name="run" depends="compile">
+ <java classname="Main" fork="yes">
+ <arg value="example.xml"/>
+ <classpath refid="compile.classpath"/>
+ <classpath>
+ <pathelement location="."/>
+ </classpath>
+ </java>
+ </target>
+</project>
Added: jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/example.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/example.xml?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/example.xml (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/example.xml Thu Feb 3 17:51:43 2005
@@ -0,0 +1,29 @@
+<!--
+ Copyright 2004 The Apache Software Foundation.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<address-book>
+ <person id="1" category="acquaintance">
+ <name>Gonzo</name>
+ <email type="business">gonzo@muppets.com</email>
+ </person>
+
+ <person id="2" category="rolemodel">
+ <name>Kermit</name>
+ <email type="business">kermit@muppets.com</email>
+ <email type="home">kermie@acme.com</email>
+ </person>
+
+</address-book>
\ No newline at end of file
Added: jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/log4j.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/log4j.xml?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/log4j.xml (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/log4j.xml Thu Feb 3 17:51:43 2005
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration>
+ <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern"
+ value="aa:%p#%d#%c#%m%n"/>
+ </layout>
+ </appender>
+
+ <category name="org.apache.log4j.xml">
+ <priority value="INFO" />
+ </category>
+
+ <root>
+ <priority value = "DEBUG2"/>
+ <appender-ref ref="STDOUT" />
+ </root>
+</log4j:configuration>
+
Added: jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/readme.txt
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/readme.txt?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/readme.txt (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/examples/api/addressbook/readme.txt Thu Feb 3 17:51:43 2005
@@ -0,0 +1,49 @@
+#########################################################################
+# Copyright 2004 The Apache Software Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#########################################################################
+
+== overview
+
+The files in this directory are intended as an example of how to use
+the Apache Digester's basic functionality via its java interface.
+
+Topics covered:
+* how to create a digester instance
+* how to parse a file
+* how to use the "object create" rule to create java objects
+* how to use the "set properties" rule (basic usage) to map xml attributes
+ to java bean properties.
+* how to use the "set next" rule to build trees of java objects.
+* how to use the "call method rule" (basic usage)
+* how to use the "call parameter rule" to process the text contained
+ in a tag's body
+* how to use the "call parameter rule" to process the contents of an
+ xml attribute.
+
+== compiling and running
+
+First rename the build.properties.sample file in the parent directory
+to build.properties and edit it to suit your environment. Then in this
+directory:
+
+* to compile:
+ ant compile
+
+* to run:
+ ant run
+
+Alternatively, you can set up your CLASSPATH appropriately, and
+run the example directly. See the build.properties and build.xml
+files for details.
Added: jakarta/commons/proper/digester/branches/digester2/src/examples/api/build.properties
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/examples/api/build.properties?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/examples/api/build.properties (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/examples/api/build.properties Thu Feb 3 17:51:43 2005
@@ -0,0 +1,33 @@
+#####################################################
+# Copyright 2004 The Apache Software Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+####################################################
+
+#
+# Example build properties
+#
+# Copy this to build.properties and then edit the properties to
+# provide local references.
+#
+
+
+myjars=/home/simon/jar
+
+commons-beanutils.jar=${myjars}/commons-beanutils.jar
+commons-collections.jar=${myjars}/commons-collections.jar
+commons-logging.jar=${myjars}/commons-logging.jar
+commons-digester.jar=/home/simon/digester2/target/commons-digester-1.6.jar
+log4j.jar=${myjars}/log4j.jar
+
+
Added: jakarta/commons/proper/digester/branches/digester2/src/examples/api/build.xml
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/examples/api/build.xml?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/examples/api/build.xml (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/examples/api/build.xml Thu Feb 3 17:51:43 2005
@@ -0,0 +1,98 @@
+<!--
+ Copyright 2004 The Apache Software Foundation.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!--
+*******************************************************
+API Examples Script
+===================
+Provides helpful services to get folks up and running
+the examples quickly.
+
+* Compile - compiles all the examples to the directories
+in which the their source files reside.
+
+* Run - runs each example in turn.
+
+Note:
+These examples will only build and run if the
+rights jars are in the classpath. The classpath
+can be set by copying the build.properties.sample file
+in this directory to build.properties and then setting
+the properties appropriately. Or by editing the
+build.properties file (based on the build.properties.sample
+file in CVS) so that it contains absolute paths.
+
+Note:
+build.xml files are provided in each subdirectory. This
+provide similar fuctionality for each example individually.
+
+Note:
+The examples are graduated. It is best to look at them
+in order. Please consult the documentation for more details.
+
+*******************************************************
+-->
+<project name="Examples" default="about" basedir=".">
+
+ <target name='about'>
+ <echo>
+*******************************************************
+API Examples Script
+===================
+Provides helpful services to get folks up and running
+the examples quickly.
+
+* Compile - compiles all the examples to the directories
+in which the their source files reside.
+
+* Run - runs each example in turn.
+
+Note:
+These examples will only build and run if the
+rights jars are in the classpath. The classpath
+can be set by copying the build.properties.sample file
+in this directory to build.properties and then setting
+the properties appropriately. Or by editing the
+build.properties file (based on the build.properties.sample
+file in CVS) so that it contains absolute paths.
+
+Note:
+build.xml files are provided in each subdirectory. This
+provide similar fuctionality for each example individually.
+
+Note:
+The examples are graduated. It is best to look at them
+in order. Please consult the documentation for more details.
+
+*******************************************************
+ </echo>
+ </target>
+
+ <target name="compile">
+ <ant dir="addressbook" target="compile"/>
+ <ant dir="catalog" target="compile"/>
+ </target>
+
+ <target name="run" depends="compile">
+ <ant dir="addressbook" target="compile"/>
+ <ant dir="catalog" target="compile"/>
+ </target>
+
+ <target name="clean">
+ <ant dir="addressbook" target="clean"/>
+ <ant dir="catalog" target="clean"/>
+ </target>
+
+</project>
Added: jakarta/commons/proper/digester/branches/digester2/src/examples/api/readme.txt
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/examples/api/readme.txt?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/examples/api/readme.txt (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/examples/api/readme.txt Thu Feb 3 17:51:43 2005
@@ -0,0 +1,32 @@
+#########################################################################
+# Copyright 2004 The Apache Software Foundation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#########################################################################
+
+The subdirectories of this directory provide examples of how to use
+the Apache Digester's java API.
+
+With the API approach, java code is used to configure the digester with
+a set of rules to execute when xml is processed. It is these rules that
+determine how the input xml is mapped into a tree of java objects.
+
+An alternative is to use the "xmlrules" digester extension, which allows
+the digester rules to be configured via an xml file. This allows the
+mapping between input xml and java objects to be modified without
+recompilation of any source code.
+
+The examples are graduated in the following order:
+
+1. addressbook
+2. catalog
\ No newline at end of file
Added: jakarta/commons/proper/digester/branches/digester2/src/examples/readme.txt
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/examples/readme.txt?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/examples/readme.txt (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/examples/readme.txt Thu Feb 3 17:51:43 2005
@@ -0,0 +1,10 @@
+The subdirectories of this directory divide the examples into topics.
+
+The examples in API deal with the main Digester API.
+
+The xmlrules directory deals with the xmlrules extension which allows
+the digester rules to be configured via an xml file. This allows the
+mapping between input xml and java objects to be modified without
+recompilation of any source code.
+
+
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/AbstractAction.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/AbstractAction.java?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/AbstractAction.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/AbstractAction.java Thu Feb 3 17:51:43 2005
@@ -0,0 +1,129 @@
+/* $Id: $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.digester2;
+
+import org.xml.sax.Attributes;
+
+/**
+ * Provides a base implementation for custom actions (ie things that
+ * should be executed when certain input xml is seen).
+ * <p>
+ * Note that extending this abstract class rather than directly implementing
+ * the Action interface provides much better "forward compatibility". Digester
+ * minor releases (2.x -> 2.y) guarantee not to break any classes that subclass
+ * this abstract class. However no such guarantee exists for classes that
+ * directly implement the Action interface.
+ * <p>
+ * You <strong>must</strong> read the comments on the Action interface before
+ * implementing any subclass of this class, as there are constraints on the
+ * permitted behaviour of Action classes.
+ */
+
+public abstract class AbstractAction implements Action {
+
+ /**
+ * This method is called once at the start of parsing of an input
+ * document. The context object is the one that will be used during
+ * the parsing of this document.
+ */
+ public void startParse(Context context)
+ throws ParseException {
+ }
+
+ /**
+ * This method is called when the beginning of a matching XML element
+ * is encountered.
+ *
+ * @param context is the current processing context object.
+ * @param namespace the namespace URI of the matching element, or an
+ * empty string if the element has no namespace
+ * @param name the local name of the element
+ * @param attributes The attribute list of this element
+ */
+ public void begin(Context context, String namespace, String name, Attributes attributes)
+ throws ParseException {
+ }
+
+ /**
+ * This method is called when the body of a matching XML element is
+ * encountered. If the element has no body, this method is not called at
+ * all.
+ * <p>
+ * Note that if the element has multiple pieces of body text separated by
+ * child elements (ie is "mixed content") then this method is called once
+ * for each separate block of text, at the point that the child element
+ * is encountered. In each call, only the text since the last call to this
+ * method (ie since the last nested child element) is passed.
+ * <p>
+ * In the case of an element with just text content (no child elements),
+ * this method is exactly equivalent to the body method; either can be
+ * overridden to perform the necessary work.
+ *
+ * @param context is the current processing context object.
+ * @param namespace the namespace URI of the matching element, or an
+ * empty string if the element has no namespace
+ * @param name the local name of the element.
+ * @param text The text of the body of this element
+ */
+ public void bodySegment(Context context, String namespace, String name, String text)
+ throws ParseException {
+ }
+
+ /**
+ * This method is called when the body of a matching XML element is
+ * encountered. If the element has no body, this method is not called at
+ * all.
+ * <p>
+ * Note that if the element has multiple pieces of body text separated by
+ * child elements (ie is "mixed content") then all the text is merged
+ * into a single string and this method is called only once with the
+ * complete text as a parameter.
+ *
+ * @param context is the current processing context object.
+ * @param namespace the namespace URI of the matching element, or an
+ * empty string if the element has no namespace
+ * @param name the local name of the element.
+ * @param text The text of the body of this element
+ */
+ public void body(Context context, String namespace, String name, String text)
+ throws ParseException {
+ }
+
+ /**
+ * This method is called when the end of a matching XML element
+ * is encountered.
+ *
+ * @param context is the current processing context object.
+ * @param namespace the namespace URI of the matching element, or an
+ * empty string if the element has no namespace
+ * @param name the local name of the element.
+ */
+ public void end(Context context, String namespace, String name)
+ throws ParseException {
+ }
+
+ /**
+ * This method is called after all parsing methods have been
+ * called, to allow Actions to remove temporary data.
+ *
+ * @param context is the current processing context object.
+ */
+ public void finishParse(Context context)
+ throws ParseException {
+ }
+}
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Action.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Action.java?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Action.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Action.java Thu Feb 3 17:51:43 2005
@@ -0,0 +1,139 @@
+/* $Id: $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.digester2;
+
+import org.xml.sax.Attributes;
+
+/**
+ * Defines the interface required of classes which implement actions to be
+ * taken when a corresponding nested pattern of XML elements has been matched.
+ * <p>
+ * Classes implementing the Action interface <i>must</i> not alter any instance
+ * variables during parsing (ie from the init/begin/body/end/finish methods).
+ * All necessary state-related data <i>must</i> be stored instead on the Context
+ * object passed as a parameter to each parsing-related method.
+ * <p>
+ * An Action instance may be added to the same RuleManager more than once, with
+ * different associated patterns, or the pattern may include wildcards; either
+ * of these situations may cause the rule to be invoked in a "re-entrant"
+ * manner, where the pattern of calls is like:
+ * <pre>
+ * begin[1]/begin[2]/body[2]/end[2]/body[1]/end[1]
+ * </pre>
+ * This obviously will cause errors if the Action object stores state on itself.
+ * <p>
+ * In addition, an Action object may be added to different Digester instances,
+ * which potentially are parsing different documents concurrently in
+ * different threads. Again, storing state on the Action instance itself will
+ * cause problems in these situations.
+ * <p>
+ * <strong>IMPORTANT NOTE</strong>: Anyone implementing a custom Action is
+ * strongly encouraged to subclass AbstractAction rather than implement this
+ * interface directly. Digester minor releases (2.x -> 2.y) guarantee that
+ * subclasses of AbstractAction will not be broken. However the Action
+ * interface <i>may</i> change in minor releases, which will break any class
+ * which implements this interface directly.
+ */
+
+public interface Action {
+
+ /**
+ * This method is called once at the start of parsing of an input
+ * document. The context object is the one that will be used during
+ * the parsing of this document.
+ */
+ public void startParse(Context context) throws ParseException;
+
+ /**
+ * This method is called when the beginning of a matching XML element
+ * is encountered.
+ *
+ * @param context is the current processing context object.
+ * @param namespace the namespace URI of the matching element, or an
+ * empty string if the element has no namespace
+ * @param name the local name of the element
+ * @param attributes The attribute list of this element
+ */
+ public void begin(
+ Context context, String namespace,
+ String name, Attributes attributes)
+ throws ParseException;
+
+ /**
+ * This method is called when the body of a matching XML element is
+ * encountered. If the element has no body, this method is not called at
+ * all.
+ * <p>
+ * Note that if the element has multiple pieces of body text separated by
+ * child elements (ie is "mixed content") then this method is called once
+ * for each separate block of text, at the point that the child element
+ * is encountered. In each call, only the text since the last call to this
+ * method is passed.
+ * <p>
+ * In the case of an element with just text content (no child elements),
+ * this method is exactly equivalent to the body method; either can be
+ * overridden to perform the necessary work.
+ *
+ * @param context is the current processing context object.
+ * @param namespace the namespace URI of the matching element, or an
+ * empty string if the element has no namespace
+ * @param name the local name of the element.
+ * @param text The text of the body of this element
+ */
+ public void bodySegment(Context context, String namespace, String name, String text)
+ throws ParseException;
+
+ /**
+ * This method is called when the body of a matching XML element is
+ * encountered. If the element has no body, this method is not called at
+ * all.
+ * <p>
+ * Note that if the element has multiple pieces of body text separated by
+ * child elements (ie is "mixed content") then all the text is merged
+ * into a single string and this method is called only once with the
+ * complete text as a parameter.
+ *
+ * @param context is the current processing context object.
+ * @param namespace the namespace URI of the matching element, or an
+ * empty string if the element has no namespace
+ * @param name the local name of the element.
+ * @param text The text of the body of this element
+ */
+ public void body(Context context, String namespace, String name, String text)
+ throws ParseException;
+
+ /**
+ * This method is called when the end of a matching XML element
+ * is encountered.
+ *
+ * @param context is the current processing context object.
+ * @param namespace the namespace URI of the matching element, or an
+ * empty string if the element has no namespace
+ * @param name the local name of the element.
+ */
+ public void end(Context context, String namespace, String name)
+ throws ParseException;
+
+ /**
+ * This method is called after all parsing methods have been
+ * called, to allow Actions to remove temporary data.
+ *
+ * @param context is the current processing context object.
+ */
+ public void finishParse(Context context) throws ParseException;
+}
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/ArrayStack.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/ArrayStack.java?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/ArrayStack.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/ArrayStack.java Thu Feb 3 17:51:43 2005
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.digester2;
+
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+
+/**
+ * An implementation of the {@link java.util.Stack} API that is based on an
+ * <code>ArrayList</code> instead of a <code>Vector</code>, so it is not
+ * synchronized to protect against multi-threaded access. The implementation
+ * is therefore operates faster in environments where you do not need to
+ * worry about multiple thread contention.
+ * <p>
+ * The removal order of an <code>ArrayStack</code> is based on insertion
+ * order: The most recently added element is removed first. The iteration
+ * order is <i>not</i> the same as the removal order. The iterator returns
+ * elements from the bottom up, whereas the inherited ArrayList.remove() method
+ * removes them from the top down.
+ * <p>
+ * Unlike <code>Stack</code>, <code>ArrayStack</code> accepts null entries.
+ * <p>
+ * This code is copied from the Apache Jakarta Commons collections library,
+ * version 3.1, with minor modifications.
+ *
+ * @see java.util.Stack
+ * @since Commons Collections 1.0
+ * @version $Revision: 1.17 $ $Date: 2004/02/18 01:15:42 $
+ *
+ * @author Craig R. McClanahan
+ * @author Paul Jack
+ * @author Stephen Colebourne
+ */
+public class ArrayStack extends ArrayList {
+
+ /** Ensure serialization compatibility */
+ private static final long serialVersionUID = 2130079159931574599L;
+
+ /**
+ * Constructs a new empty <code>ArrayStack</code>. The initial size
+ * is controlled by <code>ArrayList</code> and is currently 10.
+ */
+ public ArrayStack() {
+ super();
+ }
+
+ /**
+ * Constructs a new empty <code>ArrayStack</code> with an initial size.
+ *
+ * @param initialSize the initial size to use
+ * @throws IllegalArgumentException if the specified initial size
+ * is negative
+ */
+ public ArrayStack(int initialSize) {
+ super(initialSize);
+ }
+
+ /**
+ * Return <code>true</code> if this stack is currently empty.
+ * <p>
+ * This method exists for compatibility with <code>java.util.Stack</code>.
+ * New users of this class should use <code>isEmpty</code> instead.
+ *
+ * @return true if the stack is currently empty
+ */
+ public boolean empty() {
+ return isEmpty();
+ }
+
+ /**
+ * Returns the top item off of this stack without removing it.
+ *
+ * @return the top item on the stack
+ * @throws EmptyStackException if the stack is empty
+ */
+ public Object peek() throws EmptyStackException {
+ int n = size();
+ if (n <= 0) {
+ throw new EmptyStackException();
+ } else {
+ return get(n - 1);
+ }
+ }
+
+ /**
+ * Returns the n'th item down (zero-relative) from the top of this
+ * stack without removing it.
+ *
+ * @param n the number of items down to go
+ * @return the n'th item on the stack, zero relative
+ * @throws EmptyStackException if there are not enough items on the
+ * stack to satisfy this request
+ * @throws ArrayOutOfBoundsException if n is < 0
+ */
+ public Object peek(int n)
+ throws EmptyStackException, IndexOutOfBoundsException {
+ int m = (size() - n) - 1;
+ if (m < 0) {
+ throw new EmptyStackException();
+ } else {
+ return get(m);
+ }
+ }
+
+ /**
+ * Pops the top item off of this stack and return it.
+ *
+ * @return the top item on the stack
+ * @throws EmptyStackException if the stack is empty
+ */
+ public Object pop() throws EmptyStackException {
+ int n = size();
+ if (n <= 0) {
+ throw new EmptyStackException();
+ } else {
+ return remove(n - 1);
+ }
+ }
+
+ /**
+ * Pushes a new item onto the top of this stack. The pushed item is also
+ * returned. This is equivalent to calling <code>add</code>.
+ *
+ * @param item the item to be added
+ * @return the item just pushed
+ */
+ public Object push(Object item) {
+ add(item);
+ return item;
+ }
+
+ /**
+ * Returns the one-based position of the distance from the top that the
+ * specified object exists on this stack, where the top-most element is
+ * considered to be at distance <code>1</code>. If the object is not
+ * present on the stack, return <code>-1</code> instead. The
+ * <code>equals()</code> method is used to compare to the items
+ * in this stack.
+ *
+ * @param object the object to be searched for
+ * @return the 1-based depth into the stack of the object, or -1 if not found
+ */
+ public int search(Object object) {
+ int i = size() - 1; // Current index
+ int n = 1; // Current distance
+ while (i >= 0) {
+ Object current = get(i);
+ if ((object == null && current == null) ||
+ (object != null && object.equals(current))) {
+ return n;
+ }
+ i--;
+ n++;
+ }
+ return -1;
+ }
+}
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Context.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Context.java?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Context.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Context.java Thu Feb 3 17:51:43 2005
@@ -0,0 +1,477 @@
+/* $Id: $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.digester2;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.lang.reflect.InvocationTargetException;
+import java.util.EmptyStackException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.collections.ArrayStack;
+
+
+/**
+ * <p>Holds information that evolves as the parsing of an input xml document
+ * progresses. The Action objects regularly interact with this object when their
+ * various methods fire as a result of their associated patterns being matched
+ * by input data. </p>
+ *
+ * <p>A new Context object is created for each document parsed, to ensure that
+ * state left over from a previous parse does not affect later parses. It
+ * is the SAXHandler class that creates the Context instances.</p>
+ *
+ * <p>This class does not hold information that is directly related to
+ * handling sax parsing events.</p>
+ */
+
+public class Context {
+
+ // --------------------------------------------------------- Constructors
+
+ /**
+ * Construct a new Context.
+ */
+ public Context(SAXHandler saxHandler, Log log) {
+ this.saxHandler = saxHandler;
+ this.log = log;
+ }
+
+ // --------------------------------------------------- Instance Variables
+
+ /**
+ * The owner of this object.
+ */
+ private SAXHandler saxHandler = null;
+
+ /**
+ * An object through which log messages can be issued. Note that this
+ * is equivalent to saxHandler.getLogger(), and a direct reference is
+ * kept here only for performance.
+ */
+ private Log log;
+
+ /**
+ * The owner of the set of rules (pattern, action pairs).
+ */
+ private RuleManager ruleManager = null;
+
+ /**
+ * Stack whose elements are List objects, each containing a list of
+ * Action objects as returned from RuleManager.getMatchingActions().
+ * As each xml element in the input is entered, the list of matching
+ * actions is pushed onto this stack. After the end tag is reached, the
+ * matches are popped again. The depth of is stack is therefore exactly
+ * the same as the current "nesting" level of the input xml.
+ */
+ private ArrayStack matchedActionLists = new ArrayStack(10);
+
+ /**
+ * The path to the xml element for which Actions are currently being fired.
+ */
+ private Path currentElementPath = new Path();
+
+ /**
+ * The parameters stack being utilized by CallMethodAction and
+ * CallParamAction.
+ */
+ private ArrayStack params = new ArrayStack();
+
+ /**
+ * The object that forms the root of the tree of objects being
+ * created during a parse. Note that if setRoot has been called, then
+ * this is the same as looking at the bottom element on the object stack.
+ * However when an Action has created the root object, then the root should
+ * be acessable even after the parse is complete (at which time the stack
+ * will be empty).
+ */
+ private Object root;
+
+ /**
+ * The object stack being constructed.
+ */
+ private ArrayStack stack = new ArrayStack();
+
+ /**
+ * Stacks used by Action objects to store internal state.
+ * They can also be used for inter-action communication.
+ *
+ * By convention, Action instances use their class name as the key
+ * (or as a key prefix) to this map.
+ */
+ private HashMap stacksByName = new HashMap();
+
+ // ------------------------------------------------------------- Properties
+
+ /**
+ * Return the current Logger associated with this instance of the Digester
+ */
+ public Log getLogger() {
+ return log;
+ }
+
+ /**
+ * Return the path to the xml element currently being processed.
+ */
+ public String getMatchPath() {
+ return currentElementPath.getPath();
+ }
+
+ /**
+ * Enter a new element.
+ */
+ public String pushMatchPath(String namespace, String elementName) {
+ currentElementPath.push(namespace, elementName);
+ return currentElementPath.getPath();
+ }
+
+ /**
+ * Leave an element; restore the previous match path.
+ */
+ public String popMatchPath() {
+ currentElementPath.pop();
+ return currentElementPath.getPath();
+ }
+
+ public void pushMatchingActions(List actions) {
+ matchedActionLists.push(actions);
+ }
+
+ public List popMatchingActions() {
+ return (List) matchedActionLists.pop();
+ }
+
+ public List peekMatchingActions() {
+ return (List) matchedActionLists.peek();
+ }
+
+ public ClassLoader getClassLoader() {
+ return saxHandler.getClassLoader();
+ }
+
+ public SAXHandler getSAXHandler() {
+ return saxHandler;
+ }
+
+ // --------------------------------------------------- Object Stack Methods
+
+ /**
+ * The root object of the Object stack.
+ */
+ public void setRoot(Object o) {
+ stack.clear(); // just in case setRoot called multiple times
+ stack.push(o);
+ root = o;
+ }
+
+ /**
+ * <p>Is the object stack empty?</p>
+ *
+ * @return true if the object stack if empty
+ */
+ public boolean isEmpty() {
+ return stack.isEmpty();
+ }
+
+ /**
+ * Return the current depth of the object stack.
+ */
+ public int getStackSize() {
+ return stack.size();
+ }
+
+ /**
+ * Return the top object on the stack without removing it.
+ *
+ * @throws EmptyStackException (a RuntimeException subclass) if the stack
+ * is empty. Note that all the Digester.parse methods will turn this into
+ * a (checked) DigestionException.
+ */
+ public Object peek() throws EmptyStackException {
+ return stack.peek();
+ }
+
+ /**
+ * Return the n'th object down the stack, where 0 is the top element
+ * and [getStackSize()-1] is the bottom element.
+ *
+ * @param n Index of the desired element, where 0 is the top of the stack,
+ * 1 is the next element down, and so on.
+ *
+ * @throws EmptyStackException (a RuntimeException subclass) if the index
+ * is out-of-range. Note that all the Digester.parse methods will turn this
+ * into a (checked) DigestionException.
+ *
+ * @throws ArrayOutOfBoundsException (a RuntimeException subclass) if
+ * index < 0. Note that all the Digester.parse methods will turn this
+ * into a (checked) DigestionException.
+ */
+ public Object peek(int n)
+ throws EmptyStackException, IndexOutOfBoundsException {
+ return stack.peek(n);
+ }
+
+ /**
+ * Pop the top object off of the stack, and return it.
+ *
+ * @throws EmptyStackException (a RuntimeException subclass) if the stack
+ * is empty. Note that all the Digester.parse methods will turn this into
+ * a (checked) DigestionException.
+ */
+ public Object pop() throws EmptyStackException {
+ return stack.pop();
+ }
+
+ /**
+ * Push a new object onto the top of the object stack.
+ *
+ * @param object The new object
+ */
+ public void push(Object object) {
+ if (stack.isEmpty()) {
+ root = object;
+ }
+ stack.push(object);
+ }
+
+ /**
+ * <p>Is the stack with the given name empty?</p>
+ * <p><strong>Note:</strong> a stack is considered empty
+ * if no objects have been pushed onto it yet.</p>
+ *
+ * @param stackName the name of the stack whose emptiness
+ * should be evaluated
+ *
+ * @return true if the given stack if empty
+ */
+ public boolean isEmpty(String stackName) {
+ boolean result = true;
+ ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+ if (namedStack != null ) {
+ result = namedStack.isEmpty();
+ }
+ return result;
+ }
+
+ /**
+ * Return the current depth of the specified stack.
+ *
+ * @param stackName the name of the stack to be peeked
+ */
+ public int getStackSize(String stackName) {
+ boolean result = true;
+ ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+ if (namedStack != null ) {
+ return namedStack.size();
+ }
+ return 0;
+ }
+
+ /**
+ * <p>Gets the top object from the stack with the given name.
+ * This method does not remove the object from the stack.
+ * </p>
+ * <p><strong>Note:</strong> a stack is considered empty
+ * if no objects have been pushed onto it yet.</p>
+ *
+ * @param stackName the name of the stack to be peeked
+ * @return the top <code>Object</code> on the stack.
+ * @throws EmptyStackException if the named stack is empty
+ */
+ public Object peek(String stackName) throws EmptyStackException {
+ ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+ if (namedStack == null ) {
+ if (log.isDebugEnabled()) {
+ log.debug("Stack '" + stackName + "' is empty");
+ }
+ throw new EmptyStackException();
+ } else {
+ return namedStack.peek();
+ }
+ }
+
+ /**
+ * Returns an element from the stack with the given name. The element
+ * returned is the n'th object down the stack, where 0 is the top element
+ * and [getStackSize()-1] is the bottom element.
+ *
+ * <p><strong>Note:</strong> a stack is considered empty
+ * if no objects have been pushed onto it yet.</p>
+ *
+ * @param stackName the name of the stack to be peeked
+ *
+ * @param n Index of the desired element, where 0 is the top of the stack,
+ * 1 is the next element down, and so on.
+ *
+ * @throws EmptyStackException (a RuntimeException subclass) if the index
+ * is out-of-range. Note that all the Digester.parse methods will turn this
+ * into a (checked) DigestionException.
+ *
+ * @throws ArrayOutOfBoundsException (a RuntimeException subclass) if
+ * index < 0. Note that all the Digester.parse methods will turn this
+ * into a (checked) DigestionException.
+ */
+ public Object peek(String stackName, int n)
+ throws EmptyStackException, IndexOutOfBoundsException {
+ ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+ if (namedStack == null ) {
+ if (log.isDebugEnabled()) {
+ log.debug("Stack '" + stackName + "' is empty");
+ }
+ throw new EmptyStackException();
+ } else {
+ return namedStack.peek(n);
+ }
+ }
+
+ /**
+ * <p>Pops (gets and removes) the top object from the stack with the
+ * given name.</p>
+ *
+ * <p><strong>Note:</strong> a stack is considered empty
+ * if no objects have been pushed onto it yet.</p>
+ *
+ * @param stackName the name of the stack from which the top value is to
+ * be popped
+ *
+ * @return the top <code>Object</code> on the stack.
+ *
+ * @throws EmptyStackException if the named stack is empty, or has not
+ * yet been created.
+ */
+ public Object pop(String stackName) throws EmptyStackException {
+ ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+ if (namedStack == null) {
+ if (log.isDebugEnabled()) {
+ log.debug("Stack '" + stackName + "' is empty");
+ }
+ throw new EmptyStackException();
+ } else {
+ return namedStack.pop();
+ }
+ }
+
+ /**
+ * Pushes the given object onto the stack with the given name.
+ * If no stack already exists with the given name then one will be created.
+ *
+ * @param stackName the name of the stack onto which the object should be pushed
+ * @param value the Object to be pushed onto the named stack.
+ */
+ public void push(String stackName, Object value) {
+ ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+ if (namedStack == null) {
+ namedStack = new ArrayStack();
+ stacksByName.put(stackName, namedStack);
+ }
+ namedStack.push(value);
+ }
+
+ /**
+ * Returns the root element of the tree of objects created as a result
+ * of applying the action objects to the input XML.
+ * <p>
+ * If the digester stack was "primed" by explicitly calling setRoot before
+ * parsing started, then that root object is returned here.
+ * <p>
+ * Alternatively, if an Action which creates an object (eg ObjectCreateAction)
+ * matched the root element of the xml, then the object created will be
+ * returned here.
+ * <p>
+ * In other cases, the object most recently pushed onto an empty digester
+ * stack is returned. This would be a most unusual use of digester, however;
+ * one of the previous configurations is much more likely.
+ * <p>
+ * Note that when using one of the Digester.parse methods, the return
+ * value from the parse method is exactly the same as the return value
+ * from this method. However when the Digester's SAXHandler has been used
+ * explicitly as the content-handler for a user-provided sax parser, no
+ * such return value is available; in this case, this method allows you
+ * to access the root object that has been created after parsing has
+ * completed.
+ *
+ * @return the root object that has been created after parsing
+ * or null if the digester has not parsed any XML yet.
+ */
+ public Object getRoot() {
+ return root;
+ }
+
+ /**
+ * <p>Return the top object on the parameters stack without removing it.</p>
+ *
+ * <p>The parameters stack is used to store <code>CallMethodAction</code>
+ * parameters. See {@link #params}.</p>
+ *
+ * @throws EmptyStackException if the parameters stack is empty.
+ */
+ public Object peekParams() throws EmptyStackException {
+ return params.peek();
+ }
+
+ /**
+ * <p>Return the n'th object down the parameters stack, where 0 is the
+ * top element and [stacksize-1] is the bottom element.
+ *
+ * <p>The parameters stack is used to store <code>CallMethodAction</code>
+ * parameters. See {@link #params}.</p>
+ *
+ * @param n Index of the desired element, where 0 is the top of the stack,
+ * 1 is the next element down, and so on.
+ *
+ * @throws EmptyStackException if the parameters stack is empty.
+ */
+ public Object peekParams(int n) throws EmptyStackException {
+ return params.peek(n);
+ }
+
+ /**
+ * <p>Pop the top object off of the parameters stack, and return it.</p>
+ *
+ * <p>The parameters stack is used to store <code>CallMethodAction</code>
+ * parameters. See {@link #params}.</p>
+ *
+ * @throws EmptyStackException if the parameters stack is empty.
+ */
+ public Object popParams() throws EmptyStackException {
+ return params.pop();
+ }
+
+ /**
+ * <p>Push a new object onto the top of the parameters stack.</p>
+ *
+ * <p>The parameters stack is used to store <code>CallMethodAction</code>
+ * parameters. See {@link #params}.</p>
+ *
+ * @param object The new object
+ */
+ public void pushParams(Object object) {
+ params.push(object);
+
+ }
+}
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/DefaultRuleManager.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/DefaultRuleManager.java?view=auto&rev=151287
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/DefaultRuleManager.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/DefaultRuleManager.java Thu Feb 3 17:51:43 2005
@@ -0,0 +1,245 @@
+/* $Id: $
+ *
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.commons.digester2;
+
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+
+/**
+ * <p>Default implementation of the <code>RuleManager</code> interface that supports
+ * the standard rule matching behavior. This class can also be used as a
+ * base class for specialized <code>RuleManager</code> implementations.</p>
+ *
+ * <p>The matching policies implemented by this class support two different
+ * types of pattern matching rules:</p>
+ * <ul>
+ * <li><em>Exact Match</em> - A pattern "/a/b/c" exactly matches a
+ * <code><c></code> element, nested inside a <code><b></code>
+ * element, which is nested inside an <code><a></code> element.</li>
+ * <li><em>Tail Match</em> - A pattern "a/b" matches a
+ * <code><b></code> element, nested inside an <code><a></code>
+ * element, no matter how deeply the pair is nested.</li>
+ * </ul>
+ * <p>
+ * ActionManager objects cannot be shared between Digester objects; if you have
+ * multiple Digester objects then a different RuleManager object must be
+ * created for each one. However the copy() method may be used to duplicate
+ * an existing RuleManager instance.
+ */
+
+public class DefaultRuleManager extends RuleManager {
+
+ // ----------------------------------------------------- Instance Variables
+
+ /**
+ * Map of namespace-prefix to namespace-uri, used only by the
+ * addAction() method.
+ */
+ private HashMap namespaces = new HashMap();
+
+ /**
+ * The list of all actions in the cache. This set allows us to
+ * iterate over the set of actions to invoke the startParse/finishParse
+ * methods.
+ */
+ protected ArrayList actions = new ArrayList(20);
+
+ /**
+ * Map of expanded-pattern -> list-of-actions, so that we can
+ * find the pattern that matches the current xml element, then
+ * return the list of actions.
+ */
+ private MultiHashMap rules = new MultiHashMap();
+
+ // --------------------------------------------------------- Public Methods
+
+ /**
+ * Return a clone of this object. The Action objects currently
+ * registered are not copied, as Action objects are required to be
+ * re-entrant and thread-safe.
+ */
+ public RuleManager copy() {
+ DefaultRuleManager copy = new DefaultRuleManager();
+ copy.namespaces = (HashMap) this.namespaces.clone();
+ copy.actions = (ArrayList) this.actions.clone();
+ copy.rules = (MultiHashMap) this.rules.clone();
+ return copy;
+ }
+
+ /**
+ * This method is called at the start of parsing a new input document.
+ * <p>
+ * TODO: build a mapping from element-name to "list of patterns ending
+ * in that element name". When we have to do leading-wildcard-matching,
+ * therefore, we can omit all the patterns that don't match the last
+ * element, which will be a massive optimisation over scanning the entire
+ * list of patterns. And we only need to compute this first time, or if
+ * new rules have been added in the meantime.
+ */
+ public void startParse(Context context) {
+ }
+
+ /**
+ * This method is called after parsing of a new input document has completed.
+ * <p>
+ * Note that if an error has occurred during parsing, then this method
+ * might not be called.
+ */
+ public void finishParse(Context context) {
+ }
+
+ /**
+ * When rules are added, the pattern is of form
+ * <pre>
+ * /prefix:element/prefix:element/prefix:element....
+ * </pre>
+ * The prefixes must have previously been defined here.
+ */
+ public void addNamespace(String prefix, String uri) {
+ namespaces.put(prefix, uri);
+ }
+
+ /**
+ * Store the specified Action.
+ * <p>
+ * The pattern may include namespace-prefixes, in which case the prefixes
+ * are expanded to the corresponding namespace URIs using the mapping
+ * previously defined in the addNamespace method.
+ */
+ public void addRule(String pattern, Action action)
+ throws InvalidRuleException {
+ // if pattern has namespaces, then convert them to URIs.
+ String path = patternToPath(namespaces, pattern);
+
+ // if the action isn't already in the unique-action list, add it
+ if (!actions.contains(action)) {
+ actions.add(action);
+ }
+
+ // add the mapping to the multilist
+ rules.put(path, action);
+ }
+
+ /**
+ * Given a string of form "prefix:name/prefix:name", return a string of
+ * form "{namespace-uri}name/{namespace-uri}/name".
+ */
+ public String patternToPath(Map namespaces, String pattern)
+ throws InvalidRuleException {
+ int nsEndPos = pattern.indexOf(':');
+ if (nsEndPos == -1) {
+ /* no namespace prefixes present */
+ return pattern;
+ }
+
+ int currPos = 0;
+ StringBuffer out = new StringBuffer();
+ while (nsEndPos != -1) {
+ int nsStartPos = pattern.lastIndexOf('/', nsEndPos);
+ String prefix = pattern.substring(nsStartPos+1, nsEndPos);
+
+ String uri = (String) namespaces.get(prefix);
+ if (uri == null) {
+ throw new InvalidRuleException(
+ "No namespace for prefix [" + prefix + "]");
+ }
+
+ String prePrefix = pattern.substring(currPos, nsStartPos);
+ out.append(prePrefix);
+
+ out.append('{');
+ out.append(uri);
+ out.append('}');
+
+ currPos = nsEndPos + 1;
+ nsEndPos = pattern.indexOf(':', nsEndPos+1);
+ }
+ out.append(pattern.substring(currPos));
+
+ return out.toString();
+ }
+
+ /**
+ * Return a List of all registered Action instances that match the specified
+ * path, or a zero-length List if there are no matches. If more
+ * than one Action instance matches, they <strong>must</strong> be returned
+ * in the order originally registered through the <code>add()</code>
+ * method.
+ *
+ * @param path
+ */
+ public List getMatchingActions(String path) {
+ // assert path.startsWith('/');
+ List actionList = (List) rules.get(path);
+
+ if ((actionList == null) || (actionList.size() < 1)) {
+ /*
+ * Ok, there is no absolute path that matches. So what we need to
+ * do now is iterate over all the available paths which are not
+ * absolute, and see which is the longest match.
+ */
+
+ int longestMatch = -1;
+ int thisPathLength = path.length();
+ Iterator keys = this.rules.keySet().iterator();
+ while (keys.hasNext()) {
+ String key = (String) keys.next();
+ if (!key.startsWith("/")) {
+ // yep, this is non-absolute
+ int thisKeyLength = key.length();
+ if ((thisKeyLength > longestMatch) && path.endsWith(key)) {
+
+ // just check that we aren't trying to match a
+ // pattern of "a/b" against a path of "/gotcha/b"!
+ if (path.charAt(thisPathLength - thisKeyLength - 1) == '/') {
+ actionList = (List) rules.get(key);
+ longestMatch = thisKeyLength;
+ }
+ }
+ }
+ }
+ }
+
+ if (actionList == null) {
+ return java.util.Collections.EMPTY_LIST;
+ }
+ else {
+ return actionList;
+ }
+ }
+
+
+ /**
+ * Return a List of all registered Action instances, or a zero-length List
+ * if there are no registered Action instances.
+ * <p>
+ * The rules are returned in the order they were added. If an Action
+ * instance has been added multiple times, then its order is set by the
+ * first time it was added.
+ */
+ public List actions() {
+ return this.actions;
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org