apache tomcat 6.0.14

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Sevlet Container » apache tomcat 6.0.14 
tomcat 6
License:Apache License
URL:http://tomcat.apache.org/
Description:
Package NameComment
javax.annotation
javax.annotation.security
javax.ejb
javax.el
javax.mail
javax.mail.internet
javax.persistence
javax.servlet The javax.servlet package contains a number of classes and interfaces that describe and define the contracts between a servlet class and the runtime environment provided for an instance of such a class by a conforming servlet container.
javax.servlet.http The javax.servlet.http package contains a number of classes and interfaces that describe and define the contracts between a servlet class running under the HTTP protocol and the runtime environment provided for an instance of such a class by a conforming servlet container.
javax.servlet.jsp Classes and interfaces for the Core JSP 2.0 API.

The javax.servlet.jsp package contains a number of classes and interfaces that describe and define the contracts between a JSP page implementation class and the runtime environment provided for an instance of such a class by a conforming JSP container.

javax.servlet.jsp.el Classes and interfaces for the JSP 2.0 Expression Language API.

The JavaServer Pages(tm) (JSP) 2.0 specification provides a portable API for evaluating "EL Expressions". As of JSP 2.0, EL expressions can be placed directly in the template text of JSP pages and tag files.

This package contains a number of classes and interfaces that describe and define programmatic access to the Expression Language evaluator. This API can also be used by an implementation of JSP to evaluate the expressions, but other implementations, like open-coding into Java bytecodes, are allowed. This package is intended to have no dependencies on other portions of the JSP 2.0 specification.

javax.servlet.jsp.tagext Classes and interfaces for the definition of JavaServer Pages Tag Libraries.

The JavaServer Pages(tm) (JSP) 2.0 specification provides a portable mechanism for the description of tag libraries.

A JSP tag library contains

  • A Tag Library Descriptor
  • A number of Tag Files or Tag handler classes defining request-time behavior
  • Additional classes and resources used at runtime
  • Possibly some additional classes to provide extra translation information

The JSP 2.0 specification and the reference implementation both contain simple and moderately complex examples of actions defined using this mechanism. These are available at JSP's web site, at http://java.sun.com/products/jsp. Some readers may want to consult those to get a quick feel for how the mechanisms work together.

javax.xml.ws
org.apache
org.apache.catalina
org.apache.catalina.ant

This package contains a set of Task implementations for Ant (version 1.6.x or later) that can be used to interact with the Manager application to deploy, undeploy, list, reload, start and stop web applications from a running instance of Tomcat. For more information, see http://jakarta.apache.org/tomcat/tomcat-5.5-doc/manager-howto.html.

The attributes of each task element correspond exactly to the request parameters that are included with an HTTP request sent directly to the Manager application. They are summarized as follows:

Attribute Description
url The URL of the Manager web application you will use to perform the requested operations. If not specified, defaults to http://localhost:8080/manager (which corresponds to a standard installation of Tomcat 5).
username The username of a Tomcat user that has been configured with the manager role, as required to execute Manager application commands. This attribute is required.
password The password of a Tomcat user that has been configured with the manager role, as required to execute Manager application commands. This attribute is required.
config A URL pointing at the context configuration file (i.e. a file containing only the <Context> element, and its nested elements, from server.xml for a particular web application). This attribute is supported only on the install target, and is required only if you wish to install an application with non-default configuration characteristics.
path The context path (including the leading slash) of the web application this command is intended to manage, or a zero-length string for the ROOT web application. This attribute is valid for the install, reload, remove, start, and stop tasks only, and is required in all of those cases.
war A jar: URL that points at a web application archive (WAR) file, or a file: URL that points at an unpacked directory containing the web application. This attribute is supported only on the install target. You must specify at least one of the config and war attributes; if you specify both, the war attribute overrides the docBase attribute in the context configuration file.

NOTE - Commands executed through the Manager application are NOT reflected in updates to the Tomcat server.xml configuration file, so they do not persist past the next time you restart the entire Tomcat container.

org.apache.catalina.ant.jmx

This package contains a set of JMX Task implementations for Ant (version 1.6 or later) that can be used to interact with the Remote JMX JSR 160 RMI Adaptor to get/set attributes, invoke MBean operations and query for Mbeans inside a running instance of Tomcat. For more information, see http://jakarta.apache.org/tomcat/tomcat-5.5-doc/monitoring.html.

Each task element can open a new jmx connection or reference an existing one. The following attribute are exists in every tasks:

Attribute Description
url The JMX Connection URL of the remote Tomcat MBeansServer.
username The username of a MBeanServer auth, when configured.
password The password of a MBeanServer auth, when configured.
host The JMX Connection host.
port The JMX Connection port.
ref The name of the ant internal reference for a jmx connection.

NOTE - This Tasks only work, when JSR 160 MBean Adaptor as remote jvm is configured.

org.apache.catalina.authenticator

This package contains Authenticator implementations for the various supported authentication methods (BASIC, DIGEST, and FORM). In addition, there is a convenience base class, AuthenticatorBase, for customized Authenticator implementations.

If you are using the standard context configuration class (org.apache.catalina.startup.ContextConfig) to configure the Authenticator associated with a particular context, you can register the Java class to be used for each possible authentication method by modifying the following Properties file:

    src/share/org/apache/catalina/startup/Authenticators.properties

Each of the standard implementations extends a common base class (AuthenticatorBase), which is configured by setting the following JavaBeans properties (with default values in square brackets):

  • cache - Should we cache authenticated Principals (thus avoiding per-request lookups in our underyling Realm) if this request is part of an HTTP session? [true]
  • debug - Debugging detail level for this component. [0]

The standard authentication methods that are currently provided include:

  • BasicAuthenticator - Implements HTTP BASIC authentication, as described in RFC 2617.
  • DigestAuthenticator - Implements HTTP DIGEST authentication, as described in RFC 2617.
  • FormAuthenticator - Implements FORM-BASED authentication, as described in the Servlet API Specification, version 2.2.
org.apache.catalina.connector
org.apache.catalina.core
org.apache.catalina.deploy

This package contains Java objects that represent complex data structures from the web application deployment descriptor file (web.xml). It is assumed that these objects will be initialized within the context of a single thread, and then referenced in a read-only manner subsequent to that time. Therefore, no multi-thread synchronization is utilized within the implementation classes.

org.apache.catalina.ha

This package contains code for Clustering, the base class of a Cluster is org.apache.catalina.Cluster implementations of this class is done when implementing a new Cluster protocol

org.apache.catalina.ha.authenticator
org.apache.catalina.ha.context
org.apache.catalina.ha.deploy
org.apache.catalina.ha.session
org.apache.catalina.ha.tcp
org.apache.catalina.ha.util
org.apache.catalina.loader
org.apache.catalina.manager
org.apache.catalina.manager.host
org.apache.catalina.manager.util
org.apache.catalina.mbeans
org.apache.catalina.realm

This package contains Realm implementations for the various supported realm technologies for authenticating users and identifying their associated roles. The Realm that is associated with a web application's Context (or a hierarchically superior Container) is used to resolve authentication and role presence questions when a web application uses container managed security as described in the Servlet API Specification, version 2.2.

The implementations share a common base class that supports basic functionality for all of the standard Realm implementations, and can be configured by setting the following properties (default values are in square brackets):

  • debug - Debugging detail level for this component. [0]

