|
|||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Class Summary | |
ArrayStack | Implementation of the java.util.Stack API that is based on
an ArrayList rather than a Vector . |
BeanUtils | Deprecated. At some point after Struts 1.0 final, will be replaced by an equivalent class in the Jakarta Commons Beanutils package. |
ConvertUtils | Deprecated. At some point after Struts 1.0 final, will be replaced by an equivalent class in the Jakarta Commons Beanutils package. |
ErrorMessages | Deprecated. Use org.apache.struts.action.ActionErrors instead |
FastArrayList | Deprecated. At some point after Struts 1.0 final, will be replaced by an equivalent class in the Jakarta Commons Collections package. |
FastHashMap | Deprecated. At some point after Struts 1.0 final, will be replaced by an equivalent class in the Jakarta Commons Collections package. |
FastTreeMap | Deprecated. At some point after Struts 1.0 final, will be replaced by an equivalent class in the Jakarta Commons Collections package. |
GenericConnection | Generic wrapper implementation of a Connection that
works with GenericDataSource to wrap connections for any
JDBC driver. |
GenericDataSource | Generic data source implementation of the DataSource
interface. |
IteratorAdapter | Utility method for converting Enumeration to an Iterator class. |
MessageResources | General purpose abstract class that describes an API for retrieving
Locale-sensitive messages from underlying resource locations of an
unspecified design, and optionally utilizing the MessageFormat
class to produce internationalized messages with parametric replacement. |
MessageResourcesFactory | Factory for MessageResources instances. |
PropertyMessageResources | Concrete subclass of MessageResources that reads message keys
and corresponding strings from named property resources in the same manner
that java.util.PropertyResourceBundle does. |
PropertyMessageResourcesFactory | Factory for PropertyMessageResources instances. |
PropertyUtils | Deprecated. At some point after Struts 1.0 final, will be replaced by an equivalent class in the Jakarta Commons Beanutils package. |
RequestUtils | General purpose utility methods related to processing a servlet request in the Struts controller framework. |
ResponseUtils | General purpose utility methods related to generating a servlet response in the Struts controller framework. |
ServletContextWriter | A PrintWriter implementation that uses the logging facilities of a
javax.servlet.ServletContext to output its results. |
The Utilities package provides a variety of families of classes,
to solve problems that are commonly encountered in building web applications.
The Struts Utilities Package offers several families of classes that assist in solving commonly encountered problems when building web applications. Most of the classes in this package do not rely on the controller servlet framework, or the custom tag libraries, so they are also suitable for general Java application programming. The following families are included:
java.util.Locale
object representing a
particular user's preferred language.FIXME
FIXME some parts of this might me moved to Taglibs
The BeanUtils
and PropertyUtils
utilities are
used through out struts including the IteratorTag, WriteTag
.
Much of these utilities rely on and make use of Java reflection, to manipulate
Java beans . Creating a valid Java bean is essential !
Briefly referring to the example class ProductBean
below would follow these rules :
public class ProductBean() { private String value; public String getvalue() (return this.value} public void setvalue(String value) (this.value = value} }
Observing these conventions will avoid unnecessary errors and save time.
This makes it possible to create a JSP page such as:
<logic:iterate id="product" name="receivedForm" property="receivedList"> <bean:write name="product" property="description" /> <bean:write name="product" property="value" /> </logic:iterate>In this case receiveForm is an ActionForm, with a definition such as
public class ReceivedForm extends ActionForm { private ProductList productList; public void setReceivedList(Enumeration enum) { productList = new ProductList(enum,Limits.ARRAY_SIZE_MIN); } /** * Defined so java.bean reflection will see getReceivedList * as a getter for receivedList */ public void setReceivedList(ProductList productlist) { } /** * Returns an Array list of ProductBeans. */ public ProductList getReceivedList() { return productList; }; } //ReceiveForm
Version 1.2 of the Java 2 Standard Edition (J2SE) introduced a powerful
set of collection classes that are generally useful in Java programming, based
on the fundamental interfaces java.util.Collection
,
java.util.List
, java.util.Map
, and
java.util.Set
. Compared to the collection classes available in
JDK 1.1 (principally java.util.Hashtable
and
java.util.Vector
), the new classes offer much richer functionality
as well as the opportunity to improve performance.
The performance increase potential comes from the fact that none of the
methods used to access the new collection classes are synchronized
as were the methods of Hashtable
and Vector
. In a
single thread application, this means that method calls can execute much more
quickly because synchronization is never necessary. In a multiple thread
environment, though, it is up to the developer to ensure that any method calls
made while another thread is modifying the collection must be synchronized.
There are many cases in multithreaded server environments (such as a web
application) where data structures are initialized at application startup
time, and are then predominantly accessed in a read-only manner. An example
of this is the Struts controller application, which initializes its collection
of ActionMapping
instances (each corresponding to an
<action>
element in the struts-config.xml
file) at startup time. However, it is legal for an application to dynamically
change the set of available mappings while the application is running -- so,
to be safe, it would normally be necessary to synchronize access to such
collections, even though 99% of those accesses are read only and would not
otherwise require synchronization.
To deal with such scenarios, the Struts utility package includes a series of specialized collection classes designed to operate in a multithread environment where the large majority of accesses are read only, without requiring synchronization on every operation, but still protecting against the possibility of runtime modifications to the underlying collection.
Each of the available collection classes operates in one of two modes:
fast or slow. When first created, the collection operates
in slow mode, which is appropriate for initially populating the
contents of the collection. Once the initial population is complete, switch
to fast mode by calling setFast(true)
for maximum
performance when most accesses are read-only.
When operating in slow mode, all methods that access this
collection, even read-only methods, are synchronized - resulting in impacts on
performance similar to that always performed by the Hashtable
and
Vector
classes. This mode is appropriate when you are
initializing the content of the collection, or when you need to perform a large
series of updates.
Using fast mode, on the other hand, causes method calls to operate in the following manner:
As you can see, modification operations are much more expensive when operating in fast mode, but doing things in this way allows read only operations, which should be the vast majority, to operate at maximum speed.
If your collection will never be accessed in a multithread environment, you should use one of the standard collection classes instead, without synchronization, for maximum performance.
The following collection classes, with the ability to operate in either fast or slow mode, are included:
java.util.ArrayList
.java.util.HashMap
.java.util.TreeMap
.A large number of web applications require interaction with a relational database to access or update persistently stored information. In a typical client-server application, each concurrent user opens their own database connection at program initialization, and uses this connection throughout the period of time the application is open.
While this approach can work well in an environment where the number of active users is reasonably fixed, it does not scale well to a web application where the number of simultaneous users could be very large. In addition, open database connections (even when not actively used) do impose some overhead costs, and most web application users (at a given instant) are reviewing the contents of a previously generated page (or typing in their next set of input information), rather than actively accessing the database.
To deal with this situation, several basic strategies are possible:
The first strategy has the virtue of simplicity - you merely need to open a database connection any time you need one, perform the appropriate data accesses and updates, and close the connection. However, it suffers from a major disadvantage: on most databases, establishing a connection can be very time consuming (often requiring multiple seconds of clock time), in order to perform a database transaction that might take milliseconds.
Opening a connection per user, as the second strategy suggests, is similar to the approach taken with client-server applications described earlier. As long as the number of simultaneous users can be controlled at a manageable number (such as with many intranet-based applications), this approach is feasible. However, it becomes unmanageable when the number of users can climb rapidly to very large numbers (as is typical of many Internet-hosted public applications), and still requires more overhead than a strategy that would share a smaller number of connections.
Connection pooling is an implementation of the third strategy. It is based on the assumption that most users of a web application will be interacting locally with the last page that was sent to their browser. The number of users actually performing a request at any given time is usually a very small percentage of the total number of active users, and during request processing is the only time that a database connection is required.
Struts provides a simple connection pool class called
org.apache.struts.util.GenericDataSource
. It allows you to
configure a set of connections (with identical connection parameters) to a
particular database, using a particular JDBC driver, and then share those
connections among a number of simultaneously operating threads (such as the
various request threads that are concurrently active in a servlet container).
The GenericDataSource
class implements the
javax.sql.DataSource
interface from the Java Database Connectivity
(version 2.0) Standard Extension API, so any programs you use to access it
should reference this interface, rather than the class name directly.
That way, you can migrate to a more advanced connection pool implementation
later, with little or no impact on your application.
For more information about the JDBC 2.0 Standard Extension API, you can download the spec (and the corresponding API classes), from http://java.sun.com/products/jdbc. You can also find pointers to a substantial amount of other information about available JDBC drivers, programming tutorials, and so on, at this web address.
The following instructions show you how to configure the connection pool class and use it, from any Java application. As you will see below, the Struts controller servlet offers you convenient mechanisms to configure one or more connection pools, and make them available to Action classes and JSP pages by storing the connection pool instances as servlet context attributes (in JSP terms, application-scope beans).
To configure a GenericDataSource
instance, you must first
create one:
GenericDataSource dataSource = new GenericDataSource();
Next, you must set the appropriate properties, by calling the corresponding JavaBeans property setter methods provided by this class. (See the Javadoc API for the GenericDataSource class for more details on the available properties). An example of configuring the connection pool object to a Postgres database might look like this:
dataSource.setAutoCommit(false); dataSource.setDescription("My Database Connection Pool"); dataSource.setDriverClass("org.postgresql.Driver"); dataSource.setMaxCount(4); dataSource.setMinCount(1); dataSource.setPassword("mypassword"); dataSource.setUrl("jdbc:postgresql://localhost/mydatabase"); dataSource.setUser("myusername");
Finally, you must open()
the connection pool. This will
establish the initial connections to the database (based on the value you have
configured for the minCount
property). As you use connections
from the pool in multiple threads, additional connections (up to the number
you specify with the maxCount
property) will be created as needed.
try { dataSource.open(); } catch (SQLException e) { ... deal with exception ... }
When you are completely through with the connection pool, you can gracefully close all of the currently open database connections by executing
try { dataSource.close(); } catch (SQLException e) { ... deal with exception ... }
To access the database from within an application class, you must follow a simple four-step procedure each time you need a connection:
An example code sequence that performs this procedure might look like this:
DataSource dataSource = ... acquire reference to dataSource ... Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { conn = dataSource.getConnection(); stmt = conn.prepareStatement("SELECT cust_id, name FROM customers" + " WHERE (last_purchase_date >= ?)" + " ORDER BY name"); stmt.setDate(1, lastPurchaseDate); rs = stmt.executeQuery(); while ((row = rs.next()) != null) { ... process this row ... } rs.close(); rs = null; stmt.close(); stmt = null; conn.commit(); conn.close(); conn = null; } catch (SQLException e) { if (rs != null) { try { rs.close(); } catch (SQLException f) { ; } rs = null; } if (stmt != null) { try { stmt.close(); } catch (SQLException f) { ; } stmt = null; } if (conn != null) { try { conn.rollback(); } catch (SQLException f) { ... deal with exception ... } } ... deal with exception ... } finally { if (conn != null) { try { conn.close(); } catch (SQLException f) { ... deal with exception ... } conn = null; } }
One aspect of the above code example that might surprise developers who
have previously used JDBC connections individually is the idea of calling
close() on the Connection. Normally, this call will sever the Connection's
underlying link to the database, and render that Connection unuseable for
any further operations. However, when used in a connection pool environment,
the actual Connection you receive by calling getConnection()
is a customized "wrapper" around a real JDBC Connection instance. Calling
close()
on this wrapper simply causes this connection to be
returned to the pool.
What would happen if your application failed to return a connection to the pool when it was through? As you might expect, that particular connection becomes "lost" to the server, and can never again be used (even though it remains connected to the database throughout the life of the connection pool itself). If this happens repeatedly, you will eventually exhaust the pool of available connections, and application processing will stop.
To avoid this problem, your application logic must ensure that it
ALWAYS returns allocated connections to the pool, no matter
what problems might happen in the interim. The Java language provides one
convenient mechanism to achieve this - using a finally
block,
as in the code example above. This is not the only way to ensure that a
connection is always returned, but it is very convenient.
If your application is running underneath the Struts controller servlet
(org.apache.struts.action.ActionServlet
), you can take advantage
of the servlet's ability to preconfigure one or more connection pools for you,
based on information included in the struts-config.xml
file.
Simply include a section that looks like this:
<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>
After being initialized, the connection pools will be stored as servlet
context attributes under the bean name specified by the key
attribute. If you did not specify a key
, the default key is the
value of the string constant Action.DATA_SOURCE_KEY
. Thus, you
can access and utilize a connection, from within an Action
class,
like this (for the default data source):
DataSource dataSource = (DataSource) servlet.getServletContext().getAttribute(Action.DATA_SOURCE_KEY); conn = dataSource.getConnection(); ... perform required functions as in the previous example ... conn.close();
Modern applications often include the requirement to support multiple languages, for users who prefer to interact in a language other than the default language configured on the server platform. In addition, sentences often need to be constructed, with dynamic content whose placement in the message depends on the standard sentence structure in that particular language.
The standard Java platform includes a family of classes
(java.util.ResourceBundle
) designed to support looking up message
strings based on a standard "key". The resource bundle classes automatically
access a Java class (or properties file) that is named with a naming
convention that includes the Locale to which messages in that class (or file)
pertain. However, this selection is based only on the default Locale of the
server platform, and cannot be adjusted on a per-user basis as required for an
internationalized web application.
Struts includes a family of classes
(org.apache.struts.util.MessageResources
) that extends the basic
approach to looking up message strings by key, allowing you to optionally
specify a Locale along with the key. In this way, you can build applications
that let your users select which Locale they wish to operate within, and then
look up messages in that language - using the same message keys no matter what
language is selected.
In addition to supporting dynamic selection of a Locale for message lookup,
the MessageResources
family of classes optionally allow you to
specify up to four parameter replacement objects, which are used to replace the
parameter placeholders "{0}" through "{3}" in the retrieved message. This
replacement uses the facilities of the standard Java
java.text.MessageFormat
class, which supports many extended
formatting capabilities as well.
For more information about internationalized messages, consult the following resources in your Java Development Kit documentation bundle:
<$JAVA_HOME/docs/guide/internat/index.html>
.
The "Internationalization Overview" section includes useful information
about Locales, localized resources, message formatting, and other
relevant topics.java.text.MessageFormat
java.util.ResourceBundle
java.util.PropertyResourceBundle
java.util.Properties
- See the documentation for the
load()
method for the valid syntax of properties files
that you prepare.The standard MessageResources
implementation provided by the
Struts library uses Java properties files to initialize message strings, in a
manner very similar to that supported by the
java.util.PropertyResourceBundle
class. The following steps are
required to use these facilities in your Java application.
First, prepare a Java properties file for each language (or Locale) in which you wish to support your messages. The filenames you use must conform to the naming convention for property resource bundles, as described in the documentation referenced above. Be sure you use the same message keys in each file to identify the same message.
For example, you might prepare files in French, Spanish, and English that
contain language-specific versions of the word "Hello". The French file would
be named Messages_fr.properties
and contain the following:
hi=Bonjour
while the Spanish and English files would be named
Messages_es.properties
and Messages_en.properties
respectively. The corresponding message string definitions would say
hi=Hola
and hi=Hello
in these files.
Second, place these properties files into the class path for your application, exactly as you would with class files themselves. The name actually used to load resources will look like a fully qualified Java class name (with appropriate package prefixes), so the file should be nested inside a directory structure that matches the packaging (either in an unpacked directory, or within a JAR file, as appropriate). For example, assume you place directory "foo" on your classpath, and stored the above properties files in directory "foo/com/mycompany/mypackage". (If you were using a JAR file like "foo.jar" instead, the files would be in directory "com/mycompany/mypackage" within the JAR file).
Third, initialize a MessageResources
object that corresponds
to the set of properties files for a particular name, within a particular
package. The easiest way to do this is to initialize a variable in your main
application class, like this:
public static MessageResources messages = MessageResources.getMessageResources("com.mycompany.mypackage.Messages");
Note that the "com.mycompany.mypackage" part of the name matches the package
directory into which you placed your properties files, and "Messages" is the
filename prefix for the particular family of properties files supported by this
MessageResources
instance. Depending on your development process,
you might find it convenient to store all message strings for an entire
application in a single properties file family, or to have several families -
in Struts, for example, there is a family of properties files for each Java
package.
To access a message string with a particular Locale, execute a statement like this:
Locale locale = ... select the locale to be used ... String message = messages.getMessage(locale, "hi");
In this case, the variable message
will contain the message
string corresponding to the key "hi", in the language that corresponds to the
locale that was selected.
For an example of message formatting with replaceable parameters, assume that the message strings looked like this, instead (only the English version is shown - corresponding changes would be made in the other files):
hi=Hello {0}
Now, you can personalize the retrieved message like this:
Locale locale = ... select the locale to be used ... String name = "Joe"; String message = messages.getMessage(locale, "hi", name);
and the marker "{0}" will have been replaced by the specified name (Joe),
no matter which language is in use. See the JavaDoc API documentation for the
java.text.MessageFormat
class for more advanced uses of the
parameter replacement mechanism.
In the above example, we were using the default
MessageResources
implementation supplied by Struts, which uses
property files to store the message strings. It is also possible to create
customized mechanisms to retrieve messages (such as loading them on demand
from a database). The steps required are as follows:
org.apache.struts.util.MessageResources
that implements
message lookup operations as you require.org.apache.struts.util.MessageResourcesFactory
that will
create an instance of your custom MessageResources
class
when the createResources
method is called. Note that the
"config" argument to this method can be used to select families of
messages in any manner appropriate to your needs - you are not required
to emulate the "fully qualified Java class name" approach that is used
by the standard PropertyMessageResourcesFactory
class.MessageResourcesFactory
class the name of the
customized MessageResourcesFactory
implementation to use
when creating new factory instances.MessageResources
instance for you.A code example that illustrates this technique is:
MessageResourcesFactory.setFactoryClass("com.mycompany.mypkg.MyFactory"); MessageResourcesFactory factory = MessageResourcesFactory.createFactory(); MessageResources resources = factory.createResources("configuration information");
Once you have created your custom MessageResources instance, you utilize it to access message strings (with or without parameter replacement objects), exactly as we illustrated with the standard implementation in the previous section.
If your application uses the Struts controller servlet, you can optionally configure Struts to load an application-specific message resources instance for you, and make it available as a servlet context attribute (in JSP terms, an application-scope bean). This mechanism is managed by setting the following servlet initialization parameters in the web application deployment descriptor:
createResources()
method of the message
resources factory, in order to identify the family of resources to be
supported. If you use the standard message resources factory, this must
be the base fully qualified name of the property resources files used
to contain these messages, as illustrated above.MessageResourcesFactory
to be used. By default, the standard
implementation provided by Struts
(org.apache.struts.util.PropertyMessageResourcesFactory
)
will be used.Struts provides several JSP custom tags that assume the existence of a
java.util.Locale
attribute in the user's session, under the key
named by the constant string value of Action.LOCALE_KEY
. Your own
application logic can set this attribute at any time, or you can ask Struts to
set it automatically (if not already set) based on the
Accept-Language
HTTP header included with the request. There are
two mechanisms by which you request Struts to perform this service:
locale
to
the value true
in the application deployment descriptor.<form:html ... locale="true" ... />
tag at the top of each page.
|
|||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |