In the following sections we'll go through some configuration of the various layers. This is necessary before we can write some presentation code and deploy the web application.
We'll start with the persistence layer. All objects that are going to be persisted need to be mapped. This includes the Customer
, Address
, Account
, and Loan
objects. The validation message objects don't need to be mapped because they are not going to be persisted. Most of the time the default mapping settings will be used. The @Entity
annotation will be used to declare that a class should be persistent, and we'll also explicitly specify the table name. Every entity needs an ID. A uuid
field of type String
will be added to every entity. The @Id
annotation will declare that this uuid
field is the ID of an entity. The customer's accounts will be mapped with a @OneToMany
annotation, which declares that one customer can have many accounts. Let's now look at a mapping of the Customer
class:
@Entity @Table(name = "app_customer") public class Customer implements Serializable { @Id private String uuid; private String firstName; private String lastName; private Date dateOfBirth; private Address address; @OneToMany(mappedBy="owner") private Set<Account> accounts; private String phoneNumber;
Code listing 1: Code extract from the Customer class (the Customer.java file)
Please consult the hibernate manual for advanced mapping (http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/).
We're using uuids
as IDs, because they are much easier to work with. We can assign them at object-creation time instead of object-persistence time as is the case with database-assigned IDs. The standard java.util.UUID
class will be used to generate the uuid
fields. We can define a factory for creating our domain objects that will automatically assign an uuid
object to every new object:
public class DefaultBankingFactory implements BankingFactory { @Override public Customer createCustomer() { Customer customer = new Customer(); customer.setUuid(UUID.randomUUID().toString()); Set<Account> accounts = new HashSet<Account>(); customer.setAccounts(accounts); return customer; }
Code listing 2: The DefaultBankingFactory class that follows the Factory design pattern (the DefaultBankingFactory.java file)
Our factory implements the BankingFactory
interface, which contains all the factory methods such as createCustomer
, createAddress
, createAccount
, and so on. These methods make sure that all created objects have their references correctly set, for example, the createAccount
method takes a customer as an argument and adds the newly created account to the collection of the customer's accounts and also sets this customer as the owner of this account. This keeps the referential integrity intact. We can even declare a domain object's constructors as "package private" so that new instances can be created only through this factory.
Next, we'll work on the JPA 2.0 provider configuration. This configuration also defines the classes that should be made persistent. All this information will be contained in a so-called persistence-unit
. This configuration is as follows:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0"> <persistence-unit name="droolsbook.persistence" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <mapping-file>META-INF/Taskorm.xml</mapping-file> <mapping-file>META-INF/JBPMorm-JPA2.xml</mapping-file> <mapping-file>META-INF/ProcessInstanceInfoMapping-JPA2.xml</mapping-file> <class>droolsbook.bank.model.Customer</class> <class>droolsbook.bank.model.Address</class> <class>droolsbook.bank.model.Account</class> <class>droolsbook.bank.model.LoanApprovalHolder</class> <class>org.drools.persistence.info.SessionInfo</class> <class>org.drools.persistence.info.WorkItemInfo</class> <class>org.jbpm.persistence.processinstance.ProcessInstanceInfo</class> <class>org.jbpm.persistence.processinstance.ProcessInstanceEventInfo</class> <class>org.jbpm.task.Attachment</class> <class>org.jbpm.task.Content</class> <class>org.jbpm.task.BooleanExpression</class> <class>org.jbpm.task.Comment</class> <class>org.jbpm.task.Deadline</class> <class>org.jbpm.task.Comment</class> <class>org.jbpm.task.Deadline</class> <class>org.jbpm.task.Delegation</class> <class>org.jbpm.task.Escalation</class> <class>org.jbpm.task.Group</class> <class>org.jbpm.task.I18NText</class> <class>org.jbpm.task.Notification</class> <class>org.jbpm.task.EmailNotification</class> <class>org.jbpm.task.EmailNotificationHeader</class> <class>org.jbpm.task.PeopleAssignments</class> <class>org.jbpm.task.Reassignment</class> <class>org.jbpm.task.Status</class> <class>org.jbpm.task.Task</class> <class>org.jbpm.task.TaskData</class> <class>org.jbpm.task.SubTasksStrategy</class> <class>org.jbpm.task.OnParentAbortAllSubTasksEndStrategy</class> <class>org.jbpm.task.OnAllSubTasksEndParentEndStrategy</class> <class>org.jbpm.task.User</class> </persistence-unit> </persistence>
Code listing 3: JPA 2.0 configuration (the persistence.xml file)
All this information is stored in a file called persistence.xml
. This file should be stored on the classpath under the META-INF/
folder. The name of our persistence unit is droolsbook.persistence
. The transaction type we're using is RESOURCE_LOCAL
, which is enough since we'll be working with one resource only, that is, database. The <provider>
element specifies the actual provider; in our case, it is org.hibernate.ejb.HibernatePersistence
. Next, we load JPA mapping files as we've seen in Chapter 8, Defining Processes with jBPM, and tell the hibernate provider what additional files to look into Customer
, Address
, Account
, and LoanApprovalHolder
, including the standard jBPM classes for JPA annotations. All these classes are declared to be persistent.
We'll configure the Spring framework. This can be done in various ways. XML is the most commonly used. The configuration will reside in three XML files. We'll start with a file called applicationContext.xml
that will hold configuration related to the service layer (persistence, transactions, knowledge base configuration, and individual services configurations):
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:drools="http://drools.org/schema/drools-spring" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://drools.org/schema/drools-spring http://drools.org/schema/drools-spring.xsd">
Code listing 4: Extract from the Spring configuration (the applicationContext.xml file)
The various Spring configuration files will use more or less the same header (as seen in Code listing 4); they will differ only in the XSD namespaces used. The previous file declares four namespaces that will be used: beans
as the default one, and aop
, tx
, and drools
from the drools-spring
module. For more information about the Spring namespaces please consult the Spring documentation (http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/).
We've already defined the persistence configuration in the persistence.xml
file. These were just the very basics. We'll now enhance this configuration in Spring. The Spring configuration files will be the ultimate place where everything is configured. The following is the definition of an entityManagerFactory
interface that will be responsible for creating EntityManagers
, which will store our objects into the dataSource
persistent store. The entityManagerFactory
interface references the persistence-unit configuration named droolsbook.persistence
defined earlier. It also specifies a bunch of properties that will be simply passed to the persistence provider:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="persistenceUnitName" value="droolsbook.persistence" /> <property name="jpaPropertyMap" ref="jpaPropertyMap" /> </bean> <bean id="jpaPropertyMap" class="org.springframework.beans.factory.config.MapFactoryBean"> <property name="sourceMap"> <map> <entry key="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> <entry key="hibernate.show_sql" value="true" /> <entry key="hibernate.format_sql" value="true" /> <entry key="hibernate.use_sql_comments" value="true"/> <entry key="hibernate.hbm2ddl.auto" value="create-drop" /> </map> </property> </bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver" /> <property name="url" value="jdbc:h2:droolsBookDatabaseH2" /> <property name="username" value="sa" /> <property name="password" value="sasa" /> </bean>
Code listing 5: Extract from the Spring configuration (the applicationContext.xml file), entityManagerFactory bean definition
The entityManagerFactory
interface is an instance of LocalContainerEntityManagerFactoryBean
. It will read the contents of the persistence.xml
file, and based on them and value-pairs in the jpaPropertyMapit
method, it will create the entityManagerFactory
interface. The jpaPropertyMap
method is declared as a separate bean so that it can be easily reused later on.
The first JPA property, hibernate.dialect
, specifies a class that represents the dialect of our database. As you can see we'll use the H2 database (http://www.h2database.com). It can run entirely in memory, which is ideal for our purposes. The next few properties are self-explanatory. Then, we'll see the hibernate.hbm2ddl.auto
property, whose value is set to create-drop
, which specifies that we want to recreate the database (structure and data) every time we start the application. Finally, we're also defining the data source itself.
The applicationContext.xml
file also defines some beans that we'll use later:
<bean name="bankingFactory" class="droolsbook.bank.model.DefaultBankingFactory" /> <bean name="reportFactory" class="droolsbook.bank.service.impl.DefaultReportFactory" /> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <bean name="customerRepository" class="droolsbook.sampleApplication.repository.jpa.JPACustomerRepository" />
Code listing 6: Extract from the Spring configuration (the applicationContext.xml file), which shows various bean definitions
The first two are factories. We've already seen the DefaultBankingFactory
interface in Code listing 2 and the DefaultReportFactory
interface was described in Chapter 3, Validating. The next two beans configure a customer repository. The PersistenceAnnotationBeanPostProcessor
method is responsible for injecting EntityManagers
into repositories. We'll see how it's done in the next few.
The core components of the persistence and service layers are there. We can start work on the presentation layer. We'll start with the web.xml
web application configuration file. It is a standard web-app configuration file that defines the basics of a web application such as the name, welcome file list, and some initialization servlets. The initialization servlets will be called when we start the application in a server:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>sampleApplication</display-name> <servlet> <servlet-name>sampleApplication</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>sampleApplication</servlet-name> <url-pattern>*.htm</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
Code listing 7: Web application configuration (the web.xml file)
As can be seen from the previous code, Spring's DispatcherServlet
is loaded on the startup. This servlet by default looks for the sampleApplication-servlet.xml
configuration file. We'll soon define this file. Just make sure it is placed in the webRoot/WEB-INF/
directory. The configuration also defines a servlet mapping for all resources ending with .htm
to this DispatcherServlet
. The welcome file is set to index.jsp
. This file has to be present in the webRoot/
directory. For testing purposes index.jsp
will contain a listing of various entry points into the application (list all customers link, add customer link, request loan link, and so on).
As promised, the sampleApplication-servlet.xml
Spring configuration file is given next. It will import the already defined applicationContext.xml
configuration file.
Furthermore, the configuration file will define a standard "view resolver". This view resolver will be set to look for views in the webRoot/WEB-INF/jsp/
directory—view as in model-view-controller (MVC) that can be found at http://en.wikipedia.org/wiki/Model-view-controller. This will help us to separate our controllers from the view implementations. We'll see how it works in a few sections:
<import resource="classpath:applicationContext.xml" /> <context:annotation-config /> <context:component-scan base-package="droolsbook.sampleApplication.web"/> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/WEB-INF/jsp/" /> <property name="suffix" value=".jsp" /> </bean>
Code listing 8: Extract from the Spring configuration (the sampleApplication-servlet.xml file), which is an initial configuration
The import resource
elements are simply importing the contents of the resource into one big Spring application context. The <context:annotation-config />
element activates Spring's annotation support for easier configuration of controllers. For the interface layer we'll use full Spring annotation auto-wiring, because the presentation layer changes more frequently. In the persistence and services layer, reliability is the most important, so we define the wiring ourselves. Then the <context:component-scan ..>
element tells Springs to scan the given package for various components; in our case it is controllers, so we don't have to define them in the XML file.
The deployment involves copying the contents of the webRoot
directory into Tomcat's webapps
directory and renaming it to sampleApplication
. Then create a new lib directory under webapps/sampleApplication/WEB-INF/
and copy all libraries that are on the classpath into this directory. All other resources on the classpath should go to the webapps/sampleApplication/WEB-INF/classes
directory. That is all in terms of deployment. Tomcat can be started, and we can access the application at http://localhost:8080/sampleApplication/
. The index.jsp
welcome page should be displayed.
The deployment can be even easier if you have installed an Eclipse plugin called Web Tools Platform (WTP). You can then create a dynamic web project; set up a server (Tomcat) and the WTP plugin will do the deployments for you. Note that the WTP plugin is a standard part of Eclipse IDE for Java EE Developers (http://www.eclipse.org/downloads/).
18.216.34.146