The standard Realm implementations that are currently available include the following (with additional configuration properties as specified):

  • JDBCRealm - Implementation of Realm that operates from data stored in a relational database that is accessed via a JDBC driver. The name of the driver, database connection information, and the names of the relevant tables and columns are configured with the following additional properties:
    • connectionURL - The URL to use when connecting to this database. [REQUIRED - NO DEFAULT]
    • driverName - Fully qualified Java class name of the JDBC driver to be used. [REQUIRED - NO DEFAULT]
    • roleNameCol - Name of the database column that contains role names. [REQUIRED - NO DEFAULT]
    • userCredCol - Name of the database column that contains the user's credentials (i.e. password) in cleartext. [REQUIRED - NO DEFAULT]
    • userNameCol - Name of the database column that contains the user's logon username. [REQUIRED - NO DEFAULT]
    • userRoleTable - Name of the database table containing user role information. This table must include the columns specified by the userNameCol and roleNameCol properties. [REQUIRED - NO DEFAULT]
    • userTable - Name of the database table containing user information. This table must include the columns specified by the userNameCol and userCredCol properties. [REQUIRED - NO DEFAULT]
  • MemoryRealm - Implementation of Realm that uses the contents of a simple XML file (conf/tomcat-users.xml) as the list of valid users and their roles. This implementation is primarily to demonstrate that the authentication technology functions correctly, and is not anticipated as adequate for general purpose use. This component supports the following additional properties:
    • pathname - Pathname of the XML file containing our user and role information. If a relative pathname is specified, it is resolved against the pathname specified by the "catalina.home" system property. [conf/tomcat-users.xml]
org.apache.catalina.security
org.apache.catalina.servlets

This package contains Servlets that implement some of the standard functionality provided by the Catalina servlet container. Because these servlets are in the org.apache.catalina package hierarchy, they are in the privileged position of being able to reference internal server data structures, which application level servlets are prevented from accessing (by the application class loader implementation).

To the extent that these servlets depend upon internal Catalina data structures, they are obviously not portable to other servlet container environments. However, they can be used as models for creating application level servlets that provide similar capabilities -- most obviously the DefaultServlet implementation, which serves static resources when Catalina runs stand-alone.

org.apache.catalina.session

This package contains the standard Manager and Session implementations that represent the collection of active sessions and the individual sessions themselves, respectively, that are associated with a Context. Additional implementations of the Manager interface can be based upon the supplied convenience base class (ManagerBase), if desired. Different implementations of Session are possible, but a need for functionality beyond what is provided by the standard implementation (StandardSession) is not expected.

The convenience ManagerBase base class is configured by setting the following properties:

  • algorithm - Message digest algorithm to be used when generating session identifiers. This must be the name of an algorithm supported by the java.security.MessageDigest class on your platform. [DEFAULT_ALGORITHM]
  • debug - Debugging detail level for this component. [0]
  • distributable - Has the web application we are associated with been marked as "distributable"? If it has, attempts to add or replace a session attribute object that does not implement the java.io.Serializable interface will be rejected. [false]
  • entropy - A string initialization parameter that is used to increase the entropy of the seeding of the random number generator used in creation of session identifiers. [NONE]
  • maxInactiveInterval - The default maximum inactive interval, in minutes, for sessions created by this Manager. The standard implementation automatically updates this value based on the configuration settings in the web application deployment descriptor. [60]
  • randomClass - The Java class name of the random number generator to be used when creating session identifiers for this Manager. [java.security.SecureRandom]

The standard implementation of the Manager interface (StandardManager) supports the following additional configuration properties:

  • checkInterval - The interval, in seconds, between checks for sessions that have expired and should be invalidated. [60]
  • maxActiveSessions - The maximum number of active sessions that will be allowed, or -1 for no limit. [-1]
  • pathname - Pathname to the file that is used to store session data persistently across container restarts. If this pathname is relative, it is resolved against the temporary working directory provided by our associated Context, if any. ["sessions.ser"]
org.apache.catalina.ssi

This package contains code that is used by the SsiInvoker.

This class consists of SsiMediator.java which works as a mediator between the different SsiCommands. To add a command you have to implement the SsiCommand interface and extend the SsiMediator. Commands currently implemented are

  • SsiConfig - Implementation of the NCSA command Config i.e. <!--#config errmsg="error?"-->
  • SsiEcho - Implementation of the NCSA command Echo i.e. <!--#echo var="SERVER_NAME"-->
  • SsiExec - Not implemented
  • SsiFlastMod - Implementation of the NCSA command flastmod i.e. <!--#flastmod virtual="file"-->
  • SsiFsize - Implementation of the NCSA command fsize i.e. <!--#fsize file="file"-->
  • SsiInclude - Implementation of the NCSA command Include i.e. <!--#config virtual="includefile"-->
org.apache.catalina.startup
org.apache.catalina.tribes Apache Tribes - The Tomcat Cluster Communication Module

QuickStart


            //create a channel
            Channel myChannel = new GroupChannel();

            //create my listeners
            MyMessageListener msgListener = new MyMessageListener();
            MyMemberListener mbrListener = new MyMemberListener();

            //attach the listeners to the channel
            myChannel.addMembershipListener(mbrListener);
            myChannel.addChannelListener(msgListener);

            //start the channel
            myChannel.start(Channel.DEFAULT);

            //create a message to be sent, message must implement java.io.Serializable
            //for performance reasons you probably want them to implement java.io.Externalizable
            Serializable myMsg = new MyMessage();

            //retrieve my current members
            Member[] group = myChannel.getMembers();

            //send the message
            channel.send(group,myMsg,Channel.SEND_OPTIONS_DEFAULT);

    

Interfaces for the Application Developer

  1. org.apache.catalina.tribes.Channel Main component to interact with to send messages
  2. org.apache.catalina.tribes.MembershipListener Listen to membership changes
  3. org.apache.catalina.tribes.ChannelListener Listen to data messages
  4. org.apache.catalina.tribes.Member Identifies a node, implementation specific, default is org.apache.catalina.tribes.membership.MemberImpl

Interfaces for the Tribes Component Developer

  1. org.apache.catalina.tribes.Channel Main component to that the application interacts with
  2. org.apache.catalina.tribes.ChannelReceiver IO Component to receive messages over some network transport
  3. org.apache.catalina.tribes.ChannelSender IO Component to send messages over some network transport
  4. org.apache.catalina.tribes.MembershipService IO Component that handles membership discovery and
  5. org.apache.catalina.tribes.ChannelInterceptor interceptors between the Channel and the IO layer
  6. org.apache.catalina.tribes.ChannelMessage The message that is sent through the interceptor stack down to the IO layer
  7. org.apache.catalina.tribes.Member Identifies a node, implementation specific to the underlying IO logic
org.apache.catalina.tribes.demos
org.apache.catalina.tribes.group
org.apache.catalina.tribes.group.interceptors
org.apache.catalina.tribes.io
org.apache.catalina.tribes.membership
org.apache.catalina.tribes.test
org.apache.catalina.tribes.test.channel
org.apache.catalina.tribes.test.interceptors
org.apache.catalina.tribes.test.io
org.apache.catalina.tribes.test.membership
org.apache.catalina.tribes.test.transport
org.apache.catalina.tribes.tipis
org.apache.catalina.tribes.transport
org.apache.catalina.tribes.transport.bio
org.apache.catalina.tribes.transport.bio.util
org.apache.catalina.tribes.transport.nio
org.apache.catalina.tribes.util
org.apache.catalina.users
org.apache.catalina.util
org.apache.catalina.valves

This package contains a variety of small Valve implementations that do not warrant being packaged separately. In addition, there is a convenience base class (ValveBase) that supports the usual mechanisms for including custom Valves into the corresponding Pipeline.

Other packages that include Valves include org.apache.tomcat.logger and org.apache.tomcat.security.

org.apache.coyote
org.apache.coyote.ajp
org.apache.coyote.http11
org.apache.coyote.http11.filters
org.apache.coyote.memory
org.apache.el
org.apache.el.lang
org.apache.el.parser
org.apache.el.util
org.apache.jasper
org.apache.jasper.compiler
org.apache.jasper.compiler.tagplugin
org.apache.jasper.el
org.apache.jasper.runtime
org.apache.jasper.security
org.apache.jasper.servlet
org.apache.jasper.tagplugins.jstl
org.apache.jasper.tagplugins.jstl.core
org.apache.jasper.util
org.apache.jasper.xmlparser
org.apache.jk.apr
org.apache.jk.common
org.apache.jk.config
org.apache.jk.core

Jk2 interfaces

Core interfaces for jk2, similar with the interfaces defined in the C side ( jk2/include ).

The implementations are in common/ and server/.


org.apache.jk.server
org.apache.juli
org.apache.juli.logging

Overview

This implementation of commons-logging uses a commons-logging.jar specific to a particular logging framework, instead of discovery. This takes out the guessing, is simpler, faster and more robust. Just like you chose a logging implementation, you should also use a matching commons-logging - for example you download log4j.jar and commons-logging-log4j.jar, or use jdk logging and use commons-logging-jdk.jar.

A similar packaging is used by Eclipse SWT - they provide a common widget API, but each platform uses a different implementation jar - instead of using a complex discovery/plugin mechanism.

This package generates commons-logging-jdk14.jar - i.e. the java.util implementation of commons-logging api.

org.apache.naming

This package contains a memory based naming service provider.

org.apache.naming.factory

This package contains object factories used by the naming service.

org.apache.naming.factory.webservices
org.apache.naming.java

This package contains the URL context factory for the "java" namespace.

org.apache.naming.resources

This package contains the resources directory context implemetation. This includes :

  • A CacheDirContext which handles caching and acts as a proxy for the real resources context
  • A FileDirContext, an implementation of DirContext to access the filesystem

org.apache.naming.resources.jndi
org.apache.tomcat
org.apache.tomcat.buildutil
org.apache.tomcat.jni
org.apache.tomcat.util
org.apache.tomcat.util.buf

Buffers and Encodings

This package contains buffers and utils to perform encoding/decoding of buffers. That includes byte to char conversions, URL encodings, etc.

Encoding is a critical operation for performance. There are few tricks in this package - the C2B and B2C converters are caching a ISReader/OSWriter and keep everything allocated to do the conversions in any VM without any garbage.

This package must accomodate future extensions and additional converters ( most imporant: the nio.charset, which should be detected and used if available ). Also, we do have one hand-written UTF8Decoder, and other tuned encoders could be added.

My benchmarks ( I'm costin :-) show only small differences between C2B, B2C and hand-written codders/decoders, so UTF8Decoder may be disabled.

org.apache.tomcat.util.collections util.collections

Specialized collections

This package includes a number of special collections, tunned for server-side applications. The utils are not tomcat specific, but use MessageBytes and few other top-level utils.
org.apache.tomcat.util.digester Package Documentation for org.apache.commons.digester Package The Digester package provides for rules-based processing of arbitrary XML documents.

External Dependencies

Introduction

In many application environments that deal with XML-formatted data, it is useful to be able to process an XML document in an "event driven" manner, where particular Java objects are created (or methods of existing objects are invoked) when particular patterns of nested XML elements have been recognized. Developers familiar with the Simple API for XML Parsing (SAX) approach to processing XML documents will recognize that the Digester provides a higher level, more developer-friendly interface to SAX events, because most of the details of navigating the XML element hierarchy are hidden -- allowing the developer to focus on the processing to be performed.

In order to use a Digester, the following basic steps are required:

  • Create a new instance of the org.apache.commons.digester.Digester class. Previously created Digester instances may be safely reused, as long as you have completed any previously requested parse, and you do not try to utilize a particular Digester instance from more than one thread at a time.
  • Set any desired configuration properties that will customize the operation of the Digester when you next initiate a parse operation.
  • Optionally, push any desired initial object(s) onto the Digester's object stack.
  • Register all of the element matching patterns for which you wish to have processing rules fired when this pattern is recognized in an input document. You may register as many rules as you like for any particular pattern. If there is more than one rule for a given pattern, the rules will be executed in the order that they were listed.
  • Call the digester.parse() method, passing a reference to the XML document to be parsed in one of a variety of forms. See the Digester.parse() documentation for details. Note that you will need to be prepared to catch any IOException or SAXException that is thrown by the parser, or any runtime expression that is thrown by one of the processing rules.

For example code, see the usage examples, and the FAQ .

Digester Configuration Properties

A org.apache.commons.digester.Digester instance contains several configuration properties that can be used to customize its operation. These properties must be configured before you call one of the parse() variants, in order for them to take effect on that parse.

Property Description
classLoader You can optionally specify the class loader that will be used to load classes when required by the ObjectCreateRule and FactoryCreateRule rules. If not specified, application classes will be loaded from the thread's context class loader (if the useContextClassLoader property is set to true) or the same class loader that was used to load the Digester class itself.
errorHandler You can optionally specify a SAX ErrorHandler that is notified when parsing errors occur. By default, any parsing errors that are encountered are logged, but Digester will continue processing as well.
namespaceAware A boolean that is set to true to perform parsing in a manner that is aware of XML namespaces. Among other things, this setting affects how elements are matched to processing rules. See Namespace Aware Parsing for more information.
ruleNamespaceURI The public URI of the namespace for which all subsequently added rules are associated, or null for adding rules that are not associated with any namespace. See Namespace Aware Parsing for more information.
rules The Rules component that actually performs matching of Rule instances against the current element nesting pattern is pluggable. By default, Digester includes a Rules implementation that behaves as described in this document. See Pluggable Rules Processing for more information.
useContextClassLoader A boolean that is set to true if you want application classes required by FactoryCreateRule and ObjectCreateRule to be loaded from the context class loader of the current thread. By default, classes will be loaded from the class loader that loaded this Digester class. NOTE - This property is ignored if you set a value for the classLoader property; that class loader will be used unconditionally.
validating A boolean that is set to true if you wish to validate the XML document against a Document Type Definition (DTD) that is specified in its DOCTYPE declaration. The default value of false requests a parse that only detects "well formed" XML documents, rather than "valid" ones.

In addition to the scalar properties defined above, you can also register a local copy of a Document Type Definition (DTD) that is referenced in a DOCTYPE declaration. Such a registration tells the XML parser that, whenever it encounters a DOCTYPE declaration with the specified public identifier, it should utilize the actual DTD content at the registered system identifier (a URL), rather than the one in the DOCTYPE declaration.

For example, the Struts framework controller servlet uses the following registration in order to tell Struts to use a local copy of the DTD for the Struts configuration file. This allows usage of Struts in environments that are not connected to the Internet, and speeds up processing even at Internet connected sites (because it avoids the need to go across the network).

    URL url = new URL("/org/apache/struts/resources/struts-config_1_0.dtd");
    digester.register
      ("-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
       url.toString());

As a side note, the system identifier used in this example is the path that would be passed to java.lang.ClassLoader.getResource() or java.lang.ClassLoader.getResourceAsStream(). The actual DTD resource is loaded through the same class loader that loads all of the Struts classes -- typically from the struts.jar file.

The Object Stack

One very common use of org.apache.commons.digester.Digester technology is to dynamically construct a tree of Java objects, whose internal organization, as well as the details of property settings on these objects, are configured based on the contents of the XML document. In fact, the primary reason that the Digester package was created (it was originally part of Struts, and then moved to the Commons project because it was recognized as being generally useful) was to facilitate the way that the Struts controller servlet configures itself based on the contents of your application's struts-config.xml file.

To facilitate this usage, the Digester exposes a stack that can be manipulated by processing rules that are fired when element matching patterns are satisfied. The usual stack-related operations are made available, including the following:

  • clear() - Clear the current contents of the object stack.
  • peek() - Return a reference to the top object on the stack, without removing it.
  • pop() - Remove the top object from the stack and return it.
  • push() - Push a new object onto the top of the stack.

A typical design pattern, then, is to fire a rule that creates a new object and pushes it on the stack when the beginning of a particular XML element is encountered. The object will remain there while the nested content of this element is processed, and it will be popped off when the end of the element is encountered. As we will see, the standard "object create" processing rule supports exactly this functionalility in a very convenient way.

Several potential issues with this design pattern are addressed by other features of the Digester functionality:

  • How do I relate the objects being created to each other? - The Digester supports standard processing rules that pass the top object on the stack as an argument to a named method on the next-to-top object on the stack (or vice versa). This rule makes it easy to establish parent-child relationships between these objects. One-to-one and one-to-many relationships are both easy to construct.
  • How do I retain a reference to the first object that was created? As you review the description of what the "object create" processing rule does, it would appear that the first object you create (i.e. the object created by the outermost XML element you process) will disappear from the stack by the time that XML parsing is completed, because the end of the element would have been encountered. However, Digester will maintain a reference to the very first object ever pushed onto the object stack, and will return it to you as the return value from the parse() call. Alternatively, you can push a reference to some application object onto the stack before calling parse(), and arrange that a parent-child relationship be created (by appropriate processing rules) between this manually pushed object and the ones that are dynamically created. In this way, the pushed object will retain a reference to the dynamically created objects (and therefore all of their children), and will be returned to you after the parse finishes as well.

Element Matching Patterns

A primary feature of the org.apache.commons.digester.Digester parser is that the Digester automatically navigates the element hierarchy of the XML document you are parsing for you, without requiring any developer attention to this process. Instead, you focus on deciding what functions you would like to have performed whenver a certain arrangement of nested elements is encountered in the XML document being parsed. The mechanism for specifying such arrangements are called element matching patterns.

A very simple element matching pattern is a simple string like "a". This pattern is matched whenever an <a> top-level element is encountered in the XML document, no matter how many times it occurs. Note that nested <a> elements will not match this pattern -- we will describe means to support this kind of matching later.

The next step up in matching pattern complexity is "a/b". This pattern will be matched when a <b> element is found nested inside a top-level <a> element. Again, this match can occur as many times as desired, depending on the content of the XML document being parsed. You can use multiple slashes to define a hierarchy of any desired depth that will be matched appropriately.

For example, assume you have registered processing rules that match patterns "a", "a/b", and "a/b/c". For an input XML document with the following contents, the indicated patterns will be matched when the corresponding element is parsed:

  <a>         -- Matches pattern "a"
    <b>       -- Matches pattern "a/b"
      <c/>    -- Matches pattern "a/b/c"
      <c/>    -- Matches pattern "a/b/c"
    </b>
    <b>       -- Matches pattern "a/b"
      <c/>    -- Matches pattern "a/b/c"
      <c/>    -- Matches pattern "a/b/c"
      <c/>    -- Matches pattern "a/b/c"
    </b>
  </a>

It is also possible to match a particular XML element, no matter how it is nested (or not nested) in the XML document, by using the "*" wildcard character in your matching pattern strings. For example, an element matching pattern of "*/a" will match an <a> element at any nesting position within the document.

It is quite possible that, when a particular XML element is being parsed, the pattern for more than one registered processing rule will be matched either because you registered more than one processing rule with the same matching pattern, or because one more more exact pattern matches and wildcard pattern matches are satisfied by the same element.

When this occurs, the corresponding processing rules will all be fired in order. begin (and body) method calls are executed in the order that the Rules where initially registered with the Digester, whilst end method calls are execute in reverse order. In other words - the order is first in, last out.

Processing Rules

The previous section documented how you identify when you wish to have certain actions take place. The purpose of processing rules is to define what should happen when the patterns are matched.

Formally, a processing rule is a Java class that subclasses the org.apache.commons.digester.Rule interface. Each Rule implements one or more of the following event methods that are called at well-defined times when the matching patterns corresponding to this rule trigger it:

  • begin() - Called when the beginning of the matched XML element is encountered. A data structure containing all of the attributes corresponding to this element are passed as well.
  • body() - Called when nested content (that is not itself XML elements) of the matched element is encountered. Any leading or trailing whitespace will have been removed as part of the parsing process.
  • end() - Called when the ending of the matched XML element is encountered. If nested XML elements that matched other processing rules was included in the body of this element, the appropriate processing rules for the matched rules will have already been completed before this method is called.
  • finish() - Called when the parse has been completed, to give each rule a chance to clean up any temporary data they might have created and cached.

As you are configuring your digester, you can call the addRule() method to register a specific element matching pattern, along with an instance of a Rule class that will have its event handling methods called at the appropriate times, as described above. This mechanism allows you to create Rule implementation classes dynamically, to implement any desired application specific functionality.

In addition, a set of processing rule implementation classes are provided, which deal with many common programming scenarios. These classes include the following:

  • ObjectCreateRule - When the begin() method is called, this rule instantiates a new instance of a specified Java class, and pushes it on the stack. The class name to be used is defaulted according to a parameter passed to this rule's constructor, but can optionally be overridden by a classname passed via the specified attribute to the XML element being processed. When the end() method is called, the top object on the stack (presumably, the one we added in the begin() method) will be popped, and any reference to it (within the Digester) will be discarded.
  • FactoryCreateRule - A variation of ObjectCreateRule that is useful when the Java class with which you wish to create an object instance does not have a no-arguments constructor, or where you wish to perform other setup processing before the object is handed over to the Digester.
  • SetPropertiesRule - When the begin() method is called, the digester uses the standard Java Reflection API to identify any JavaBeans property setter methods (on the object at the top of the digester's stack) who have property names that match the attributes specified on this XML element, and then call them individually, passing the corresponding attribute values. These natural mappings can be overridden. This allows (for example) a class attribute to be mapped correctly. It is recommended that this feature should not be overused - in most cases, it's better to use the standard BeanInfo mechanism. A very common idiom is to define an object create rule, followed by a set properties rule, with the same element matching pattern. This causes the creation of a new Java object, followed by "configuration" of that object's properties based on the attributes of the same XML element that created this object.
  • SetPropertyRule - When the begin() method is called, the digester calls a specified property setter (where the property itself is named by an attribute) with a specified value (where the value is named by another attribute), on the object at the top of the digester's stack. This is useful when your XML file conforms to a particular DTD, and you wish to configure a particular property that does not have a corresponding attribute in the DTD.
  • SetNextRule - When the end() method is called, the digester analyzes the next-to-top element on the stack, looking for a property setter method for a specified property. It then calls this method, passing the object at the top of the stack as an argument. This rule is commonly used to establish one-to-many relationships between the two objects, with the method name commonly being something like "addChild".
  • SetTopRule - When the end() method is called, the digester analyzes the top element on the stack, looking for a property setter method for a specified property. It then calls this method, passing the next-to-top object on the stack as an argument. This rule would be used as an alternative to a SetNextRule, with a typical method name "setParent", if the API supported by your object classes prefers this approach.
  • CallMethodRule - This rule sets up a method call to a named method of the top object on the digester's stack, which will actually take place when the end() method is called. You configure this rule by specifying the name of the method to be called, the number of arguments it takes, and (optionally) the Java class name(s) defining the type(s) of the method's arguments. The actual parameter values, if any, will typically be accumulated from the body content of nested elements within the element that triggered this rule, using the CallParamRule discussed next.
  • CallParamRule - This rule identifies the source of a particular numbered (zero-relative) parameter for a CallMethodRule within which we are nested. You can specify that the parameter value be taken from a particular named attribute, or from the nested body content of this element.
  • NodeCreateRule - A specialized rule that converts part of the tree into a DOM Node and then pushes it onto the stack.

You can create instances of the standard Rule classes and register them by calling digester.addRule(), as described above. However, because their usage is so common, shorthand registration methods are defined for each of the standard rules, directly on the Digester class. For example, the following code sequence:

    Rule rule = new SetNextRule(digester, "addChild",
                                "com.mycompany.mypackage.MyChildClass");
    digester.addRule("a/b/c", rule);

can be replaced by:

    digester.addSetNext("a/b/c", "addChild",
                        "com.mycompany.mypackage.MyChildClass");

Logging

Logging is a vital tool for debugging Digester rulesets. Digester can log copious amounts of debugging information. So, you need to know how logging works before you start using Digester seriously.

Digester uses Jakarta Commons Logging. This component is not really a logging framework - rather an extensible, configurable bridge. It can be configured to swallow all log messages, to provide very basic logging by itself or to pass logging messages on to more sophisticated logging frameworks. Commons-Logging comes with connectors for many popular logging frameworks. Consult the commons-logging documentation for more information.

Two main logs are used by Digester:

  • SAX-related messages are logged to org.apache.commons.digester.Digester.sax. This log gives information about the basic SAX events received by Digester.
  • org.apache.commons.digester.Digester is used for everything else. You'll probably want to have this log turned up during debugging but turned down during production due to the high message volume.

Complete documentation of how to configure Commons-Logging can be found in the Commons Logging package documentation. However, as a simple example, let's assume that you want to use the SimpleLog implementation that is included in Commons-Logging, and set up Digester to log events from the Digester logger at the DEBUG level, while you want to log events from the Digester.log logger at the INFO level. You can accomplish this by creating a commons-logging.properties file in your classpath (or setting corresponding system properties on the command line that starts your application) with the following contents:

  org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
  org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester=debug
  org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester.sax=info

Usage Examples

Creating a Simple Object Tree

Let's assume that you have two simple JavaBeans, Foo and Bar, with the following method signatures:

  package mypackage;
  public class Foo {
    public void addBar(Bar bar);
    public Bar findBar(int id);
    public Iterator getBars();
    public String getName();
    public void setName(String name);
  }

  public mypackage;
  public class Bar {
    public int getId();
    public void setId(int id);
    public String getTitle();
    public void setTitle(String title);
  }

and you wish to use Digester to parse the following XML document:

  <foo name="The Parent">
    <bar id="123" title="The First Child"/>
    <bar id="456" title="The Second Child"/>
  </foo>

A simple approach will be to use the following Digester in the following way to set up the parsing rules, and then process an input file containing this document:

  Digester digester = new Digester();
  digester.setValidating(false);
  digester.addObjectCreate("foo", "mypackage.Foo");
  digester.addSetProperties("foo");
  digester.addObjectCreate("foo/bar", "mypackage.Bar");
  digester.addSetProperties("foo/bar");
  digester.addSetNext("foo/bar", "addBar", "mypackage.Bar");
  Foo foo = (Foo) digester.parse();

In order, these rules do the following tasks:

  1. When the outermost <foo> element is encountered, create a new instance of mypackage.Foo and push it on to the object stack. At the end of the <foo> element, this object will be popped off of the stack.
  2. Cause properties of the top object on the stack (i.e. the Foo object that was just created and pushed) to be set based on the values of the attributes of this XML element.
  3. When a nested <bar> element is encountered, create a new instance of mypackage.Bar and push it on to the object stack. At the end of the <bar> element, this object will be popped off of the stack (i.e. after the remaining rules matching foo/bar are processed).
  4. Cause properties of the top object on the stack (i.e. the Bar object that was just created and pushed) to be set based on the values of the attributes of this XML element. Note that type conversions are automatically performed (such as String to int for the id property), for all converters registered with the ConvertUtils class from commons-beanutils package.
  5. Cause the addBar method of the next-to-top element on the object stack (which is why this is called the "set next" rule) to be called, passing the element that is on the top of the stack, which must be of type mypackage.Bar. This is the rule that causes the parent/child relationship to be created.

Once the parse is completed, the first object that was ever pushed on to the stack (the Foo object in this case) is returned to you. It will have had its properties set, and all of its child Bar objects created for you.

Processing A Struts Configuration File

As stated earlier, the primary reason that the Digester package was created is because the Struts controller servlet itself needed a robust, flexible, easy to extend mechanism for processing the contents of the struts-config.xml configuration that describes nearly every aspect of a Struts-based application. Because of this, the controller servlet contains a comprehensive, real world, example of how the Digester can be employed for this type of a use case. See the initDigester() method of class org.apache.struts.action.ActionServlet for the code that creates and configures the Digester to be used, and the initMapping() method for where the parsing actually takes place.

(Struts binary and source distributions can be acquired at http://jakarta.apache.org/struts/.)

The following discussion highlights a few of the matching patterns and processing rules that are configured, to illustrate the use of some of the Digester features. First, let's look at how the Digester instance is created and initialized:

    Digester digester = new Digester();
    digester.push(this); // Push controller servlet onto the stack
    digester.setValidating(true);

We see that a new Digester instance is created, and is configured to use a validating parser. Validation will occur against the struts-config_1_0.dtd DTD that is included with Struts (as discussed earlier). In order to provide a means of tracking the configured objects, the controller servlet instance itself will be added to the digester's stack.

    digester.addObjectCreate("struts-config/global-forwards/forward",
                             forwardClass, "className");
    digester.addSetProperties("struts-config/global-forwards/forward");
    digester.addSetNext("struts-config/global-forwards/forward",
                        "addForward",
                        "org.apache.struts.action.ActionForward");
    digester.addSetProperty
      ("struts-config/global-forwards/forward/set-property",
       "property", "value");

The rules created by these lines are used to process the global forward declarations. When a <forward> element is encountered, the following actions take place:

  • A new object instance is created -- the ActionForward instance that will represent this definition. The Java class name defaults to that specified as an initialization parameter (which we have stored in the String variable forwardClass), but can be overridden by using the "className" attribute (if it is present in the XML element we are currently parsing). The new ActionForward instance is pushed onto the stack.
  • The properties of the ActionForward instance (at the top of the stack) are configured based on the attributes of the <forward> element.
  • Nested occurrences of the <set-property> element cause calls to additional property setter methods to occur. This is required only if you have provided a custom implementation of the ActionForward class with additional properties that are not included in the DTD.
  • The addForward() method of the next-to-top object on the stack (i.e. the controller servlet itself) will be called, passing the object at the top of the stack (i.e. the ActionForward instance) as an argument. This causes the global forward to be registered, and as a result of this it will be remembered even after the stack is popped.
  • At the end of the <forward> element, the top element (i.e. the ActionForward instance) will be popped off the stack.

Later on, the digester is actually executed as follows:

    InputStream input =
      getServletContext().getResourceAsStream(config);
    ...
    try {
        digester.parse(input);
        input.close();
    } catch (SAXException e) {
        ... deal with the problem ...
    }

As a result of the call to parse(), all of the configuration information that was defined in the struts-config.xml file is now represented as collections of objects cached within the Struts controller servlet, as well as being exposed as servlet context attributes.

Parsing Body Text In XML Files

The Digester module also allows you to process the nested body text in an XML file, not just the elements and attributes that are encountered. The following example is based on an assumed need to parse the web application deployment descriptor (/WEB-INF/web.xml) for the current web application, and record the configuration information for a particular servlet. To record this information, assume the existence of a bean class with the following method signatures (among others):

  package com.mycompany;
  public class ServletBean {
    public void setServletName(String servletName);
    public void setServletClass(String servletClass);
    public void addInitParam(String name, String value);
  }

We are going to process the web.xml file that declares the controller servlet in a typical Struts-based application (abridged for brevity in this example):

  <web-app>
    ...
    <servlet>
      <servlet-name>action</servlet-name>
      <servlet-class>org.apache.struts.action.ActionServlet<servlet-class>
      <init-param>
        <param-name>application</param-name>
        <param-value>org.apache.struts.example.ApplicationResources<param-value>
      </init-param>
      <init-param>
        <param-name>config</param-name>
        <param-value>/WEB-INF/struts-config.xml<param-value>
      </init-param>
    </servlet>
    ...
  </web-app>

Next, lets define some Digester processing rules for this input file:

  digester.addObjectCreate("web-app/servlet",
                           "com.mycompany.ServletBean");
  digester.addCallMethod("web-app/servlet/servlet-name", "setServletName", 0);
  digester.addCallMethod("web-app/servlet/servlet-class",
                         "setServletClass", 0);
  digester.addCallMethod("web-app/servlet/init-param",
                         "addInitParam", 2);
  digester.addCallParam("web-app/servlet/init-param/param-name", 0);
  digester.addCallParam("web-app/servlet/init-param/param-value", 1);

Now, as elements are parsed, the following processing occurs:

  • <servlet> - A new com.mycompany.ServletBean object is created, and pushed on to the object stack.
  • <servlet-name> - The setServletName() method of the top object on the stack (our ServletBean) is called, passing the body content of this element as a single parameter.
  • <servlet-class> - The setServletClass() method of the top object on the stack (our ServletBean) is called, passing the body content of this element as a single parameter.
  • <init-param> - A call to the addInitParam method of the top object on the stack (our ServletBean) is set up, but it is not called yet. The call will be expecting two String parameters, which must be set up by subsequent call parameter rules.
  • <param-name> - The body content of this element is assigned as the first (zero-relative) argument to the call we are setting up.
  • <param-value> - The body content of this element is assigned as the second (zero-relative) argument to the call we are setting up.
  • </init-param> - The call to addInitParam() that we have set up is now executed, which will cause a new name-value combination to be recorded in our bean.
  • <init-param> - The same set of processing rules are fired again, causing a second call to addInitParam() with the second parameter's name and value.
  • </servlet> - The element on the top of the object stack (which should be the ServletBean we pushed earlier) is popped off the object stack.

Namespace Aware Parsing

For digesting XML documents that do not use XML namespaces, the default behavior of Digester, as described above, is generally sufficient. However, if the document you are processing uses namespaces, it is often convenient to have sets of Rule instances that are only matched on elements that use the prefix of a particular namespace. This approach, for example, makes it possible to deal with element names that are the same in different namespaces, but where you want to perform different processing for each namespace.

Digester does not provide full support for namespaces, but does provide sufficient to accomplish most tasks. Enabling digester's namespace support is done by following these steps:

  1. Tell Digester that you will be doing namespace aware parsing, by adding this statement in your initalization of the Digester's properties:
        digester.setNamespaceAware(true);
        
  2. Declare the public namespace URI of the namespace with which following rules will be associated. Note that you do not make any assumptions about the prefix - the XML document author is free to pick whatever prefix they want:
        digester.setRuleNamespaceURI("http://www.mycompany.com/MyNamespace");
        
  3. Add the rules that correspond to this namespace, in the usual way, by calling methods like addObjectCreate() or addSetProperties(). In the matching patterns you specify, use only the local name portion of the elements (i.e. the part after the prefix and associated colon (":") character:
        digester.addObjectCreate("foo/bar", "com.mycompany.MyFoo");
        digester.addSetProperties("foo/bar");
        
  4. Repeat the previous two steps for each additional public namespace URI that should be recognized on this Digester run.

Now, consider that you might wish to digest the following document, using the rules that were set up in the steps above:

<m:foo
   xmlns:m="http://www.mycompany.com/MyNamespace"
   xmlns:y="http://www.yourcompany.com/YourNamespace">

  <m:bar name="My Name" value="My Value"/>

  <y:bar id="123" product="Product Description"/>L

</x:foo>

Note that your object create and set properties rules will be fired for the first occurrence of the bar element, but not the second one. This is because we declared that our rules only matched for the particular namespace we are interested in. Any elements in the document that are associated with other namespaces (or no namespaces at all) will not be processed. In this way, you can easily create rules that digest only the portions of a compound document that they understand, without placing any restrictions on what other content is present in the document.

You might also want to look at Encapsulated Rule Sets if you wish to reuse a particular set of rules, associated with a particular namespace, in more than one application context.

Using Namespace Prefixes In Pattern Matching

Using rules with namespaces is very useful when you have orthogonal rulesets. One ruleset applies to a namespace and is independent of other rulesets applying to other namespaces. However, if your rule logic requires mixed namespaces, then matching namespace prefix patterns might be a better strategy.

When you set the NamespaceAware property to false, digester uses the qualified element name (which includes the namespace prefix) rather than the local name as the patten component for the element. This means that your pattern matches can include namespace prefixes as well as element names. So, rather than create namespace-aware rules, create pattern matches including the namespace prefixes.

For example, (with NamespaceAware false), the pattern 'foo:bar' will match a top level element named 'bar' in the namespace with (local) prefix 'foo'.

Limitations of Digester Namespace support

Digester does not provide general "xpath-compliant" matching; only the namespace attached to the last element in the match path is involved in the matching process. Namespaces attached to parent elements are ignored for matching purposes.

Pluggable Rules Processing

By default, Digester selects the rules that match a particular pattern of nested elements as described under Element Matching Patterns. If you prefer to use different selection policies, however, you can create your own implementation of the org.apache.commons.digester.Rules interface, or subclass the corresponding convenience base class org.apache.commons.digester.RulesBase. Your implementation of the match() method will be called when the processing for a particular element is started or ended, and you must return a List of the rules that are relevant for the current nesting pattern. The order of the rules you return is significant, and should match the order in which rules were initally added.

Your policy for rule selection should generally be sensitive to whether Namespace Aware Parsing is taking place. In general, if namespaceAware is true, you should select only rules that:

  • Are registered for the public namespace URI that corresponds to the prefix being used on this element.
  • Match on the "local name" portion of the element (so that the document creator can use any prefix that they like).

ExtendedBaseRules

ExtendedBaseRules, adds some additional expression syntax for pattern matching to the default mechanism, but it also executes more slowly. See the JavaDocs for more details on the new pattern matching syntax, and suggestions on when this implementation should be used. To use it, simply do the following as part of your Digester initialization:

  Digester digester = ...
  ...
  digester.setRules(new ExtendedBaseRules());
  ...

RegexRules

RegexRules is an advanced Rules implementation which does not build on the default pattern matching rules. It uses a pluggable RegexMatcher implementation to test if a path matches the pattern for a Rule. All matching rules are returned (note that this behaviour differs from longest matching rule of the default pattern matching rules). See the Java Docs for more details.

Example usage:

  Digester digester = ...
  ...
  digester.setRules(new RegexRules(new SimpleRegexMatcher()));
  ...
RegexMatchers

Digester ships only with one RegexMatcher implementation: SimpleRegexMatcher. This implementation is unsophisticated and lacks many good features lacking in more power Regex libraries. There are some good reasons why this approach was adopted. The first is that SimpleRegexMatcher is simple, it is easy to write and runs quickly. The second has to do with the way that RegexRules is intended to be used.

There are many good regex libraries available. (For example Jakarta ORO, Jakarta Regex, GNU Regex and Java 1.4 Regex) Not only do different people have different personal tastes when it comes to regular expression matching but these products all offer different functionality and different strengths.

The pluggable RegexMatcher is a thin bridge designed to adapt other Regex systems. This allows any Regex library the user desires to be plugged in and used just by creating one class. Digester does not (currently) ship with bridges to the major regex (to allow the dependencies required by Digester to be kept to a minimum).

WithDefaultsRulesWrapper

WithDefaultsRulesWrapper allows default Rule instances to be added to any existing Rules implementation. These default Rule instances will be returned for any match for which the wrapped implementation does not return any matches.

For example,

    Rule alpha;
    ...
    WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
    rules.addDefault(alpha);
    ...
    digester.setRules(rules);
    ...
when a pattern does not match any other rule, then rule alpha will be called.

WithDefaultsRulesWrapper follows the Decorator pattern.

Encapsulated Rule Sets

All of the examples above have described a scenario where the rules to be processed are registered with a Digester instance immediately after it is created. However, this approach makes it difficult to reuse the same set of rules in more than one application environment. Ideally, one could package a set of rules into a single class, which could be easily loaded and registered with a Digester instance in one easy step.

The RuleSet interface (and the convenience base class RuleSetBase) make it possible to do this. In addition, the rule instances registered with a particular RuleSet can optionally be associated with a particular namespace, as described under Namespace Aware Processing.

An example of creating a RuleSet might be something like this:

public class MyRuleSet extends RuleSetBase {

  public MyRuleSet() {
    this("");
  }

  public MyRuleSet(String prefix) {
    super();
    this.prefix = prefix;
    this.namespaceURI = "http://www.mycompany.com/MyNamespace";
  }

  protected String prefix = null;

  public void addRuleInstances(Digester digester) {
    digester.addObjectCreate(prefix + "foo/bar",
      "com.mycompany.MyFoo");
    digester.addSetProperties(prefix + "foo/bar");
  }

}

You might use this RuleSet as follow to initialize a Digester instance:

  Digester digester = new Digester();
  ... configure Digester properties ...
  digester.addRuleSet(new MyRuleSet("baz/"));

A couple of interesting notes about this approach:

  • The application that is using these rules does not need to know anything about the fact that the RuleSet being used is associated with a particular namespace URI. That knowledge is emedded inside the RuleSet class itself.
  • If desired, you could make a set of rules work for more than one namespace URI by providing constructors on the RuleSet to allow this to be specified dynamically.
  • The MyRuleSet example above illustrates another technique that increases reusability -- you can specify (as an argument to the constructor) the leading portion of the matching pattern to be used. In this way, you can construct a Digester that recognizes the same set of nested elements at different nesting levels within an XML document.

Using Named Stacks For Inter-Rule Communication

Digester is based on Rule instances working together to process xml. For anything other than the most trival processing, communication between Rule instances is necessary. Since Rule instances are processed in sequence, this usually means storing an Object somewhere where later instances can retrieve it.

Digester is based on SAX. The most natural data structure to use with SAX based xml processing is the stack. This allows more powerful processes to be specified more simply since the pushing and popping of objects can mimic the nested structure of the xml.

Digester uses two basic stacks: one for the main beans and the other for parameters for method calls. These are inadequate for complex processing where many different Rule instances need to communicate through different channels.

In this case, it is recommended that named stacks are used. In addition to the two basic stacks, Digester allows rules to use an unlimited number of other stacks referred two by an identifying string (the name). (That's where the term named stack comes from.) These stacks are accessed through calls to:

Note: all stack names beginning with org.apache.commons.digester are reserved for future use by the Digester component. It is also recommended that users choose stack names perfixed by the name of their own domain to avoid conflicts with other Rule implementations.

Registering DTDs

Brief (But Still Too Long) Introduction To System and Public Identifiers

A definition for an external entity comes in one of two forms:

  1. SYSTEM system-identifier
  2. PUBLIC public-identifier system-identifier

The system-identifier is an URI from which the resource can be obtained (either directly or indirectly). Many valid URIs may identify the same resource. The public-identifier is an additional free identifier which may be used (by the parser) to locate the resource.

In practice, the weakness with a system-identifier is that most parsers will attempt to interprete this URI as an URL, try to download the resource directly from the URL and stop the parsing if this download fails. So, this means that almost always the URI will have to be an URL from which the declaration can be downloaded.

URLs may be local or remote but if the URL is chosen to be local, it is likely only to function correctly on a small number of machines (which are configured precisely to allow the xml to be parsed). This is usually unsatisfactory and so a universally accessable URL is preferred. This usually means an internet URL.

To recap, in practice the system-identifier will (most likely) be an internet URL. Unfortunately downloading from an internet URL is not only slow but unreliable (since successfully downloading a document from the internet relies on the client being connect to the internet and the server being able to satisfy the request).

The public-identifier is a freely defined name but (in practice) it is strongly recommended that a unique, readable and open format is used (for reasons that should become clear later). A Formal Public Identifier (FPI) is a very common choice. This public identifier is often used to provide a unique and location independent key which can be used to subsistute local resources for remote ones (hint: this is why ;).

By using the second (PUBLIC) form combined with some form of local catalog (which matches public-identifiers to local resources) and where the public-identifier is a unique name and the system-identifier is an internet URL, the practical disadvantages of specifying just a system-identifier can be avoided. Those external entities which have been store locally (on the machine parsing the document) can be identified and used. Only when no local copy exists is it necessary to download the document from the internet URL. This naming scheme is recommended when using Digester.

External Entity Resolution Using Digester

SAX factors out the resolution of external entities into an EntityResolver. Digester supports the use of custom EntityResolver but ships with a simple internal implementation. This implementation allows local URLs to be easily associated with public-identifiers.

For example:

    digester.register("-//Example Dot Com //DTD Sample Example//EN", "assets/sample.dtd");

will make digester return the relative file path assets/sample.dtd whenever an external entity with public id -//Example Dot Com //DTD Sample Example//EN is needed.

Note: This is a simple (but useful) implementation. Greater sophistication requires a custom EntityResolver.

Troubleshooting

Debugging Exceptions

Digester is based on SAX. Digestion throws two kinds of Exception:

  • java.io.IOException
  • org.xml.sax.SAXException

The first is rarely thrown and indicates the kind of fundemental IO exception that developers know all about. The second is thrown by SAX parsers when the processing of the XML cannot be completed. So, to diagnose the cause a certain familiarity with the way that SAX error handling works is very useful.

Diagnosing SAX Exceptions

This is a short, potted guide to SAX error handling strategies. It's not intended as a proper guide to error handling in SAX.

When a SAX parser encounters a problem with the xml (well, ok - sometime after it encounters a problem) it will throw a SAXParseException. This is a subclass of SAXException and contains a bit of extra information about what exactly when wrong - and more importantly, where it went wrong. If you catch an exception of this sort, you can be sure that the problem is with the XML and not Digester or your rules. It is usually a good idea to catch this exception and log the extra information to help with diagnosing the reason for the failure.

General SAXException instances may wrap a causal exception. When exceptions are throw by Digester each of these will be wrapped into a SAXException and rethrown. So, catch these and examine the wrapped exception to diagnose what went wrong.

Frequently Asked Questions

Known Limitations

Accessing Public Methods In A Default Access Superclass

There is an issue when invoking public methods contained in a default access superclass. Reflection locates these methods fine and correctly assigns them as public. However, an IllegalAccessException is thrown if the method is invoked.

MethodUtils contains a workaround for this situation. It will attempt to call setAccessible on this method. If this call succeeds, then the method can be invoked as normal. This call will only succeed when the application has sufficient security privilages. If this call fails then a warning will be logged and the method may fail.

Digester uses MethodUtils and so there may be an issue accessing methods of this kind from a high security environment. If you think that you might be experiencing this problem, please ask on the mailing list.

org.apache.tomcat.util.http util.http Special utils for handling HTTP-specific entities - headers, parameters, cookies, etc. The utils are not specific to tomcat, but use util.MessageBytes.
org.apache.tomcat.util.http.fileupload Overview of the org.apache.commons.fileupload component

Component for handling html file uploads as given by rfc 1867 RFC 1867.

Normal usage of the package involves {@link org.apache.commons.fileupload.DiskFileUpload DiskFileUpload} parsing the HttpServletRequest and returning a list of {@link org.apache.commons.fileupload.FileItem FileItem}'s. These FileItem's provide easy access to the data given in the upload. There is also a low level api for manipulating the upload data encapsulated in the {@link org.apache.commons.fileupload.MultipartStream MultipartStream} class.

Normal usage example:


    public void doPost(HttpServletRequest req, HttpServletResponse res)
    {
        DiskFileUpload fu = new DiskFileUpload();
        // maximum size before a FileUploadException will be thrown
        fu.setSizeMax(1000000);
        // maximum size that will be stored in memory
        fu.setSizeThreshold(4096);
        // the location for saving data that is larger than getSizeThreshold()
        fu.setRepositoryPath("/tmp");

        List fileItems = fu.parseRequest(req);
        // assume we know there are two files. The first file is a small
        // text file, the second is unknown and is written to a file on
        // the server
        Iterator i = fileItems.iterator();
        String comment = ((FileItem)i.next()).getString();
        FileItem fi = (FileItem)i.next();
        // filename on the client
        String fileName = fi.getName();
        // save comment and filename to database
        ...
        // write the file
        fi.write("/www/uploads/" + fileName);
    }

In the example above the first file is loaded into memory as a String. Before calling the getString method, the data may have been in memory or on disk depending on its size. The second file we assume it will be large and therefore never explicitly load it into memory, though if it is less than 4096 bytes it will be in memory before it is written to its final location. When writing to the final location, if the data is larger than the threshold, an attempt is made to rename the temporary file to the given location. If it cannot be renamed, it is streamed to the new location.

org.apache.tomcat.util.http.mapper
org.apache.tomcat.util.log
org.apache.tomcat.util.modeler Package Documentation for COMMONS-MODELER

The Modeler component of the Jakarta Commons subproject offers convenient support for configuring and instantiating Model MBeans (management beans), as described in the JMX Specification. It is typically used within a server-based application that wants to expose management features via JMX. See the JMX Specification (Version 1.1) for more information about Model MBeans and other JMX concepts.

Model MBeans are very powerful - and the JMX specification includes a mechanism to use a standard JMX-provided base class to satisfy many of the requirements, without having to create custom Model MBean implementation classes yourself. However, one of the requirements in creating such a Model MBean is to create the corresponding metadata information (i.e. an implementation of the javax.management.modelmbean.ModelMBeanInfo interface and its corresponding subordinate interfaces). Creating this information can be tedious and error prone. The Modeler package makes the process much simpler, because the required information is constructed dynamically from an easy-to-understand XML description of the metadata. Once you have the metadata defined, and registered at runtime in the provided Registry, Modeler also supports convenient factory methods to instantiate new Model MBean instances for you.

The steps required to use Modeler in your server-based application are described in detail below. You can find some simple usage code in the unit tests that come with Modeler (in the src/test subdirectory of the source distribution), and much more complex usage code in Tomcat 4.1 (in the org.apache.catalina.mbeans package).

. More advanced uses can be found in Tomcat 5 and jakarta-tomcat-connectors.

1. Acquire a JMX Implementation

Modeler has been tested with different JMX implementations:

After unpacking the release, you will need to ensure that the appropriate JAR file (jmxri.jar or mx4j.jar) is included on your compilation classpath, and in the classpath of your server application when it is executed.

2. Create a Modeler Configuration File

Modeler requires that you construct a configuration file that describes the metadata ultimately need to construct the javax.management.modelmbean.ModelMBeanInfo structure that is required by JMX. Your XML file must conform to the mbeans-descriptors.dtd DTD that defines the acceptable structure.

Fundamentally, you will be constructing an <mbean> element for each type of Model MBean that a registry will know how to create. Nested within this element will be other elements describing the constructors, attributes, operations, and notifications associated with this MBean. See the comments in the DTD for detailed information about the valid attributes and their meanings.

A simple example configuration file might include the following components (abstracted from the real definitions found in Tomcat 4.1's use of Modeler):


  <?xml version="1.0"?>
  <!DOCTYPE mbeans-descriptors PUBLIC
   "-//Apache Software Foundation//DTD Model MBeans Configuration File"
   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">

  <mbeans-descriptors>

    <!-- ... other MBean definitions ... -->

    <mbean         name="Group"
              className="org.apache.catalina.mbeans.GroupMBean"
            description="Group from a user database"
                 domain="Users"
                  group="Group"
                   type="org.apache.catalina.Group">

      <attribute   name="description"
            description="Description of this group"
                   type="java.lang.String"/>

      <attribute   name="groupname"
            description="Group name of this group"
                   type="java.lang.String"/>

      <attribute   name="roles"
            description="MBean Names of roles for this group"
                   type="java.lang.String[]"
              writeable="false"/>

      <attribute   name="users"
            description="MBean Names of user members of this group"
                   type="java.lang.String[]"
              writeable="false"/>

      <operation   name="addRole"
            description="Add a new authorized role for this group"
                 impact="ACTION"
             returnType="void">
        <parameter name="role"
            description="Role to be added"
                   type="java.lang.String"/>
      </operation>

      <operation   name="removeRole"
            description="Remove an old authorized role for this group"
                 impact="ACTION"
             returnType="void">
        <parameter name="role"
            description="Role to be removed"
                   type="java.lang.String"/>
      </operation>

      <operation   name="removeRoles"
            description="Remove all authorized roles for this group"
                 impact="ACTION"
             returnType="void">
      </operation>

    </mbean>

    <!-- ... other MBean definitions ... -->

  </mbeans-descriptors>

This MBean represents an instance of org.apache.catalina.Group, which is an entity representing a group of users (with a shared set of security roles that all users in the group inherit) in a user database. This MBean advertises support for four attributes (description, groupname, roles, and users) that roughly correspond to JavaBean properties. By default, attributes are assumed to have read/write access. For this particular MBean, the roles and users attributes are read-only (writeable="false"). Finally, this MBean supports three operations (addRole, removeRole, and removeRoles) that roughly correspond to JavaBean methods on the underlying component.

In general, Modeler provides a standard ModelMBean implementation that simply passes on JMX calls on attributes and operations directly through to the managed component that the ModelMBean is associated with. For special case requirements, you can define a subclass of BaseModelMBean that provides override methods for one or more of these attributes (i.e. the property getter and/or setter methods) and operations (i.e. direct method calls).

For this particular MBean, a custom BaseModelMBean implementation subclass is described (org.apache.catalina.mbeans.GroupMBean) is configured. It was necessary in this particular case because several of the underlying Catalina component's methods deal with internal objects or arrays of objects, rather than just the Strings and primitives that are supported by all JMX clients. Thus, the following method on the Group interface:

    public void addRole(Role role);

is represented, in the MBean, by an addRole method that takes a String argument representing the role name of the required role. The MBean's implementation class acts as an adapter, and looks up the required Role object (by name) before calling the addRole method on the underlying Group instance within the Server.

3. Create Modeler Registry at Startup Time

The metadata information, and the corresponding Model MBean factory, is represented at runtime in an instance of Registry whose contents are initialized from the configuration file prepared as was described above. Typically, such a file will be included in the JAR file containing the MBean implementation classes themselves, and loaded as follows:

    URL url= this.getClass().getResource
      ("/com/mycompany/mypackage/mbeans-descriptors.xml");
    Registry registry = Registry.getRegistry();
    registry.loadMetadata(url);

Besides using the configuration file, it is possible to configure the registry metadata by hand, using the addManagedBean() and removeManagedBean() methods. However, most users will find the standard support for loading a configuration file to be convenient and sufficient.

Modeler will also look for a mbeans-descriptors.xml in the same package with the class beeing registered and in its parent. If no metadata is found, modeler will use a number of simple patterns, similar with the ones used by ant, to determine a reasonable metadata

In a future version we should also support xdoclet-based generation of the descriptors

4. Instantiate Model MBeans As Needed

When your server application needs to instantiate a new MBean and register it with the corresponding MBeanServer, it can execute code like this:

  Group group = ... managed component instance ...;

  MBeanServer mserver = registry.getMBeanServer();

  String oname="myDomain:type=Group,name=myGroup";

  registry.registerComponent( group, oname, "Group" );

After the Model MBean has been created and registered, it is accessible to JMX clients through the standard JMX client APIs.

org.apache.tomcat.util.modeler.modules org.apache.commons.modeler.modules

Implementation classes - should not be used directly. The API is not stable but eventually the code will be refactored as a collection of mbeans that will be useable ( more or less ) indepedently.

The MbeanDescriptors* classes are used to extract metadata from different sources. They are result of few stages of refactoring - now they look very similar with ant tasks and are close to normal mbeans, with an execute() method. DOM, SER, Introspection and Dynamic mbean will load metadata from the corresponding sources.

MbeansSource will load an extended MLET file, similar with jboss. It is not completely implemented - only modeler mbeans and dynamic mbeans are loaded. The important characteristic is that all declared mbeans will be registered in the mbean server as model mbeans. For regular java classes, the description will be used to construct the model mbean. DynamicMbeans metadata will be converted to model mbean and the model mbean wrapper will be loaded.

The goal of MbeansSource is to implement a simple persistence mechanism. Since all components are model mbeans, we can detect all changes. The source will be loaded as DOM and modifications will be made to the tree. The save() method will save the DOM tree - preserving all comments and having only the changes that are needed.

There are few remaining issues. First, we need to use the persistence metadata to avoid saving transient fields ( we save an attribute when we detect a change - but we don't know if this attribute should be saved ). The solution is to use the persistence fields in the spec - with some reasonable defaults or patterns for introspection or backward compat.

Another problem is implementing adding and removing components. In catalina, a factory is used to create the components, and save will operate on all mbeans. For creation we need to also use a factory - using the "Type" as a parameter. This will also work very well with Ant1.6 where we can use the component factory to do a "natural" mapping ( i.e. mbeans can be treated as tasks, with attributes as task attributes ). The second part can be solve by either using a parameter on the factory method ( saveTo ? ), or by having a single mbeans source per domain.

org.apache.tomcat.util.net
org.apache.tomcat.util.net.jsse
org.apache.tomcat.util.net.puretls
org.apache.tomcat.util.res
org.apache.tomcat.util.threads
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.