The Spring Petclinic Application
Updated :
01-DEC-2004 - Ken Krebs
16-AUG-2003 - Ken Krebs
Introduction
Spring is a collection of small, well-focused, loosely coupled Java
frameworks that can be used independently or collectively to build
industrial strength applications of many different types. The Petclinic
sample application is designed to show how the Spring
application frameworks can be used to build simple, but powerful
database-oriented applications. It will demonstrate the use
of Spring's core functionality:
- JavaBeans based application configuration using
Inversion-Of-Control
- Model-View-Controller web Presentation Layer
- Practical database access through JDBC, Hibernate, or Apache OJB
- Declarative Transaction Management using AOP
- Data Validation that supports but is not dependent on the
Presentation Layer
The Spring frameworks provide a great deal of useful infrastructure to
simplify the tasks faced by application developers. This infrastructure
helps developers to create applications that are :
- concise
by handling a lot of the complex control flow that is needed to use the
Java API's, such as JDBC, JNDI, JTA, RMI, and EJB.
- flexible
by simplifying the process of external application configuration
through
the use of Reflection and JavaBeans. This allows the developer to
achieve a clean separation of configuration data from application code.
All application and web application objects, including validators,
workflow controllers, and views, are JavaBeans that can be configured
externally.
- testable
by supplying an interface based design to maximize pluggability. This
facilitates unit testing of Business Logic without requiring the
presence
of application or live database servers.
- maintainable
by facilitating a clean separation of the application layers. It most
importantly helps maintain the independence of the Business Layer
from the Presentation layer. Petclinic demonstrates the use of a
Model-View-Controller
based web presentation framework that can work seamlessly with many
different types of view technologies. The Spring web application
framework helps developers to implement their Presentation as a clean
and thin layer focused on its main missions of translating user actions
into application events and rendering model data.
It is assumed that users of this tutorial will have a basic knowledge
of object-oriented design, Java, Servlets, JSP, and relational
databases. It also assumes a basic knowledge of the use of a J2EE web
application container.
Since the purpose of the sample application is tutorial in nature, the
implementation presented here will of course provide only a small
subset
of the functionality that would be needed by a real world version of a
Petclinic application.
Petclinic Sample Application Requirements
The application requirement is for an information system that is
accessible through a web browser. The users of the application are
employees of the clinic who in the course of their work need to view
and
manage information regarding the veterinarians, the clients, and their
pets. The sample application supports the following:
Use Cases:
- View a list of veterinarians and their specialties
- View information pertaining to a pet owner
- Update the information pertaining to a pet owner
- Add a new pet owner to the system
- View information pertaining to a pet
- Update the information pertaining to a pet
- Add a new pet to the system
- View information pertaining to a pet's visitation history
- Add information pertaining to a visit to the pet's visitation
history
Business Rules:
- An owner may not have multiple pets with the same
case-insensitive name.
Petclinic Sample Application Design & Implementation
Server
Technology
The sample application should be usable with any J2EE web application
container that is compatible with the Servet 2.3 and JSP 1.2
specifications. Some of the deployment files provided are designed
specifically for Apache Tomcat. These files specify container-supplied
connection-pooled data sources. It is not necessary to use these files.
The application has been configured by default to use a data source
without connection pooling to simplify usage. Configuration details are
provided in the Developer Instructions section. The view technologies
that are to be used for rendering the application are Java Server Pages
(JSP) along with the Java Standard Tag Library (JSTL).
Database
Technology
The sample application uses a relational database for data storage.
Support has been provided for a choice of 1 of 2 database selections,
MySql or HypersonicSQL. HypersonicSQL version 1.7.2 is the default
choice and a copy is provided with the application. It is possible to
easily configure the application to use either database. Configuration
details are provided in the Developer Instructions section.
Development
Environment
A copy of the Spring runtime library jar file is provided with the
sample application along with some of the other required jar files. The
developer will need to obtain the following tools externally, all of
which are freely available:
- Java SDK 1.4.x
- Ant 1.5.x
- Tomcat 4.1.x, or some other web application container
- JUnit 3.8.1 - needed to run the tests
- (Optional) MySql 3.23.53 with mysql-connector 2.0.14
NOTE: The version numbers
listed
are those that were used in the development of the Petclinic
application. Other versions of the same tools may or may not work.
Download links for the various tools needed are provided in the
Developer Instructions section.
Petclinic
Database
The following is an overview of the database schema used in Petclinic.
Detailed field descriptions can be found in the "initDB.txt" SQL
script
files in the database-specific "db" sub-directories. All "id" key
fields
are of Java type int.
TABLE: owners
PRIMARY KEY id
TABLE: types
PRIMARY KEY id
TABLE: pets
PRIMARY KEY id
FOREIGN KEY type_id
references the types
table id field
FOREIGN KEY owner_id
references the owners
table id field
TABLE: vets
PRIMARY KEY id
TABLE: specialties
PRIMARY KEY id
TABLE: vet_specialties-
a link table for vets
and their specialties
FOREIGN KEY vet_id
references the vets
table id field
FOREIGN KEY specialty_id
references the specialties
table id field
TABLE: visits
PRIMARY KEY id
FOREIGN KEY pet_id
references the pets
table id field
Directory
Structure
d-- indicates a directory holding source code, configuration files, etc.
D-- indicates a directory that is created by the build script
d-- petclinic :
the root directory of the project contains build related files
d-- src : contains
Java source code files and ORM configuration files
d-- war : contains
the web application resource files
d-- html : contains
tutorial files
D-- docs : contains
Javadoc files
d-- web-inf :
contains web application configuration files and application context
files
d-- jsp:
contains Java Server Page files
D-- lib:
contains application dependencies
d-- test : contains
testing related
Java source code files
d-- db : contains
database sql scripts and other related files/directories
d-- hsqldb :
contains files related to HSQL, contains scripts and a Tomcat
context definition file
d-- mysql :
contains files related to MySQL, contains scripts and a Tomcat context
definition file
D-- .classes :
contains compiled Java class files
D-- .testclasses :
contains compiled testing related Java class files
D-- junit-reports :
contains generated xml-formatted test reports
D-- reports/html :
contains generated html-formatted test reports
D-- dist : contains
packaged archives of files
Petclinic Application Design
Logging
Spring supports the use of the Apache
Commons Logging API.This API provides the ability to use Java 1.4
loggers, the simple Commons loggers, and Apache Log4J loggers.
Petclinic uses Log4J
to provide sophisticated and configurable logging capabilities. The
file, war/WEB-INF/log4j.properties
configures the definition of Log4j loggers.
BusinessLayer
The
Business Layer consists of a number of basic JavaBean classes
representing the application domain objects and associated validation
objects that are used by the
Presentation Layer.The validation objects used in Petclinic are
all implementations of the org.springframework.validation.Validator
interface.
- org.springframework.samples.petclinic.Entity
is a simple JavaBean superclass used for all persistable objects.
- org.springframework.samples.petclinic.NamedEntity
is an extension of Entity that
adds a name property.
- org.springframework.samples.petclinic.Specialty
is an extension of NamedEntity.
- org.springframework.samples.petclinic.PetType
is an extension of NamedEntity.
- org.springframework.samples.petclinic.Person is
an extension of Entity that
provides a superclass for all objects that implement the notion
of
a person.
- org.springframework.samples.petclinic.Vet is
an extension of Person that implements a
veterinarian. It holds a List of
specialties that the Vet is
capable of.
- org.springframework.samples.petclinic.Owner
is
an extension of Person that implements a pet owner.
It holds a List of pets
owned.
- org.springframework.samples.petclinic.Pet
is an extension of
NamedEntity that
implements a pet. It holds a List of
visits made concerning the
pet.
- org.springframework.samples.petclinic.Visit
is a simple JavaBean that implements the notion of a clinic visit
for a pet.
- org.springframework.samples.petclinic.util.EntityUtils
provides utility methods for handling enitites.
- org.springframework.samples.petclinic.validation.FindOwnerValidator
is
a Spring Validator that
verifies correct data entry for the FindOwner form.
- org.springframework.samples.petclinic.validation.OwnerValidator
is a Spring Validator that
verifies correct data entry for the Add and Edit Owner forms.
- org.springframework.samples.petclinic.validation.PetValidator
is a Spring Validator that
verifies correct data entry for the Add and Edit Pet forms.
- org.springframework.samples.petclinic.validation.VisitValidator
is a Spring Validator that
verifies correct data entry for the AddVisit form.
Business/Persistence
Layer
Since
the Petclinic application is all about database access and there is
very little business logic in the application outside of that, there is
no separation of the primary Business and Persistence Layer API's.
While
this design technique should not be used for an application with more
complex business logic, it is acceptable here because all of the
non-persistence related business rules have been implemented in
business
objects and have not leaked into the Persistence Layer. The most
important facet of the design is that the Business and Persistence
Layers are COMPLETELY independent
of the Presentation Layer.
The Persistence Layer can be configured to use either HSQL or MySQL
with any one of three strategies aided by infrastructure
provided by Spring:
- JDBC
- Hibernate
- Apache OJB
NOTE: Spring also provides
infrastructure for using other Object-Relational-Mapping frameworks such as JDO
and iBATIS SqlMaps but these are not demonstrated in Petclinic.
One of the key elements provided by Spring is the use of a common set
of meaningful data access exceptions that can be used regardless of
which database or access strategy is used. All of these exceptions
derive from org.springframework.dao.DataAccessException.
Since most exceptions encountered during database access are indicative
of programming errors, DataAccessException
is an abstract RuntimeException whose
derivatives only need to be caught by application code to handle
recoverable errors when it makes sense to do so. This greatly
simplifies application code compared to, for example, code
using JDBC directly where SqlExceptions
must be caught and database specific error codes must be
decoded. Examination of the Petclinic source code will show that the
persistence-oriented code is completely focused on the relevant
transfer of data to/from the referenced objects without extraneous
error handling.
The high-level business/persistence API for Petclinic is the org.springframework.samples.petclinic.Clinic
interface. Spring provides several convenient abstract
DaoSupport classes for each of the persistence strategies. Each
persistence strategy in Petclinic is a different implementation of the Clinic interface that extends the
respective DaoSupport class. In each case, the Clinic implementation is fronted by
a transactional proxy that also implements Clinic. These objects are standard
Java dynamic proxies which are created by an instance of org.springframework.transaction.interceptor.TransactionProxyFactoryBean.
These proxies are configured in the respective application context file
and specify that all Clinic methods
are run in a transactional context.The transaction managers used in
Petclinic are all implementations of the org.springframework.transaction.PlatformTransactionManager
interface. All of the implementations are by default configured
to use a local DataSource that
will work in any environment through the use of an instance of org.springframework.jdbc.datasource.DriverManagerDataSource.
While this is appropriate for use in a demo or single user
program, a connection pooling DataSource,
such as an instance of org.apache.commons.dbcp.BasicDataSource,
is more appropriate for use in a multi-user application. Another
alternative is to obtain one through the J2EE environment
using an instance of org.springframework.jndi.JndiObjectFactoryBean.
JDBC
Clinic Implementation
Spring provides a number of high-level database
access convenience classes in the package org.springframework.jdcb.object.
These
classes and the lower-level Spring classes that they use in the org.springframework.jdcb.core package
provide a
higher level of abstraction for using JDBC that keeps the developer
from having to correctly implement the handling of the checked SqlExceptions with ugly error-prone
nested try-catch-finally blocks. Using the classes in this package
allows the developer to focus efforts on the functionality being
implemented rather than the mechanics of error handling. When using
these classes, it is the responsibility of the developer to provide the
SQL needed and to map the parameters to/from the repective domain
object. This typically is done by extending one of the org.springframework.jdcb.object classes,
initializing its SQL, and overriding a method that takes care of
the mapping. In this way, the developer gets to focus on implementing
functionality rather than application plumbing. These classes also
take care of closing connections to prevent hard to find resource
leakage problems. It should be noted that instances of these classes
are
lightweight, reusable, and threadsafe.
All of these objects in Petclinic initialize the SQL in their
constructors. SQL "Select" type
queries are implemented by subclassing org.springframework.jdcb.object.MappingSqlQuery.
These subclasses override the mapRow(ResultSet,
int rowNum) method to extract data from the ResultSet returned to the framework
by execution of the query. The framework calls this method once for
every row in the ResultSet.
SQL "Update" and "Insert" type queries are implemented by
subclassing org.springframework.jdcb.object.SqlUpdate.
These subclasses override or call an update(Object[]) method that
places the
domain object data into an Object array which is substituted into the
appropriate SqlParameters of
a PreparedStatement.
The primary JDBC implementation of the Clinic
interface is org.springframework.samples.petclinic.jdbc.AbstractJdbcClinic.
It defines and uses the following inner classes:
- VetsQuery is
the base class for any Vet Query
Objects. It provides an "All Vets" query as a convenience.
- SpecialtiesQuery
is the "All Vet's Specialties"
Query Object.
- VetSpecialtiesQuery
is a particular Vet's specialties
Query Object.
- OwnersQuery
is an abstract base class for all Owner
Query Objects.
- OwnerQuery
is an Owner by id Query
Object.
- OwnersByNameQuery
is an Owners by last name
Query Object.
- OwnerUpdate
is an Owner Update Object.
- OwnerInsert
is an Owner Insert Object.
- TypesQuery
is
an "All Pet types" Query
Object.
- PetsQuery is an abstract
base class for all Pet Query
Objects.
- PetQuery is a Pet by id Query Object.
- PetsByOwnerQuery
is a Pets by Owner Query Object.
- PetUpdate is
a Pet Update Object.
- PetInsert is
a Pet Insert Object.
- VisitsQuery
is a Visits by Pet Query Object.
- VisitInsert
is a Visit Insert Object.
The HSQL specific extension of AbstractJdbcClinic
is org.springframework.samples.petclinic.petclinic.jdbc.HsqlClinic. It provides
an HSQL implementation of the getIdentityQuery() method.
The MySQL specific extension of AbstractJdbcClinic
is org.springframework.samples.petclinic.petclinic.jdbc.MysqlClinic.
It provides an MySQL implementation of the getIdentityQuery() method.
The transaction manager used in the JDBC Clinic Implementation is an
instance of org.springframework.jdbc.datasource.DataSourceTransactionManager
that can be used for local transactions.
Hibernate
Clinic Implementation
The Hibernate implementation of the Clinic
interface is org.springframework.samples.petclinic.hibernate.HibernateClinic.
To simplify using Hibernate, Spring provides the org.springframework.orm.hibernate.LocalSessionFactoryBean.
The Hibernate configuration is provided by the file src/petclinic.hbm.xml.
Apache OJB
Clinic Implementation
The Apache OJB implementation of the Clinic
interface is org.springframework.samples.petclinic.ojb.PersistenceBrokerClinic.
To simplify using OJB, Spring provides the org.springframework.orm.ojb.PersistenceBrokerTransactionManager.
The Apache OJB configuration is provided by the files src/OJB-repository.xml and src/OJB.properties.
ApplicationContext
A Spring org.springframework.context.ApplicationContext object
provides a map of user-defined JavaBeans that specify either a
singleton object or the initial construction of prototype instances.
These beans constitute the Business/Persistence
Layer of Petclinic.The
following beans are defined in all of the 3 versions (1 per
access strategy) of the Petclinic applicationContext-???.xml
file:
- propertyConfigurer
is
a singleton bean that replaces ${...} placeholders with values from a
properties file, in this case, JDBC-related settings for the dataSource bean
described below (see
war/WEB-INF/jdbc.properties).
- dataSource is
a singleton bean that defines the implementation of the source of
database connections used by the application.
- clinicTarget
is
a singleton bean that defines the implementation of the Clinic interface that provides the
primary Business Layer API of the application.
- transactionManager
is
a singleton bean that defines the implementation of the transaction
management strategy for the application.
- clinic is
a singleton bean that provides the transactional proxy for the clinicTarget
bean.
Presentation
Layer
The
Presentation Layer is implemented as a J2EE Web Application and
provides a very thin and concise Model-View-Controller type user
interface to the Business and Persistence Layers.
The Petclinic web application is configured via the following files:
- war/WEB-INF/web.xml
is the web application configuration file.
- war/WEB-INF/petclinic-servlet.xml
configures the petclinic dispatcher servlet and the other controllers
and forms that it uses. The beans defined in this file reference the
Business/Persistence Layer beans defined in applicationContext-???.xml.
- war/WEB-INF/classes/views*.properties
configures the definition of internationalizable Spring views.
- war/WEB-INF/classes/messages*.properties
configures the definition of internationalizable message resources.
Examine the comments provided in each of these files for a more
in-depth understanding of the details of how the application is
configured.
General
- In web.xml,
a context-param, "webAppRootkey",
provides the key for a system property that specifies the root
directory for the web application. This parameter, "petclinic.root", can be used to aid
in configuring the application.
- In web.xml,
a org.springframework.web.context.ContextLoaderServlet
is
defined that loads the root ApplicationContext
object of this webapp at startup, by default from the designated /WEB-INF/applicationContext-???.xml.
Note that it is preferable to use org.springframework.web.context.ContextLoaderListener
in a servlet container that follows the Servlet 2.4
initialization order (many Servlet 2.3 containers do). The
root org.springframework.web.context.WebApplicationContext
of
Petclinic is an instance of org.springframework.web.context.support.XmlWebApplicationContext
and
is the parent of all servlet-specific ApplicationContexts.
The Spring root ApplicationContext object
provides a map of user-defined JavaBeans that can be used in any and
all layers of the application. Beans defined in the root ApplicationContext are automatically
available in all child ApplicationContext
objects
as (external) bean references. Beans defined in an ApplicationContext can also be
accessed directly by Java code through getBean(name)
method calls.
- In web.xml,
a Servlet named "petclinic" is specified to act as
a dispatcher for the entire application. This org.springframework.web.servlet.DispatcherServlet
is used to handle all URL's matching the pattern "*.htm". As with any Servlet, multiple URL mappings may
be defined. It is also possible to define multiple instances of DispatcherServlet. Each DispatcherServlet dispatches
requests to registered handlers (Controller
interface implementations) indirectly through a org.springframework.web.servlet.handler.HandlerMapping
implementation. Each DispatcherServlet
has its own ApplicationContext,
by default defined in "{servlet-name}-servlet.xml".
In this case, it is in the file "petclinic-servlet.xml".
This ApplicationContext is
used to specify the various web application user interface beans and
the
URL mappings that are used by the DispatcherServlet
to control the handling of requests.
The
files web.xml and log4j.properties specify
the configuration of logging in the system:
- In web.xml,
a "log4jConfigLocation" context-param
is specified that sets the location of the Log4j configuration file. The
default location for this file is /WEB-INF/classes/log4j.properties.
Specifying this parameter explicitly allows the location to be changed
from the default and is also used to cause periodic Log4j configuration refresh checks.
- In web.xml,
a Log4jConfigListener is
specified that will initialize Log4j using
the specified configuration file when the web app starts. The Log4jConfigListener is commented out
in the file because of a conflict when using JBoss. It should also be
noted that if the container initializes Servlets before Listeners as
some pre-Servlet 2.4 containers do, a Log4jConfigServlet should
be used instead.
- In log4j.properties,
the following loggers are specified:
- "stdout" provides
logging messages to the container's log file.
- "logfile" provides
logging messages to a rolling file that is specifed using the
previously defined "petclinic.root".
Examination and study of these logging files will provide insight into
the operation of the Spring framework and the application as well as
valuable troubleshooting information should something not work
correctly.
DispatcherServlet
The following beans are accessible to the DispatcherServlet
and are defined
in the Petclinic petclinic-servlet.xml
file. This dispatcher uses these defintions to delegate actual display
and form processing tasks to implementations of the Spring org.springframework.web.servlet.mvc.Controller
interface. The DispatcherServlet
acts as the main application Front
Controller and is responsible for
dispatching all requests to the appropriate Controller indirectly through a URL
mapping handler. These Controllers are
responsible for the
mechanics of interaction with the user and ultimately delegate action
to the Business/Persistence Layers.
- messageSource
is a singleton bean that defines a message source for this ApplicationContext. Messages are
loaded from localized "messages_xx"
files in the classpath, such as "/WEB-INF/classes/messages.properties"
or "/WEB-INF/classes/messages_de.properties". getMessage() calls to this context will use
this
source. Child contexts can have their own message sources, which will
inherit all messages from this source and are able to define new
messages and override ones defined in the primary message source.
- viewResolver
is
a singleton bean that defines the view mappings used by the dispatcher.
This definition specifies explicit view mappings in a resource bundle
(properties file) instead of using the default InternalResourceViewResolver. It
fetches the view mappings from localized "views_xx.properties" files, i.e. "/WEB-INF/classes/views.properties"
or "/WEB-INF/classes/views_de.properties"
that are loaded from the classpath. Symbolic view names returned by
controllers will be resolved in the respective properties file,
allowing
for arbitrary mappings between view names and resources.
- exceptionResolver
is
a singleton bean that defines how exceptions are propogated. Exceptions
encountered that are not specified are propogated to the servlet
container.
- urlMapping is
a singleton bean that defines the URL mapping handler that is to be
used by the dispatcher. The definition specifies the use of a SimpleUrlHandlerMapping instead of
the default BeanNameUrlHandlerMapping.
This allows specific URL's to be mapped directly to display or form
Controllers.
- clinicController
is a singleton bean that defines the Controller
that is used by the dispatcher to handle non-form based display tasks.
This bean is a org.springframework.web.servlet.mvc.multiaction.MultiActionController that
can handle multiple request URLs. A method is provided to handle each
type of request that is supported.
- clinicControllerMethodnameResolver
is a singleton bean that defines a mapping of URL's to method names for
the clinicController
bean.
- 6 singleton Form beans are defined that are extensions of
the Petclinic class AbstractClinicForm
which
is itself an extension of the Spring class SimpleFormController. These beans
are used to handle the various Search, Add and Edit form processing
tasks for the dispatcher.
- 3 singleton beans are defined that are implementations of the org.springframework.validation.Validator interface.
These beans are used by the Form beans to validate their input
parameters and to bind localizable error messages for display should a
processing error occur on submission.
Controllers
Spring provides a
number of useful MVC abstractions to developers of J2EE web
applications. The Controller interface
specifies a single method, handleRequest(HttpServletRequest, HttpServletResponse) that must be provided by
implementing classes to handle request processing. This method returns
a org.springframework.web.servlet.mvc.ModelAndView
to the DispatcherServlet for
rendering. Spring provides several convenient implementations of the Controller interface that
developers can use to simplify their task, the most significant of
which
are MultiActionController, SimpleFormController, and AbstractWizardFormController. AbstractWizardFormController is not
used in Petclinic and is not discussed here. A MultiActionController is used to
define a Controller with
multiple handling methods the selection of which can be configured
using
a separate MethodNameResolver object.
"FormControllers", including SimpleFormController, are used to process html forms and
can automatically populate "command" objects with data supplied via
request parameters and vice versa. SimpleFormController
is part of a deep hierarchy of objects which is discussed here.
Additional detail is avaliable in the Spring API Javadoc.
- org.springframework.context.support.ApplicationObjectSupport
is an implementation of org.springframework.context.ApplicationContextAware
which provides its subclasses with a method, initApplicationContext(), which can
be overridden to provide custom initialization behavior.
- org.springframework.web.servlet.support.WebContentGeneratoris
an ApplicationObjectSupport
extension that is a convenient superclass for any kind of web content
generator, like AbstractController and MultiActionController. It
supports HTTP cache control options.
- org.springframework.web.servlet.mvc.AbstractController is a WebContentGenerator extension that
is
a convenient superclass for controller implementations. It provides
several properties that can be set by users, supportedMethods i.e. "GET",
"POST",
etc., requireSession, and cacheSeconds. It uses the Template
Method design pattern in its final
implementation of handleRequest()whichcoordinates
how these properties are used and calls a similar handleRequestInternal() method
that subclasses must override to provide their own processing of
request
handling.
- org.springframework.web.servlet.mvc.BaseCommandController
is
an AbstractController extension that provides
infrastructure to its subclasses to support the binding and validating
process. This infrastructure creates a "command" object on receipt of a
request, and attempts to populate the command's JavaBean properties
with
request attributes. Once created, commands can be validated using a
Validator associated with this class. Type mismatches populating a
command are treated as validation errors, but are caught by the
framework, not application code. Users can directly set the commandClass and validator properties to specify
the objects of interest. It also provides default implementations of
several methods that can be overridden to further customize the binding
and validation process. Some of these methods are:
- userObject(HttpServletRequest
request) is used to create the command object.
- initBinder(HttpServletRequest request, ServletRequestDataBinder binder)
is
used to initialize the binder instance and is typically overridden to
specify a custom PropertyEditor.
- onBindAndValidate(HttpServletRequest
request, Object command, BindException errors) is used to
provide
custom post-processing for the binding and validation process. It is
called after standard binding and validation and before error
evaluation.
- org.springframework.web.servlet.mvc.AbstractFormController is a BaseCommandController extension that provides infrastructure to its subclasses to
support html forms. It controls the form display and submission process
in its final implementation
of handleRequestInternal().
- The sessionForm property, when true,
forces the creation of an HttpSession to hold the command object so
that
it is retained between requests.
- The bindOnNewFormproperty,
when true, forces population of the form from data provided by the
command object. This is particularly useful for forms that are used to
edit an existing object.
- It provides an isFormSubmission(HttpServletRequest)method that subclasses can override to determine
if a given request represents a form submission. The default implementation treats a POST request as
form submission. If the form
session attribute doesn't exist when using session form mode, the request is always treated as
new form by handleRequestInternal(). Subclasses can override this to
implement
a custom strategy. Petclinic uses the default implementation.
- It provides a final method showNewForm(HttpServletRequest,
HttpServletResponse)
to
handle display and data binding of a new form.
- It provides a method formBackingObject(HttpServletRequest) that subclasses can override to provide
a preinitialized backing
object.
- It provides a method referenceData(HttpServletRequest,
Object, Errors) that
subclasses can override to provide reference data to be used in rendering
the view.
- It provides a method handleInvalidSubmit(HttpServletRequest,
HttpServletResponse) to handle an invalid form submission.
Subclasses should override this method to disallow duplicate form
submission. The default implementation simply resubmits the form.
- It provides a method processSubmit(HttpServletRequest,
HttpServletResponse, Object, BindException) that
subclasses must override to
provide custom submission handling.
- It provides several showForm() methods that are used
to display the form.
- org.springframework.web.servlet.mvc.SimpleFormController is a concrete extension of AbstractFormController that provides configurable
form and success views,
and an onSubmit chain for convenient overriding.
Views
The Controllers used by the
dispatcher handle the work flow of the application. The actual display
tasks are delegated by the Controllers
to implementations of the Spring View
interface.
These View objects are
themselves beans that can render a particular type of view. The
handling Controller supplies
the View with a data model to
render.
The data model is provided to the View
as
a Map of objects. Views are only responsible for
rendering a display of the data model and performing any display logic
that is particular to the type of View
being
rendered. Spring provides support for rendering many different types of
views: JSP, XSLT, PDF, Velocity templates, Excel files, and others. By
using a View mapping
strategy,
Spring supplies the developer with a great deal of flexibility in
supporting easily configurable view substitution. Petclinic defines a
number of
View beans in the file, views.properties.
2 of these beans are instances of RedirectView
which simply redirects to another URL. The other View beans are instances of JstlView which provides some handy
support for supporting internationalization/localization in JSP pages
that use JSTL.
Messages
The messages*.properties
files are loaded from the classpath to provide localized messages for
the supported languages. Petclinic supplies only a single localized
message, "welcome" in the
default, English, and German properties files respectively. See the
"countries" sample application for a more detailed example of Spring's
support for internationalization.
Presentation
Layer classes
- org.springframework.petclinic.web.ClinicController
is an extension of MultiactionController
that is used to handle simple display oriented URLs.
- org.springframework.petclinic.web.AbstractClinicForm
is an extension of SimpleFormController
that is the superclass of Petclinic's form objects. It provides its
subclasses with a some commonly needed form behavior:
- It provides a clinic property
that gives access to the Clinic implementation
that is used to access the Business/Persistence Layer.
- It overrides initBinder() to
provide a DateFormat PropertyEditor to handle the
specialized binding of request parameters to Date fields.
- It provides a disallowDuplicateFormSubmission()
method to enure correct handling of form submission initiated through
use of
the browser "Back" button:
- It disallows duplicate form submission for "Add" forms by
overriding handleInvalidSubmit().
- It allows duplicate form submission for "Edit" forms by not overriding handleInvalidSubmit().
- org.springframework.petclinic.web.FindOwnersForm is an
extension
of AbstractClinicForm that
is used to find owners by last name.
- org.springframework.petclinic.web.AddOwnerForm is an
extension
of AbstractClinicForm that
is used to add a new Owner.
- org.springframework.petclinic.web.EditOwnerForm is an
extension
of AbstractClinicForm that
is used to edit an existing Owner. A
copy of the existing Owner is
used for editing.
- org.springframework.petclinic.web.AddPetForm
is an
extension
of AbstractClinicForm that
is used to add a new Pet to
an existing Owner.
- org.springframework.petclinic.web.EditPetForm is an
extension
of AbstractClinicForm that
is used to edit an existing Pet.
A copy of the existing Pet is
used for editing.
- org.springframework.petclinic.web.AddVisitForm
is an
extension
of AbstractClinicForm that
is used to add a new Visit to
an existing Pet.
View Beans
& Implemented Use Cases
- welcomeView is
the "home" screen. It provides links to display a list of all vets,
find an owner, or view documentation.
- vetsView displays
all vets and their specialties.
- findOwnersForm
is used to find owners by last name.
- findOwnersRedirectView
redirects to findOwnerForm.
- selectOwnerView
allows user to select from a list of multiple owners with the same last
name.
- ownerView displays
a owner's data and a list of the owner's pets and their data.
- ownerRedirect
redirects to ownerView.
- ownerForm supports
AddOwnerForm
and EditOwnerForm
- petForm supports AddPetForm
and web.EditPetForm
- visitForm supports AddVisitForm
- dataAccessFailure
displays a stacktrace
JSP Pages
- index.jsp redirects
to the "welcome" page.
- includes.jsp
is
statically included in all
JSP's used in the application. It sets session="false" to prevent
inappropriate session creation and specifies the taglibs that are in
use.
- uncaughtException.jsp
is the web.xml configured
"error-page". It displays a stack trace and normally wouldn't be used
in a production version of an application. It can be seen in action by
entering a URL of "editOwner.htm" or "editpet.htm". The handlers for
these URLs normally expect to see a respective "ownerId" or "petId"
request parameter and throw a ServletExceptionwhen
it isn't found.
- welcome.jsp implements welcomeView.
- vets.jsp implements vetsView.
- findOwners.jsp
implements
findOwnersForm.
- owners.jsp
implements selectOwnerView.
- owner.jsp
implements
ownerView.
- ownerForm.jsp
implements ownerForm.
- petForm.jsp
implements petForm.
- visitForm.jsp
implements
visitForm.
- dataAccessFailure.jsp
displays a stacktrace
- header.jsp
and footer.jsp
display info common to virtually all pages. Spring also supplies
support for the integration of Tiles
(included in Struts) but this is not used in Petclinic.
The following JSP's each display a form field and the bound error data
for that field:
- address.jsp
- city.jsp
- telephone.jsp
- lastName.jsp
- firstName.jsp
The following items should be noted regarding the web application
implementation design:
- all JSP's are stored under /WEB-INF/jsp except
for index.jsp which
is the configured "welcome-file"
- The use of JSP technology in the appplication is not exposed to
the user, i.e., the end user never sees a URL ending in ".jsp".
- By convention, all URL's in the application ending in ".htm" are
handled by web application controllers. Static html pages ending in ".html", such as
Javadocs, will be directly served to the end user.
- The results of all form entries are handled using browser round
trip redirection to minimize possible end user confusion.
- All pages are extremely simple JSP implementations that focus
only on providing the necessary functionality.
- References to Entity objects
are passed around in the application by supplying the object's Id as a
request parameter.
Testing
- org.springframework.petclinic.OwnerTests is a JUnit
TestCase that supports Business Rule #1.
- org.springframework..petclinic.AbstractJdbcClinicTests
is a JUnit TestCase requiring a live database connection that is used
to
confirm correct operation of the database access objects implemented in
AbstractJdbcClinic and its
subclasses. Subclasses of AbstractJdbcClinicTests provide
the location of the application context file to use for the tests to be
run.
Ant Setup
Make sure that the Ant executable is in your command shell path. Ant
will need to reference classes from JUnit
and
the database(s) of interest. Place a copy of any needed jar files in
Ant's /lib directory,
i.e.:
- JUnit - junit.jar
- HSQL - hsqldb.jar
- MYSQL - mysql-connector-java-2.0.14-bin.jar
or other
HSQL Setup
Create a new directory containing the a copy of the entire contents of
the directory petclinic/db/hsqldb.
The file petclinic.script
is the data file that will be used by the server. It has been
initialized with some sample data. Start a server on the standard port
by executing server.sh(Unix)
or server.bat (Windows)
or alterrnatively edit the file to select a port of your choosing.
A useful database manager can be started by by executing manager.sh (Unix)
or manager.bat (Windows).
When the application opens, connect to the "HSQL Database Engine
Server" using the default parameters. This tool can also be used to
manage other databases. To use a different port, it will be necessary
to
change the Petclinic Database Setup. It may also be necessary to
consult
the HSQL documentation for instructions on to change the port the
server
uses.
MYSQL
Setup (optional)
Add the Petclinic database to a running server by running the SQL
script db/mysql/initDB.txt.
Petclinic expects, by default to be able to access the server via the
standard port 3306. To use a different port, it will be necessary to
change the Petclinic Database Setup.
Petclinic
Database Setup
To use a J2EE server supplied connection-pooled data source with
Tomcat, it will be
necessary to use and possibly edit the appropriate context definition
file for the petclinic webapp. To use it, deploy a copy of the
appropriate context definition file in Tomcat's webapps directory and
restart the server. Consult the Tomcat log files if something goes
wrong when starting either Tomcat or the Petclinic application. The
context files are named petclinic_tomcat_*.xml,
where * is
a codename for the database. There is a context file supplied for each
database in its respective directory. There is also a context file db/petclinic_tomcat_all.xml
that will provide a JNDI connection-pooled datasource for all supported
databases.
Should you use this file, you must of course make sure that all the
database servers are running when you restart Tomcat.
NOTES:
- Should you deploy one of the context files or define a context in
Tomcat's server.xml,
Tomcat will not automatically deploy the webapp from the petclinic.war file.
The webapp will then need to be manually extracted to the target
directory.
- The context files will also configure logging to supply a
separate log file for the petclinic context. This will separate the
container logging for petclinic from that of the other webapps. This
should not be confused with the application log file provided through Log4j.
- An Ant script (db/build.xml )
has been provided that can be used to re-initialize either database. To
select or configure the data source used for the webapp and for
testing,
you will need to edit the files:
- war/WEB-INF/applicationContext.xml
(for the webapp)
- build.properties
(for testing)
- test/src/testContext.xml (for testing)
Building
the Petclinic Application
Open a command line shell and navigate to the directory containing
Petclinic and execute "ant". This will display a list of the Ant
targets
that are available. Make sure the database is running and execute "ant
all". This will run the Ant "all" target which will clean and compile
everything, produce Javadocs, and execute the tests, including a
live test using the database. The other Ant targets provide subsets of
this functionality.
Deploying
the Petclinic Application
Deploy the web application to the server in the usual way (see notes regarding database setup). If you need
instructions for web application deployment, see the Tomcat
documentation for details. The Web ARchive file is petclinic.war
and
can be found in the dist directory.
Using the
Petclinic Application
Make sure the Petclinic web application is running and browse to http://localhost:8080/petclinic
or check it
out online.