Integration of Struts and EJB

EJB integration in a struts application

Introduction

The usage of enterprise java beans in combination with struts is the goal of this tutorial. We create an EJB project and use the business processes (methods) later in the Struts application. As an example we use a library application, where you can manage books and users. In additional it should be possible, that a user can borrow a book.

General

Author:

Sascha Wolski

Sebastian Hennebrüder

http://www.laliluna.de/tutorials.html

Date:

November, 22nd 2004
Development Tools

Eclipse 3.x
MyEclipse plugin 3.8

Database

PostgreSQL 8.0 Beta

Application Server

Jboss 3.2.5


Source code:

http://www.laliluna.de/download/struts-ejb-integration.zip

The sources does not contain the project files. So create a project first and copy the sources to this projects.

PDF Version des Tutorials:

http://www.laliluna.de/download/struts-ejb-integration-en.pdf

Requirements

We are not repeating all the basics here. Have a look at the basic EJB tutorials before you start this tutorial.

Table of Contents

EJB integration in a struts application 1

Introduction 1

General 1

Requirements 1

Create a database and a datasource file 3

Configure xDoclet 3

Create the entity beans 5

Edit the entity beans 7

Add the relation 11

Create the session beans 14

Create the dialogs 22

Create a default, welcome page 25

Global Action Forwards and Action Mappings 27

Book list 30

Add, edit, borrow and delete books 35

User list 46

Add, edit, delete users 51

Test the applications 58

Create a ejb project

Create a new enterpise java bean project (File > New > J2EE > EJB Project).




Set a nice name for the project. It is recommended that you add Ejb to the end of the project name, so it is evident that we are dealing with an ejb project.








Add a package for the entity and session beans
You have to add .ejb to the end of the package name. In the default configuration xDoclet expects EJBs to be placed in such packages..





Create a database and a datasource file

Create a new postgre database named ejbexample. Add a datasource file named ejbexample-ds.xml to the folder Jboss/server/deploy.

Examples for all kinds of supported databases can be found in the directory:

...jboss-3.2.5docsexamplesjca

Add the following configuration to the file:

<datasources>
<local-tx-datasource>
<jndi-name>ejbexample</jndi-name>
<connection-url>jdbc:postgresql://localhost:5432/ejbexample</connection-url>
<driver-class>org.postgresql.Driver</driver-class>
<user-name>postgres</user-name>
<password>pgsql</password>
</local-tx-datasource>
</datasources>



Be sure that the port, the user and the password are correct for your database.

Configure xDoclet

Open the project properties (Strg + Enter). On ?MyEclipse- Xdoclet? right click in the upper right window and choose ?Add Standard?, than ?Standard EJB?. Now you will find ?Standard EJB? in the uppen right window.



Choose ?Standard EJB? and call the menu ?Add? (right click) on the window below. Choose ?jboss? from the list.




Now you find a menu entry jboss.





Set up xDoclet as shown in the picture below.




Thats all we need to do to configure xDoclet.

Create the entity beans

Create a new entity bean. Right click on the package > New > EJB(session...).




Set the properties like the picture below.






Create a second entity bean named User. Set it up like the bean befor.



Edit the entity beans

First we have to edit the xDoclet configuration for the class.

Entity Bean Book

/**
* @author laliluna.de
*
* @ejb.bean name = "Book"
* type = "CMP"
* cmp-version = "2.x"
* display-name = "Book"
* description = "Book EJB"
* view-type = "both"
* jndi-name = "ejb/BookHome"
* local-jndi-name = "ejb/BookLocalHome"
* primkey-field = "id"
*
* @ejb.util generate="physical"
* @ejb.persistence table-name = "tbooks"
* @ejb.value-object match = "*" name="Book"
*
* @ejb.finder signature = "java.util.Collection findAll()"
* query = "select object(c) from Book as c"
*
* @jboss.persistence create-table = "true"
* remove-table = "true"
* @jboss.entity-command name="postgresql-fetch-seq"
*/
public abstract class Book implements EntityBean {



primkey-field = "id"

Define the primary key field of the class

@ejb.util generate="physical"

Define how the Util class will generated and which lookup method are used. We use the physical JNDI lookup.

@ejb.persistence table-name = "tbooks"

Define the real table name in your database

@ejb.value-object match = "*" name="Book"

Define the value object

Value Object Design Pattern

When you call a setName, setTitle method you create a roundtrip over the network between Application Server and Database Server. Roundtrips costs time. This is why, people invented the Value Object. Instead of working field per field a complete class instance is passed to methods or returned by them.



@ejb.finder signature = "java.util.Collection findAll()" 
query = "select object(c) from Book as c"

Define a finder method

@jboss.persistence create-table = "true" 
remove-table = "true"

Define if the table will be automaticly created on deploy and removed on undeploy.

@jboss.entity-command name="postgresql-fetch-seq"

Define which entity command is used for generating the bean.



In the next step we define the properties of the entity beans. Which fields are included on the table.

The bean book has the following properties

Add the getter- and setter-methods for the properties:

	/**
* @ejb.interface-method view-type = "both"
* @ejb.persistence column-name = "fid"
* sql-type = "SERIAL"
* jdbc-type = "INTEGER"
* @ejb.pk-field
*
* @return
*/
public abstract Integer getId();

/**
* @ejb.interface-method view-type = "both"
* @param id
*/
public abstract void setId(Integer id);

/**
* @ejb.interface-method view-type = "both"
* @ejb.persistence column-name = "ftitle"
* @return
*/
public abstract String getTitle();

/**
* @ejb.interface-method view-type = "both"
* @param title
*/
public abstract void setTitle(String title);

/**
* @ejb.interface-method view-type = "both"
* @ejb.persistence column-name = "fauthor"
* @return
*/
public abstract String getAuthor();

/**
* @ejb.interface-method view-type = "both"
* @param author
*/
public abstract void setAuthor(String author);

/**
* @ejb.interface-method view-type = "both"
* @ejb.persistence column-name = "favailable"
* @return
*/
public abstract Boolean getAvailable();

/**
* @ejb.interface-method view-type = "both"
* @param available
*/
public abstract void setAvailable(Boolean available);

/**
* @ejb.interface-method view-type = "both"
* @ejb.persistence column-name = "fuser_id"
* @return
*/
public abstract Integer getUserId();

/**
* @ejb.interface-method view-type = "both"
* @param user_id
*/
public abstract void setUserId(Integer user_id);



After adding the getter- and setter-methods run xDoclet.
Notice: Right click on the project > MyEclipse > Run xDoclet

xDoclet generated the value object of the entity bean, so we can add a getter and setter for this object.

	/**
* @ejb.interface-method view-type = "both"
* @return
*/
public abstract BookValue getBookValue();

/**
* @ejb.interface-method view-type = "both"
* @param bookValue
*/
public abstract void setBookValue(BookValue bookValue);



Entity Bean User

First we also edit the xDoclet configuration for the class

/**
* @author laliluna.de
*
* @ejb.bean name = "User"
* type = "CMP"
* cmp-version = "2.x"
* display-name = "User"
* description = "User EJB"
* view-type = "both"
* jndi-name = "ejb/UserHome"
* local-jndi-name = "ejb/UserLocalHome"
* primkey-field = "id"
*
* @ejb.util generate="physical"
* @ejb.persistence table-name = "tusers"
* @ejb.value-object match = "*" name="User"
*
* @ejb.finder signature = "java.util.Collection findAll()"
* query = "select object(c) from User as c"
*
* @jboss.persistence create-table = "true"
* remove-table = "true"
* @jboss.entity-command name="postgresql-fetch-seq"
*/
public abstract class User implements EntityBean {



The entity bean User has also four properties

Add the getter- and setter methods.

	/**
* @ejb.interface-method view-type = "both"
* @ejb.persistence column-name = "fid"
* sql-type = "SERIAL"
* jdbc-type = "INTEGER"
* @ejb.pk-field
*
* @return
*/
public abstract Integer getId();

/**
* @ejb.interface-method view-type = "both"
* @param id
*/
public abstract void setId(Integer id);

/**
* @ejb.interface-method view-type = "both"
* @ejb.persistence column-name = "fname"
* @return
*/
public abstract String getName();

/**
* @ejb.interface-method view-type = "both"
* @param name
*/
public abstract void setName(String name);

/**
* @ejb.interface-method view-type = "both"
* @ejb.persistence column-name = "flastname"
* @return
*/
public abstract String getLastName();

/**
* @ejb.interface-method view-type = "both"
* @param lastname
*/
public abstract void setLastName(String lastname);

/**
* @ejb.interface-method view-type = "both"
* @ejb.persistence column-name = "fage"
* @return
*/
public abstract Integer getAge();

/**
* @ejb.interface-method view-type = "both"
* @param age
*/
public abstract void setAge(Integer age);



Run xDoclet. After it has generated the Value Object class, you can implement the getters and setters for the value object.

	/**
* @ejb.interface-method view-type = "both"
* @return
*/
public abstract UserValue getUserValue();

/**
* @ejb.interface-method view-type = "both"
* @param userValue
*/
public abstract void setUserValue(UserValue userValue);

Add the relation

In your application a user can borrow a book, so we need a relation between the book bean and the user bean. A user can borrow many books, but one book can only be borrow by one user. Its a one to many relation between user and books .

Add the getter- and setter-methods for the relation. Make sure that the interface viewtype is local.

Book.java

	/**
* @ejb.interface-method view-type = "local"
* @ejb.relation name = "user_book"
* role-name = "book_user"
* @jboss.relation related-pk-field = "id"
* fk-column = "fuser_id"
* fk-constraint = "true"
* @return
*/
public abstract UserLocal getUser();

/**
* @ejb.interface-method view-type = "local"
* @param user
*/
public abstract void setUser(UserLocal user);

User.java

	/**
* @ejb.interface-method view-type = "local"
* @ejb.relation name = "user_book"
* role-name = "user_book"
*
* @return Collection
*/
public abstract Collection getBooks();

/**
* @ejb.interface-method view-type = "local"
* @param books
*/
public abstract void setBooks(Collection books);



The view classes for the value objects

It is possible that you edit the value object class, for example add the new method. But the problem arises when you run xDoclet again. It will replace the class and your method will be removed. Create a class that contain the value object and delegate the method of the class is a good and safe way to solve this problem. We name this class view, because it can contain additional methods for displaying, for example formated float value or sum of values.

We create a new package de.laliluna.tutorial.library.view und add two new classes BookView and UserView. Define the value object BookValue in the class BookView and the same for UserValue in UserView. Generate the getter- and setter-methods and delegate all methods of the objects.



Delegate pattern (design pattern)

If you want to add particular properties to a class, it is the best way to use composition. In our case we want to extend the class BookValue with the user, which has borrowed the book.

You create an outer class, which contains the class as locale variable. The class BookView behaves like a book, so we can define for each method of the class BookValue a delegate method.

With eclipse you can create easly delegate methods. In your souce code click the right mouse button and choose the function ?Source? -> ?Delegate Methods?. Now you let MyEclipse create the delegate methods for you.

We need an additional object that contains the information of the user, who borrows the book, in your BookView class. We define an instance of the class UserView and generate the getter- and setter-methods.

The class looks like the following:

public class BookView {

private BookValue bookValue = new BookValue();
private UserView userView = new UserView();

public BookValue getBookValue() {
return bookValue;
}
public void setBookValue(BookValue bookValue) {
this.bookValue = bookValue;
}
public UserView getUserView() {
return userView;
}
public void setUserView(UserView userView) {
this.userView = userView;
}
public boolean authorHasBeenSet() {
return bookValue.authorHasBeenSet();
}
public boolean availableHasBeenSet() {
return bookValue.availableHasBeenSet();
}
public boolean equals(Object arg0) {
return bookValue.equals(arg0);
}
public String getAuthor() {
return bookValue.getAuthor();
}
public Boolean getAvailable() {
return bookValue.getAvailable();
}
public Integer getId() {
return bookValue.getId();
}
public Integer getPrimaryKey() {
return bookValue.getPrimaryKey();
}
public String getTitle() {
return bookValue.getTitle();
}
public Integer getUserId() {
return bookValue.getUserId();
}
public int hashCode() {
return bookValue.hashCode();
}
public boolean idHasBeenSet() {
return bookValue.idHasBeenSet();
}
public boolean isIdentical(Object other) {
return bookValue.isIdentical(other);
}
public void setAuthor(String author) {
bookValue.setAuthor(author);
}
public void setAvailable(Boolean available) {
bookValue.setAvailable(available);
}
public void setId(Integer id) {
bookValue.setId(id);
}
public void setPrimaryKey(Integer pk) {
bookValue.setPrimaryKey(pk);
}
public void setTitle(String title) {
bookValue.setTitle(title);
}
public void setUserId(Integer userId) {
bookValue.setUserId(userId);
}
public boolean titleHasBeenSet() {
return bookValue.titleHasBeenSet();
}
public String toString() {
return bookValue.toString();
}
public boolean userIdHasBeenSet() {
return bookValue.userIdHasBeenSet();
}
}



public class UserView {

private UserValue userValue = new UserValue();


public UserValue getUserValue() {
return userValue;
}
public void setUserValue(UserValue userValue) {
this.userValue = userValue;
}
public boolean ageHasBeenSet() {
return userValue.ageHasBeenSet();
}
public boolean equals(Object arg0) {
return userValue.equals(arg0);
}
public Integer getAge() {
return userValue.getAge();
}
public Integer getId() {
return userValue.getId();
}
public String getLastName() {
return userValue.getLastName();
}
public String getName() {
return userValue.getName();
}
public Integer getPrimaryKey() {
return userValue.getPrimaryKey();
}
public int hashCode() {
return userValue.hashCode();
}
public boolean idHasBeenSet() {
return userValue.idHasBeenSet();
}
public boolean isIdentical(Object other) {
return userValue.isIdentical(other);
}
public boolean lastNameHasBeenSet() {
return userValue.lastNameHasBeenSet();
}
public boolean nameHasBeenSet() {
return userValue.nameHasBeenSet();
}
public void setAge(Integer age) {
userValue.setAge(age);
}
public void setId(Integer id) {
userValue.setId(id);
}
public void setLastName(String lastName) {
userValue.setLastName(lastName);
}
public void setName(String name) {
userValue.setName(name);
}
public void setPrimaryKey(Integer pk) {
userValue.setPrimaryKey(pk);
}
public String toString() {
return userValue.toString();
}
}



Create the session beans

Book Session Bean

Create a new session bean BookSession.
Right click on the package > New > EJB (Session...)




We want to add the following business processes to the session bean class BookSession.



Get all existing books

Within the method getAllBooks() we call a finder, that get all existing books. A Finder is a search method of the entity bean, which can return one or more beans.

We only want to use view object, so the method loops over the returned collection of the finder and fill an array with the view objects.

/**
* This method return all books as a collection
*
* @ejb.interface-method view-type = "both"
*/
public BookView[] getAllBooks() throws EJBException {
try {
InitialContext context = new InitialContext();
//Get the home interface with JNDI from the application server
BookLocalHome bookLocalHome = (BookLocalHome)context.lookup(BookLocalHome.JNDI_NAME);

//get all books with the local home interface
Collection collection = bookLocalHome.findAll();

//define an ArrayList
ArrayList arrayList = new ArrayList();

//loop over the collection
for (Iterator iter = collection.iterator(); iter.hasNext();) {
BookLocal element = (BookLocal) iter.next();

//define a new BookView object
BookView bookView = new BookView();

//set the BookValue in bookView
bookView.setBookValue(element.getBookValue());

//set the UserValue in bookView
if(element.getUser() != null)
bookView.getUserView().setUserValue(element.getUser().getUserValue());

//add the bookView object to the ArrayList
arrayList.add(bookView);
}

//return the array of BookView
return (BookView[])arrayList.toArray(new BookView[0]);

} catch (NamingException e) {
throw new EJBException(e.getMessage());
} catch (FinderException e) {
throw new EJBException(e.getMessage());
}
}



Get a book by primary key

The method getBookByPrimaryKey() gets a book by the primary key and returns a BookView object.

/** 
* This methode get a book by primary key
*
* @ejb.interface-method view-type = "both"
*/
public BookView getBookByPrimaryKey(Integer primaryKey) throws EJBException {
try {
InitialContext context = new InitialContext();
BookView bookView = new BookView();

//Get the home interface with JNDI from the application server
BookLocalHome bookLocalHome = (BookLocalHome)context.lookup(BookLocalHome.JNDI_NAME);

//search for a book with the primary key
BookLocal bookLocal = bookLocalHome.findByPrimaryKey(primaryKey);

//set the BookValue object in BookView
bookView.setBookValue(bookLocal.getBookValue());

//set the UserValue in BookView
if(bookLocal.getUser() != null)
bookView.getUserView().setUserValue(bookLocal.getUser().getUserValue());

//return the book value object
return bookView;

} catch (NamingException e) {
throw new EJBException(e.getMessage());
} catch (FinderException e) {
throw new EJBException(e.getMessage());
}
}



User borrow a book

The method borrowBook() is called with the primary key of a book and a user. It saves the relation between the book and the user.

/** 
* This methode borrow a book for a user
*
* @ejb.interface-method view-type = "both"
*/
public void borrowBook(Integer primaryKey, Integer userPrimaryKey) throws EJBException {
try {
InitialContext context = new InitialContext();

//Get the home interface with JNDI from the application server
BookLocalHome bookLocalHome = (BookLocalHome)context.lookup(BookLocalHome.JNDI_NAME);
UserLocalHome userLocalHome = (UserLocalHome)context.lookup(UserLocalHome.JNDI_NAME);

//find the book by primary key
BookLocal bookLocal = bookLocalHome.findByPrimaryKey(primaryKey);

//find the user by primary key
UserLocal userLocal = userLocalHome.findByPrimaryKey(userPrimaryKey);

//set the local inferface of user to assign him to a book
bookLocal.setUser(userLocal);

} catch (NamingException e) {
throw new EJBException(e.getMessage());
} catch (FinderException e) {
throw new EJBException(e.getMessage());
}
}



User return a book

This method remove the relation between one book and one user. The user return the book.

/**
* This methode return a book from a user by primary key
*
* @ejb.interface-method view-type = "both"
*/
public void returnBook(Integer primaryKey) throws EJBException {
try {
InitialContext context = new InitialContext();

//Get the home interface with JNDI from the application server
BookLocalHome bookLocalHome = (BookLocalHome)context.lookup(BookLocalHome.JNDI_NAME);

//find a book by primary key
BookLocal bookLocal = bookLocalHome.findByPrimaryKey(primaryKey);

//remove the relation between the user
bookLocal.setUser(null);

} catch (NamingException e) {
throw new EJBException(e.getMessage());
} catch (FinderException e) {
throw new EJBException(e.getMessage());
}
}


Update / add a book

The task of the method is saving a book. If the method cannot find the primary key it add a new book, otherwise it update the properties.

/**
* This method save the value object of the book
*
* @ejb.interface-method view-type = "both"
*/
public void saveBook(BookValue bookValue) throws EJBException {

try {
InitialContext context = new InitialContext();

//Home Interface �ber JNDI beim Appliacation Server holen
BookLocalHome bookLocalHome = (BookLocalHome)context.lookup(BookLocalHome.JNDI_NAME);

//check if the book can be found for update, otherwise insert it as a new book
BookLocal bookLocal = null;
try {
if(bookValue.getId()==null)bookValue.setId(new Integer(0));
bookLocal = bookLocalHome.findByPrimaryKey(bookValue.getId());
} catch (FinderException e1) {
bookLocal = bookLocalHome.create();
}

//update the values of the book
bookLocal.setBookValue(bookValue);

} catch (NamingException e) {
throw new EJBException(e.getMessage());
} catch (CreateException e) {
throw new EJBException(e.getMessage());
}
}



Remove a book

The method removeBookByPrimaryKey() deletes a book by its primary key.

/**
* This method removes a book from the database
*
* @ejb.interface-method view-type = "both"
*/
public void removeBookByPrimaryKey(Integer primaryKey) throws EJBException {

try {
InitialContext context = new InitialContext();

//Get the home interface with JNDI from the application server
BookLocalHome bookLocalHome = (BookLocalHome)context.lookup(BookLocalHome.JNDI_NAME);

//find the book by primary key
BookLocal bookLocal = bookLocalHome.findByPrimaryKey(primaryKey);

//remove the book
bookLocal.remove();

} catch (RemoveException e) {
throw new EJBException(e.getMessage());
} catch (NamingException e) {
throw new EJBException(e.getMessage());
} catch (FinderException e) {
throw new EJBException(e.getMessage());
}
}



User Session Bean

Create a new session bean UserSession that contains the business processes of the users.




We also need methods for the following business methods.



Get all users

This methods gets all users and returns a collection.

/**
* This method return all users as a collection
*
* @ejb.interface-method view-type = "both"
*/
public Collection getAllUsers() throws EJBException {
try {
InitialContext context = new InitialContext();

//Get the home interface with JNDI from the application server
UserLocalHome userLocalHome = (UserLocalHome)context.lookup(UserLocalHome.JNDI_NAME);

//find all users and return them as collection
return userLocalHome.findAll();

} catch (NamingException e) {
throw new EJBException(e.getMessage());
} catch (FinderException e) {
throw new EJBException(e.getMessage());
}
}



Get a user by primary key

This method calls a finder to get user by primary key.

/**
* This methode get a user by primary key
*
* @ejb.interface-method view-type = "both"
*/
public UserValue getUserByPrimaryKey(Integer primaryKey) throws EJBException {
try {
InitialContext context = new InitialContext();

//Get the home interface with JNDI from the application server
UserLocalHome userLocalHome = (UserLocalHome)context.lookup(UserLocalHome.JNDI_NAME);

//find a user by primary key
UserLocal userLocal = userLocalHome.findByPrimaryKey(primaryKey);

//return the book value object
return userLocal.getUserValue();

} catch (NamingException e) {
throw new EJBException(e.getMessage());
} catch (FinderException e) {
throw new EJBException(e.getMessage());
}
}



Update / add a user

The task of this method is saving a user. If the primary key of the user cannot be found, a new user will be created, otherwise the properties of the user will be updated.

/**
* This methode update or add a user.
*
* @ejb.interface-method view-type = "both"
*/
public void saveUser(UserValue userValue) throws EJBException {
try {
InitialContext context = new InitialContext();
//Get the home interface with JNDI from the application server
UserLocalHome userLocalHome = (UserLocalHome)context.lookup(UserLocalHome.JNDI_NAME);

//check if the user can be found for update, otherwise insert it as a new user
UserLocal userLocal = null;
try {
if(userValue.getId()==null)userValue.setId(new Integer(0));
userLocal = userLocalHome.findByPrimaryKey(userValue.getId());
} catch (FinderException e1) {
userLocal = userLocalHome.create();
}

//set the value object of the local interface
userLocal.setUserValue(userValue);

} catch (NamingException e) {
throw new EJBException(e.getMessage());
} catch (CreateException e) {
throw new EJBException(e.getMessage());
}
}



Remove a user

This method removes a user by its primary key.

/**
* This method remove a user by primary key
*
* @ejb.interface-method view-type = "both"
*/
public void removeUserByPrimaryKey(Integer primaryKey) throws EJBException {

try {
InitialContext context = new InitialContext();

//Get the home interface with JNDI from the application server
UserLocalHome userLocalHome = (UserLocalHome)context.lookup(UserLocalHome.JNDI_NAME);

//find the user by primary key
UserLocal userLocal = userLocalHome.findByPrimaryKey(primaryKey);

//remove the user
userLocal.remove();

} catch (RemoveException e) {
throw new EJBException(e.getMessage());
} catch (NamingException e) {
throw new EJBException(e.getMessage());
} catch (FinderException e) {
throw new EJBException(e.getMessage());
}
}



Congratulation, thats all.

Create the dialogs

Create a new struts project with File > New > Project or use the shortcut Strg + n.
Select the Wizard in J2EE Web Project.




Set a nice name for your project.






After creating the project, your Package Explorer looks like the picture below.














For now your project is still a normal J2EE project, so we need to add the struts capabilityies. Right click on the project and add the capabilityies for struts with Add Struts Capabilityies.






Change the Base package for new classes and
Default application resource




Configure the java build path

Open the project properties and select on java build path the ejb project ?LibraryWebEjb?.






Create a default, welcome page

Ok, now we want to create a default page. Right click (yes again) on the Folder WebRoot in the Project and choose New > JSP.






Set the name to index.jsp and choose on template to use > Standard JSP using Struts 1.1 MyEcplise will use the template to create the JSP File.








You will find the file index.jsp in the folder WebRoot of the project. On the top of the file you will find the declaration of the struts tag libraries. These includes will be use to access the tags of struts. In this case we only need the logic tag library.






Insert the following line below the included logic tag.

<logic:forward name="welcome" /> 


This line instructs struts to look for a forward with the name welcome. If the application don�t find this forward it will state an error. In the next section I briefly explain the action forward.



Create a second index.jsp file in the folder /WebRoot/jsp
Change the body of the file to the following:

<body>
Welcome!
<br>
<html:link action="bookList">Show the book list</html:link>
<br>
<html:link action="userList">Show the user list</html:link>
</body>



Global Action Forwards and Action Mappings

What is an action forward?
A action forward can be used to forward to a jsp or action mapping. There are two different action forwards. The global action forward and the local action forward. You can access a global action forward on each jsp or action class. A local action forward can only be accessed by the assigned action class.



What is a action mapping?
The action mapping is the heart of struts. It managed all actions between the application and the user. You can define which action will be executed by creating a action mapping.

The diagram show you, how the application server manage the request of the index.jsp or a non existing action mapping.








In the first step create a new action mapping. MyEclipse provides some nice features for creating struts files. Open the struts-config.xml, you will find it in the folder WebRoot/WEB-INF.

Click with the right mouse button on the entry action-mappings to create a new action with the wizard.


outline-view.gif


Choose Use Case default and Action Type Forward. The Forward Path is the welcome page /jsp/index.jsp






To catch all requests of non existing action mappings, we have to add manually a parameter unknow="true" to the action forward.

<action-mappings >
<action forward="/jsp/index.jsp" path="/default" unknown="true"/>
</action-mappings>



Create the jsp specified above and change the code to the following:

<%@ page language="java"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html:html locale="true">
<head>
<html:base />

<title>index.jsp</title>

<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>

<body>
Welcome!
<br>
<html:link action="bookList">Show the book list</html:link>
<br>
<html:link action="userList">Show the user list</html:link>
</body>
</html:html>



In the second step you create a global action forward. Go back to the outline window of MyEclipse and choose Global Forward






Choose the Forward Scope Global Forward. For name use the same you have set in your default page. The Global Forward refers to your action mapping.






You will see the following in your editor window.

<global-forwards >
<forward name="welcome" path="/default.do" redirect="true" />
</global-forwards>
<action-mappings >
<action forward="/jsp/index.jsp" path="/default" unknown="true" />
</action-mappings>


Book list

This use case list all available books.

Open the struts-config.xml. Right click on Form Bean in the outline window.






Use Case is bookList, Superclass org.apache.struts.ActionForm. Select public void reset.. to create this method. Set the name of the jsp file on the JSP tab.








The package explorer looks like the pictures below.





Edit the source code of the action form class

Open the file BookListForm.java and add the following.

public class BookListForm extends ActionForm {

private BookView[] bookViews = new BookView[0];

public BookView[] getBookViews() {
return bookViews;
}
public void setBookViews(BookView[] bookViews) {
this.bookViews = bookViews;
}
}



Define an array of type BookView and generate a getter and setter.



Action mapping und action class of the book list

Open the struts-config.xml and create a new action mapping.

Use Case is bookList, choose Create new Action Class
Superclass org.apache.struts.Action
On Optional Details choose the Form Bean bookListForm.
The input source is /jsp/bookList.jsp








Now add a forward showList to the action mapping.






You will find the action class bookListAction in your package de.laliluna.tutorial.library.action.



Edit the source code of the action class

Open the class bookListAction and edit the method execute. Create a local home interface of the class BookSession and call the method that gets all books. Save the array of books returned by the method in the form bean. The command mapping.findForward(?showList?) will search for a local forward with the name showList.

/** 
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
BookListForm bookListForm = (BookListForm) form;


try {
InitialContext context = new InitialContext();

//holen des Home Interfaces f�r BookSession mit JNDI vom Appplication Server
BookSessionHome bookSessionHome = (BookSessionHome)context.lookup(BookSessionHome.JNDI_NAME);
BookSession bookSession = bookSessionHome.create();

//lies alle B�cher aus und setze diese im Form Bean
bookListForm.setBookViews(bookSession.getAllBooks());

} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showList");
}




Yeah thats all, you have now created your form bean with an action form class, an action mapping with an action class and the jsp to display something.



Display the books list in the jsp file.

Open the bookList.jsp and add the following source code.

<%@ page language="java"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>

<html>
<head>
<title>Show book list</title>
</head>
<body>

<table border="1">
<tbody>
<%-- set the header --%>
<tr>
<td>Author</td>
<td>Book name</td>
<td>Available</td>
<td>Borrowed by</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<%-- start with an iterate over the array bookViews --%>
<logic:iterate name="bookListForm" property="bookViews" id="book">
<tr>
<%-- book informations --%>
<td><bean:write name="book" property="author" /></td>
<td><bean:write name="book" property="title" /></td>
<td><html:checkbox disabled="true"
name="book"
property="available"/>
</td>
<td>
<%-- check if a user borrowed a book,
when its true display his name
otherwise display nothing --%>
<logic:notEmpty name="book" property="userView.name">
<bean:write name="book" property="userView.name" />,
<bean:write name="book" property="userView.lastName" />
</logic:notEmpty>
<logic:empty name="book" property="userView.name">
-
</logic:empty>
</td>
<%-- borrow, edit and delete link for each book --%>
<td>
<%-- check if a user borrowed a book,
when its true display the return link
otherwise display the borrow link --%>
<logic:notEmpty name="book" property="userView.name">
<html:link action="bookEdit.do?do=returnBook"
paramName="book"
paramProperty="id"
paramId="id">Return book</html:link>
</logic:notEmpty>
<logic:empty name="book" property="userView.name">
<html:link action="bookEdit.do?do=borrowBook"
paramName="book"
paramProperty="id"
paramId="id">Borrow book</html:link>
</logic:empty>
</td>
<td><html:link action="bookEdit.do?do=editBook"
paramName="book"
paramProperty="id"
paramId="id">Edit</html:link>
</td>
<td><html:link action="bookEdit.do?do=deleteBook"
paramName="book"
paramProperty="id"
paramId="id">Delete</html:link>
</td>
</tr>
</logic:iterate>
<%-- end interate --%>

<%-- if books cannot be found display a text --%>
<logic:notPresent name="book">
<tr>
<td colspan="5">No books found.</td>
</tr>
</logic:notPresent>

</tbody>
</table>

<br>
<%-- add and back to menu button --%>
<html:button property="add"
onclick="location.href='bookEdit.do?do=addBook'">Add a new book
</html:button>
&nbsp;
<html:button property="back"
onclick="location.href='default.do'">Back to menu
</html:button>
</body>
</html>



The tag <logic:iterate> loops over the array of books. Within the tag you have access to the properties of the books with the name book. The tag <bean:write> prints out a property of a book, for example the title. With the tag <logic:notEmpty> and <logic:empty> we check, if a user has borrowed a book or not.

Add, edit, borrow and delete books

In the next step we have to add the following use cases.

New form bean

Create a new form bean and action form class. Set Use case to bookEdit and remove all methods on Optional details ? Methods. Let MyEcplise create the jsp file for us.

Open the class BookEditForm.java in de.laliluna.tutorial.library.form .

Create a new instance bookView of the class BookView


private BookView bookView = new BookView();



Generate a getter and setter for this instance.






Delegate all methods of the class BookView.






The source code looks like the following.

public class BookEditForm extends ActionForm {

private BookView bookView = new BookView();

public BookView getBookView() {
return bookView;
}
public void setBookView(BookView bookView) {
this.bookView = bookView;
}
public boolean authorHasBeenSet() {
return bookView.authorHasBeenSet();
}
public boolean availableHasBeenSet() {
return bookView.availableHasBeenSet();
}
public boolean equals(Object arg0) {
return bookView.equals(arg0);
}
public String getAuthor() {
return bookView.getAuthor();
}
public Boolean getAvailable() {
return bookView.getAvailable();
}
public BookValue getBookValue() {
return bookView.getBookValue();
}
public Integer getId() {
return bookView.getId();
}
public Integer getPrimaryKey() {
return bookView.getPrimaryKey();
}
public String getTitle() {
return bookView.getTitle();
}
public Integer getUserId() {
return bookView.getUserId();
}
public UserView getUserView() {
return bookView.getUserView();
}
public int hashCode() {
return bookView.hashCode();
}
public boolean idHasBeenSet() {
return bookView.idHasBeenSet();
}
public boolean isIdentical(Object other) {
return bookView.isIdentical(other);
}
public void setAuthor(String author) {
bookView.setAuthor(author);
}
public void setAvailable(Boolean available) {
bookView.setAvailable(available);
}
public void setBookValue(BookValue bookValue) {
bookView.setBookValue(bookValue);
}
public void setId(Integer id) {
bookView.setId(id);
}
public void setPrimaryKey(Integer pk) {
bookView.setPrimaryKey(pk);
}
public void setTitle(String title) {
bookView.setTitle(title);
}
public void setUserId(Integer userId) {
bookView.setUserId(userId);
}
public void setUserView(UserView userView) {
bookView.setUserView(userView);
}
public boolean titleHasBeenSet() {
return bookView.titleHasBeenSet();
}
public String toString() {
return bookView.toString();
}
public boolean userIdHasBeenSet() {
return bookView.userIdHasBeenSet();
}
}



Action Mapping

Create a new action mapping. There is a different between our first action class. The new action class will extends to the superclass org.apache.struts.DispatchAction.




On Parameter we add a parameter do. These parameter is needed by the dispatch action class.














Add four new forwards. One is for the edit page, the second for the add page, where you can add the books, the third forward to the borrow page and the last forward redirect the user to the book listing.







The last forward is different to the others. It refers to an existing action mapping and redirect the user.



Create the non existing jsp files with New > JSP.

bookAdd.jsp

bookBorrow.jsp

Create the source code of the jsp files

Open the file bookAdd.jsp and add the following source code.

<%@ page language="java"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>

<html>
<head>
<title>Add a book</title>
</head>
<body>
<%-- create a html form --%>
<html:form action="bookEdit">
<%-- print out the form data --%>
<table border="1">
<tbody>
<tr>
<td>Author:</td>
<td><html:text property="author" /></td>
</tr>
<tr>
<td>Title:</td>
<td><html:text property="title" /></td>
</tr>
<tr>
<td>Available:</td>
<td><html:checkbox property="available" /></td>
</tr>
</tbody>
</table>
<%-- set the parameter for the dispatch action --%>
<html:hidden property="do" value="saveBook" />

<br>
<%-- submit and back button --%>
<html:button property="back"
onclick="history.back();">
Back
</html:button>
&nbsp;
<html:submit>Save</html:submit>
</html:form>


</body>
</html>




The tag <html:form> creates a new HTML form and refers with the parameter action=?bookEdit? to the action mapping. The Tag <html:text> creates a text field with the property author of the book. <html:hidden> is a hidden form field with the name do. We need this hidden field, because it tells the dispatch action class which method will called.

Open the file bookEdit.jsp. You can use the source code of the of the file bookAdd.jsp and change the following lines.

<title>Edit a book</title>



Add the following line above <html:hidden property="do" value="saveBook" />

<%-- hidden fields for id and userId --%>
<html:hidden property="id" />
<html:hidden property="userId" />



Open the file bookBorrow.jsp and add the following.

<%@ page language="java"%>
<%@ page isELIgnored="false"%>

<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>

<html>
<head>
<title>Show user</title>
</head>
<body>
<html:form action="bookEdit">
<table border="1">
<tbody>
<%-- set the header --%>
<tr>
<td>Last name</td>
<td>Name</td>
<td>Borrowed</td>
</tr>

<%-- start with an iterate over the collection users --%>
<logic:iterate name="users" id="user">
<tr>
<%-- book informations --%>
<td><bean:write name="user" property="lastName" /></td>
<td><bean:write name="user" property="name" /></td>
<td><html:radio property="userId" value="${user.id}" /></td>
</tr>
</logic:iterate>
<%-- end interate --%>

<%-- if users cannot be found display a text --%>
<logic:notPresent name="user">
<tr>
<td colspan="5">No users found.</td>
</tr>
</logic:notPresent>
</tbody>
</table>

<%-- set the book id to borrow --%>
<html:hidden property="id" />

<%-- set the parameter for the dispatch action --%>
<html:hidden property="do" value="save" />

<%-- submit and back button --%>
<html:button property="back"
onclick="history.back();">
Back
</html:button>
&nbsp;
<html:submit>Save</html:submit>
</html:form>
</body>
</html>





Ok, thats all.





Methods of the dispatch action class

DispatchAction

Normally you set up each action event to always correspond to a unique Action class. There is nothing wrong with doing this but if you want to condense related events into one Action class you can do this by using a DispatchAction class or some of it sub classes.

Open the file bookEditAction.java and add the following methods

public ActionForward editBook(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
BookEditForm bookEditForm = (BookEditForm) form;

/* lalinuna.de 04.11.2004
* get id of the book from request
*/
Integer id = Integer.valueOf(request.getParameter("id"));

/* lalinuna.de 16.11.2004
* load the session facade and get the book by primary key
*/
try {
InitialContext context = new InitialContext();
//holen des Home Interfaces f�r BookSession mit JNDI vom Appplication Server
BookSessionHome bookSessionHome = (BookSessionHome)context.lookup(BookSessionHome.JNDI_NAME);
BookSession bookSession = bookSessionHome.create();

//bestimme das Buch anhand seines Prim�rschl�ssels und setzte es im Form Bean
bookEditForm.setBookValue(bookSession.getBookByPrimaryKey(id));

} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showEdit");

}

The method editBook gets the id from the request and gets the book by the primary key from the database. The forward showEdit refers to the jsp file where you can edit the book.

public ActionForward borrowBook(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
BookEditForm bookEditForm = (BookEditForm) form;

/* lalinuna.de 04.11.2004
* get id of the book from request
*/
Integer id = Integer.valueOf(request.getParameter("id"));

/* lalinuna.de 16.11.2004
* load the session facade for book and user
* get the book information and get all users
*/
try {
InitialContext context = new InitialContext();

//holen des Home Interfaces f�r BookSession mit JNDI vom Appplication Server
BookSessionHome bookSessionHome = (BookSessionHome)context.lookup(BookSessionHome.JNDI_NAME);
BookSession bookSession = bookSessionHome.create();;

//holen des Home Interfaces f�r UserSession mit JNDI vom Appplication Server
UserSessionHome userSessionHome = (UserSessionHome)context.lookup(UserSessionHome.JNDI_NAME);
UserSession userSession = userSessionHome.create();

//lies das Buch anhand seines Prim�rschl�ssels und setzte es im Form Bean
bookEditForm.setBookView(bookSession.getBookByPrimaryKey(id));

//bestimme alle Benutzer und setzte diese im Request
request.setAttribute("users", userSession.getAllUsers());

} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showBorrowUser");
}

The method contains the process that a user can borrow a book. It assigns a user to a book.

public ActionForward returnBook(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
BookEditForm bookEditForm = (BookEditForm) form;

/* lalinuna.de 04.11.2004
* get id of the book from request
*/
Integer id = Integer.valueOf(request.getParameter("id"));

/* lalinuna.de 16.11.2004
* load the session facade and delete the book by primary key
*/
try {
InitialContext context = new InitialContext();

//holen des Home Interfaces f�r BookSession mit JNDI vom Appplication Server
BookSessionHome bookSessionHome = (BookSessionHome)context.lookup(BookSessionHome.JNDI_NAME);
BookSession bookSession = bookSessionHome.create();

//l�scht die Beziehung zwischen Benutzer und Buch
bookSession.returnBook(id);


} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showList");
}

The next method removes the relation between a user and a book, the book is returned by a user.

public ActionForward deleteBook(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
BookEditForm bookEditForm = (BookEditForm) form;

/* lalinuna.de 04.11.2004
* get id of the book from request
*/
Integer id = Integer.valueOf(request.getParameter("id"));

/* lalinuna.de 16.11.2004
* load the session facade and delete the book by primary key
*/
try {
InitialContext context = new InitialContext();
//holen des Home Interfaces f�r BookSession mit JNDI vom Appplication Server
BookSessionHome bookSessionHome = (BookSessionHome)context.lookup(BookSessionHome.JNDI_NAME);
BookSession bookSession = bookSessionHome.create();

//l�scht eine Buch anhand des Prim�rschl�ssels
bookSession.removeBookByPrimaryKey(id);


} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showList");
}

The method deleteBook gets the parameter id of the request and deletes the book from the database. Then the forward showList displays the book list page.

public ActionForward addBook(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
BookEditForm bookEditForm = (BookEditForm) form;

return mapping.findForward("showAdd");

}

The method addBook refers to the bookAdd.jsp

public ActionForward saveBorrow(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
BookEditForm bookEditForm = (BookEditForm) form;

/* lalinuna.de 16.11.2004
* load the session facade and save the book by primary key
*/
try {
InitialContext context = new InitialContext();

//holen des Home Interfaces f�r BookSession mit JNDI vom Appplication Server
BookSessionHome bookSessionHome = (BookSessionHome)context.lookup(BookSessionHome.JNDI_NAME);
BookSession bookSession = bookSessionHome.create();

//ein Buch an einen Benutzer verleihen
bookSession.borrowBook(bookEditForm.getId(), bookEditForm.getUserId());

} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showList");
}

This method assigns a user to a book, if a user borrows a book.

public ActionForward saveBook(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
BookEditForm bookEditForm = (BookEditForm) form;


/* lalinuna.de 16.11.2004
* load the session facade and save the book by primary key
*/
try {
InitialContext context = new InitialContext();

//holen des Home Interfaces f�r BookSession mit JNDI vom Appplication Server
BookSessionHome bookSessionHome = (BookSessionHome)context.lookup(BookSessionHome.JNDI_NAME);
BookSession bookSession = bookSessionHome.create();

//speichern des Book Value Ojekts
bookSession.saveBook(bookEditForm.getBookValue());


} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showList");
}

The last method updates a book.

User list

We create this list on the same way like the book list.

Open the struts-config.xml. Right click on Form Bean in the outline window.

Use Case is userList, Superclass org.apache.struts.ActionForm On Methods choose only public void reset. On JSP set a name for the jsp file.




Edit the source code of the action class

Open the file UserListForm.java and add the following source code.

public class UserListForm extends ActionForm {

private Collection users;

/* lalinuna.de 02.11.2004
* get the collection books
*/
public Collection getUsers() {
return users;
}
/* lalinuna.de 02.11.2004
* set the collection books
*/
public void setUsers(Collection users) {
this.users = users;
}

/* lalinuna.de 02.11.2004
* reset the collection books
*/
public void reset(ActionMapping arg0, HttpServletRequest arg1) {
users = new ArrayList();
}

}

We define a collection users and generate a getter and setter. Within the method reset we initialize the collection as a new array list.

Action mapping and action class for the user list

Open the struts-config.xml and create a new action mapping.

Use Case userList, choose Create new Action Class
Superclass org.apache.struts.Action
Choose on Optional Details the form bean userListForm and on Input Source the jsp file
/jsp/userList.jsp







Edit the action class

Open the file UserListAction.java and add the following source code.

/** 
* Method execute
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
UserListForm userListForm = (UserListForm) form;


/* lalinuna.de 16.11.2004
* load the session facade and get all users
*/
try {
InitialContext context = new InitialContext();

//holen des Home Interfaces f�r BookSession mit JNDI vom Appplication Server
UserSessionHome userSessionHome = (UserSessionHome)context.lookup(UserSessionHome.JNDI_NAME);
UserSession userSession = userSessionHome.create();

//lies alle Benutzer aus und setze diese im form bean
userListForm.setUsers(userSession.getAllUsers());

} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showUserList");
}

The method gets all users and set them in the form bean.

Displaying the book list in the jsp file

Open the jsp file userList.jsp and change the content of the file like the following.

<%@ page language="java"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>

<html>
<head>
<title>Show user list</title>
</head>
<body>

<table border="1">
<tbody>
<%-- set the header --%>
<tr>
<td>Last name</td>
<td>Name</td>
<td>Age</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<%-- start with an iterate over the collection users --%>
<logic:iterate name="userListForm" property="users" id="user">
<tr>
<%-- book informations --%>
<td><bean:write name="user" property="lastName" /></td>
<td><bean:write name="user" property="name" /></td>
<td><bean:write name="user" property="age" /></td>

<%-- edit and delete link for each book --%>
<td><html:link action="userEdit.do?do=editUser"
paramName="user"
paramProperty="id"
paramId="id">Edit</html:link>
</td>
<td><html:link action="userEdit.do?do=deleteUser"
paramName="user"
paramProperty="id"
paramId="id">Delete</html:link>
</td>
</tr>
</logic:iterate>
<%-- end interate --%>

<%-- if users cannot be found display a text --%>
<logic:notPresent name="user">
<tr>
<td colspan="5">No users found.</td>
</tr>
</logic:notPresent>

</tbody>
</table>

<br>
<%-- add and back to menu button --%>
<html:button property="add"
onclick="location.href='userEdit.do?do=addUser'">Add a new user
</html:button>
&nbsp;
<html:button property="back"
onclick="location.href='default.do'">Back to menu
</html:button>
</body>
</html>



Add, edit, delete users

In the next step we want to add the following use cases.

New form bean

Add a new form bean, with an action form class. Set the Use case userEdit. Choose on Optional details ? Methods no methods. On JSP select that the jsp file will be created.

Open the class UserEditForm.java on de.laliluna.tutorial.library.form .
Add a new instance of userView of the class UserView .

private UserView userView = new UserView();



Generate a getter- and setter-method and delegate all methods of the class, like you have done it with the book form bean.




The source code of the class looks like the following

public class UserEditForm extends ActionForm {

private UserView userView = new UserView();

public UserView getUserView() {
return userView;
}
public void setUserView(UserView userView) {
this.userView = userView;
}
public boolean ageHasBeenSet() {
return userView.ageHasBeenSet();
}
public boolean equals(Object arg0) {
return userView.equals(arg0);
}
public Integer getAge() {
return userView.getAge();
}
public Integer getId() {
return userView.getId();
}
public String getLastName() {
return userView.getLastName();
}
public String getName() {
return userView.getName();
}
public Integer getPrimaryKey() {
return userView.getPrimaryKey();
}
public UserValue getUserValue() {
return userView.getUserValue();
}
public int hashCode() {
return userView.hashCode();
}
public boolean idHasBeenSet() {
return userView.idHasBeenSet();
}
public boolean isIdentical(Object other) {
return userView.isIdentical(other);
}
public boolean lastNameHasBeenSet() {
return userView.lastNameHasBeenSet();
}
public boolean nameHasBeenSet() {
return userView.nameHasBeenSet();
}
public void setAge(Integer age) {
userView.setAge(age);
}
public void setId(Integer id) {
userView.setId(id);
}
public void setLastName(String lastName) {
userView.setLastName(lastName);
}
public void setName(String name) {
userView.setName(name);
}
public void setPrimaryKey(Integer pk) {
userView.setPrimaryKey(pk);
}
public void setUserValue(UserValue userValue) {
userView.setUserValue(userValue);
}
public String toString() {
return userView.toString();
}
}

Action Mapping und Action Klasse

Open the struts-config.xml and create a new action mapping.




Set the Use case to userEdit. Choose Create new Action class and on Superclass org.apache.struts.actions.DispatchAction. On Optional Details > Form choose the form bean.






Set the parameter on Option Details to do.




At the end add three forwards to the different pages.




Edit the source code of the action class

Open the class UserEditAction.java in the package de.laliluna.tutorial.library.action and add the following methods.

/** 
* Method editBook
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward editUser(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
UserEditForm userEditForm = (UserEditForm) form;

/* lalinuna.de 04.11.2004
* get id of the book from request
*/
Integer id = Integer.valueOf(request.getParameter("id"));

/* lalinuna.de 16.11.2004
* load the session facade and get the book by primary key
*/
try {
InitialContext context = new InitialContext();

//holen des Home Interfaces f�r UserSession mit JNDI vom Appplication Server
UserSessionHome userSessionHome = (UserSessionHome)context.lookup(UserSessionHome.JNDI_NAME);
UserSession userSession = userSessionHome.create();

//bestimmen eines Benutzers anhand seines Prim�rschl�ssels und setzen im Form Bean
userEditForm.setUserValue(userSession.getUserByPrimaryKey(id));

} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showEdit");
}

This method gets a user by his primary key and save them in the form bean.

/** 
* Method deleteBook
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward deleteUser(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
UserEditForm userEditForm = (UserEditForm) form;

/* lalinuna.de 04.11.2004
* get id of the book from request
*/
Integer id = Integer.valueOf(request.getParameter("id"));

/* lalinuna.de 16.11.2004
* load the session facade and delete the user by primary key
*/
try {
InitialContext context = new InitialContext();

//holen des Home Interfaces f�r UserSession mit JNDI vom Appplication Server
UserSessionHome userSessionHome = (UserSessionHome)context.lookup(UserSessionHome.JNDI_NAME);
UserSession userSession = userSessionHome.create();

//l�schen eine Benutzer anhand seines Prim�rschl�ssels
userSession.removeUserByPrimaryKey(id);


} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showUserList");
}

The next method deletes a user by primary key and forwards to the user list page.



/** 
* Method addBook
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward addUser(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
UserEditForm userEditForm = (UserEditForm) form;

return mapping.findForward("showAdd");

}

This method forwards to the add dialog

/** 
* Method saveBook
* @param mapping
* @param form
* @param request
* @param response
* @return ActionForward
*/
public ActionForward saveUser(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response) {
UserEditForm userEditForm = (UserEditForm) form;

/* lalinuna.de 16.11.2004
* load the session facade and save the book by primary key
*/
try {
InitialContext context = new InitialContext();

//holen des Home Interfaces f�r UserSession mit JNDI vom Appplication Server
UserSessionHome userSessionHome = (UserSessionHome)context.lookup(UserSessionHome.JNDI_NAME);
UserSession userSession = userSessionHome.create();

//aktualisiert oder legt eine neues Buch an
userSession.saveUser(userEditForm.getUserValue());


} catch (RemoteException e) {
e.printStackTrace();
} catch (NamingException e) {
e.printStackTrace();
} catch (CreateException e) {
e.printStackTrace();
}

return mapping.findForward("showUserList");
}

This method updates and adds a user, like the method in the book action class. It forwards to the user list page.



Edit the source code of the jsp files

Create a new file named userAdd.jsp in the folder WebRoot/jsp/.

Open the file userAdd.jsp and change the content of the file.

<%@ page language="java"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean" prefix="bean"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-html" prefix="html"%>
<%@ taglib uri="http://jakarta.apache.org/struts/tags-logic" prefix="logic" %>

<html>
<head>
<title>Add a user</title>
</head>
<body>
<%-- create a html form --%>
<html:form action="userEdit">
<%-- print out the form data --%>
<table border="1">
<tbody>
<tr>
<td>Last name:</td>
<td><html:text property="lastName" /></td>
</tr>
<tr>
<td>Name:</td>
<td><html:text property="name" /></td>
</tr>
<tr>
<td>Age:</td>
<td><html:text property="age" /></td>
</tr>
</tbody>
</table>
<%-- set the parameter for the dispatch action --%>
<html:hidden property="do" value="saveUser" />

<br>
<%-- submit and back button --%>
<html:button property="back"
onclick="history.back();">
Back
</html:button>
&nbsp;
<html:submit>Save</html:submit>
</html:form>
</body>
</html>


It is quite the same like the book edit page.

Open the file userEdit.jsp copy the source code of the file userAdd.jsp and add above the line <html:hidden property="do" value="saveUser" /> the following

<%-- hidden field that contains the id of the user --%>
<html:hidden property="id" />



Test the applications

Start the jboss and deploy the project as package archiv.




Call the project in your favorite web browser. http://localhost:8080/LibraryWeb/



Nice, thats all.