A good first look at the file can be gotten by looking at the DTD for the XML (see Listing 10.1). The full file (for Struts version 1.1) can be found on the Jakarta Web site at
http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd
<!ELEMENT struts-config (data-sources?, form-beans?, global-exceptions?, global-forwards?, action-mappings?, controller?, message-resources*, plug-in*)> |
One reason that it’s important to take a look at the DTD is that the parameters in the config file (like most XML files) are order-dependent, so it’s crucial to put the subelements in the correct order. Now we’ll consider each element in turn.
The data-sources element is defined in Listing 10.2. It defines the preconfigured JDBC data sources that are made available to your application.
<!ELEMENT data-sources (data-source*)> <!ELEMENT data-source (set-property*)> <!ATTLIST data-source id ID #IMPLIED> <!ATTLIST data-source className %ClassName; #IMPLIED> <!ATTLIST data-source key %AttributeName; "org.apache.struts.action.DATA_SOURCE"> <!ATTLIST data-source type %ClassName; #IMPLIED> |
The individual data-source tags inside the surrounding data-sources tag can be used to configure database connections (specifically, JDBC 2.0 DataSource objects).
The first real attribute, className, can be left off (in which case it defaults to the regular Struts DataSource configuration bean class, org.apache.struts.config.Config). This class is used to configure the data source, so it should handle all the properties used to instantiate a DataSource of the type being requested. In other words, it should handle all the properties specified in the set-property clauses of the tag.
The second argument, key, is a handle that the application can use to get the configured DataSource. If there is an application module prefix, it will be appended to this key. The default, if nothing is specified, is org.apache.struts.action.DATA_SOURCE. For example, the StockTrack application would use the servlet context attribute org.apache.struts.action.DATA_SOURCE/stocktrack.
The last argument, type, specifies the class name of the DataSource, which must implement javax.sql.DataSource. This DataSource is configured using the configuration bean class in order to instantiate an instance of the DataSource.
All these values can and will be left off in most normal cases.
Contained in the data-source tag is a series of set-property tags that are used to configure the DataSource. The DTD fragment for set-property (which is also used by some of the other tags in the DTD) is shown in Listing 10.3.
<!ELEMENT set-property EMPTY> <!ATTLIST set-property id ID #IMPLIED> <!ATTLIST set-property property %PropName; #REQUIRED> <!ATTLIST set-property value CDATA #REQUIRED> |
As you can see, the set-property tag consists of a property name and a value to assign to the property.
If you look at an actual data-sources clause taken from the copy of the config file supplied with Struts, it will probably help make sense of what you’ve just read. For that, see Listing 10.4.
<data-sources> <data-source> <set-property property="autoCommit" value="false"/> <set-property property="description" value="Example Data Source Configuration"/> <set-property property="driverClass" value="org.postgresql.Driver"/> <set-property property="maxCount" value="4"/> <set-property property="minCount" value="2"/> <set-property property="password" value="mypassword"/> <set-property property="url" value="jdbc:postgresql://localhost/mydatabase"/> <set-property property="user" value="myusername"/> </data-source> </data-sources> |
An important thing to note is that the class for the database driver itself is not configured using either of the classes in the data-source tag attributes, but is instead supplied as an argument using the set-property tag.
To gain access to the data source from an action, you use the following snippet of code:
ds = servlet.getServletContext().getAttribute("org.apache.struts.action.DATA_SOURCE /stocktrack");
The form-beans and form-bean tags are used to tell Struts what ActionForm classes are associated with what unique identifier. It is also used to initialize DynaForms (see Chapter 17, “DynaForms and the Validator”).
Listing 10.5 shows the applicable piece of the DTD for these tags.
<!ELEMENT form-beans (form-bean*)> <!ATTLIST form-beans id ID #IMPLIED> <!ATTLIST form-beans type %ClassName; #IMPLIED> <!ELEMENT form-bean (icon?, display-name?, description?, set-property*, form-property*)> <!ATTLIST form-bean id ID #IMPLIED> <!ATTLIST form-bean className %ClassName; #IMPLIED> <!ATTLIST form-bean dynamic %Boolean; #IMPLIED> <!ATTLIST form-bean name %BeanName; #REQUIRED> <!ATTLIST form-bean type %ClassName; #REQUIRED> <!ELEMENT form-property (set-property*)> <!ATTLIST form-property className %ClassName; #IMPLIED> <!ATTLIST form-property initial CDATA #IMPLIED> <!ATTLIST form-property name %PropName; #REQUIRED> <!ATTLIST form-property type %ClassName; #REQUIRED> <!ELEMENT icon (small-icon?, large-icon?)> <!ATTLIST icon id ID #IMPLIED> |
The form-beans tag is simply a wrapper around the list of defined form beans. The type attribute has been deprecated.
Each form-bean tag defines a single form. The className attribute can be used to define a configuration bean for this form, similar to the way one can be defined for data sources. You should rarely be required to use this.
The dynamic attribute has been deprecated.
The name attribute is the unique identifier used to access the form, and also to associate a form with an action later in the file. Importantly, if a form has session or application scoping, you can use this name to get a handle to the form using getAttribute().
The type should be set to a valid ActionForm class. This is the class that will be instantiated for the form.
The icon, display-name, and description subtags are used to define a graphical icon, short name, and descriptive information for this form, respectively, but only for use by graphical IDE tools that may be used with Struts itself.
If the type extends (or is) org.apache.struts.action.DynaActionForm, the form-property tags are also inspected by Struts. Each form-property tag defines an initial value, a name, and a type (java.lang.String, for example) for each property of the form. DynaForms are discussed in more detail in Chapter 17.
Listing 10.6 shows the form-beans clause of the StockTrack application.
<form-beans type="org.apache.struts.action.ActionFormBean"> <form-bean name="blankForm" type="stocktrack.struts.form.BlankForm" /> <form-bean name="loginForm" type="stocktrack.struts.form.LoginForm" /> <form-bean name="newUserNameForm" type="stocktrack.struts.form.NewUserNameForm" /> <form-bean name="newUserAddressForm" type="org.apache.struts.validator.DynaValidatorForm"> <form-property name="streetAddress1" type="java.lang.String"/> <form-property name="streetAddress2" type="java.lang.String"/> <form-property name="city" type="java.lang.String"/> <form-property name="state" type="java.lang.String"/> <form-property name="postalCode" type="java.lang.String"/> <form-property name="homePhone" type="java.lang.String"/> <form-property name="workPhone" type="java.lang.String"/> <form-property name="workExt" type="java.lang.String"/> <form-property name="bankRouting" type="java.lang.String"/> </form-bean> <form-bean name="addTransactionForm" type= "stocktrack.struts.form.AddTransactionForm" /> </form-beans> |
Using the global-exceptions tag, you can define handlers for exceptions that might occur during processing of Web pages. The global-exceptions clause is defined by the DTD fragment shown in Listing 10.7.
<!ELEMENT exception (icon?, display-name?, description?, set-property*)> <!ATTLIST exception id ID #IMPLIED> <!ATTLIST exception bundle %AttributeName; #IMPLIED> <!ATTLIST exception className %ClassName; #IMPLIED> <!ATTLIST exception handler %ClassName; #IMPLIED> <!ATTLIST exception key CDATA #REQUIRED> <!ATTLIST exception path %RequestPath; #IMPLIED> <!ATTLIST exception scope CDATA #IMPLIED> <!ATTLIST exception type %ClassName; #REQUIRED> |
The bundle attribute specifies the name of the resource bundle that will hold the message resources for this exception.
handler is the class that’s called when this exception occurs. It defaults to and must extend org.apache.struts.action.ExceptionHandler.
The key attribute is used to specify the template for the error message that will be generated, which is looked up in the message resource bundle.
When the exception occurs, control is redirected to the (module-relative) URL specified in the path attribute.
The scope attribute tells Struts whether to store the ActionErrors created by handling the exception in session or request scope.
Finally, the type attribute names the exception that is to be intercepted by this handler.
Listing 10.8 shows an example of a global exception handler.
<global-exceptions> <exception key="database.error" path="/errors/generalErrors.jsp" scope="request" type="javax.sql.SQLException"/> </global-exceptions> |
With this exception in place, if a SQL exception were thrown during processing, the default resource bundle (ApplicationResources.properties) would be used to find the database.error template, a new ActionError would be created using the template and placed on the request’s attributes, and control would be handed over to the general errors page.
Global forwards are used to define forwarding paths that are available to all actions defined in the configuration. For example, if a number of actions might pass control to a login screen, you can define that forward here rather than individually in each action. The DTD is shown in Listing 10.9.
<!ELEMENT global-forwards (forward*)> <!ATTLIST global-forwards id ID #IMPLIED> <!ATTLIST global-forwards type %ClassName; #IMPLIED> <!ELEMENT forward (icon?, display-name?, description?, set-property*)> <!ATTLIST forward id ID #IMPLIED> <!ATTLIST forward className %ClassName; #IMPLIED> <!ATTLIST forward contextRelative %Boolean; #IMPLIED> <!ATTLIST forward name CDATA #REQUIRED> <!ATTLIST forward path %RequestPath; #REQUIRED> <!ATTLIST forward redirect %Boolean; #IMPLIED> |
The contextRelative tag (which defaults to false) tells Struts whether the path should be considered relative to the module of a modular application (if false) or to the entire Web application (if true).
name is the unique identifier used in the findForward() method inside an Action to return the path.
If redirect is true, control will be transferred to the page with a redirect rather than a forward, meaning that a new request is created.
Although you can specify set-property tags inside the global-forward tag, the base class has no useful properties to set. However, you if extend the class and specify your new class in the className attribute, you can pass in bean values using set-property.
Listing 10.10 shows global forwards in use.
<global-forwards> <forward name="home" path="/home.jsp" /> </global-forwards> |
The action tag is where Struts ties forms, actions, and forwards together. They are bundled together under the action-mappings DTD shown in Listing 10.11.
<!ELEMENT action-mappings (action*)> <!ATTLIST action-mappings id ID #IMPLIED> <!ATTLIST action-mappings type %ClassName; #IMPLIED> <!ELEMENT action (icon?, display-name?, description?, set-property*, exception*, forward*)> <!ATTLIST action id ID #IMPLIED> <!ATTLIST action attribute %BeanName; #IMPLIED> <!ATTLIST action className %ClassName; #IMPLIED> <!ATTLIST action forward %RequestPath; #IMPLIED> <!ATTLIST action include %RequestPath; #IMPLIED> <!ATTLIST action input %RequestPath; #IMPLIED> <!ATTLIST action name %BeanName; #IMPLIED> <!ATTLIST action parameter CDATA #IMPLIED> <!ATTLIST action path %RequestPath; #REQUIRED> <!ATTLIST action prefix CDATA #IMPLIED> <!ATTLIST action roles CDATA #IMPLIED> <!ATTLIST action scope %RequestScope; #IMPLIED> <!ATTLIST action suffix CDATA #IMPLIED> <!ATTLIST action type %ClassName; #IMPLIED> <!ATTLIST action unknown %Boolean; #IMPLIED> <!ATTLIST action validate %Boolean; #IMPLIED> |
Starting at the top, the attribute attribute enables you to specify a different unique ID to store the ActionForm under the request or session scope; otherwise, the name is used.
The forward and include attributes can be used to directly pass on control to a new path rather than processing the action directly.
The input attribute allows the action to redirect back to the form that was used to enter the form values by specifying its path.
The parameter attribute can be used to pass a single parameter to the action, but you’re probably better off using the more general set-property tag and defining specify bean properties for the class.
The path attribute is used to match up the request with the action—it should be the path of the action without any suffixes. For example, if you specified action="/foo/bar.do" in a form, it would match up with an action whose path is /foo/bar.
The prefix attribute enables you to specify a prefix that is added to the bean property names of the action form before matching them to the request parameter names. Similarly, the suffix attribute adds a suffix at the end of the property names.
By specifying a comma-separated list of security role names in the roles attribute, you can restrict access to this mapping to certain classes of users.
The value of scope determines whether the form is kept around for the length of the request or the entire session.
You specify the class of the Action that will process this action with the type attribute.
If you want an action that can be used to process action requests that would not otherwise find a match, set unknown to true. Only one action per configuration can have this set.
Finally, if validate (which defaults true) is false, the validate method of the ActionForm will not be called.
Because the ActionForm (and even the Action itself) are optional, there are a large number of different varieties of this tag. A few are shown in Listing 10.12.
<action-mappings> <action path="/index" forward="home.jsp"/> <action path="/newaccount" type="stocktrack.struts.action.NewAccountAction" name="blankForm" scope="request" input="/home.jsp"> <forward name="newUser" path="/newUserName.jsp" /> </action> <action path="/login" type="stocktrack.struts.action.LoginAction" name="loginForm" scope="request" input="/home.jsp" /> <action path="/newUserName" type="stocktrack.struts.action.NewUserNameAction" name="newUserNameForm" scope="session" input="/newUserName.jsp"> <forward name="newUserAddress" path="/newUserAddress.jsp" /> </action> |
Note that local uses of the forward, exception, and set-property tags are allowed inside an action; they pertain only to the action being defined. The set-property tag can be very useful to pass in information to an action. For example, if a single action class is being used to process several different forms, you can use a set-property tag to tell the action which form is being processed.
The controller tag (whose DTD is shown in Listing 10.13) is probably the least-used tag in Struts. You probably won’t use it unless you really enjoy messing with the innards of the implementation.
<!ELEMENT controller (set-property*)> <!ATTLIST controller id ID #IMPLIED> <!ATTLIST controller bufferSize %Integer; #IMPLIED> <!ATTLIST controller className %ClassName; #IMPLIED> <!ATTLIST controller contentType CDATA #IMPLIED> <!ATTLIST controller debug %Integer; #IMPLIED> <!ATTLIST controller forwardPattern CDATA #IMPLIED> <!ATTLIST controller inputForward %Boolean; #IMPLIED> <!ATTLIST controller locale %Boolean; #IMPLIED> <!ATTLIST controller maxFileSize CDATA #IMPLIED> <!ATTLIST controller multipartClass %ClassName; #IMPLIED> <!ATTLIST controller nocache %Boolean; #IMPLIED> <!ATTLIST controller pagePattern CDATA #IMPLIED> <!ATTLIST controller processorClass %ClassName; #IMPLIED> <!ATTLIST controller tempDir CDATA #IMPLIED> |
By setting bufferSize, you can change the size of the input buffer used when processing file uploads. The maxFileSize attribute defines the largest file that can be uploaded, and can include a K, M, or G afterward to specify kilobytes, megabytes, and so on. The multipartClass value can be set to a fully qualified class name, which is used to handle file uploads. tempDir is the temporary directory to be used when uploading files.
If you will be typically delivering pages other than HTML, the contentType attribute enables you to define a different default content type (such as "text/xml").
You can enable debugging by setting debug to a value greater than 0.
You can alter how an application-specific path is mapped into a context-relative URL by using the forwardPattern. The value $A is expended to the application prefix (/stocktrack, for example) and $P is expanded into the path requested. The default is $A$P.
If you set inputForward to true, the input parameters of action tags are treated as forwards rather than paths. That means they are looked up against the locally and globally defined forward tags rather than being used as raw URIs.
If the locale attribute set to true, it tells Struts to store a locale in the user’s session if one isn’t already there.
By setting nocache to true, a request to disable content caching will be sent to the client browser with each HTTP response.
The pagePattern setting tells Struts how to relate pages to the underlying URL, in much the same way that the forwardPattern does.
Finally, the processorClass enables you to replace the default Struts request processor with one of your own, should you want to change basic functionality of Struts.
Listing 10.14 shows a few of these values being configured.
<controller nocache="true" contentType="image/jpg"/> |
The message-resources tag (whose DTD in Listing 10.15) enables you to configure message resource bundles for use with your application.
<!ELEMENT message-resources (set-property*)> <!ATTLIST message-resources id ID #IMPLIED> <!ATTLIST message-resources className %ClassName; #IMPLIED> <!ATTLIST message-resources factory %ClassName; #IMPLIED> <!ATTLIST message-resources key %AttributeName; "org.apache.struts.action.MESSAGE"> <!ATTLIST message-resources null %Boolean; #IMPLIED> <!ATTLIST message-resources parameter CDATA #REQUIRED> |
The factory attribute enables you to specify where the message resource will get its data. By default, it is configured to use property files.
When the application goes looking for the resource bundle in the servlet context, it will use the key as the lookup, similar to how DataSources are stored. By default, the StockTrack application would store its message bundle in org.apache.struts.action.MESSAGE/stocktrack.
The null attribute enables you to specify what to do if no match is found in the bundle for a given message key. If set to true, it will return null; if set to false, it will return a message with the bad key.
The parameter is handed to the factory when the bundle is created. For property-file-based factories, this is the path to the property file. Listing 10.16 shows an example of a message-resources tag in use.
<message-resources key="com.stocktrack.STOCKTICKER_MESSAGES" parameter="com.stocktrack.StocktickerMessages"/> |
This enables you to get a handle on the resource bundle stored in the StocktickerMessages.properties file by using the servlet context attribute called com.stocktrack.STOCKTICKER_MESSAGES/stocktrack.
The final element of the DTD is the plug-in tag, which allows additional functionality to be dynamically loaded into the Struts framework. Listing 10.17 shows the DTD for the tag.
<!ELEMENT plug-in (set-property*)> <!ATTLIST plug-in id ID #IMPLIED> <!ATTLIST plug-in className %ClassName; #REQUIRED> |
In the case of this tag, the only things you need to do are to specify the className, which specifies the class that loads the plug-in, and to use the set-property tag to pass in any required arguments to the plug-in. Listing 10.18 shows how you can use this tag to load the Struts Validator plug-in, which is discussed in Chapter 17.
<plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/WEB-INF/validator-rules.xml, /WEB-INF/validation.xml"/> </plug-in> |
The struts-config.xml file is what Struts uses to load its initial configuration. After Struts is up and running, you can gain access to the in-memory version of this data using this snippet:
ApplicationConfig ap = (ApplicationConfig) request.getAttribute(Action.APPLICATION_KEY);
From the ApplicationConfig object, you can gain access to all the various parts of the Struts configuration, using accessors such as findConfigs and findForwardConfig. You can also add and remove values from the configuration. For example, Listing 10.19 shows how you could configure a new Action on the fly.
ApplicationConfig ap = (ApplicationConfig) request.getAttribute(Action.APPLICATION_KEY); ActionConfig ac = new ActionConfig(); ac.setInput("/bankruptcy.jsp"); ac.setPath("/goBankrupt"); ac.setName("bankruptcyForm"); ac.setType("stocktrack.struts.action.BankruptcyAction"); ap.addActionConfig(ac); |
Clearly, this functionality is not intended for everyday use, although it can be useful for Actions and ActionForms to be able to introspect their ApplicationConfig.
You can also access the Struts configuration information using the bean:struts tag. For more information on this tag, see Chapter 13, “Struts Bean Tags: Storing and Passing Data.”