J2EE Practical Guide Bea Weblogic

Shree-Technologies 11/29/2008

Shrikant

Table of Contents Module: Architecture ............................................................................................................................ 13 Lab exercise - WebLogic setup..................................................................................................... 13 Installing your WebLogic server................................................................................................... 13 Creating aliases for commonly used commands ........................................................................... 14 Deleting your WebLogic directory ............................................................................................... 15 Copying your WebLogic directory ............................................................................................... 15 Module: Architecture ........................................................................................................................ 15 Lab exercise - Familiarisation 1 - Installing Eclipse ..................................................................... 15 Installing Workshop For Weblogic ............................................................................................... 15 Creating a project .......................................................................................................................... 17 Deploying static HTML ................................................................................................................ 20 Running the HTML page .............................................................................................................. 22 Module: Architecture ........................................................................................................................ 25 Lab exercise - Familiarisation 2 .................................................................................................... 25 The environment ........................................................................................................................... 25 Familiarisation with the directory structure .................................................................................. 26 Starting your WebLogic server ..................................................................................................... 27 Getting started ............................................................................................................................... 28 Reading the configuration ............................................................................................................. 28 Relevant areas: .............................................................................................................................. 28 DOMAIN: ..................................................................................................................................... 29 Changing the configuration........................................................................................................... 30 Module: Servlets ............................................................................................................................... 32 Lab exercise - Hello World Servlet............................................................................................... 32 A HelloWorld servlet .................................................................................................................... 32 Using Eclipse to create a servlet ................................................................................................... 32 Packaging your servlet 1: directory structure................................................................................ 36

2

Packaging your servlet 2: deployment descriptor ......................................................................... 37 Packaging your servlet 3: static HTML files ................................................................................ 39 Packaging your servlet 4: create the WAR file ............................................................................. 41 Deploying your web application ................................................................................................... 42 Testing your web application ........................................................................................................ 43 Exploring the WebLogic console.................................................................................................. 43 Reflection ...................................................................................................................................... 46 Module: Servlets ............................................................................................................................... 47 Lab exercise - Counter Servlet ...................................................................................................... 47 A Counter servlet .......................................................................................................................... 47 Copying an existing Servlet .......................................................................................................... 47 Servlets and threading ................................................................................................................... 48 Running your servlet ..................................................................................................................... 48 Module: Servlets ............................................................................................................................... 51 Lab exercise - Form parameters .................................................................................................... 51 A SettableCounter servlet ............................................................................................................. 52 Request and Response objects ...................................................................................................... 52 Reading form parameters .............................................................................................................. 53 Aside: printing all form parameters .............................................................................................. 54 Module: Servlets ............................................................................................................................... 55 Lab exercise - HTTP Sessions ...................................................................................................... 55 A SessionCounter servlet .............................................................................................................. 55 The state problem.......................................................................................................................... 55 Sessions and Java .......................................................................................................................... 56 SessionCounterServlet .................................................................................................................. 57 Aside: common usage pattern for sessions ................................................................................... 57 URL Rewriting.............................................................................................................................. 57 Module: Servlets ............................................................................................................................... 60

3

Tutorial - Accessing resources (e.g. relative files) ........................................................................ 60 Some sample code......................................................................................................................... 60 Module: Servlets ............................................................................................................................... 61 Tutorial exercise - Creating a WAR file manually ....................................................................... 61 Manually creating a servlet ........................................................................................................... 61 Packaging your servlet 1: directory structure................................................................................ 62 Packaging your servlet 2: deployment descriptor ......................................................................... 63 Packaging your servlet 3: static HTML files ................................................................................ 64 Packaging your servlet 4: final check ........................................................................................... 64 Packaging your servlet 5: create the WAR file ............................................................................. 65 Deploying your web application ................................................................................................... 65 Testing your web application ........................................................................................................ 66 Reflection ...................................................................................................................................... 66 Module: JSP ...................................................................................................................................... 67 Lab exercise - Hello World JSP .................................................................................................... 67 A HelloWorld JSP......................................................................................................................... 67 Creating a subfolder (subdirectory) .............................................................................................. 68 Module: JSP ...................................................................................................................................... 70 Lab exercise - JSP and form parameters ....................................................................................... 70 More implicit objects in JSP ......................................................................................................... 70 Reading form parameters in JSP ................................................................................................... 70 JSP declarations, scriptlets and expressions.................................................................................. 71 The exercise - changing background colours ................................................................................ 72 Module: JSP ...................................................................................................................................... 73 Lab exercise - JSP and sessions .................................................................................................... 73 Accessing sessions in JSP ............................................................................................................. 73 Using Java class libraries in JSP ................................................................................................... 74 The exercise - storing a history of background colours ................................................................ 74

4

Module: JSP ...................................................................................................................................... 76 Lab exercise - JSP and sessions .................................................................................................... 76 Accessing sessions in JSP ............................................................................................................. 76 Using Java class libraries in JSP ................................................................................................... 77 The exercise - storing a history of background colours ................................................................ 77 Module: JSP ...................................................................................................................................... 78 Lab exercise - Web authentication ................................................................................................ 78 HTTP Basic Authentication .......................................................................................................... 79 Module: JSP ...................................................................................................................................... 83 Lab exercise - Using a JavaBean .................................................................................................. 83 Why use JavaBeans? ..................................................................................................................... 84 What are JavaBeans? .................................................................................................................... 84 Creating your JavaBean ................................................................................................................ 85 Packaging your JavaBean ................................................................................................................. 87 Creating your JSP page ................................................................................................................. 88 Adding new properties .................................................................................................................. 89 Beans and sessions ........................................................................................................................ 89 Module: JSP ...................................................................................................................................... 90 Lab exercise - Using Struts ........................................................................................................... 90 Adding support for Struts.................................................................................................................. 90 Our Lab example............................................................................................................................... 91 Struts Configuration ...................................................................................................................... 92 Struts layout .................................................................................................................................. 92 Modifying struts ............................................................................................................................ 92 More tasks ..................................................................................................................................... 94 References ......................................................................................................................................... 94 Module: JDBC .................................................................................................................................. 94 Lab exercise - Oracle Familiarisation - command line version .................................................... 94

5

Setting up your Oracle account ..................................................................................................... 95 Creating an SQL command file .................................................................................................... 95 Starting SQL*Plus ........................................................................................................................ 97 Running your SQL command file ................................................................................................. 98 Running ad-hoc SQL queries and SQL*Plus commands ............................................................. 98 Quick SQL*Plus Tutorial.............................................................................................................. 98 Changing your password............................................................................................................... 98 Disconnecting from SQL*Plus ..................................................................................................... 99 Oracle Tools .................................................................................................................................. 99 Oracle Documentation .................................................................................................................. 99 Module: JDBC .................................................................................................................................. 99 Lab exercise - Oracle Familiarisation - Workshop for Weblogic version .................................. 100 Setting up your Oracle account ................................................................................................... 100 Setting up your Workshop project .............................................................................................. 100 Creating an SQLpage file............................................................................................................ 100 Creating a Database Connection ................................................................................................. 102 Running your SQL command file ............................................................................................... 102 Exploring your Database............................................................................................................. 103 Disconnecting ............................................................................................................................. 104 Module: JDBC ................................................................................................................................ 105 Lab exercise - Hello World JDBC .............................................................................................. 105 A HelloWorld JDBC application ................................................................................................ 105 Running in Workshop ................................................................................................................. 106 Running from the Command Prompt .......................................................................................... 106 Notes ........................................................................................................................................... 107 Module: JDBC ................................................................................................................................ 107 Lab exercise - JDBC in a JavaBean ............................................................................................ 108 JDBC in a JavaBean.................................................................................................................... 108

6

A unit test for the JDBC JavaBean ............................................................................................. 109 Module: JDBC ................................................................................................................................ 110 Lab exercise - JDBC in a JavaBean in a JSP .............................................................................. 111 Adding JSP.................................................................................................................................. 111 Improving formatting .................................................................................................................. 112 Better Solution ............................................................................................................................ 112 Module: JDBC ................................................................................................................................ 113 Lab exercise - Connection Pools and Data Sources .................................................................... 113 JDBC Connection Pools.............................................................................................................. 113 Verifying your Connection Pool and Data Source...................................................................... 115 The exercise ................................................................................................................................ 115 Testing your new bean ................................................................................................................ 116 Module: JDBC ................................................................................................................................ 117 Tutorial - Using other databases with Weblogic 10 .................................................................... 117 Module: JDBC ................................................................................................................................ 120 Tutorial - ODBC example ........................................................................................................... 120 Creating an ODBC DSN ............................................................................................................. 121 Accessing the ODBC DSN from a Java program ....................................................................... 122 Module: JDBC ................................................................................................................................ 122 Tutorial - Oracle SQL*Plus ........................................................................................................ 122 Running SQL*Plus ..................................................................................................................... 123 Useful SQL*Plus commands ...................................................................................................... 123 Module: JDBC ................................................................................................................................ 124 Tutorial - Quick SQL Refresher.................................................................................................. 125 SQL SELECT statement ............................................................................................................. 125 SQL CREATE/DROP statements ............................................................................................... 128 SQL INSERT/DELETE statements ............................................................................................ 129 SQL UPDATE statements .......................................................................................................... 130

7

Module: RMI .................................................................................................................................. 131 Lab exercise - RMI client/server application .............................................................................. 131 Overview of RMI ........................................................................................................................ 132 Development Process .................................................................................................................. 132 Creating a simple RMI application ............................................................................................. 133 Running the HelloWorld example .............................................................................................. 137 Next step ... ................................................................................................................................. 138 Module: JNDI ................................................................................................................................. 139 Lab exercise - overview .............................................................................................................. 139 About LDAP and directory structures......................................................................................... 140 Accessing an LDAP Directory from the command line ............................................................. 140 Module: JNDI ................................................................................................................................. 142 Lab exercise - LDAP programming ............................................................................................ 142 An example first .......................................................................................................................... 143 Accessing an LDAP Directory from a web application .............................................................. 143 Module: JNDI ................................................................................................................................. 144 Tutorial - Looking up Weblogic LDAP ...................................................................................... 144 Viewing internal LDAP objects .................................................................................................. 144 Setting up Weblogic LDAP for external access.......................................................................... 144 Using the Weblogic Embedded LDAP directory server ............................................................. 145 Module: EJB ................................................................................................................................... 146 Lab exercise - Stateless Session Bean - Manual technique......................................................... 146 Overview of EJB ......................................................................................................................... 146 Development Process .................................................................................................................. 147 Creating an EJB stateless session bean ....................................................................................... 148 Running the HelloWorld EJB example ....................................................................................... 156 Next step ... ................................................................................................................................. 156 Module: EJB ................................................................................................................................... 156

8

Lab exercise - Using Eclipse + Xdoclet to generate EJB............................................................ 156 Rapid code development ............................................................................................................. 156 Using Weblogic Workshop EJBgen ........................................................................................... 157 Using Eclipse & XDoclet............................................................................................................ 157 Step 2 - Create a new Session Bean ............................................................................................ 161 Step 3: Enhancing the Enterprise JavaBean ................................................................................ 164 Step 4: Deploy the bean .............................................................................................................. 165 Step 5: Creating the client: .......................................................................................................... 165 Step 6: Running the client ........................................................................................................... 167 Problems you may encounter ...................................................................................................... 167 Next step ... ................................................................................................................................. 167 Module: EJB ................................................................................................................................... 168 Lab exercise - CMP Entity Bean- manually ............................................................................... 168 Overview of Entity Beans ........................................................................................................... 168 Development Process .................................................................................................................. 169 Creating an EJB CMP Entity bean .............................................................................................. 169 Module: EJB ................................................................................................................................... 175 Lab exercise - CMP Entity Bean-using Eclipse + XDoclet ........................................................ 176 Entity Beans using XDoclet ........................................................................................................ 176 Development Process .................................................................................................................. 176 Creating an EJB CMP Entity bean .............................................................................................. 176 Creating a custom ejbCreate() method........................................................................................ 179 Deploying it ................................................................................................................................ 181 Client code. ................................................................................................................................. 181 More things to do ........................................................................................................................ 183 Facade patterns................................................................................................................................ 183 What if the EJB's are in seperate projects? ................................................................................. 184 Module: EJB ................................................................................................................................... 184

9

Creating EAR files for deployment ............................................................................................ 184 Directory structure ...................................................................................................................... 185 application.xml deployment descriptor ....................................................................................... 185 Notes about EAR files (and why they are good)......................................................................... 186 Referencing EJBs that your components use .............................................................................. 186 Steps in deploying a Java application with many parts............................................................... 189 Using Eclipse to generate EAR files ............................................................................................... 189 An example EAR file .................................................................................................................. 190 Module: XML ................................................................................................................................. 191 Lab exercise - Parsing XML in a JSP ......................................................................................... 191 XML............................................................................................................................................ 191 Parsing an XML file with SAX................................................................................................... 191 Module: XML (DOM) .................................................................................................................... 196 Lab exercise - Writing XML via DOM ...................................................................................... 196 Understanding the code............................................................................................................... 196 Adding indenting to show nesting level ...................................................................................... 200 Formatting the data in a table...................................................................................................... 201 Printing a subset of the data ........................................................................................................ 201 Module: XML ................................................................................................................................. 202 Lab exercise - Transforming XML in a JSP ............................................................................... 202 Creating an XSLT sample file .................................................................................................... 202 Using a web browser to do transformations................................................................................ 204 Using Java to do transformations ................................................................................................ 204 More exercises: XSLT functions ................................................................................................ 205 Advanced exercises:.................................................................................................................... 205 Printing a subset of the data ........................................................................................................ 206 Formatting the data in a table...................................................................................................... 206 Module: Web Services .................................................................................................................... 206

10

Lab exercise 1 - Exploring RPC Web Services .......................................................................... 206 Finding Web services .................................................................................................................. 206 Using Xmethods.com .................................................................................................................. 207 Using the Weblogic Universal Test Client ..................................................................................... 207 Alternative testing points ............................................................................................................ 209 Lab exercise 2 - Exploring other Web Services .......................................................................... 212 Reflection ........................................................................................................................................ 213 Module: Web Services .................................................................................................................... 213 Lab exercise 3 - Writing a simple RPC client ............................................................................. 213 JAX-RPC Static clients ................................................................................................................... 214 Create new project .......................................................................................................................... 214 Generating a static client stub ..................................................................................................... 214 Module: Web Services .................................................................................................................... 216 Lab exercise 5 - Writing a simple web service ........................................................................... 216 Writing the server code ............................................................................................................... 217 Generating the code .................................................................................................................... 217 Test.............................................................................................................................................. 218 Problems ..................................................................................................................................... 218 Module: Web Services .................................................................................................................... 218 Lab exercise 6 - Adding Basic security to a simple web service ................................................ 218 Setting up usernames & roles...................................................................................................... 219 Writing the server code ............................................................................................................... 220 Redeploy & Test ......................................................................................................................... 220 Generating the Client skeleton .................................................................................................... 221 Test.............................................................................................................................................. 221 Module: Web Services .................................................................................................................... 222 Lab exercise 7 - Writing a more complex web service ............................................................... 222 Other data types .......................................................................................................................... 223

11

Lab Exercise: Returning complex types ......................................................................................... 223 Creating a JavaBean .................................................................................................................... 223 Add new complex methods to your class.................................................................................... 224 Building a client .............................................................................................................................. 224 Module: Security............................................................................................................................. 225 Lab exercise - Confidentiality ..................................................................................................... 225 Using SSL ................................................................................................................................... 226 Enforcing SSL ............................................................................................................................. 226 Module: Security............................................................................................................................. 227 Lab exercise - Web authentication .............................................................................................. 227 Declarative web authentication ................................................................................................... 228 Programmatic web authentication ............................................................................................... 228 Module: Transactions...................................................................................................................... 229 Lab exercise - Transactions......................................................................................................... 229 Transactions ................................................................................................................................ 230 Starting a transaction in a servlet ................................................................................................ 231 Module: Legacy .............................................................................................................................. 231 Lab exercise - Using CORBA..................................................................................................... 231 CORBA - C example .................................................................................................................. 232 Java CORBA client ..................................................................................................................... 234 Additional exercises .................................................................................................................... 235 Module: Legacy .............................................................................................................................. 235 Lab exercise - Using JMS ........................................................................................................... 235 Point-to-Point messaging ............................................................................................................ 236 Extra work................................................................................................................................... 239

12

Module: Architecture
Lab exercise - WebLogic setup
This laboratory exercise should be the first one you attempt, as it gives instructions on the steps to follow to set WebLogic up for use in the Faculty of IT environment. Level of Difficulty: 1 (easy) Estimated time: 10 minutes

Installing your WebLogic server
With the WebLogic setup we are using, each person will run their own separate copy of the WebLogic server on the lab workstations. Each student will also have their own configuration for their server. This configuration is stored in your home directory. The first step is to logon to the lab workstations. You will have been allocated to a specific machine. This will be the workstation allocated to you for the rest of the semester. Open a terminal. To do this, select System → Terminal. If you are using KDE, you can also press Right Mouse Button → Terminal. Enter:
/opt/bea10/wlserver_10.0/common/bin/config.sh

Handy hint: Linux let's you complete the command line by pressing the first letter then the tab key. The BEA WebLogic Configuration Window should appear. Take the following steps to set up WebLogic on your account: 1. At the Welcome panel: Select [x] Create a new WebLogic domain. Then press the [Next] button. 2. At The Select Domain Source panel: Select [x] Base this domain on an existing template Leave the default directory and file: (/opt/bea10/wlserver_10.0/common/templates/domains/wls.jar) 3. At The Configure administrator username panel: Enter: Username: weblogic Password: weblogic 4. At The Configure server start mode and JDK panel: Select [x] Development Mode and select [x] BEA supplied JDK, and select jRockit 5. At The Customize environment panel: [x] No

13

6. At Create WebLogic Domain panel: Domain name: weblogic & Domain location: /home/userid (where userid is your Faculty of IT userid 7. At Creating Domain panel: [done] 8. Now note that the weblogic install is now in the in /home/userid/weblogic directory Note: you have now completed the one mandatory part of this lab exercise. You should read the following information, but you do not need to carry out the tasks below immediately.

Creating aliases for commonly used commands
There are a few commands you will need to use over and over again. It might be useful for you to create aliases for those commands to save you time and avoid repetitive typing. Note that the following instructions assuming you are using the Bash shell (which is the default within the Faculty). If you have changed your Unix shell to something else, the following syntax may need to be adjusted to your shell. Paste the following bash functions into a file in your home directory called: .bashrc (note the leading "."). Create this file if it doesn't already exist. Note: Don't forget the . (period) characters and spaces.
if [ -d /opt/bea10/wlserver_10.0 ] ; then wlenv() { pushd .; . ~/weblogic/bin/setDomainEnv.sh; popd; } wlstart() { cd ~/weblogic/; ./startWebLogic.sh; } wlstop() { java weblogic.Admin -url t3://localhost:7001 \ -username weblogic -password weblogic FORCESHUTDOWN; } wlenv fi

With these aliases:
• • •

'wlenv' will set your environment variables ready to compile code for WebLogic 'wlstart' will start your server 'wlstop' will stop your server

You should also modify your: .bash_profile file with the following
source .bashrc export PS1="[\u@\h:\w]\\$"

14

Deleting your WebLogic directory
During the semester, you may find that part of your WebLogic configuration becomes corrupted, and your server will not start. If this happens, the easiest solution is to remove your webLogic directory, and re-create it. Be sure you have kept a copy of all of your deployed applications before you delete the directory though! To delete your WebLogic directory, run the Unix command:
cd ~/weblogic rm -r .

Note: be very careful to type this command correctly, as it will recursively delete all files in the named directory. In particular, take care that there is no space following the tilde character (~) or you will erase your entire home directory! After deleting your webLogic directory, you can re-create it as described above.

Copying your WebLogic directory
If you wish to copy your webLogic directory, DO NOT use the Unix 'cp' command. Your webLogic directory contains a number of symbolic links, and it is important that these are kept as symbolic links. Use the following command if you wish to copy your entire webLogic directory (replacing 'destdir' with the actual destination directory name):
cd; tar cf - weblogic | (cd destdir; tar xfBp -)

Module: Architecture
Lab exercise - Familiarisation 1 - Installing Eclipse
The laboratory exercise for this module to install Eclipse and then develop a one or two static HTML pages Level of Difficulty: 2 (moderately easy) Estimated time: 30 minutes Pre-requisites:
• •

Completed WebLogic setup lab exercise Run 'setDomainEnv.sh' to set your environment correctly

Installing Workshop For Weblogic
Open a terminal, then type the following commands

15

mkdir ~/workspace tar xvf /pub/ajpcpe/workspace.tar

You now should have a directory called workspace. This is where your lab files will be stored when using Workshop for WebLogic To start workshop, type
cd ~/workspace ./workshop4WP

You now should see

16

You should click on the X on the [Welcome] tab to close this window to get the following window:

This is the main J2EE "perspective".

Creating a project
To create a new J2EE project, we are going to create a Web application first. Step 1: From the Project Explorer:, Right Mouse Button click -> New-> Dynamic Web Project (alternatively: Choose the File->New->Other->Web->Dynamic Web Project )

17

18

Choose the name: labs Target runtime: BEA Weblogic Configurations: Weblogic Web Project Facets (minimal) (hint: Press the down arrow in the Configuration box to get the list) Then press [Next] Step 2: We now get a Project Facets popup screen. A 'project facet' is Eclipse terminology for the additional wizards and tools installed for this project. As you can see, there are many to choose from such as Java Annotation processing (this handles Java 5 @annotations). For the moment, don't change this screen.

Then press [Next] Step 3: We now get a Web Module popup screen:

19

Change the Context root from "labs" to / (note: this is the "subdirectory" of the web page, so we are now creating a home page for the Weblogic server!) Content directory: WebContent Java source: src Then press [Next] Step 4: From the Weblogic Web Module panel: [x] Use Shared Libraries & press [Finish]

Deploying static HTML
The next challenge is to create HTML files for our web site From Project Explorer select Labs

20

Now Right Mouse Button click -> New > HTML


(note: WebContent is highlighted)
21

Filename: index.html & press [Next] At the Select HTML Template panel: HTML 4.01 Transitional & press [Finish] You can now see it generates a HTML page which you can edit. Why not add some text or HTML formatting tags - change the title and maybe add a a <h1> in the body would be nice. Use Ctrl-S (or File->Save) to save this file.

Running the HTML page
Before you can start testing, you need to define a server to run this web page one. We will use Weblogic as a normal web server for the moment. Select the labs project in the Project Explorer and press the Right mouse button Select Run As -> Run on Server

You will get a define new server panel:

22

Choose [x] Manually define a new server Server host name: localhost Server type: Bea Systems->BEA Weblogic Server v10 Server runtime: BEA weblogic v10 Select [x] Set server as project default: You will now get a Define a weblogic server panel:

23

Domain Home: /home/userid/weblogic & select [finish] button (note: userid should be your faculty userid) You should get a "Add and Remove Projects" panel. You can have more than one project running on each Weblogic server. For the moment, we will leave this as-is. Press [finish] to continue. You should get weblogic server starting in a new window - see the Console view on the bottom right hand side for % progress) Wait till the <Server started in RUNNING mode> message appears. You should get a minibrowser in eclipse window with your web page! You can add many extra pages. Try make them link eg: <a href=.."> If you get an error message saying "Publish was cancelled" this could be because your server and project is already running. If this is the case, you could start the server manually, by pressing the green arrow

If you double-click on the server name (eg: "BEA Weblogic Server V10.0" above), you can also get the server configuration settings. This will allow you to manually remove (ie: "undeploy" ) a project which may be preventing weblogic from starting (for example, "labs" )

24

If you need to restart the internal browser for any reason, use Window -> Show View -> Other -> General -> Internet Web Browser, however, it is better to start an external browser, as the internal browser may not support all the latest browser functionality. Test to see that your new application works. In a browser, open a URL like:
http://localhost:7001/index.html

Note that in most cases you will have a "Context root" which is effectively a subdirectory. So if our web Context root was, for example, labs, our URL would be: http://localhost:7001/labs/index.html Notes:
• • •

Write down notes as you go, particular parts of the process that seem difficult or confusing. Ask questions. Use the WebLogic documentation to help you (start to become familiar with browsing the documentation). You can find the documentation at: o http://e-docs.bea.com/wls/docs1001/

For an introduction to WAR files, JAR files and EAR files, read Understanding WebLogic Server Applications, URL: http://e-docs.bea.com/wls/docs100/programming/concepts.html This will give you a head start on some of the later course material.

Module: Architecture
Lab exercise - Familiarisation 2
This laboratory exercise is intended to help you become familiar with running the application server. It will cover starting up and shutting down the server, setting some of the configuration options, and deploying static HTML web pages into the server. Level of Difficulty: 1 (easy) Estimated time: 45 minutes Pre-requisites:
• •

Completed WebLogic setup lab exercise Completed Familiarisation 1 lab exercise

The environment

25

You will be running WebLogic Server on a Linux workstation. The WebLogic software is installed centrally on file server, and is NFS mounted across all workstations, so everybody will run the same version of the software. In addition to the central installation of the software, every person will have their own private WebLogic "domain". Each person will start up their own copy of the WebLogic software, and load their domain. Your WebLogic domain configuration will be stored in a subdirectory off your home directory. There are three parts to using WebLogic: 1. running the server (starting/stopping) 2. using the management console (in a web browser) 3. installing your own applications This lab exercise is designed to help you become familiar with the first two.

Familiarisation with the directory structure
Record your answers to the following questions.

In which directory is your domain's config file, config.xml installed?

____________________________________________________________

In the bin directory, there is a file called 'setDomainEnv.sh'. Have a look at the contents of this file and see what it does. You should run this file every time, before you work with WebLogic. If you haven't run it already in this session, do so now. Note that you must run it by prefixing it with a dot, followed by a space, e.g. . setDomainEnv.sh Note that the alias you created earlier called wlenv also executes this shell script. If you have started a new shell, then this alias should be created and you can type wlenv instead.

In which directory is the WebLogic Server installed? (Hint: echo $CLASSPATH)

____________________________________________________________

What version of Java are you using? (hint: java -version)

____________________________________________________________

26

Does your PATH environment variable include the path to the correct version of Java? (hint: echo $PATH). If not, you have not run setDomainEnv.sh correctly. What is the path to the Java compiler?

____________________________________________________________

In which directory are the WebLogic Java class libraries?

____________________________________________________________

BEA provide some examples as part of the distribution of WebLogic. In which directory are the examples located?

____________________________________________________________

In your own WebLogic domain, in which directory is the file 'startWebLogic.sh' located in?

____________________________________________________________

Starting your WebLogic server
IMPORTANT: Make sure you only run 1 copy of weblogic at a time on the workstation. This includes the test weblogic server running within Eclipse Ensure that if this is the case, you should stop the weblogic server within eclipse first! Use the following steps to start your WebLogic server: 1. First, check that you are logged in to a workstation machine, and NOT charlie or sally. You must NOT run WebLogic on charlie or sally. If you are not sure which host you are logged in to, type the Unix command:
2. hostname

3. Change into the directory where your 'startWebLogic.sh' script is located. You must run the server from this directory. e.g.
4. 6. cd ~/weblogic/ ./startWebLogic.sh

5. Start the server running: You could also use the wlstart alias your set up in an earlier lab.
27

Getting started

What are the ports your server is listening on? (hint: netstat -an )

____________________________________________________________
• •

Start your default WebLogic console by opening a web browser, and accessing the URL:
http://localhost:7001/console/

Note: If you are accessing this workstation from another machine, change localhost to the name of the workstation

Note that in the earlier lab, we defined an alias called wlstop, and this had hardcoded the userid and password. Is this a good thing to do? Why?

____________________________________________________________

____________________________________________________________ Enter 'weblogic' for the userid and 'weblogic' to logon to the WebLogic console.

Reading the configuration

Once you logon to the WebLogic console, you will see that there are various options to change and view.

Relevant areas:

28

DOMAIN:
(this is the top of the menu tree [weblogic] in our console) This provides management of the entire weblogic domain. Note in production you may have more than 1 server. We will just use the adminServer also as the development server. You can start/stop server by [control] tab. Select AdminServer(admin) & then you can start/resume/shutdown etc.

Shutting down the server: Note that if you just press Shutdown, WebLogic will wait until all requests are serviced. If your program (JSP/Servlet etc) is in a loop, you can click on the pull down and select Force Shutdown Now
29

ENVIRONMENT: Don't worry about these options, this is used for clustering and production environments DEPLOYMENTS: You will see that this lists all J2EE applications and shared librarys installed ("deployed") on your server. Some relevant tabs to look at:

[Control tab] You can individually (or globally) start or stop the applications. If you have [Lock & Edit] the configuration, you can also install new apps, update and delete existing apps. If you select any app, you will see it's [settings]. This has details like name, context root, path (if you generated this from eclipse, it will be something like /home/chw/workspace/.metadata/.plugins/org.eclipse.core.resources/.projects/labs/ beadep/weblogic/labs !! [Testing] tab is particularly handy to see what the full URL of the application is and any welcome files in the web application. [Monitoring] is good to see how many active servlets are being used (note: each JSP is also considered to be a servlet) [Monitoring[Servlets]] is good for seeing the servlets available. FileServlet, JSPServlet & WebServiceServlet are automatically generated ones from weblogic. [Monitoring [Sessions]] will track HTTP sessions being used.

SERVICES: this section covers the J2EE services that the container must provide eg: JDBC, JMS etc When using Database access, you need to define your JDBC details here. SECURITY REALMS: You can define a security realm to protect your web application. The default realm is 'myrealm' but you can create many more.Within this tab is [Configuration] & [Users and Groups] where you can define users and groups.

Changing the configuration
Be careful at this point! Don't change anything you don't understand! In order to change any parameter, you need to click the [Lock & Edit] button on the upper left corner of the control panel

30

Change the port that your server listens on to be port 12345. What additional step is needed before the change is committed? ________________________________________________________

• • •

Shut down your server using the WebLogic console. Generally, you should always shut down gracefully using the console, or the command-line shutdown utility - don't just close the Unix shell window. Restart your server (from the Windows Command Prompt). Change your port back to what it was before. Add some 'Notes' to your domain (or server).

Eclipse Links http://www.stanford.edu/class/cs108/JavaTools/eclipse-guide/#NewProject

31

Module: Servlets
Lab exercise - Hello World Servlet
This laboratory exercise involves developing a Hello World servlet, step by step. It is a long process, but each step should be simple enough. Take careful note of what you are doing at each step, and the commands you need to run. It gets easier once you've worked out the process - your first servlet will be your hardest! Level of Difficulty: 1 (easy) Estimated time: 30 minutes Pre-requisites:
• •

Run 'setEnv.sh' to set your environment correctly Start your WebLogic server running in the background

A HelloWorld servlet
There are 2 main ways of creating a servlet
Manually creating a servlet

Before the days of Integrated Development Environments, programmers had to develop servlets much like any other Java package (eg: Applets). The steps involved were
1. Create a development directory structure (typically a source code, build and deployment directory). 2. Create a java class file which imports the relevant javax.servlet.* package (plus any other utility packages you might need such as java.io.*) 3. This class needs to extend javax.servlet.http.HttpServlet and implements the doGet() (and possibly doPost() )methods 4. You then compile this class into the build directory into the WEB-INF/classes directory 5. You then create & edit a deployment descriptor (WEB-INF/web.xml) with the relevant servlet details 6. Add any extra files like graphics, html and .properties files into the top of the build directory. 7. You then use the jar cvf HelloWorldApp.war command to archive the entire build directory into a single WAR file 8. You then deploy (copy) this .war file following the instructions of your particular web application server.

You can optionally attempt this later by looking at the "tutorial: creating war files manually".

Using Eclipse to create a servlet
In this lab we will use Eclipse (Workshop for Weblogic) to create our first servlet. This exercise will lead you step by step through writing and deploying your first Java servlet.

32

1. We will re-use the existing lab project from the previous module. However, there is one change that we will make - we will remove the default context since this is effectively hardcoding our URL! From the Project Explorer, DOUBLE click on Weblogic Deployment Descriptor. Select the Design tab and select the wls:context-root attribute. Press RIGHT Mouse button, and select Remove. Save the changes (Control-S).

2.

Now to create a servlet, highlight the project name (labs) and use the RIGHT mouse button to select New -> Servlet

3.

4. In the Create Servlet wizard window, enter the Class name for the servlet - ie: HelloWorldServlet. You can optionally enter a Java Package name but this and future lab

33

examples won't use one for the moment. Press Next to continue.

5. We finish by entering information about the servlet deployment descriptor - the name defaults to HelloWorldServlet, but we will change this to HelloWorld. Enter a description as well. Finally, change the URL mapping (the default is /HelloWorldServlet). To do this, highlight the URL mapping and click Edit. Press Finish to create the Servlet.

34

6. Eclipse now creates a skeleton of the Servlet code. Eclipse tags the places where you enter your own code with the comment // TODO: Auto Generated Method Stub

7. Replace this comment with the following code fragment. FOR THE MOMENT, PLEASE DON'T CUT AND PASTE THE CODE. We will experiment with Eclipse's Code assist features to help you enter the correct code as you type!
response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<html><head><title>Hello, World response</title></head><body>"); out.println("<h1>Hi, this is from a servlet</h1>"); out.println("doesnt do much so far."); out.println("</body></html>");

As you type resp, you can press Ctrl-spacebar to ask Eclipse to show you the valid candidates which you can legally enter in the Java class that start with the letters resp. Try it...

35

8. Pressing Enter will insert the whole string response for you. Now if we press the . key to continue, Eclipse will pop up a list of valid methods for this object - we can type-ahead to narrow this list down. Try the first 4 letters setc to get the list down to setContentType. The really neat thing about Eclipse is it also describes what the method does. This even works for your own custom built methods. However, you do need to use Javadoc /** descriptors before your methods for this to work...

Pressing Enter will insert the template for this method. You simply replace the highlighted string with your own code.
9. Finish typing in the rest of the code now. In later labs you are welcome to cut and paste the code directly into Eclipse, but for the moment, just get used to the Eclipse code editor by typing it in by hand....

10.

Packaging your servlet 1: directory structure
36

Java servlets execute as part of a web server. You cannot run or test them from the command line. The web server you will use to run your servlet is the web server built in to the application server (WebLogic). To "run" your servlet, you will access a URL in your web browser. This is quite similar to running a CGI program, or running a PHP script. Before you can install your servlet into the application server, it needs to be packaged properly. Servlets are part of what J2EE calls 'web applications', and web applications should be packaged in a Web Application Archive file, or WAR file. A WAR file is basically a compressed zip file that contains all parts of your web application. The parts may include:
• • •

static web site files (HTML, GIF, JPEG, CSS, etc) Java servlets a deployment descriptor (described later)

When you package your application as a WAR file, it must follow a particular directory structure like the following.

Packaging your servlet 2: deployment descriptor

37

As mentioned above, a WAR file contains static HTML (etc) files, Java servlet classes, and a deployment descriptor. The next step is for you to create a deployment descriptor. A deployment descriptor is an XML file describing the properties of your 'web application'. When your web application includes servlets, the deployment descriptor file describes the name of each servlet, and what URL should be used to invoke the servlet. In the case of web applications, the deployment descriptor is contained in a file called web.xml, and it must be placed in the WEB-INF directory. The Eclipse Servlet wizard automatically updates and generates this web.xml file. To view this file, check the double click the Deployment Descriptor (alternatively, look in the WEB-INF subdirectory for web.xml )

You could also view this in the Deployment Descriptor/Design tab

38

Points to note:

• •

servlet-name can be any name you choose. It does not have to be the same as the filename in which the servlet class is stored. Every servlet referenced in your web.xml must have a unique servlet-name within that one web.xml file. servlet-class specifies the name of the Java class file containing the compiled servlet code. url-pattern specifies the URL by which you want users to be able to execute your servlet. In the example shown above, the url-pattern is "/HW", so the URL that will be used to invoke the servlet will look like http://hostname:7001/HelloWorldApp/HW

Packaging your servlet 3: static HTML files
Your WAR file can also include static HTML files, as well as images (GIF, JPEG), style sheets (CSS), and any other static files you would expect to find on a web server. In the WAR file, these files must be placed outside the WEB-INF directory. Any files not in the WEB-INF directory can be accessed through the web browser. Any files that are inside the WEB-INF directory (including your web.xml deployment descriptor, and your servlet class files) will be protected, and are not accessible to users over the web.

39

You can create subdirectories visible to the user by selecting WebContent and Right Mouse clicking and selecting New -> Folder. CAUTION: Any subdirectory created OUTSIDE of WebContent will not be accessible to web users - this includes any file placed in WEB-INF!! You should already have a static HTML file called index.html from the previous lab. Modify this file to link to your new servlet.
<h1>My first WAR file</h1> <P>Run my <A HREF="HW">Hello World servlet</A>.</P>

NOTE: Notice that our HREF refers to HW not /HW or HelloWorldServlet. This is because a putting a / in front of a reference will make the browser look for the absolute URL at the root context (ie: / ) of the web site, not the relative sub-context (ie: /labs ) which we will be deployed as. So putting a /HW will force the web browser to look for http://localhost:7001/HW instead of http://localhost:7001/labs/HW Here is a rough mapping of how your Eclipse/Workshop project maps to a WAR file.

40

Packaging your servlet 4: create the WAR file
When testing using Eclipse/Workshop we have been running under what's called an "exploded war directory", ie. the war file has not been archived. While this isn't specified in the Java Enterprise standard, most vendors including Weblogic allow you to specify a directory instead of a WAR file to deploy. This is great for application development and testing. If you are curious about where this directory is located when developing using Eclipse, look at the Weblogic console for a deployment module called "_workshop_auto_generated_ear_" file. Let's now create a war file which we can distribute and deploy seperately.
1. Step 1: Select the project you wish to create (in our case, labs ) and press Right mouse button. Select Export -> WAR file

2. Next , choose the destination file - let's call this helloWorldApp.war. You should put this into your own directory (I created a local directory called aip to put these files in) Note: Normally you don't includfe source files, but when developing I tend to do this so when I debug I can view which version of the source code I used. You must export the source files when submitting assignments though, so let's Select "Export Source Files" now.. You may also have to select "Overwrite existing file" if helloWorldApp.war exists already.

41

Also note that the META-INF directory and the MANIFEST.MF file are automatically added by Eclipse.You can ignore them for the moment.

Deploying your web application
Now that you have a WAR file, you can "deploy" it to the web server. Deployment is the process of installing an application. In WebLogic, there are a variety of ways you can deploy an application. The simplest is just to copy your WAR file into your WebLogic server's "autodeploy" directory.
cp helloWorldApp.war ~/weblogic/autodeploy

You can do this when the server is running. The server checks the contents of the autodeploy directory every few seconds, and when it sees a new WAR file, or one with an updated timestamp, it automatically deploys (or redeploys) it. Note: if you don't have a weblogic.xml file with a wls:context-root entry in it, weblogic will use the name of the war file as the context-root. So in our case, the context-root will be helloWorldApp NOTE: URL's in Java Enterprise are case sensitive!!! So if you type in /HelloWorldApp or /helloworldapp on the browser, you will get a 404 Not Found error!!

42

Testing your web application
If you have followed the steps above exactly, try accessing your application through the following URL:
http://localhost:7001/helloWorldApp/

It should show you the contents of your index.html file. If you click on the link to your servlet, it should execute your servlet and display the servlet's "Hello World" message.

Note that when you deployed your WAR file into WebLogic, it created a virtual directory under the root of your web server with the same name as your WAR file. So the name you choose for your WAR files is important, because the WAR filename will become part of the URL.

Exploring the WebLogic console
Open the weblogic console (hint: http://localhost:7001/console) and enter the usual administrator userid and password (recall: we set this to weblogic and weblogic respectively??) On the left hand menu (Domain Structure menu) is a choice called deployments. Select this and you should see the Summary of Deployments" screen like:

43

(this may not be exactly the same as yours) You should see a module called _appsdir_helloWorldApp_war (autodeployed) module. Click on this to see the Settings for this deployed war file.

44

You can see that the path is where the actual WAR file resides - in our ~/autodeploy directory. Also note that the console will display any sub-modules of your deployed module. In our case, there is a Web Application called _appsdir_helloWorldApp_war (autodeployed) which if clicked, returns to this very same page!! (this is more useful when we have an Enterprise Archive (EAR) file which may contain many sub-modules. Click on the Testing tab at the top. This allows you to check what Weblogic thinks the URL to this application should be. If it is something other than "http://127.0.0.1" just ignore that for the moment. (technically this is because Weblogic binds to all the available network addresses of the host. So it could be something like http://138.25.16.222 or some other weird number). For the moment, the only important item we want to observe here is the URL and note that the default URL is something like http://xxx.xxx.xxx.xxx/helloWorldApp So if you are trying to debug your web application and can't seem to start, use this to find out what the default URL should be. As mentioned earlier, note that there is a Deployment module called "_workshop_auto_generated_ear_". If you select this you could also click on this to see the labs web module, and do the same exploring we did the the helloWorldApp module..
45

Reflection
This exercise took you through the steps to to create a Servlet using Eclipse (Workshop for Weblogic). Certainly it is possible to create a WAR file by creating a directory structure much like a WAR file, creating web.xml/weblogic.xml by hand, creating Servlet java files and compiling them by hand (or with a build script like Makefile or Ant) and finally generating a WAR file using the jar cvf command. Using tools like Eclipse improve programmer efficiency by allowing you to incrementally build and test and using wizards to generate & "instantly" test your application. Note what steps you took, and don't forget to ask your tutor for assistance as necessary. Furthur labs will not be as detailed as this one, so you must be comfortable using the Eclipse IDE as we go on further

46

Module: Servlets
Lab exercise - Counter Servlet
This laboratory exercise involves modifying your Hello World servlet to make it keep count of the number of times it has been invoked. Level of Difficulty: 2 (moderately easy) Estimated time: 15 minutes Pre-requisites:

Completed the Hello World servlet lab exercise

A Counter servlet
The goal of this exercise is to create a servlet that maintains a counter of the number of times it has been invoked since it was last reloaded by the web server. It will use a class variable (i.e. static) to keep count of the number of invocations. Each time the servlet is invoked, it will print out the value of the counter. There are 2 main ways to do this lab.

Method 1 is to create a new Servlet (as per the Hello World Servlet lab) and name this CounterServlet, with the URL mapping of /Counter. You then add the required code to perform the desired task. This is fairly straight forward. Method 2 is to copy the existing Servlet and to add it into the deployment descriptor. This is a touch more complicated, so we will do this in this lab to show you how to copy an existing servlet class and insert it into the web project.

Copying an existing Servlet
Begin by copying your Hello World servlet code, and putting it into a file called CounterServlet.java. You may keep it in the same project (WAR file) as before, or put it in a separate WAR file (if you would like more practice at the process of creating WAR files). Make the following modifications to your Hello World servlet source code: 1. You can cut and paste the HelloWorldServlet from the src folder. Rename the class to
CounterServlet

2. Declare a class variable to hold the value of your counter.
3. private static int numRequests = 0;

4. Declare a synchronized method to update the value of the numRequests variable.
private synchronized void incNumRequests() { numRequests++; }

47

5. Modify the code inside your existing doGet() method to make it call the incNumRequests method you have just created, and print out the current value of the counter.
incNumRequests(); out.println("Number of requests since reload: " + numRequests);

Servlets and threading
The question you should be asking yourself right now is: why do I need to create an extra method just to increment the value of numRequests? Why can't I just have my servlet increment the value directly? The answer lies in the way servlets handle threading. By default, every servlet you create is multi-threaded. That means that at any given instant in time, multiple instances of your doGet() method could be executing simultaneously. Also recall the meaning of a class variable (i.e. declared as static) in Java. A static variable is one that is shared between all instances of a given class. So if you have 10 instances of your CounterServlet executing, all 10 instances will be sharing a single copy of the numRequests variable. What happens if two different instances of your servlet running at the same time both try and update the value of numRequests at the same time? In theory, this could lead to a semantic error in the program because two threads are trying to update the same shared resource simultaneously. [Although strictly speaking in this case there is not much danger because all we are doing is incrementing a single value.] The general principle that you should follow is that if you ever write a Java servlet where multiple threads will be accessing a single, non-shareable resource, you must programmatically ensure that at most one thread can be accessing the resource at any one time. Java provides this facility through the use of its synchronized keyword. If you have studied operating systems, note that this is similar in concept to monitors and semaphores used to ensure at most one process is executing a critical section at any given time.

Running your servlet
48

Follow the same steps you used when creating your Hello World servlet to edit and compile the code. You now need to do some additional work.. Declare this servlet in your web.xml deployment descriptor. The following steps shows you how to do this via Eclipse/Workshop, but do note that it can be easier just to type the extra entries into the web.xml file directly! (see step 5 for the raw XML code to add) 1. Step 1: Right click on the Deployment Descriptor item. This should show you either the source or the design views. The main advantage of using the IDE is the guarantee of a correctly formatted xml file so let's select the design (also called Deployment Descriptor) tab. 2. Step 2: Right mouse click on the Servlets entry and select New Servlet

3. Step 3: You now create the servlet. You enter the servlet name (Counter) and the name of the servlet class (CounterServlet). Note that you can also use a JSP instead of a servlet class if you wish but we will wait till a later lab to try this out.

49

4. Step 4: You now enter the servlet URL mapping. We will use /Counter to point to our servlet. You can optionally add more mappings by using the Add button on the Servlet Properties page. One neat trick is to map sub-contexts (which act like virtual subdirectories on the URL) and file names to a servlet directly. For example, you could choose a mapping called /*.counter or index.html to map to CounterServlet!

5. Step 5: If you inspected the generated XML code in web.xml, you should have entries looking somewhat like:

50

<servlet> <servlet-name>Counter</servlet-name> <servlet-class>CounterServlet</servlet-class> </servlet>

and later in the file ...
<servlet-mapping> <servlet-name>Counter</servlet-name> <url-pattern>/Counter</url-pattern> </servlet-mapping>

Note that the ORDER of these XML entities are important in web.xml. Misplacing them may result in an error or your web application to fail to deploy. 6. Eclipse automatically re-deploys the updated lab so you can now unit-test the application. Note that each time you reload the browser with the refresh button, the displayed counter should update.

7. You should now redeploy your WAR file by using the Export .. as WAR file menu and by copying the war file to your WebLogic autodeploy directory.
8. cp HelloWorldApp.war ~/weblogic/autodeploy

9. Test your new servlet, in your web browser, by viewing a URL like the following (the filename on the end of the URL will depend upon the name you chose for the <url10. pattern> http://localhost:7001/HelloWorldApp/Counter

Module: Servlets
Lab exercise - Form parameters
This laboratory exercise involves modifying your Counter servlet so that you may set the value of the counter to an arbitrary value. The servlet takes its input from a HTML form, where the user can enter a value, and the counter will be set to that value. Level of Difficulty: 3 (requires some thought) Estimated time: 20 minutes Pre-requisites:

Completed the Counter servlet lab exercise

51

A SettableCounter servlet
The goal of this exercise is to create a servlet that can both print out the value of a counter (as with the CounterServlet exercise), but also allows a user to set the counter to an arbitrary value. Begin by creating a HTML form that you will use to view and set the value of the counter. Remember this HTML file must go inside your WAR file.
<FORM METHOD="GET" ACTION="SettableCounter"> <P> Set counter to equal: <INPUT TYPE="TEXT" NAME="newvalue" SIZE="5"> </P> <P><INPUT TYPE="SUBMIT" VALUE="Set Counter"></P> </FORM> <P><A HREF="SettableCounter"> Get counter value</A></P>

As you can see, your servlet code will need to be able to read the value of a parameter taken from a HTML form. Moreover, because the same servlet is being used for both viewing the counter value and setting it, you will need to check if there is a form parameter value supplied. If so, set the counter to the supplied value. If not, just display the counter. Don't forget to set the Servlet mapping to /SettableCounter

Request and Response objects
Reading the value of form parameters in a servlet is quite easy. However before we get to that, first, notice the definition of the doGet() that you have been using in earlier servlets:
protected void doGet (HttpServletRequest request, HttpServletResponse response) ...

In this definition, there is a "request" object (called request, although you may choose another name if you wish), and a "response" object (called response). The request Java object encapsulates all the details about the HTTP request that was sent by the user's web browser. This includes the URL of the request, the request method (e.g. GET or POST), the IP address of the client's machine, etc. The request object has methods available to retrieve these various pieces of information about the request. Another piece of information associated with the request object is the names and values of any form parameters that the user might have supplied. This is what we need for this exercise.

52

The response Java object encapsulates all the details of the HTTP response that will be sent back to the user's web browser. This includes the MIME type (content type) of the document, plus the actual document itself. Even in the Hello World servlet, we have seen two examples of using the response object:
• • response.setContentType("text/html"); PrintWriter out = response.getWriter();

What happens when you change the content type to to be "text/html" instead? You should also browse the JavaDoc documentation for servlets, and get a feel for the methods available on the HttpServletRequest and HttpServletResposne objects. Both are found in the package javax.servlet.http.

Reading form parameters
By now we have established that to read HTML form parameters, we need to use a method on the request object. The method we need is called getParameter(). To read the value of a HTML form parameter named "newvalue", use the following line of Java code:
String formvalue = request.getParameter("newvalue");

If there was no form field named "newvalue", then the getParameter() function will return null. To see whether a particular form field was supplied or not, you can just compare the result of getParameter() against null. [Hint: you need to do this as part of your SettableCounterServlet.] Finally, note that when you read form parameters, they are always read as Java String objects. Your SettableCounterServlet will probably need to use the value as a Java int, not a String. Here's a reminder of how to convert a String to an int, although in general you should be able to work things like this out for yourself (remember this is not an introductory Java course). Do not expect tutors to answer questions like this for you!
int formvalueint = Integer.parseInt(formvalue);

(this may throw a NumberFormatException that you must handle). You should now have all the information you need to create your SettableCounterServlet. You just have to put it all together!!!!

53

Aside: printing all form parameters
For debugging, sometimes it is useful to have your servlet print out a list of all form field names and their associated values. Here is a piece of code to do that. Try it out in one of your own servlets if you wish, and use a HTML form with several parameters to invoke your servlet.
java.util.Enumeration e = request.getHeaderNames(); while (e.hasMoreElements()) { String hdrName = (String) e.nextElement(); String hdrValue = request.getHeader(hdrName); out.println(hdrName + ": " + hdrValue); }

54

Module: Servlets
Lab exercise - HTTP Sessions
This laboratory exercise involves modifying your Counter servlet to introduce a second counter. The second counter should keep count of how many times the current user has accessed the servlet, and this counter will be different for each user. Level of Difficulty: 4 (moderately difficult) Estimated time: 20 minutes Pre-requisites:

Completed the Counter servlet lab exercise

A SessionCounter servlet
The goal of this exercise is to create a servlet that, when invoked, will print out two different counter values:
• •

the original CounterServlet value (total number of times the servlet has been invoked since it was reloaded); a counter that keeps count of the number of times the current user has invoked the servlet in his/her current session.

This requires the use of sessions and session variables in your servlet.

The state problem
As you know, HTTP is a stateless protocol. This means that a web server sees each incoming request as being completely independent from all earlier requests. However many web applications need to keep state information at the server, so the statelessness of HTTP is a problem. For example, when you access an online banking application, you first log in with your account number and PIN, and then as you click through various pages on the bank's web site, the application running on the bank's web server needs to keep track of who you are. Another example is the ubiquitous shopping cart. As you browse through a product catalog, and add items to your cart, the web application needs to keep track of which items are currently in your cart.
55

In web application terminology, the word session refers to the interaction between a user and a web application, where the web application keeps state information about the user's interactions even though they span multiple HTTP requests. A session typically lasts for a single browsing session. If a user closes their browser and re-opens it and goes back to the web application, they will have to begin a new session. If a user doesn't access the web application for a period of time, their session might time out (whether or not it does is application-dependent). There are different ways to implement sessions on top of the stateless HTTP protocol. The two typical ways are using cookies and URL rewriting. These will be described in the lecture notes.

Sessions and Java
Java servlets have built-in support for session management that simplifies the task of creating a web application that requires a session-based interaction with a user. The abstraction used in Java is the notion of session attributes that can be stored in a session object. The session object acts like a container. You can store attributes (name/value pairs) into the session object, and you can retrieve attributes out of the session object. Attributes that are stored in the session object will still keep their value in between successive HTTP requests. Each "attribute value" is, of course, a Java object. Each attribute stored in the session has a name, and a value. The name is just a String. The value is a Java object. The HttpSession class uses the methods setAttribute() and getAttribute for storing and retrieving attributes in sessions respectively. Where do you get the session object from in the first place? From the request object. You get the session from the request. If there was already a session established, then you will have access to all the variables stored in the session. However if there was not already a session established, one will be created automatically (by default), and you will then have access to a blank session object in which you can store variables. Now for some code snippets: 1. Getting hold of a session object (from the request):
2. 4. 5. 7. HttpSession sess = request.getSession(); Integer counterval = new Integer(105); sess.setAttribute("sessioncounter", counterval); Integer newcounterval = sess.getAttribute("sessioncounter");

3. Storing an object into the session: 6. Retrieving an object from the session:

56

SessionCounterServlet
With that knowledge, work on modifying your CounterServlet to add a second counter - one that keeps track of the number of accesses a user has made in the current session. To test, try accessing your servlet from two different browsers (e.g. Firefox and IE on the same machine, or two different browsers on two different machines). Don't just use two different windows belonging to the same browser (because different browser windows still share cookie data, which is used to maintain sessions).

Aside: common usage pattern for sessions

Typically a servlet has to be able to deal with the situation when a session does not already exist and has to be initialised. One way to do this is to retrieve an attribute from the session, and if it is null (or if a flag is set to indicate that the session is new), then automatically initialise the attribute and store it in the session. This means that your servlet can both deal with existing session attributes and automatically set up a new session attribute when needed. Here is a code sample:
HttpSession sess = request.getSession(); Integer sesscounter; sesscounter = (Integer) sess.getAttribute("numaccesses"); if (sess.isNew() || sesscounter == null) { sesscounter = new Integer(0); sess.setAttribute("numaccesses", sesscounter); }

URL Rewriting
The following servlet illustrates the use of URL rewriting when cookies aren't supported in your browser. This servlet also illustrates the use of Servlet API to extract various information related to a session.
// Retrieve the count value from the session Integer ival = (Integer) session.getAttribute("numaccesses"); // If the counter is not currently contained in the session, // one needs to be created:

57

if (ival==null) { ival = new Integer(1); } else { ival = new Integer(ival.intValue() + 1); } session.setAttribute("numaccesses", ival); // Print out how many times the user has hit the current page: out.println("You have hit this page <b>" + ival + "</b> times.<p>"); out.println("Click <a href=" + response.encodeURL("SessionServletApp") + ">here</a>"); out.println(" to ensure that session tracking is working even " + "if cookies aren't supported.<br>"); out.println("<p>"); // Finally, demonstrate some of the more common methods in the // HttpSession object surrounding sessions: out.println("<h3>Request and Session Data:</h3>"); out.println("Session ID in Request: " + req.getRequestedSessionId()); out.println("<br>Session ID in Request from Cookie: " + req.isRequestedSessionIdFromCookie()); out.println("<br>Session ID in Request from URL: " + req.isRequestedSessionIdFromURL()); out.println("<br>Valid Session ID: " + req.isRequestedSessionIdValid()); out.println("<h3>Session Data:</h3>"); out.println("New Session: " + session.isNew()); out.println("<br>Session ID: " + session.getId()); out.println("<br>Creation Time: " + new Date(session.getCreationTime())); out.println("<br>Last Accessed Time: " + new Date(session.getLastAccessedTime()));

Ensure your browser accepts cookies by checking Tools -> Options -> Privacy (Firefox) or Tools -> Privacy -> Sites (Internet Explorer). If the browser is not allowed to accept cookies, please enable it to accept cookies for this exercise to work. You may need to start the browser again for any changes to take place. When you access the servlet for the very first time, observe the information returned from the server. Among many things, it should display the session as new. If you press 'Reload' button, the new session should be displayed as false. Also, the request session id from cookie and URL are true and false respectively. This is because you browser is set to accept cookies. Now, disable the cookies (see Tools -> Options -> Privacy/ Tools->Privacy-Sites). Restart the browser to take effect of this new change. Don't forget to reset to the setting you had before after the exercise. Access your servlet as before and session should be correctly reported as new. Press Reload button and what you should observe is that the session is still reported as new (same behaviour for multiple reloads). Remember, earlier new session is only reported for the first
58

time you access the page and false for any subsequent accesses (within a session). Even though you didn't use Cookies explicitly, Weblogic uses a temporary cookie to store the current session. Since your browser is set not to accept any cookies (including temporary cookies), sessions do not work correctly. However, press on 'Click here' link to enable URL writing and watch the URL that appears in the Address/Location bar. You should notice some extra text on the end of the URL indicating that URL rewriting is now being used to maintain the session state when cookies are disabled. What is also interesting to observe is that the display correctly reports the requested session id is from a URL and not from a Cookie.

59

Module: Servlets
Tutorial - Accessing resources (e.g. relative files)
Note that this is not a lab exercise - it is just some information that you may find useful when using servlets (or JSPs). So you create a web application and package it up in a WAR file. But then from within your servlet or JSP code, you want to open a file which is also stored inside the WAR file. But you can't use the normal Java File class, because it expects a full absolute pathname!!! The solution: use methods on the ServletContext.
• • •

java.net.URL getResource("/path") - this will return the URL to use to access a specific file in the war file java.util.Set getResourcePaths("/path") - this will return a directory like listing of files that start with /path java.io.InputStream getResourceAsStream("/path") - this will return the contents of the file named /path

(Follow the links above to go to the Sun JavaDoc documentation.)

Some sample code
Use your right-mouse button to save this to a local file.

ResourceTest.war A WAR file containing an example of using these methods.

60

Module: Servlets
Tutorial exercise - Creating a WAR file manually
This laboratory exercise involves developing a Hello World servlet, step by step. It is a long process, but each step should be simple enough. Take careful note of what you are doing at each step, and the commands you need to run. It gets easier once you've worked out the process - your first servlet will be your hardest! Level of Difficulty: 1 (easy) Estimated time: 30 minutes Pre-requisites:
• •

Run 'wlenv' to set your environment correctly Start your WebLogic server running in the background

Manually creating a servlet
This exercise will lead you step by step through writing and deploying your first Java servlet without an Integrated Development Environment (IDE) such as Eclipse. 1. Create a directory to store your source code. This directory should be completely outside the WebLogic server directory hierarchy, e.g.
cd mkdir aip mkdir aip/servlets mkdir ajp/servlets/helloworld cd aip/servlets/helloworld

Create a file called HelloWorldServlet.java with the following contents. If you are familiar with Unix, try the 'vi' editor, e.g. vi HelloWorldServlet.java
import javax.servlet.*; import javax.servlet.http.*; import java.io.*; public class HelloWorldServlet extends HttpServlet { public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); out.println("Hello servlet world!"); out.close(); }

61

}

Compile your source code using javac.
javac HelloWorldServlet.java

If you see an error message that it cannot import the servlet packages (javax.servlet and javax.servlet.http), then your environment is not set correctly. Go back and re-run setEnv.sh. Congratulations, you have just written your first Java servlet. Before you can run it though, you must first package it, and deploy it. These steps are described below.

Packaging your servlet 1: directory structure
Java servlets execute as part of a web server. You cannot run or test them from the command line. The web server you will use to run your servlet is the web server built in to the application server (WebLogic). To "run" your servlet, you will access a URL in your web browser. This is quite similar to running a CGI program, or running a PHP script. Before you can install your servlet into the application server, it needs to be packaged properly. Servlets are part of what J2EE calls 'web applications', and web applications should be packaged in a Web Application Archive file, or WAR file. A WAR file is basically a compressed zip file that contains all parts of your web application. The parts may include:
• • •

static web site files (HTML, GIF, JPEG, CSS, etc) Java servlets a deployment descriptor (described later)

Importantly, when you package your application as a WAR file, it must follow a particular directory structure. Starting at the same directory where your HelloWorldServlet.java file is, run the following commands. Note that the directory names are case-sensitive, so be careful to type them correctly.
mkdir WEB-INF mkdir WEB-INF/classes

Your compiled Java servlet class files must be placed in the WEB-INF/classes directory. When you compiled your HelloWorldServlet earlier, you just put the .class file in the same directory as the .java file. You'll need to fix that now.
rm *.class javac -d WEB-INF/classes HelloWorldServlet.java

62

Note the use of the '-d' option to javac, which allows you to specify the output directory (where the .class files go).

Packaging your servlet 2: deployment descriptor
As mentioned above, a WAR file contains static HTML (etc) files, Java servlet classes, and a deployment descriptor. The next step is for you to create a deployment descriptor. A deployment descriptor is an XML file describing the properties of your 'web application'. When your web application includes servlets, the deployment descriptor file describes the name of each servlet, and what URL should be used to invoke the servlet. In the case of web applications, the deployment descriptor is contained in a file called web.xml, and it must be placed in the WEB-INF directory. Edit the web.xml file now, e.g.
vi WEB-INF/web.xml

(or use the text editor of your choice). Into the web.xml file, copy the following text:
<?xml version="1.0" ?><web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"><web-app> <servlet> <servlet-name>HWServlet</servlet-name> <servlet-class>HelloWorldServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HWServlet</servlet-name> <url-pattern>/HW</url-pattern> </servlet-mapping> </web-app>

Points to note about the definitions in web.xml:

• •

can be any name you choose. It does not have to be the same as the filename in which the servlet class is stored. Every servlet referenced in your web.xml must have a unique servlet-name within that one web.xml file. servlet-class specifies the name of the Java class file containing the compiled servlet code. url-pattern specifies the URL by which you want users to be able to execute your servlet. In the example shown above, the url-pattern is "/HW", so the URL that will be used to invoke the servlet will look like http://hostname:7001/HelloWorldApp/HW
servlet-name

63

Packaging your servlet 3: static HTML files
Your WAR file can also include static HTML files, as well as images (GIF, JPEG), style sheets (CSS), and any other static files you would expect to find on a web server. In the WAR file, these files must be placed outside the WEB-INF directory. Any files not in the WEB-INF directory can be accessed through the web browser. Any files that are inside the WEB-INF directory (including your web.xml deployment descriptor, and your servlet class files) will be protected, and not accessible to users over the web. Let's create a static HTML file called index.html to go inside your WAR file. It can go in the top-level directory of your web application (i.e. the directory that has the WEB-INF subdirectory in it). Use a text editor to create index.html with the following contents:
<HTML> <BODY> <H1>My first WAR file</H1> <P> Run my <A HREF="HW">Hello World servlet</A>. </P> </BODY> </HTML>

Packaging your servlet 4: final check
When creating WAR files, it is very important that everything is in the correct directory. So before we actually create the WAR file, take a moment to check when you view your directory hierarchy, it looks something like the following:
$ ls -1F HelloWorldServlet.java WEB-INF/ index.html $ ls -1F WEB-INF classes/ web.xml $ ls -1F WEB-INF/classes HelloWorldServlet.class

i.e. the directory tree structure should look like:

64

- index.html - HelloWorldServlet.java / WEB-INF - web.xml / classes - HelloWorldServlet.class

Note that it is not essential to have your Java source code file as part of the WAR file, but it is convenient to keep all the files together.

Packaging your servlet 5: create the WAR file
Finally, you are ready to create your WAR file. Run the following command, which will create a file called HelloWorldApp.war in the parent directory of where you execute it from.
jar cf ../HelloWorldApp.war *

In the above command, the "c" means "c"reate a WAR file. Now view the contents of your WAR file to ensure that the file was created correctly. Run the following command to list the WAR file contents:
jar tf ../HelloWorldApp.war

In the above command, the "t" means to show the "t"able-of-contents of the WAR file. The output from the previous command should show something like:
META-INF/ META-INF/MANIFEST.MF HelloWorldServlet.java WEB-INF/ WEB-INF/classes/ WEB-INF/classes/HelloWorldServlet.class WEB-INF/web.xml index.html

The META-INF directory and the MANIFEST.MF file are automatically added by the jar utility. You can ignore them.

Deploying your web application
Now that you have a WAR file, you can "deploy" it to the web server. Deployment is the process of installing an application.
65

In WebLogic, there are a variety of ways you can deploy an application. The simplest is just to copy your WAR file into your WebLogic server's "autodeploy" directory.
cp ../HelloWorldApp.war ~/weblogic/autodeploy

You can do this when the server is running. The server checks the contents of the autodeploy directory every few seconds, and when it sees a new WAR file, or one with an updated timestamp, it automatically deploys (or redeploys) it.

Testing your web application
If you have followed the steps above exactly, try accessing your application through the following URL:
http://localhost:7001/HelloWorldApp/

It should show you the contents of your index.html file. If you click on the link to your servlet, it should execute your servlet and display the servlet's "Hello World" message. Note that when you deployed your WAR file into WebLogic, it created a virtual directory under the root of your web server with the same name as your WAR file. So the name you choose for your WAR files is important, because the WAR filename will become part of the URL.

Reflection
Take note of what was required to write a single servlet, package it in a WAR file, and deploy it to the web server. Note the commands, and the directory structure used. When you go to create your second servlet, you might find it easier to set up the directory structure first before beginning to write any Java source code. You will also probably find it convenient to copy your web.xml file and simply edit the values inside. You might even like to create yourself a Makefile, or a shell script which automates the process of compiling, packaging and deploying your WAR file.

66

Module: JSP
Lab exercise - Hello World JSP
JavaServer Pages is quite similar in purpose to servlet code. However the big difference is that JSP code is embedded inside a HTML web page rather than executed as a separate program. So this exercise involves creating a HTML web page with some embedded Java code. Level of Difficulty: 1 (easy) Estimated time: 15 minutes Pre-requisites:
• •

Completed the 'Servlets' labs Be comfortable with running static HTML and servlets under Eclipse

A HelloWorld JSP
There are many approaches to developing servlets and JSPs. You can create/edit SP's using vi (or notepad) and develop/package a WAR file by hand or use a code generator like XDoclet to automatically build your WAR file structure. We will cover the middle ground and will use an IDE like Eclipse/Workshop which has 'wizards' and templates to assist us to generate JSP's and WAR files. This fairly trivial introduction lab will get you started... 1. Ensure that Weblogic server is not running since we will start this from within Workshop for Weblogic. 2. Startup Workshop for Weblogic as usual and open our labs project from the Servlet lab. 3. Use Right Mouse Button -> New -> JSP to create a file called HelloWorld.jsp. Note that the "Create new Java Server Page" Wizard automatically highlights the webcontent directory. This is the root of your web application. Choose the New JSP file (html) template which should open an editor window with a skeletal JSP (much like the static html exercise). Edit the file to match the following contents: (changes are in italics)
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" " http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">

67

<title>My First JSP page</title> </head> <body> <h1>My first JSP page</h1> <p> <% out.println("Hello JSP World"); %> </p> </body> </html>

Note the following points:
o o

The Java code is embedded between the tags <% and %> This is called a JSP scriptlet. There is an implicit object called out available in every JSP page that you can use without pre-declaring. Think of it as a "built-in" object. This object is basically of type java.io.PrintWriter. Servlets that you created also used a PrintWriter, but in a servlet, you had to explicitly create the PrintWriter object, e.g.
o o PrintWriter out = request.getWriter(); out.println("Hello Servlet World");

In a JSP page, you can use the out object without needing to create an instance of it, as an instance is implicitly always available in every JSP page. You do not need to compile your JSP page. 4. Run your new JSP by doing the usual Right Mouse Button, Run As -> Run On server.
o

Once your server is running, you can also view the JSP in a web browser, by viewing a URL like the following. Note that the first part of the URL path is the context root name (in our case, labs), but this can also be the WAR filename if you exported the project as a WAR file and copied it to the autodeploy directory.
5. http://localhost:7001/labs/HelloWorld.jsp

When the web server loads your JSP file, there will be a delay of up to a few seconds. What is actually happening is that the JSP file you created is being compiled automatically into a servlet (yes, a servlet!). The web server will then execute the servlet it has generated from your JSP, and keep a cached copy of the generated class file so that it doesn't need to recompile the JSP on subsequent requests. So although there is a delay, it only happens once (or rather, only once each time you modify the JSP file). 6. If you do any subsequent changes in Eclipse, the changes should be visible immediately in the browser. HOWEVER, if you had exported and deployed a WAR file, you will need to rebuild/export and redeploy the WAR file to reflect the changes.

Creating a subfolder (subdirectory)

68

1. Create a subdirectory (subfolder or subcontext in web terminology) by selecting webcontent then pressing Right Mouse Button -> New -> Folder Let's call this images 2. Now you can create more JSP or HTML files into this directory, but for this example, we will demonstrate how to import files from the filesystem. Select the images folder and click Right Mouse Button -> Import Expand General, then choose -> File System You can then type in a file name or use the Browse button to find one. Let's browse to /pub/aip/images and select yellowstar.gif You can now see this file in your WebContent/images directory and can refer to this in your JSP 3. Modify your JSP to reference this image ie: add the line <img src="images/yellowstar.gif"> (note that we do not put a / in front of images. This is because the file must be relative to the context ie: labs) Make sure you create the subfolder under the webcontent folder. If you have the wrong directory (eg: Java Resources), bad things will happen: 1. The file will not be accessible from the web pages 2. The file may not be exported into the WAR file. So be careful. 3. Also note that the folder and filenames are Case sensitive! 4. Try it out. If running under Eclipse, you normally don't need to redeploy or even do Run As -> Run on Server. Just open the browse (or refresh the current page) to see the changes appear dynamically! 5. Finally, add a link in your index.html page to this JSP (if you don't have an index.html file, create it, this is normally the default home page of your web application!

69

Module: JSP
Lab exercise - JSP and form parameters
Just as servlets can access parameters from HTML forms, so can JSPs. This lab demonstrates how, and also introduces JSP declarations and expressions. Level of Difficulty: 2 (moderately easy) Estimated time: 20 minutes Pre-requisites:

Completed the Hello World JSP lab exercise

More implicit objects in JSP
In the Hello World JSP exercise, you saw the use of one of the JSP implicit objects called out. Now it's time to introduce two more implicit objects:
request

Encapsulates all information about the request that was sent by the web browser. It is of type javax.servlet.http.HttpServletRequest
response

Encapsulates all information about the response that will be sent back to the web browser. It is of type javax.servlet.http.HttpServletResponse These should seem familiar. In a servlet, when you implemented a doGet() or doPost() or service() method, the method implementation took two parameters - one of type HttpServletRequest and the other of type HttpServletResponse. In JSP, you do not have to declare the request and response objects before use - they are implicitly available.

Reading form parameters in JSP
Now that you know about the existence of the request implicit object, reading form parameters should be easy - the Java code has exactly the same syntax as you used for servlets, e.g.
<%! String formvalue; %> <% formvalue = request.getParameter("newvalue"); %>

70

JSP declarations, scriptlets and expressions
Look again at the code from above:
<%! String formvalue; %> <% formvalue = request.getParameter("newvalue"); %>

Notice that this time the tag used to indicate the start of the first block of Java code was <%! This sequence indicates that the enclosed block of Java code forms a JSP declaration, not a scriptlet. A JSP scriptlet (as used in the Hello World JSP example) can contain any arbitrary Java code. However a JSP declaration can only contain declarations. Inside a declaration block, you can declare variables, and you can declare functions. Code within a declaration block must never generate any output. It's time to introduce yet another kind of JSP code block - a JSP expression. Assume that you wanted to print out (into the web page) the value that the user had entered into the "newvalue" field, as shown above. In the above code, we created a Java variable called "formvalue" which holds the data we need. A JSP expression is used purely for displaying the value of a variable (or any Java expression). It only generates output. It should not be used to do any other kind of processing. So to print out the value of the "formvalue" variable, you can use the following JSP syntax:
<%= formvalue %>

This will embed into the output of the JSP page the contents of the "formvalue" variable. Notice that for a JSP expression, the starting tag is <%= Putting the example of the JSP declaration and JSP expression together, you might have a JSP file with the following code in it:
<%! String formvalue; %> <% formvalue = request.getParameter("newvalue"); %> ... other HTML code ... The value entered was: <%= formvalue %>

JSP block

Start tag

Can contain Variable and method declarations, nothing else. In particular, the code
71

declaration <%!

must not generate any output expression scriptlet
<%=

A Java expression that evaluates to a single value, which will be printed out into the surrounding web page Arbitrary Java code. This is the most general of the three, as you can basically put any Java code you wish inside the tags

<%

The exercise - changing background colours
Modify your HelloWorld JSP to process input from a HTML form. This form will allow users to select a background colour from a drop-down list. When the JSP loads, it sets the HTML background colour to the user's choice. You should create a JSP file called ColourChooser.jsp with a form that looks like:
<%! ??? %> <body bgcolor="..."> <form action="ColourChooser.jsp" method="post"> <select name="mycol" size="4"> <option selected="selected" value="red">red</option> <option value="blue">blue</option> <option value="green">green</option> <option value="yellow">yellow</option> </select> <p><input type="submit" name="submit" value="Change Colour"/> </p> </form> </body>

Note that the action of the form points to ColourChooser.jsp, i.e. it points to itself. The form has a single input field, named "mycol". At two points in the above listing, there is a ???? and a ... Your task is to fill in the two blanks and solve the problem. In your first solution, you should use both JSP declarations and expressions, rather than trying to do everything in a scriptlet. [Aside: If you want to be clever, after getting a basic solution working, think about changing your code to check whether the value of the form parameter was null, and if so, using some appropriate default colour. This will require a scriptlet, because you cannot put a Java "if" statement inside either a declaration or an expression.] Test your JSP by simply typing in the url eg: http://localhost:7001/labs/ColorChooser.jsp Don't forget to add a link to this JSP to your index.html file.

72

Module: JSP
Lab exercise - JSP and sessions
JSPs can also access information from sessions. JSPs and servlets can use session information interchangeably - they have the same interface to it. This lab illustrates how to access session information in a JSP, and as an aside, shows how to import Java class libraries for use in a JSP. Level of Difficulty: 3 (requires some thought) Estimated time: 30 minutes Pre-requisites:

Completed the JSP and form parameters lab exercise

Accessing sessions in JSP
You have seen already how to access sessions in a servlet. Accessing sessions in a JSP is almost identical - actually it's even simpler because you don't have to create your own instance of a HttpSession object - one is implicitly available. Let's review the JSP implicit objects you already know about, and introduce a new one, called session. Implicit object
out

Java Type
javax.servlet.jsp.JspWriter

Purpose Use the print() or println() methods for generating output that will be sent back to the browser Used to access information about the HTTP request (from the browser) Used to set information that becomes part of the HTTP response (sent to the browser) Used to get and set attributes associated with the current session

(like a PrintWriter)
javax.servlet.http.HttpServletRequest

request

response

javax.servlet.http.HttpServletResponse

session

javax.servlet.http.HttpSession

Using the implicit session object is quite similar as its use in servlets, e.g.
• • •

Storing an object into the session:
Integer counterval = new Integer(105); session.setAttribute("sessioncounter", counterval);

73

• •

Retrieving an object from the session:
Integer newcounterval = session.getAttribute("sessioncounter");

Using Java class libraries in JSP
Sometimes you want to access classes in one of the standard Java class libraries, or perhaps you want to import a class library you wrote yourself. In a Java servlet, you would normally put an "import" statement near the top of your Java source file, but what about JSP? JSP has a special syntax for importing, using what's called a JSP directive.
<%@ page language="java" import="java.util.*" %>

Note the new syntax again - this time the start tag is <%@ which indicates that this is a JSP directive. JSP directives are like instructions to the compiler. In this case, we are telling the compiler that the language embedded in this page is Java, and that we would like to import the java.util.* library. You can add more than one import by seperating each package with a , eg: import="java.util.*,java.io.*" Now you have seen four ways of embedding JSP information into a web page: declarations, expressions, scriptlets and directives. Each has a different starting tag.

The exercise - storing a history of background colours
Modify your ColourChooser.jsp file to store a history of all background colours the user has chosen in the current session. Make it so that the list of colours previously chosen is displayed at the bottom of the web page, underneath the form. Hints:

The basic idea is to use a java.util.Vector object to store the list of colours. Recall that a Vector is stores a set of values, and acts like a potentially infinite list of items. Forgotten how to use a Vector? Go read the API documentation at http://java.sun.com/j2se/1.4/docs/api/ and the Java platform tutorial You can, if you wish, use another data structure that comes with the Java 2 Collections framework, like a java.util.LinkedList or java.util.ArrayList, but make sure you use a synchronized version. The API docs tell you how. A Vector is good enough for what we are doing however.

74

• • • • • • • • • • •

Each time the user selects a colour (i.e. each time the page is reloaded), retrieve your Vector from the session and add a new item onto the end of it. Note that you will need to use a JSP directive to import the java.util.Vector class before you can use it. The following code snippet may help.
<%! Vector colourhistory; %> <% colourhistory = (Vector) session.getAttribute("colhist"); if (session.isNew() || colourhistory == null) { colourhistory = new Vector(); session.setAttribute("colhist", colourhistory); } %>

Java 5 adds Generics to the Java Language. If you wish, you can convert your code to be made type safe by declaring colourhistory as Vector<String> (along with modifying the rest of the code to suit generics. Note that you may get a warning on the cast to (Vector) which can be safely ignored.

Hint: You can print out the Vector directly using the <%= colourhistory %> JSP expression instead of using an Enumeration to loop through this.

75

Module: JSP
Lab exercise - JSP and sessions
JSPs can also access information from sessions. JSPs and servlets can use session information interchangeably - they have the same interface to it. This lab illustrates how to access session information in a JSP, and as an aside, shows how to import Java class libraries for use in a JSP. Level of Difficulty: 3 (requires some thought) Estimated time: 30 minutes Pre-requisites:

Completed the JSP and form parameters lab exercise

Accessing sessions in JSP
You have seen already how to access sessions in a servlet. Accessing sessions in a JSP is almost identical - actually it's even simpler because you don't have to create your own instance of a HttpSession object - one is implicitly available. Let's review the JSP implicit objects you already know about, and introduce a new one, called session. Implicit object
out

Java Type
javax.servlet.jsp.JspWriter

Purpose Use the print() or println() methods for generating output that will be sent back to the browser Used to access information about the HTTP request (from the browser) Used to set information that becomes part of the HTTP response (sent to the browser) Used to get and set attributes associated with the current session

(like a PrintWriter)
javax.servlet.http.HttpServletRequest

request

response

javax.servlet.http.HttpServletResponse

session

javax.servlet.http.HttpSession

Using the implicit session object is quite similar as its use in servlets, e.g.
• • • • •

Storing an object into the session:
Integer counterval = new Integer(105); session.setAttribute("sessioncounter", counterval);

Retrieving an object from the session:
Integer newcounterval = session.getAttribute("sessioncounter");

76

Using Java class libraries in JSP
Sometimes you want to access classes in one of the standard Java class libraries, or perhaps you want to import a class library you wrote yourself. In a Java servlet, you would normally put an "import" statement near the top of your Java source file, but what about JSP? JSP has a special syntax for importing, using what's called a JSP directive.
<%@ page language="java" import="java.util.*" %>

Note the new syntax again - this time the start tag is <%@ which indicates that this is a JSP directive. JSP directives are like instructions to the compiler. In this case, we are telling the compiler that the language embedded in this page is Java, and that we would like to import the java.util.* library. You can add more than one import by seperating each package with a , eg: import="java.util.*,java.io.*" Now you have seen four ways of embedding JSP information into a web page: declarations, expressions, scriptlets and directives. Each has a different starting tag.

The exercise - storing a history of background colours
Modify your ColourChooser.jsp file to store a history of all background colours the user has chosen in the current session. Make it so that the list of colours previously chosen is displayed at the bottom of the web page, underneath the form. Hints:

The basic idea is to use a java.util.Vector object to store the list of colours. Recall that a Vector is stores a set of values, and acts like a potentially infinite list of items. Forgotten how to use a Vector? Go read the API documentation at http://java.sun.com/j2se/1.4/docs/api/ and the Java platform tutorial You can, if you wish, use another data structure that comes with the Java 2 Collections framework, like a java.util.LinkedList or java.util.ArrayList, but make sure you use a synchronized version. The API docs tell you how. A Vector is good enough for what we are doing however.

• •

Each time the user selects a colour (i.e. each time the page is reloaded), retrieve your Vector from the session and add a new item onto the end of it. Note that you will need to use a JSP directive to import the java.util.Vector class before you can use it.
77

The following code snippet may help.
<%! Vector colourhistory; %> <% colourhistory = (Vector) session.getAttribute("colhist"); if (session.isNew() || colourhistory == null) { colourhistory = new Vector(); session.setAttribute("colhist", colourhistory); } %>

Java 5 adds Generics to the Java Language. If you wish, you can convert your code to be made type safe by declaring colourhistory as Vector<String> (along with modifying the rest of the code to suit generics. Note that you may get a warning on the cast to (Vector) which can be safely ignored.

Hint: You can print out the Vector directly using the <%= colourhistory %> JSP expression instead of using an Enumeration to loop through this.

Module: JSP
Lab exercise - Web authentication
78

In web applications, you will often need to restrict access to parts of your web site. The J2EE specification has 2 basic types of authentication - Declarative and Programmatic. This lab will examine how to use the Declarative method. In later labs, you will have the opportunity to use a Programmatic method. In this lab, you will be creating users, a security role and restricting access to the HelloWorld JSP to that user. Level of Difficulty: 2 (moderately easy) Estimated time: 30 minutes Pre-requisites:
• •

Completed the JSP Parameters lab exercise Running the Weblogic server - either through the Eclipse/Workshop IDE or from the command line

HTTP Basic Authentication
HTTP Basic authentication is the oldest and one of the most commonly used forms of authentication on the web. From a user's perspective, he/she attempts to visit a web page, but before the page is displayed, has to enter a username and password into a popup dialog box of the web browser. After entering correct credentials, the requested page is displayed. Traditionally, basic authentication of web servers is set up as part of the web server configuration. However with web applications, the authentication can be specified on a perapplication basis, by describing the authentication requirements in the application's deployment descriptor (web.xml file). Three elements are required in the web.xml file: <login-config>, <security-role> and <securityconstraint>. login-config specifies some global parameters for the application, security-role declares the names of users (roles) used by the application, while security-constraint specifies which file(s) should be protected and which users have access. Finally, the actual creation of the user (username and password) is done within the web application server (e.g. WebLogic) using its management console.
Setting up security roles in WebLogic

In J2EE applications, the descriptor file for the web application (web.xml) will contain the security declarations for the types of groups of users who can access the application. In this lab, we will create a group called "hellousers". A group is merely a set of users, and maps directly to a role.
1. 2. 3. 4. 5. Open the WebLogic Server Console Click on Lock & Edit in the top left menu. In the left side menu, click Security Realms Choose myrealm Select the Users and Groups tab 79

6. Select the Groups pane (this is just below the Users and Group line) 7. Create a new group by selecting New

Enter the name hellousers and a short description. Leave the provider as
DefaultAuthenticator

8. hellousers should now be in the list of groups. Creating users in WebLogic 1. At the top of the page, click the Users pane 2. Click New and enter a name such as student, and enter a suitable description and password. (you must enter the password twice!)

Note that Weblogic enforces a minimum password size. Later on (not NOW!) you can change this in the Securiy Realms -> myrealm -> Providers -> DefaultAuthenticator > Configuration | Provider Specific -> Minimum Password Length panel.
3. Now select the new user you created. 4. You should then select the Groups tab

You should see several groups here, including hellousers in the Available window. Select hellousers and press the right-arrow button to move this into the Current Groups window. Click Save to update this.
5. If you wish, you can add many other users, just ensure that they are also members of the hellousers group if you want them to access the Hello JSP 6. 7. Finish off with Release Configuration in the top left menu Configuring the hello JSP web application for security

You will need to modify the Deployment Descriptor (ie: web.xml file) to enable security. You can either update the web.xml file directly in the source editor (note that using Ctrlspace will show you the allowed elements in the current cursor position), or you can use the design tab to let the XML editor assist you. You right mouse button click and add a child element. Add the following tags into the web.xml file after the </welcome-file-list> tag.
<security-constraint> <web-resource-collection> <web-resource-name>Hello world</web-resource-name> <description>The Hello world application</description> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint>

80

<description>These users can use hello JSP</description> <role-name>hellousers</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>Hello World Application</realm-name> </login-config> <security-role> <description>Hello JSP users</description> <role-name>hellousers</role-name> </security-role>

What do the parameters mean?

<login-config>
login-config specifies

the authentication mechanism and the realm for authentication.

We have used code>BASIC for basic HTTP authentication. The realm refers to the scope of the username and password that are supplied - typically each application will have a different realm so that the credentials supplied for one application are not valid for another. The realm name can be any string of text you choose. You can only specify login-config once within your web.xml file (i.e. each web application can have at most one login method).

<security-role>
security-role

declares the name of a role referenced by this application. It has a purely declarative role.

You can have as many security-role elements as you need - one for each different role your application requires.

<security-constraint>
security-constraint

specifies a set of pages to protect within the web application, and which users should be permitted access. In web-resource-collection you define a url-pattern of the pages you wish to protect. By specifying we have declared that all pages in the Hello World application are protected. /P>

/*,

In auth-constraint you define a list of users (or more correctly, roles) who are permitted access. The <role-name> element may occur multiple times if you want multiple roles to have access. Each role name should be declared elsewhere in the same web.xml file in a <security-role> element.

81

The security-constraint element basically limits access to the specified url-pattern so that only the listed roles (users) have access. You may have many CODE>security-constraint elements in your web.xml file if you have different parts of your application that need to be accessed by different sets of users.
Map the roles to groups

Weblogic now requires you to map these 'roles' to groups. Previous versions (such as Weblogic 8.1) automatically did this. For EACH project, update the Weblogic Deployment Descriptor weblogic.xml to do this mapping. Modify the Weblogic Deployment Descriptor (weblogic.xml) by adding the following elements:
<wls:security-role-assignment> <wls:role-name>hellousers</wls:role-name> <wls:principal-name>hellousers</wls:principal-name> </wls:security-role-assignment>

The <role-name> is the name of the role to be used by your web application The <principal-name> is the name of the group to which this role will apply to. Note that you can map users to this principal as well. Repeat the whole security-role-assignment block for each role and principal assignment. You can map more than one principal to the same role name. Note: You can ask weblogic to do this automatically via the weblogic Administration Console. ie:
• • • • • •

Lock&Edit, select Security Realms On myrealm -> Configuration -> General page -> deselect "Combined Role Mapping Enabled" Expand Advanced -> Check Roles and Policies = "All web applications and EJBs", When Deploying Web Applications or EJBs = "Initialize roles and policies from DD" Release Configuration to save You may need to Stop and Restart weblogic to enable this configuration setting. Hint: Use the Servers tab at the bottom of the Eclipse screen & select the server & press the red square to stop. Press the Green arrow to start.

Now Weblogic will automatically create the equivalent of the above weblogic.xml descriptor... and you won't need to modify the weblogic.xml descriptor again..
Accessing authentication credentials in servlets/JSP

From within a servlet or JSP, you can determine the username that was used to authenticate by calling the getRemoteUser() method on the HTTPServletRequest object.

82

In your HelloWorld.jsp file, add the following lines to see who is the current user
<p>The following user is logged in: <% String user = request.getRemoteUser(); if (user == null) { user = "-none-"; } out.println(user); %>

If the web application wasn't protected, then the getRemoteUser() method will return null. You can also check to see if the user is in a particular role via the isUserInRole()
<% if (request.isUserInRole("hellousers")) { out.println("Is a member of hellousers"); } else { out.println("Is not a member of hellousers"); } %>

Don't forget to repackage your .WAR f file and copy it into the applications directory for redeployment.
Further reading

WebLogic specific security information can be found at http://edocs.bea.com/wls/docs100/security/thin_client.html#wp1037337

Module: JSP
Lab exercise - Using a JavaBean

83

So far, all the JSP code you have written has been embedded into the web page itself. If there is a large amount of code, the page can get quite messy, as you might imagine. Also, sometimes you need to reuse the same functionality in different pages. JSP pages can make use of your own Java class files, as helper classes, if you wish. However the preferred option is for JSP pages to use JavaBeans to encapsulate reusable functionality. A JavaBean is just a "special" Java class. Note that a JavaBean is NOT the same thing as an Enterprise JavaBean. This lab exercise takes you through the process of creating and deploying your own JavaBean, and using it in a JSP page. Level of Difficulty: 4 (moderately difficult) Estimated time: 45 minutes Pre-requisites:

Completed the JSP and sessions lab exercise

Why use JavaBeans?
JavaBeans are Java's "client-side" component model. Typical uses of JavaBeans are in creating components for use in GUIs (for example the Swing libraries use JavaBeans as their underlying model). Remember that a component is just a collection of Java classes that presents a single public interface to other objects. While EJBs need to execute in the context of an application server, client-side JavaBeans can be instantiated and used by any Java application or applet (or servlet, or JSP). Even though JSPs are not generally thought of as a client-side technology, JavaBeans have been adopted as the component model for use in JSPs. As we will see later, JSPs are a form of client in J2EE applications - JSPs are clients of EJBs. JavaBeans are used in JSPs to avoid having large amounts of code embedded in the web page itself. This increases the potential for code reuse, and provides a good separation of design tasks (performed by a web designer) and programming tasks (performed by a programmer).

What are JavaBeans?
A JavaBean is simply a normal Java class that follows certain design patterns. In this context, a design pattern is a basically a naming convention that you must follow when creating a JavaBean. Here we will only consider one basic design pattern used in JavaBeans - using getter and setter methods for properties. For more information on more complex design patterns used in JavaBeans, see a JavaBeans tutorial, such as the one from Sun http://java.sun.com/products/javabeans/docs/javaBeansTutorial-Nov97/javabeans/

84

Since JavaBeans represent data of some kind it needs to be serializable ie: able to be converted to some portable, transferable format. Therefore, JavaBeans have to implement the serializable interface.

Creating your JavaBean
For this exercise, assume we are going to use a JavaBean to represent a person. The attributes/properties of this person consist of only a name and a favourite colour. 1. The first step is to create a new Java project. Select New -> Project.. -> Java Project. Call this project mybeans 2. The next step is to create a package. You should be familar with packages, but briefly speaking this is simply a way to organise your Java classes (technically packages also influence the scope of variables and method visibility on all classes in a package). A more pragmatic view of a package is that it simply appears like a subdirectory! Recall that there are many packages in Java by default such as java java.util & so on. So let's create a simple package called myapp. This is basically a subdirectory called myapp !! Select mybeans, and Right Mouse Button -> New -> Package & enter myapp as the package name. Note that the source folder is actually mybeans. After Finishing our wizard, note that there is a new "myapp" folder. 3. Next, we will create a Java class skeleton to hold our JavaBean. If we Right Mouse Button -> New -> Class, we will be prompted by a wizard to create a new Java Class Enter myapp for the package name.(or alternatively, click the Browse button and select MyApp - note that there is a (default package) folder which represents "no package" or the top of your Java hierarchy. Enter a Person as the name of the class and click the Add button in the Interfaces section You should get a Interfaces selection window. Start typing Serializable (and note the typeahead assist to return Serializable (java.io)) then press OK 4. Now we are going to use the ability of the Eclipse IDE to generate code for us. Modify the generated Java class file as follows (basically we just added the declarations in italics.

package myapp; import java.io.Serializable;

85

public class Person implements Serializable { private String name; private String favecolour; }

Note that you may get a yellow warning light bulb icon which if you hover your cursor over it mentions that the class does not declare a static final serialVersionUID field. Don't worry about this, we will let Java use the default (which is system generated). Now let's get Eclipse to generate the getters and setters. Click on the top menu and choose Source -> Generate getters and setters. (You could also select the two declaration lines above then press Right Mouse Button -> Source -> Generate Getters and setters) You will get a Generate Getters and Setters wizard appearing. You can select the individual variable to generate code for using the check boxes and if you expand the field names you can see the default methods declarations. Note the other options - Insertion Point and Sort by. These just help you keep your source code nice and tidy. You can also generate a default Method Comment which generates JavaDoc style comments for you. Select All, then OK to finish Note the careful choice of method names. The methods are in pairs - one getter and one setter method. They are also case-sensitive - the word "get" and "set" must be in lower case, and the next character (the start of the property name) must be in upper case. So for example the methods getName() and setName() together implement a JavaBean property called "name" (in this case, the property name is all lower case the first uppercase 'N' is converted to lower case when you go to use it as a property). Your code now looks somewhat like this
package myapp; import java.io.Serializable; public class Person implements Serializable { private String name; private String favecolour; public String getFavecolour() { return favecolour; } public void setFavecolour(String favecolour) { this.favecolour = favecolour; } public String getName() { return name; } public void setName(String name) { this.name = name; } }

86

While you are getting used to the Source code generation facilities of Eclipse, why not experiment here and try things like Source -> Generate Element Comment, Source -> Format, Source -> Correct Indentation etc? Congratulations, you now have a JavaBean class

Packaging your JavaBean
A manifest file specifies that this class is in fact a JavaBean. Note that reading the source code of the class, there is nothing special about it that reveals that it is in fact a JavaBean. See http://java.sun.com/docs/books/tutorial/deployment/jar/manifestindex.html for information about the manifest file We will need to create our own manifest file in order to let Java (and other tools) know that this module is a Java Bean module.
• • • •

Select mybeans, right mouse button -> New -> file called manifest. Add the following contents
Manifest-Version: 1.0 Name: myapp/Person.class Java-Bean: True

Note that there is a blank line at the end of the file. We repeat each Name/Java-Bean lines for each Java bean we are declaring in our project.

Because we would like our JavaBean to be a reusable asset for our project work, we will simply Export the file to a Jar file. Choose Right Mouse button -> Export -> Java -> JAR This brings up a wizard to generate a Jar package and the various options to generate a JAR file. For the moment, we will choose to Export java source files - this isn't strictly necessary since sometimes we don't want others to see our source code. Select a destination file - let's call it mybeans.jar in and place this into some external development directory. Click next which gives us the packaging options window. Click next to get the Manifest window. Now choose Use existing manifest from workspace and Browse to the manifest file we created earlier.

We can manually check the contents of the JAR file by using the following command from a terminal:
87

jar tvf mybeans.jar

The table-of-contents should look like the following:
0 Tue Aug 21 00:00:00 EST 2007 META-INF/ 113 Tue Aug 21 00:00:00 EST 2007 META-INF/MANIFEST.MF 552 Tue Aug 21 00:00:00 EST 2007 myapp/Person.class 408 Tue Aug 21 00:00:00 EST 2007 myapp/Person.java

Congratulations, phase one is complete. You have built a JavaBean.

Creating your JSP page
Once the JavaBean has been created, and placed in a JAR file in the WEB-INF/lib directory, creating the JSP file that accesses the JavaBean is easy. You need to copy the jar file you created earlier into the labs project. Put the file into the WebContent / WEB-INF / lib subdirectory. Create a JSP file called FaveColour.jsp with the following contents and test it.
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <jsp:useBean id="fred" class="myapp.Person" scope="session" /> <jsp:useBean id="jane" class="myapp.Person" scope="page" /> <jsp:setProperty name="fred" property="name" value="Fred Jones" /> <jsp:setProperty name="fred" property="favecolour" value="blue" /> <jsp:setProperty name="jane" property="name" value="Jane Chan" /> <jsp:setProperty name="jane" property="favecolour" value="red" /> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>My Java Bean Test</title> </head> <body> <p>The favourite colour of <jsp:getProperty name="fred" property="name" /> is <jsp:getProperty name="fred" property="favecolour" /> . </p> <p>The favourite colour of <jsp:getProperty name="jane" property="name" /> is <jsp:getProperty name="jane" property="favecolour" /> . </p> </body> </html>

88

Adding new properties
To test that you have grasped the use of JavaBeans, modify the Person bean and add another property called "emailAddr". Modify your JSP pages accordingly. Hint: It may be easier to export the Java Bean jar file directly into the labs / WebContent / WEB-INF / lib directory. You can also investigate modifying labs to directly access the mybeans project as a utility library (we will talk about this later)

Beans and sessions
Note that in the above JSP code, the "fred" bean was defined with scope "session", while the "jane" bean was defined with scope "page". The "fred" bean, with all of its stored values, will be automatically stored in the HttpSession object. To retrieve it in another page, you just use the same code, and it will be automatically retrieved from the session, complete with its previously set values.
<jsp:useBean id="fred" class="myapp.Person" scope="session" />

To test the persistence of beans across sessions, make a second copy of the JSP file you created above. Now in the copy, delete all of the "setProperty" actions. To test, first access the original JSP file (the one with the "setProperty" actions). Then access the second JSP file (the one without the "setProperty" actions). What do you notice?

89

Module: JSP
Lab exercise - Using Struts
Level of Difficulty: 4 (moderately difficult) Estimated time: 30 minutes Pre-requisites:

Completed the Javabean lab exercise

Adding support for Struts
Workshop for Weblogic (unlike Standard Eclipse WTP) has some support for Struts. Do to this, you need to add the "Struts" 1.2 facet to your project.
• • •

Right Mouse Button click on your project, then press Properties You should see a property called "Project Facets" - note that this has Dynamic Web Module 2.4, JSTL 1.1 and Java 5 (plus maybe others) Click on Add/Remove Project Facets and check Struts. Ensure that version 1.2 is listed.

The main change to your application is that there is now a shared library called "Weblogic J2EE library [Struts 1.2] in the Labs -> Java Resources -> Libraries folder on your project. This also enables some support for the Struts configuration and validation xml files and tag libraries. You now need to modify your web.xml to support struts. To do this you need to edit your Deployment Descriptor (web.xml) by adding the following tags:
<servlet> <servlet-name>Struts Action Servlet</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>

and
<servlet-mapping> <servlet-name>Struts Action Servlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>

in the appropriate spots in your deployment descriptor, web.xml. (sample exists in /pub/aip/struts/lab/WEB-INF/web.inc )

90

Our Lab example
We are going to create a simple application that records a persons name and favourite colour, much like the servlet and JSP labs. However, we will use several struts features to show you how to create a simple MVC application using Struts. Basically we will only have a few 'states' at first - the welcome page (index.jsp), the list Persons page (listPerson.jsp), the Add person page (createPerson.jsp) and finally a reset state (which demonstrates a state with no actually JSP, we re-use the index page).

To transition between these 'states', we will use the following actions (which translate mostly to a URL consisting of /action.do index
Action Action Class Comments This has links to the 3 main actions of this application, and also displays messages to the user. ListPersonAction.java Checks if there a 'people' attribute in the JSP file if successful

index

/index.jsp

listPerson

/listPerson.jsp

91

session, if not, sets an error This is a 'forward' which invokes the createPerson.jsp, which displays the input form. The submit action is addPerson.do. /addPerson.do Note that when we add validation, this form will be re-invoked if validation fails. This is called by the createPerson.jsp form when the "submit" AddPersonAction.java button is pressed. It then creates the Person bean and stores it in the "database"

createPerson

addPerson

/index.jsp

This bean just deletes the 'person' attribute resetPerson ResetPersonAction.java from the session & leaves a message for the main page.

/index.jsp

Struts Configuration
The next step is to create a Struts configuration file to match the above configuration. We have set up a struts example in the /pub/aip/struts/lab directory.
• • •

Import into WebContent\WEB-INF: WEB-INF\struts-config.xml import into WebContent: index.jsp, createPerson.jsp and listPerson.jsp import into Java Resources\src: src\* (this includes myapp.* classes & ApplicationResources.properties

Try it and see how it works

Struts layout
Take a look at the files in this directory. Note that this Struts application doesn't have standardised messages and has no error checking and validations. You can find the java source in the src directory. Take special note of the ApplicationResource.properties file - this contains the strings which our struts application uses. The struts configuration files can be found in the WEB-INF directory.

Modifying struts
92

Your job is to create some validation rules that make name and color required. For hints, look at the /pub/aip/struts/lab.answers directory. Note that we created a validation.xml file! Note that validation-rules.xml comes with the default Struts configuration, you don't need to modify this! We also have a copy of the Eclipse/Workshop projects for each step to take: struts1 is the same as the lab, struts2 has basic validation, struts3 has validation with Javascript.
Steps to take

First step: Change WEB-INF/struts-config.xml Change references of org.apache.struts.action.DynaActionForm to org.apache.struts.validator.DynaValidatorForm (This subclass of DynaActionForm handles validation via the /WEB-INF/validation.xml and validation-rules.xml files) Add validate="true" to <action path="/addPerson" Add the validator plugin ie:
<!-- plugins --> <plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/> </plug-in>

2nd Step: Edit createPerson.java
• •

change import of DynaActionForm to import org.apache.struts.validator.DynaValidatorForm; change cast from (DynaActionForm) to (DynaValidatorForm) near line 37

You can check the steps by comparing the directory /pub/aip/struts/struts1 and /pub/aip/struts/struts2 Optional Step: Add error highlighting to CreatePerson.jsp

add the attribute errorStyle="background-color: red" to the <html:text elements.

Build & Test this Optional Step: Add Cancel button to CreatePerson.jsp This allows us to cancel even if we fail validation (since this can get you into a loop!)
• •

Add <html:cancel> to CreatePerson.jsp (just after the <html:reset>) Add the following to the <action path="/addPerson" element in struts-config.xml

<set-property property="cancellable" value="true"/> <forward name="cancelled" path="/index.jsp"/> Optional Step: Add Javascript validation

93

• •

Simply add <html:javascript formName="personForm" dynamicJavascript="true" /> to createPerson.jsp Add onsubmit="return validatePersonForm(this);" to the <html:form element

You can also see that we have 2 versions of the createPerson.jsp file in the lab.answers. createPerson_no_javascript.jsp doesn't have javascript validation and will highlight the error field in red.

More tasks
How about change the color selection to be a drop down menu? Radio buttons? Selection list? Use the appropriate Struts tag instead of the HTML one One neat trick Struts provides is the ability to dynamically generate Selection/Menu/Radio buttons from a java Collection class. See the Struts reference on how to do this.

References
Weblogic 10 has Apache Struts 1.2.9 support built in. You can read the reference guide at: http://struts.apache.org/1.2.9/

Module: JDBC
Lab exercise - Oracle Familiarisation - command line version
94

In this module, we will be writing Java programs that connect to a database server, issue queries, and update information. Before looking at the Java syntax, it is useful to take a moment to become familiar with the Oracle database server we will mostly be using. Some basic knowledge of databases is assumed, however no detailed technical knowledge is expected as the queries we will be performing are very basic. Level of Difficulty: 1 (easy) Estimated time: 15 minutes Pre-requisites:

None

Setting up your Oracle account
The faculty provides an Oracle database server on a machine called smaug.it.uts.edu.au. In order to administer this database, you will need to modify your profile to include certain environment variables and will need to update your default PATH with the oracle database code Add the following to the end of your .bashrc file.
# oracle setup export ORACLE_HOME=/opt/Oracle10g-client export PATH=$PATH:/opt/Oracle10g-client/bin export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/Oracle10g-client/lib

You should have been provided with an Oracle userid. If not, ask your tutor for the id and password. Your default oracle database (also called SID) is called ell This means the JDBC URL will be jdbc:oracle:thin:@smaug.it.uts.edu.au:1522:ell

Creating an SQL command file
Each person will have an Oracle database account set up which will contain your own database tables, separate to everyone else's. However initially, your Oracle account will be blank, so the first task is to create a test table. When working with Oracle, we will be using a command-line interface that Oracle calls SQL*Plus. In this command-line interface, you can enter SQL statements to create tables, insert data, and issue queries. However if you have a complex sequence of SQL commands to enter, it is best to create a command file, with the sequence of commands. Command files are also useful if you later want to delete your data and recreate your tables in their "initial" state. A command file is just a plain text file containing SQL commands. You create and edit it using a normal text editor.

95

Create a text file called addressbook.sql using a text editor, and enter the following contents. Substitute your own data if you prefer.
DROP TABLE addressbook; CREATE TABLE addressbook ( name VARCHAR(30) PRIMARY KEY, address VARCHAR(50), email VARCHAR(50), extn DECIMAL(4,0), birthday DATE ); -- note that dates are strings normally in the yyyy-mm-dd -- formats for SQL92 eg:mysql, pointbase etc -- oracle only accepts dd-mon-yyyy format, you need to use the non-standard -- TO_DATE() function to convert other date strings to Oracle format -- However, Oracle JDBC driver does accept the JDBC escape format eg: -- {d 'yyyy-mm-dd'} INSERT INTO addressbook VALUES ('chris','CB10.04.226', 'chw@it.uts.edu.au', 7938, '01-jan-2001' ); -- Note: we use the Oracle specific TO_DATE(string, format) function INSERT INTO addressbook VALUES ('Maolin','CB10.04.260', 'maolin@it.uts.edu.au', 7858, TO_DATE('30.12.1990','DD.MM.YYYY')); INSERT INTO addressbook VALUES ('Wayne','CB10.04.230', 'brookes@it.uts.edu.au', 7991, TO_DATE('04/29/1992','MM/DD/YYYY')); SELECT * FROM addressbook;

Points to note:
• •

• •

• •

Oracle SQL commands are not case sensitive. Case only matters when you are entering literal strings (between quotes). When you first enter Oracle's command-line mode, by default it does not actually save any of your changes until you exit. This is often not a good thing. By using the "set autocommit on" command, it forces Oracle to save your changes after each command. You should always set autocommit on, unless you are experienced with Oracle and wish to do manual commits. Single quotes must be used around strings, not double. Comments start with two dashes (--). You can also use C-style comments. You should not mix comments in with your SQL statements. Each single SQL command should be uninterrupted, and the comments can be placed between SQL commands. VARCHAR is a string data type which can contain a VARiable number of CHARacters, up to the specified maximum. DECIMAL is a data type for representing numbers, both with and without fractions. In this case we want a fixed-point number with four digits before the decimal point (integer part), and zero digits after the decimal point (fraction part). If you were

96

storing monetary values, you might choose a data type of DECIMAL(8,2) for example, allowing for 2 digits of precision after the decimal point. Oracle has a non-standard representation of DATE, which only accepts strings in the format of 'DD-MON-YYYY' where MON is a 3 character string representing the month eg: JAN = January. You can use the Oracle-only TO_DATE() function to convert from a string in many date formats using a format string such as 'YYYY-MM-DD'.

Starting SQL*Plus
The next step is to enter Oracle's command-line interface and run your command file. The version of Oracle installed at the faculty provides 2 main user interfaces
• •

A command-line client called sqlplus which can access the faculty Oracle database server from your workstation A web based client called iSQL*Plus. This can be found at http://smaug.it.uts.edu.au:7777/isqlplus Note that you need to enter ell for the Connection Identifier if you use the iSQL*Plus web page

We will use the command line version for this lab. 1. Logon to your workstation. If you have just edited your .bashrc with the Oracle variables, you will need to close the terminal and restart it to ensure that the variables are set. 2. Change directory to the directory in which you saved your SQL command file created above. 3. At your Unix shell prompt, run the SQL*Plus command as follows. Please note that you should use the Oracle username and password that you were assigned. The faculty provides an alias that allows you to remotely access the Oracle server, smaug.it.uts.edu.au. This is called ell_smaug. To use this, we pass a parameter to the sqlplus command that looks like userid@ell_smaug (where userid is your ORACLE userid).
workstation:~$ sqlplus userid@ell_smaug SQL*Plus: Release 9.2.0.1.0 - Production on Mon Mar 29 17:10:28 2004 Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved. Enter password: xxxxxx Connected to: Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options JServer Release 9.2.0.1.0 - Production SQL>

97

Your prompt has now changed to SQL>. You are no longer at your Unix shell, but are in Oracle's command-line database interface. All the commands you type at this prompt should be SQL or Oracle-specific commands.

Running your SQL command file
From the SQL*Plus prompt, type the following command, which instructs Oracle to load and execute the contents of your command file.
start addressbook.sql;

Running ad-hoc SQL queries and SQL*Plus commands
While in the SQL*Plus environment, you can also run arbitrary SQL queries and other valid SQL*Plus commands. Try the following commands, at the SQL*Plus prompt. Note that each command ends with a semi-colon. If you forget the semi-colon, SQL*Plus will go into multiline editing mode. This is okay, just enter a semi-colon and press enter to finish the command.
select * from addressbook; describe addressbook; select table_name from user_tables; drop table addressbook; start addressbook.sql;

Quick SQL*Plus Tutorial
There is also a quick SQL*Plus tutorial which summarises the few commands you will need to use Oracle in this subject. Feel free to experiment until you are comfortable with SQL*Plus.

Changing your password
You can change your password by typing the following SQL command from within sqlplus:
password

If you use the web interface, use the Preferences > Change Password menu instead

98

Disconnecting from SQL*Plus
When you are ready to leave SQL*Plus, use the quit command. If you are making changes to the database regularly, you might like to keep a window with SQL*Plus open in the background.
SQL> quit Disconnected from Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production With the Partitioning, Oracle Label Security, OLAP and Oracle Data Mining options JServer Release 9.2.0.1.0 - Production

Oracle Tools
You can also use a browser based version of Sqlplus via http://smaug.it.uts.edu.au:7777/isqlplus Conveniently, this works remotely from home via a normal browser!

Oracle Documentation
There is some Oracle documentation available online. This can be found at http://www.oracle.com/pls/db92/db92.homepage

Module: JDBC
99

Lab exercise - Oracle Familiarisation - Workshop for Weblogic version
In this module, we will be writing Java programs that connect to a database server, issue queries, and update information. Before looking at the Java syntax, it is useful to take a moment to become familiar with the Oracle database server we will mostly be using. Some basic knowledge of databases is assumed, however no detailed technical knowledge is expected as the queries we will be performing are very basic. Level of Difficulty: 1 (easy) Estimated time: 15 minutes Pre-requisites:

None

Setting up your Oracle account
The faculty provides an Oracle database server on a machine called smaug.it.uts.edu.au. In order to administer this database, you will need to modify your profile to include certain environment variables and will need to update your default PATH with the oracle database code Add the following to the end of your .bashrc file.
# oracle setup export ORACLE_HOME=/opt/Oracle10g-client export PATH=$PATH:/opt/Oracle10g-client/bin export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/Oracle10g-client/lib

You should have been provided with an Oracle userid. If not, ask your tutor for the id and password. Your default oracle database (also called SID) is called ell This means the JDBC URL will be jdbc:oracle:thin:@smaug.it.uts.edu.au:1522:ell

Setting up your Workshop project
You will need to add the Oracle JDBC jar file into your project build classpath. To do this, you need to Right Mouse Button -> Properties and select Java Build Path. (Alternative: Right Mouse Button -> Build Path -> Add external Archives ) Choose the Libraries tab and Select Add External Jars. Browse to /opt/bea10/wlserver_10.0/server/lib and select ojdbc14.jar

Creating an SQLpage file

100

Each person will have an Oracle database account set up which will contain your own database tables, separate to everyone else's. However initially, your Oracle account will be blank, so the first task is to create a test table. Eclipse/Workshop for Weblogic provides an editor for creating SQL scripts. Later versions have content assists and wizards, but the version currently installed does not provide this feature. You can create the SQL files in your project by using the Right Mouse Button -> New -> Other -> Data -> SQL scrapbook page Let's create one called addressbook.sqlpage using the following text.
DROP TABLE addressbook; CREATE TABLE addressbook ( name VARCHAR(30) PRIMARY KEY, address VARCHAR(50), email VARCHAR(50), extn DECIMAL(4,0), birthday DATE ); -- note that dates are strings normally in the yyyy-mm-dd -- formats for SQL92 eg:mysql, pointbase etc -- oracle only accepts dd-mon-yyyy format, you need to use the non-standard -- TO_DATE() function to convert other date strings to Oracle format -- However, Oracle JDBC driver does accept the JDBC escape format eg: -- {d 'yyyy-mm-dd'} INSERT INTO addressbook VALUES ('chris','CB10.04.226', 'chw@it.uts.edu.au', 7938, '01-jan-2001' ); -- Note: we use the Oracle specific TO_DATE(string, format) function INSERT INTO addressbook VALUES ('Maolin','CB10.04.260', 'maolin@it.uts.edu.au', 7858, TO_DATE('30.12.1990','DD.MM.YYYY')); INSERT INTO addressbook VALUES ('Wayne','CB10.04.230', 'brookes@it.uts.edu.au', 7991, TO_DATE('04/29/1992','MM/DD/YYYY')); SELECT * FROM addressbook;

Points to note:
• • •

Oracle SQL commands are not case sensitive. Case only matters when you are entering literal strings (between quotes). Single quotes must be used around strings, not double. Comments start with two dashes (--). You can also use C-style comments in one line /* */. You should not mix comments in with your SQL statements. Each single SQL command should be uninterrupted, and the comments can be placed between SQL commands.
101

• •

VARCHAR is a string data type which can contain a VARiable number of CHARacters, up to the specified maximum. DECIMAL is a data type for representing numbers, both with and without fractions. In this case we want a fixed-point number with four digits before the decimal point (integer part), and zero digits after the decimal point (fraction part). If you were storing monetary values, you might choose a data type of DECIMAL(8,2) for example, allowing for 2 digits of precision after the decimal point. Oracle has a non-standard representation of DATE, which only accepts strings in the format of 'DD-MON-YYYY' where MON is a 3 character string representing the month eg: JAN = January. You can use the Oracle-only TO_DATE() function to convert from a string in many date formats using a format string such as 'YYYY-MM-DD'.

Creating a Database Connection
The next step is to run the SQL page. You can do this via the Right Mouse Button -> Run SQL command. This should open up a Select Connection wizard.
• •

Select Create New Connection Choose a database manager - in this case, choose Oracle -> 10. You then add the following connection details: o JDBC Driver: Other o Database: ell o JDBC Driver Class: oracle.jdbc.driver.OracleDriver o Class location: /opt/bea10/wlserver_10.0/server/lib/ojdbc14.jar o Connection URL: jdbc:oracle:thin:@smaug.it.uts.edu.au:1522:ell o Enter your oracle userid and password in the User Information box o You can then Test Connection to check your details. Press Next to continue o The database connection wizard can filter out different schemas from the database connection - since the oracle server contains possibly hundreds of students entries, you should choose to narrow this list down to your own schemas. On the Filter wizard, Select Expression and Name "starts with the characters". In the entry field, enter your Oracle userid in UPPER CASE. (unfortunately, this is case sensitive). o Press Finish to complete.

You should then see a Data Output window appear in the lower pane. Note that there now is a Database Explorer view appearing too (If not, you can select Window -> View -> Database Explorer from the main menubar) Note that for each command that was executed, you will get a status line and SQL Editor box showing relevant messages & results. You can clear this by pressing Right Mouse Button -> Delete All to clear the results. You can also follow the above setup sequence to create new connections from the Database Explorer view by Right Mouse Button click on the Connections icon.

Running your SQL command file
102

Any time you are in an SQL Scrapbook page you can test an individual SQL statement by highlighting (selecting) the relevant SQL statement and then using the Right Mouse Button > Run SQL command Note that only valid SQL commands will work here. Do not use SQL*PLUS commands here (such as set autocommit on, password, describe addressbook etc).

Exploring your Database
The Database Explorer allows you explore your database. If you select the Database Explorer view, notice that there is a + symbol alongside the ell connection? Expand this and you should see ell -> + Schemas (Filtered). If you don't see the +, then you probably have an incorrect filter (Choose Right Mouse Button -> Filter, then correct the filter - normally this should be an UPPER CASE userid. You can optionally turn off filters by selecting the Disable Filter checkbox). Expanding this further you will see + tables, then your addressbook table.

The neat feature of Database Explorer is that you can drill down in further details (such as column definitions, indexes etc). If you select table (eg: ADDRESSBOOK) and pressing Right Mouse Button -> Data you can:
• • •

Edit the table in a spreadsheet - this lets you view, update, add, delete rows in the table Load - load data from text files (eg: CSV files) Extract - save data to a text file

Try adding, updating and deleting records from the addressbook table.

103

Finally, save the data by Extract'ing the records to a text file.

Disconnecting
When you wish to disconnect from the database, switch to the Database Explorer window and select the connection (this will be called ell by default). Press Right Mouse Button -> Disconnect

104

Module: JDBC
Lab exercise - Hello World JDBC
JDBC is the Java API for accessing databases. Eventually we will use JDBC for connecting the business logic parts of our application to the necessary databases. But first we begin at the beginning - with a Hello World example. This exercise is to create a simple command-line application that connects to a database. Level of Difficulty: 1 (easy) Estimated time: 20 minutes Pre-requisites:
• •

Run 'setEnv.sh' to set your environment correctly Completed the Oracle familiarisation lab exercise

A HelloWorld JDBC application
Because we are creating a standalone application, you do not need a WAR file, and we will not be installing it into the application server. It also does not really matter which directory you create this program in. Create the following Java class & change the oracle_userid oracle_password to your Oracle userid and password!!
import java.sql.*; public class HelloWorldJDBC { private static final String dbdriver = "oracle.jdbc.driver.OracleDriver"; private static final String dburl = "jdbc:oracle:thin:@smaug.it.uts.edu.au:1522:ell"; private static final String dbuser = "oracle_userid"; // change to your id private static final String dbpass = "oracle_password"; public static void main (String [] args) { try { // Load the driver and create connection Class.forName(dbdriver); Connection conn = DriverManager.getConnection(dburl, dbuser, dbpass); // Create a statement and execute the query Statement stmt = conn.createStatement(); stmt.executeQuery("select * from addressbook"); // Get the result set

105

ResultSet rs = stmt.getResultSet(); // Loop through and print out the values while (rs.next()) { System.out.print(rs.getString(1) + ","); System.out.print(rs.getString(2) + ","); System.out.print(rs.getString(3) + ","); System.out.print(rs.getLong(4) + ","); System.out.println(rs.getString(5)); } // now release the connection. conn.close(); } catch (Exception e) { // If anything goes wrong, print the Exception message e.printStackTrace(); } } }

To connect to the database, two essential pieces of information are required (other than the username and password):

JDBC driver class - the name of a Java class that knows how to communicate with the particular kind of database you are connecting to. You will need to specify a different driver class for each kind of database you wish to connect to. JDBC URL - a URL that specifies which database to connect to. JDBC URLs always start with the protocol "jdbc:", but the format of the remainder of the URL differs depending on the kind of database you are connecting to (i.e. each driver class has its own URL format). In the case of Oracle, the URL includes the driver type ("thin"), the hostname ("smaug.it.uts.edu.au"), the port number ("1522") and the database name ("ell").

Running in Workshop
First you have to load the Oracle JDBC library. To do this, select the project, Right Mouse Button -> Build Path -> Add External Archives then navigate to /opt/bea10/wlserver_10.0/server/lib and select ojdbc14.jar (in Windows: c:\bea\wlserver_10.0\server\lib) Note: You should pick the appropriate database driver jar file if you are using another database eg: mysql-comnector-java-commercial-5.0.3.jar for mysql To test your application, click Right Mouse Button -> Run As -> Java Application The output should appear in the Console.

Running from the Command Prompt
106

To test your application, compile it using javac (hint: did you remember to run wlenv to set your classpath?) and then run it using the command-line Java interpreter:
java HelloWorldJDBC

Notes
Note that hardcoding the JDBC URL, userid and password is not good practice to follow. You would be better off storing these as seperately as parameter files.

Module: JDBC
107

Lab exercise - JDBC in a JavaBean
This exercise demonstrates one way of using a JavaBean for data access. In this example, we use a JavaBean to issue arbitrary SQL commands on a database. The JavaBean is quite generic - however it does have the database details hard-coded!!! (don't do this in real life :-). Level of Difficulty: 2 (moderately easy) Estimated time: 20 minutes Pre-requisites:
• •

Run 'setEnv.sh' to set your environment correctly Completed the Hello World JDBC lab exercise

JDBC in a JavaBean
This time we are creating a JavaBean. We will also create a small program to test the JavaBean before we try and use it in a JSP. This is an example of unit testing, which is currently seen as a good software engineering approach. Create the following Java class. This is the JavaBean.
package myapp; import java.sql.*; import java.util.*; // All JavaBeans must be Serializable public class OracleBean implements java.io.Serializable { private static final String dbDriver = "oracle.jdbc.driver.OracleDriver"; private static final String dbURL = "jdbc:oracle:thin:@smaug.it.uts.edu.au:1522:ell"; /* Defining the attributes. Notice that they are all declared private. They cannot (and must not) be accessed directly from other objects, or it would violate the JavaBean rules. */ private String dbUser; private String dbPass; private Connection conn; public void connect() throws ClassNotFoundException, SQLException { if (dbUser != null) { Properties props = new Properties(); props.setProperty("user", dbUser); props.setProperty("password", dbPass); Class.forName(dbDriver);

108

this.conn = DriverManager.getConnection(dbURL, props); } } public void close() throws SQLException { this.conn.close(); } public ResultSet query(String sql) throws SQLException { Statement s = conn.createStatement(); return (s.executeQuery(sql)); } public int update(String sql) throws SQLException { Statement s = conn.createStatement(); return (s.executeUpdate(sql)); } /* get/set the dbUser property */ public String getDbUser() { return this.dbUser; } public void setDbUser(String dbUser) { this.dbUser = dbUser; } /* get/set the dbPass property */ public String getDbPass() { return this.dbPass; } public void setDbPass(String dbPass) { this.dbPass = dbPass; } }

Notice that this JavaBean has two properties: dbUser and dbPass. These must be set at runtime before calling the connect() method.

A unit test for the JDBC JavaBean
Now we need to unit test the JavaBean. Add the following main() method to your JavaBean. Vary the SQL query if you wish, to see different results. You can also test updating by using the o.Update() method. Now you can test the bean by using Right Mouse Button -> Run As -> Java Application
public static void main (String [] args) throws ClassNotFoundException, SQLException { OracleBean o = new OracleBean(); o.setDbUser("oracle_userid"); o.setDbPass("oracle_password"); o.connect(); ResultSet r = o.query("SELECT * FROM addressbook"); while (r.next()) { System.out.print(r.getString(1) + ","); System.out.print(r.getString(2) + ","); System.out.print(r.getString(3) + ",");

109

System.out.print(r.getLong(4) + ","); System.out.println(r.getString(5)); } }

Module: JDBC
110

Lab exercise - JDBC in a JavaBean in a JSP
Now that you have a JavaBean created to connect to the database, you can use it inside your JSP. Level of Difficulty: 2 (moderately easy) Estimated time: 20 minutes Pre-requisites:
• •

Run 'setEnv.sh' to set your environment correctly Completed the JDBC in a JavaBean lab exercise

Adding JSP
Now that you have a JavaBean, it is time to use it in a JSP. Below is a starting point for a JSP.
<%@ page language="java" contentType="text/html" import="java.sql.*, myapp.*" %> <jsp:useBean id="mydb" class="myapp.OracleBean" scope="request" /> <%! ResultSet rs = null; %> <jsp:setProperty name="mydb" property="dbUser" value="oracle_userid" /> <jsp:setProperty name="mydb" property="dbPass" value="oracle_password" /> <HTML> <HEAD> <TITLE>My JDBC JavaBean Test</TITLE> </HEAD> <BODY> <% mydb.connect(); rs = mydb.query("SELECT * FROM addressbook"); while (rs.next()) { %> <P> <%= rs.getString("name") %> <%= rs.getString("address") %> <%= rs.getString("email") %> <%= rs.getLong("extn") %> <%= rs.getString("birthday") %> </P> <% } %> <% mydb.close(); %> </BODY> </HTML>

111

Notice how the majority of the database code is removed from the JSP and placed in the JavaBean. The JSP should really only be printing out information from the JavaBean. In this case we are using a JSP Model 1 architecture (no central controller), therefore the JSP itself does contain some business logic (setting the properties on the bean, and also the SQL query).

Improving formatting
Notice that the database output in the above example is not well formatted. Use a HTML table to display the data.

Better Solution
Note that we have still hard-coded references to Oracle and JDBC in the bean A better solution could be to hide the implementation even further by using the Data Access Object pattern. To do this, you need to create a Interface with common "CRUD" access methods such as create, read, update, delete and find. This should deal with a JavaBean that represents the object you are working with. In our case, we can update the Person object from earlier labs by adding address details (such as address, email, extn and birthday). We then create a PersonDAO class which has the following methods.
void createPerson( Person) Person readPerson(String name) // since primarykey is name. Could also pass a Person object with name as key // this effectively does select * from addressbook where name = 'name' Person updatePerson(Person) // this would do update addressbook set .. where name = Person.name // note that we might have to put special processing for changing name void deletePerson(Person) // this would do delete from addressbook where name = Person.name // alternatively, could pass the name since this is the primary key Collection<Person> findAll() // does a select * from addressbook Collection<Person> findByName() // does a select where name=name - note that this is the same as readPerson() This PersonDAO will use the OracleBean to query and update the database.

We then change the JSP to use this PersonDAO bean. We then call PersonDAO. findAll() to get the collection. The best thing about this is that you can use Expression Language eg: ${person.name} and also use the EL automatic understanding of Collection classes. Try creating PersonDAO and Person and changing this JSP.

112

Module: JDBC
Lab exercise - Connection Pools and Data Sources
Establishing database connections is a very time consuming part of an application. Typically the database runs on a different server, so there is network delay added on top of the time it takes for the connection to be set up. One way to improve performance of applications that use databases is to use connection pooling. This is described more below. Level of Difficulty: 4 (moderately difficult) Estimated time: 40 minutes Pre-requisites:
• •

Run 'setEnv.sh' to set your environment correctly Completed the JDBC in a JavaBean in a JSP lab exercise

JDBC Connection Pools
The basic concept is that because establishing database connections takes so much time, applications that use databases can be made more efficient by preventing them from having to establish a new database connection each time they run. Instead, the idea is to have a pool of connections pre-established so that when the application runs, it can reuse one of the existing connections. The pool of pre-existing connections is provided by the container in which the application executes. In our case, the connection pool will be provided by the web application server. When an application (servlet/JSP, and later EJB) needs to connect to a database, it asks the container to give it one of the pooled connections. Connection Pools provide an efficient way to reuse database connections. However they do not make it easy to dynamically reconfigure where a particular application should get its data from. In an effort to isolate the database details from the application even further, JDBC uses the concept of a Data Source. When your application wishes to connect to a database, it will ask the application server for a data source. Inside the application server, each data source is mapped to a particular connection pool. To change which database an application retrieves its data from means only changing the data source configuration in the application server - no source code changes are required. This is best practice - you SHOULD use data sources in your production code.
Setting up a Connection Pool & Data Source in WebLogic

Because the connection pool & data source is managed by the container, you need to configure it in the container, not in your application. To set up a connection pool & data source in WebLogic, you need to use the web-based management console.
113

In the management console, use the menu on the left to locate "Services", then "JDBC" and then "Data Sources". Lock & Edit , then select "New" on the "Data Sources (filtered)" table. Fill in the following details: 1. JDBC Data Source properties: o Name = thinOracleDataSource o JNDI name: thinOracleDataSource o Database type = Oracle
Database driver: *Oracle's Driver (thin) Note: Use the pull down menu to get the list of drivers to use. Note: Do not use the "*BEA's Oracle Driver .."! o [NEXT] o (leave defaults) o [NEXT] 2. Transaction Options o Database name: ell o Hostname = smaug.it.uts.edu.au o Port = 1522 o Enter your Oracle Database user name & password
o

Note that this is the same information you needed inside your earlier JDBC code examples. But now instead of putting it in your Java source code, you are configuring it declaratively within the application server.
o [NEXT] 3. Connection Properties 4. Test Database Connection o You can now test this connection via the [Test Configuration] button Note that webLogic has generated the following settings:

Driver Classname = oracle.jdbc.driver.OracleDriver & URL = jdbc:oracle:thin:@smaug.it.uts.edu.au:1522:ell
o o o o o

[NEXT] Choose AdminServer & click [Finish] to create the JDBC data source. Initial Capacity = 1 Maximum Capacity = 2 Capacity Increment = 1

This tab is used for performance tuning. You can adjust the number of pooled connections, etc, to suit the size of your application, and capacity of your database.
Click "[Save]" Activate changes Click on the [Activate Changes] on the top left menu to make the changes active Usually you don't need to restart the server. However, read the green message response to check if you do need to restart weblogic or not. 5. Customising the connection settings o You can now select the thinOracleDataSource from the Data Sources table.
o o o o

114

o

Choose the Configuration - Connection Pool tab & set the following defaults:

When your server restarts, watch the messages in the shell window where you start it running. If there is an error in connecting to the database, it will show up as a Java exception in this window.

Verifying your Connection Pool and Data Source
You should have already verified your connection pool is working when you restarted your server. If there were JDBC error messages when the server was starting, then it means your connection pool is not properly setup. To verify your data source, in the management console, use the menu to go to "Servers", then "AdminServer". Choose the link to "View JNDI tree". You should see your data source name appear in the resulting web page. If your data source name does not appear, then there is a problem with the setup of your data source (or connection pool). JNDI will be explained separately.

The exercise
Now that the JDBC Data Source is available, you can use it from within your Java code. The goal of the exercise is to modify the JavaBean you created earlier to use the JDBC data source to establish the connection.
package myapp; import java.sql.*; import javax.sql.*; import javax.naming.*; import java.util.*; // All JavaBeans must be Serializable public class DataSourceBean implements java.io.Serializable { private String dbDataSource; private Connection conn; public void connect() throws ClassNotFoundException, SQLException, NamingException { Context ctx = new InitialContext(); // Lookup using JNDI name. DataSource ds = (DataSource) ctx.lookup(dbDataSource); conn = ds.getConnection(); } public void close() throws SQLException { conn.close(); }

115

public ResultSet query(String sql) throws SQLException { Statement s = conn.createStatement(); return (s.executeQuery(sql)); } public int update(String sql) throws SQLException { Statement s = conn.createStatement(); return (s.executeUpdate(sql)); } /* get/set the dbDataSource property */ public String getDbDataSource() { return this.dbDataSource; } public void setDbDataSource(String dbDataSource) { this.dbDataSource = dbDataSource; } }

Notice now how all the database connection details (JDBC driver name, JDBC URL, username, password) are removed from the Java code, because they are managed by the application server. This also means that this bean is now completely database independent. The same Java code can be used regardless of whether the database used is Oracle, Informix, Ingres, etc. When this JavaBean executes, it will ask the application server to provide a DataSource, and the application server will allocate one of the available database connections to this JavaBean for as long as it needs it. When the JavaBean closes the connection, the connection is returned to the pool and available for other applications.

Testing your new bean
To test your new bean, you will need to modify your JSP code to reflect the properties of the new bean. This is left up to you.

116

Module: JDBC
Tutorial - Using other databases with Weblogic 10
JDBC is a generic API that can be used for accessing any kind of database given the appropriate drivers. The lab exercises in this module are written to use Oracle. This is a brief explanation of how to convert the examples from using Oracle to using other JDBC databases Weblogic 10 comes with some preinstalled commerical JDBC drivers. See http://edocs.bea.com/wls/docs100/jdbc_admin/third_party_drivers.html for a definitive list and how to use them. Weblogic 10 also has a "universal" driver (called "Type 4 JDBC Drivers", also known as the BEA drivers) which were written by Merant for BEA. See http://edocs.bea.com/wls/docs100/jdbc_drivers/jdbcsupt.html for how to use them You can also use other databases if they have a JDBC driver written for them. See http://cayenne.apache.org/doc/database-support.html for a pretty good list of vendor JDBC drivers. Here is brief table of what drivers are installed by default. Note that these are already in the pre-defined Weblogic classpath so you don't have to specifically add these jar file into your classpath when running your WAR or EJB file. However, do note that Workshop for Weblogic/Eclipse WTP does not automatically add these files to your project build path properties. You can find most of these files in the /opt/bea10/wlserver_10.0/server/lib directory.
Driver Jar file Name Class Name URL

Oracle 10g (Thin ojdbc14.jar oracle.jdbc.OracleDriver client Driver)

jdbc:oracle:thin:@server:1521:db

Sybase com.sybase.jdbc.SybDriver jConne jConnect.jar com.sybase.jdbc2.jdbc.SybD jdbc:sybase:Tds:server:port/db ct 4.5, , jconn2.jar, river 5.5, jconn3.jar com.sybase.jdbc3.jdbc.SybD and 6.0 river mysqlMySQ connector- com.mysql.jdbc.Driver L 5.0.x javaorg.gjt.mm.mysql.Driver commercial -5.0.x-

jdbc:mysql://server:port/db

117

bin.jar pbclient51.j ar Pointba com.pointbase.jdbc.jdbcUni jdbc:pointbase:server://server:port/db pbembedde se 5.1 versalDriver jdbc:pointbase:embedded:db d51.jar

Weblo gic type 4 drivers: IBM DB2 8.2/9.1, Informi x, MS SQL server 2000/2 005, Oracle 9g, 10g, Sybase 12.5/15 .1

wlbase.jar, wlutil.jar wldb2.jar

-

-

weblogic.jdbc.db2.DB2Driv jdbc:bea:db2://server:port;DatabaseName=db er

wlinformix. jdbc:bea:informix://server:port;informixServer=s weblogic.jdbc.informix.In jar erver;databaseName=db

formixDriver

wlsqlserver. weblogic.jdbc.sqlserver.SQL jdbc:bea:sqlserver://server\\instance jar ServerDriver wloracle.jar weblogic.jdbc.oracle.Oracle jdbc:bea:oracle://server:port;SID=db Driver

wlsybase.jar

weblogic.jdbc.sybase.Sybase jdbc:bea:sybase://dbserver:port;SID=db Driver

Built into JDBC Java 1.4 & ODBC later bridge versions.

sun.jdbc.odbc.JdbcOdbcDriv jdbc:odbc:odbc-dsn-name er

If you want to use the following databases (and corresponding JDBC drivers), you need to download them and place them into your classpath.

org.apache.derby.jdbc.Client derbyclient. Driver Derby jdbc:derby://server:port/db jar org.apache.derby.jdbc.Embe ddedDriver Sqlite sqlitejdbc.ja org.sqlite.JDBC r jdbc:sqlite:/path/to/database.db jdbc:sqlite://path/to/database.db

118

sqlite.jar

SQLite.JDBCDriver

jdbc:sqlite:/:memory:

postgresqlPostGr 8.3*.jdbc3.j org.postgresql.Driver es ar

jdbc:postgresql://server:port/db

Step 1 - (Optional) Making WebLogic load the JDBC driver

Do this step ONLY if WebLogic does not have an existing JDBC driver (eg: for Apache Derby) Assuming you have downloaded the appropriate database client code and JDBC driver, your next step is to place the JDBC driver (normally a JAR file) into the Weblogic classpath. You can do this in three ways.

Option 1: copy the driver into the default Java classpath (ie: the JRE_HOME/lib/ext ie: /opt/bea10/jrockit_150_06/jre/lib/ext ). This is NOT RECOMMENDED because this is not portable and often you will not have root/administrator access to change these directories anyway. Option 2: Copy the jar files into the WEB-INF/lib directory (or into your EAR). This is portable, but during development you will still need to place the JAR file into your classpath. Option 3: You can change the default Weblogic setup in your domain to include the JAR file into the default classpath (assuming you have set up the wlenv alias). To do this: Edit your $DOMAIN_HOME/bin/setDomainEnv.sh and add the line:
EXT_PRE_CLASSPATH=path/to/driver.jar

(where $DOMAIN_HOME is your domain directory eg: ~/weblogic, and path/to/driver.jar is the path to the JDBC JAR file) Add this just after the WL_HOME= line. (Windows version: edit setDomainEnv.cmd and add SET EXT_PRE_CLASSPATH=path\to\driver.jar ) This is safer than editing the startWeblogic.sh command directly.

Step 2 - changing the parameters

Now that WebLogic can load the JDBC driver, you need to be able to change the code examples to refer to the new database driver rather than Oracle. You need to change any occurrence of the driver class and the matching URL. For example, for MySql, make the following changes:

JDBC driver class
oracle.jdbc.driver.OracleDriver

--> eg: Mysql: com.mysql.jdbc.Driver

119

JDBC URL Oracle: jdbc:oracle:thin:@smaug.it.uts.edu.au:1522:ell --> eg: Mysql: jdbc:mysql://localhost/mydb

Step 3 - change Oracle specific SQL

change any Oracle specific SQL (eg date formatting) to SQL92 formats. IF you used the recommended JDBC escape sequence for dates eg: { d '2001-12-30'} instead of the Oracle date format eg: '30-dec-2001', then you need to make no changes.

Module: JDBC
Tutorial - ODBC example
120

Microsoft Windows provides a universal interface to database & database-like services under windows called ODBC. For example, there are ODBC drivers for Microsoft Access, Excel spreadsheets, SQL Server and so on. There is a unix equivalent (unixODBC) on linux and solaris (and other unixes as well). Java 1.4 upwards provides JDBC driver called the Sun JDBC-ODBC bridge. This driver is provided in the default rt.jar library. Driver class: URL format:
sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbc:odbc-dsn-name

where odbc-dsn-name is the name of an existing ODBC Data Source Name (DSN) on the local computer. This syntax will vary depending on the ODBC provider. Our example will use Microsoft Access. IMPORTANT NOTE: This driver is not thread-safe and should not be used in production. Weblogic 10 does not allow you to use this driver for EJB's (though it will work for servlets and JSP's) For more details, read on ...

Creating an ODBC DSN
Windows ODBC works on the concept of data sources. Each data source has a name, called the DSN or Data Source Name. Before you can access a database via ODBC, it should have a DSN set up for it. Each DSN refers to one particular database that can be accessed via ODBC. Let's assume you want to allow your servlets/JSPs to connect to a Microsoft Access database. ODBC data sources can connect to a variety of underlying file types including Access, Excel and plain text files. Here are the steps: 1. Create your database. Open up Microsoft Access with a blank database, create one table with a few columns, and add a couple of rows of data. 2. Open up the ODBC Control Panel: o Windows 2000/XP: "Start" menu -> "Settings" -> "Control Panel" -> "Administrative Tools" -> "Data Sources (ODBC)" 3. Move to the "System DSN" tab and click the "Add" button. 4. Choose the "Microsoft Access Driver (*.mdb)". 5. Enter a name for the DSN. It can be any name you choose, but should start with a letter and for simplicity should only contain alphanumeric characters. The DSN name should somehow relate to the database name or its contents. Optionally enter a description as well if you wish. 6. Under the word "Database", click on the "Select" button and locate the Microsoft Access database (.mdb file) you created earlier. 7. Click "OK" in all the windows and your new DSN is created.
121

Accessing the ODBC DSN from a Java program
The key lines of Java code that differ between databases are loading the appropriate JDBC driver, and specifying the database URL. For accessing an ODBC DSN, the following are the two key lines:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); ... conn = DriverManager.getConnection("jdbc:odbc:mydsn");

where you replace mydsn by the name of the ODBC DSN for your database. Here is some example code you can download and try. It assumes you have a DSN actually called "mydsn" and that in your database there is a table called "test". Use your right-mouse button to save these to a local file.
• • •

odbctest.java A simple command-line application to test JDBC-ODBC. ODBCServlet.java A servlet which connects to an ODBC data source. odbctest.war A WAR file containing a (mostly) generic database access servlet and the appropriate web.xml init-param's for it to connect to an ODBC data source. To extract individual files, use the command: jar xvf odbctest.war

Module: JDBC
Tutorial - Oracle SQL*Plus

122

For working with an Oracle database, it is often convenient to use Oracle's command-line interface to the database. This is the Oracle-specific program called SQL*Plus. For the definitive SQL*Plus guide, see:

Oracle documentation at http://dragon.it.uts.edu.au:9700/iplus/help/us/toc.htm

Running SQL*Plus
1. Log in to the Oracle database server. This is a Unix machine called dragon.it.uts.edu.au. Connect with either ssh or telnet (ssh preferable). Use your regular Faculty login and password (Unix login). You will be placed in your Unix home directory (same as charlie/sally, and your X: drive on PCs). 2. Run the SQL*Plus program:
3. sqlplus

4. Enter your Oracle username and password. This is not the same as your Unix login. 5. You will now be at the SQL*Plus prompt. Here you can enter SQL statements, and SQL*Plus commands.

Useful SQL*Plus commands
Firstly, note that generally, commands in SQL*Plus should be terminated by a semi-colon (;). Secondly, if you press Enter in the middle of a command, Oracle will prompt you to enter another line that is part of the same command - you can spread a command over multiple lines. The command will be executed when you type a semi-colon. Each time you press Enter, Oracle will prompt you by showing you the current line number that you are entering.
Using command files

Rather than typing complex commands directly into the SQL*Plus interface, create a file containing the commands, and then run the command file in SQL*Plus. This also means if the database data is lost for any reason, you can easily restore it to your chosen "initial" state. Example:
start mycommandfile.sql;

or:
@ mycommandfile.sql;

You can include comments in your command file either using C-style comments /* ... */ or comments starting with two dashes (--). The C-style comments must be placed on a line of their own and not inside any block of SQL.

123

SQL*Plus also includes commands for saving the current edit buffer (SAVE) to a file and loading a file into the current edit buffer (GET).

Committing changes

In SQL*Plus, the default behaviour is not to commit changes to the database until you explicitly request it. Until changes are committed, they are not visible to other users (including JDBC accesses). There are two commands that may help:
commit;

will commit changes manually. Or:
set autocommit on;

will change the autocommit behaviour for the current SQL*Plus session so that changes are automatically committed after each SQL command.

Examining table structures

The DESCRIBE command can show the structure of a table, e.g.
describe mytable1;

Running Unix commands

To run a Unix command from within the SQL*Plus interface, just prefix the command with the keyword HOST, e.g.
host ls host pico mycommandfile.sql host vi mycommandfile.sql

Running SQL commands

In general, you will want to run SQL commands in SQL*Plus (preferably from a command file). If you need SQL help, here is a quick SQL refresher with lots of examples.

Module: JDBC
124

Tutorial - Quick SQL Refresher
The examples shown below are based on the Oracle dialect of SQL. Other databases use slightly different syntax in some places (usually the available data types, and built-in functions). For the definitive Oracle SQL reference, see:

Oracle documentation http://www.oracle.com/pls/db92/db92.homepage

SQL SELECT statement
Basic queries

General format:
SELECT column-list|* FROM table-name-list WHERE condition-list ORDER BY column-list;

Firstly, here is how to retrieve all data from a table:
SELECT * FROM mytable;

You can retrieve specific columns (but all rows) from a table:
SELECT mycol1, mycol2 FROM mytable;

WHERE clause

You can limit which rows are returned according to some criteria:
SELECT * FROM mytable WHERE mycol1 > 100;

Here is an example that limits with several conditions:
SELECT * FROM mytable

125

WHERE mycol1 > 100 AND mycol2 = 'hello world' AND mycol3 IS NOT NULL;

Note that the phrases "IS NULL" and "IS NOT NULL" are special ways to check if a particular column contains a NULL value, as distinct from having an empty value (e.g. the empty string "") Also note that single quotes are used around strings in SQL, and a single equals sign is used to test equality.

LIKE operator

You can use the LIKE operator to do pattern matching. Within a pattern, you can use an underscore (_) to match exactly one character, and a percent sign (%) to match zero or more characters. For example:
SELECT * FROM mytable WHERE mycol1 LIKE 'SM_TH%';

This pattern will match SMITH, SMYTH, SMITHSON, SMYTHE, etc. Any single character can be placed between the M and T, and zero or more characters may follow the H.

Built-in Functions

You can apply an aggregate function to a column - e.g. counting the number of rows:
SELECT COUNT(*) FROM mytable WHERE mycol1 > 100;

Here is a different function - maximum value in a column. There are lots of functions available.
SELECT MAX(mycol1) FROM mytable;

Sorting

You can sort the result by a particular column:
126

SELECT mycol1, mycol2 FROM mytable ORDER BY mycol2;

Here is more complex sorting. Sort by "mycol2" in descending order followed by "mycol1" in ascending order (the default):
SELECT mycol1, mycol2 FROM mytable ORDER BY mycol2 DESCENDING, mycol1;

Joining tables

If you want a single query to retrieve data that is in multiple tables, you can join the tables. To join two tables you list both table names in the FROM clause, and you include (at least) one join condition in the WHERE clause. A standard join condition should specify that a column in one table equals a different column in another table. For example, consider the following example tables and SQL query.
Table: PERSON PersonID Surname Firstname 1 2 Brookes Wayne Johnson Chris Table: ORDERS OrderID PersonID OrderValue 1 2 $99.99

SELECT person.surname, orders.ordervalue FROM person, orders WHERE orders.personid = person.personid;

This query would return one row, with the values "Johnson", "$99.99". Note that the join condition is used to specify on which column the two tables should be joined.

127

Subqueries

Sometimes you want to test membership in a set of values. For example, using the example tables above, you might want a list of the names of all customers who have placed an order:
SELECT surname, firstname FROM person WHERE personid IN ( SELECT personid FROM orders );

The subquery is the one in parentheses. You can negate the condition if you want to see a list of all customers who have not placed an order. Note that the subquery stays the same, just the IN operator becomes NOT IN:
SELECT surname, firstname FROM person WHERE personid NOT IN ( SELECT personid FROM orders );

The subquery should return only one column of data.

SQL CREATE/DROP statements
Basic table creation

General format:
CREATE TABLE table-name ( col-name-1 data-type-1, col-name-2 data-type-2, col-name-3 data-type-3 );

For example:
128

CREATE TABLE mytable1 ( mycol1 VARCHAR(20), mycol2 NUMBER(4,2), mycol3 DATE );

If a column is not allowed to contain NULL values, you can specify that it should be NOT NULL. If the data in a column must be guaranteed to uniquely identify rows within the table, you can declare it as a PRIMARY KEY. For example:
CREATE TABLE mytable1 ( name VARCHAR(20) PRIMARY KEY, height NUMBER(4,2), dateofbirth DATE NOT NULL );

To remove a table definition, and all the data in it, use the DROP statement. Note: you will receive no warning, and no second chance!
DROP TABLE mytable1;

SQL INSERT/DELETE statements
The INSERT/DELETE statements are for adding and deleting rows in an existing table.
Inserting rows

General format:
INSERT INTO table-name VALUES ( col-1-value, col-2-value, col-3-value );

An example:
INSERT INTO table-name VALUES (

129

'Wayne', 123, TO_DATE('2001-01-01', 'YYYY-MM-DD'), NULL );

Notes on data types:
• • • •

Strings are enclosed in single quotes Numbers are not enclosed by any characters Dates need to be converted from strings into the DATE type using the Oracle TO_DATE() function A null value for a column can be specified with the keyword NULL (no quotes)

Deleting rows

The syntax of the SQL DELETE statement is quite similar to the SELECT statement, except no column-list is used. You can delete all data in a table as follows:
DELETE FROM mytable1;

You can selectively delete rows by adding a WHERE clause, with the same syntax as for a SELECT, e.g.:
DELETE FROM mytable1 WHERE mycol1 LIKE '%ayn%';

SQL UPDATE statements
The SQL UPDATE statement is for updating existing data within a table. General format:
UPDATE table-name SET column-name = value WHERE condition-list;

Here's a simple example - update the orders table and set every row to have the OrderValue set to 10.

130

UPDATE orders SET ordervalue = 10;

The next example only updates certain rows in the table - not all of them. To do this, a WHERE clause is used, with the same syntax as for an SQL SELECT.
UPDATE orders SET ordervalue = 10 WHERE personid > 99;

You can update multiple columns at once if you need to, e.g.:
UPDATE orders SET ordervalue = 10, personid = 0 WHERE personid > 99;

Module: RMI
Lab exercise - RMI client/server application
131

This lab exercise shows you how to create a simple RMI application in a non-J2EE context. Level of Difficulty: 1 (easy) Estimated time: 45 minutes Pre-requisites:

Run 'wlenv' to set your environment correctly

Overview of RMI
RMI is Java's Remote Method Invocation. It allows objects in different Java Virtual Machines to communicate, by allowing one object to invoke a method on another object that is remotely located. Typically these objects are executing on different machines, but not necessarily. RMI is Java's implementation of Remote Procedure Call (RPC), a wellestablished computing paradigm for building distributed applications. RMI is a client/server protocol. In a J2EE setting, RMI may be used in a number of places:
• • •

a servlet calling a method on an EJB one EJB calling a method on another EJB a (non-web) Java client calling a method on an EJB

This exercise demonstrates none of these. While RMI can be (and is) used in J2EE applications, it can also be used by non-J2EE applications that wish to communicate. For now, we will use "pure" RMI, not in a J2EE context.

Development Process
Because RMI uses a client/server architecture, you need to create both a client program and a server program. Because there are many steps in developing a pure RMI application, it is important to follow the correct sequence of steps, as outlined below. 1. Define the remote interface. The "remote interface" is where you decide what kind of service(s) your server is going to offer to its clients. The remote interface is a Java interface that defines a set of method signatures that the server will implement, and that the clients can call. The remote interface is shared by both clients and the server.
2. Implement the RMI server. This is a Java class that implements all the methods you defined in your remote interface. This is where you write the code for what the server is going to do. 3. Generate RMI skeletons and stubs. RMI has a special pre-processor that will automatically generate some of the low-level communications code for you. The autogenerated code is called stubs (for the client's part) and skeletons (for the server's part). 4. Implement an RMI server registration class. The class you created above when you implemented the RMI server only implements the

132

business logic methods. You also need a class to actually make your server run (i.e. one you can execute from the command line - with a main() method). This is the server registration. 5. Implement an RMI client. The final step is to implement a client class that will connect to your server.

Creating a simple RMI application

Step 1 - Define the remote interface

The remote interface is a Java interface declaration, containing a list of methods (signature only) that you want your clients to be able to invoke. Create and compile the following Java source file.
/** The remote interface - both the client and the server share a common view of this interface. */ import java.rmi.*; public interface HelloWorld extends Remote { String sayit() throws RemoteException; }

Points to notice:
• • •

Clients will only be able to invoke one method on the server - the method is called sayit(), and it takes no arguments and returns a String. The interface extends Remote (java.rmi.Remote). All remote interfaces must do this. The method declares that it may throw a RemoteException. All methods in a remote interface must declare this. A RemoteException may be thrown by the underlying infrastructure if anything goes wrong with the communication between the client and server. Although it is not clearly shown here, both the parameters and the return type of remote methods must be Java classes that implement the java.io.Serializable interface.

Step 2 - Implement the remote methods

This is the server-side class that implements the remote interface. It must provide public method implementations for all methods defined in the remote interface. The server class may define other methods, but only the ones listed in the remote interface can be invoked over the network by clients.

133

Create and compile the following Java source file.
/** Class that implements the RMI server */

import java.rmi.*; import java.rmi.server.UnicastRemoteObject;

public class HelloWorldImpl extends UnicastRemoteObject implements HelloWorld { // Implementation must have an explicit constructor // in order to declare the RemoteException exception public HelloWorldImpl() throws RemoteException { super(); }

// Method implementation public String sayit() throws RemoteException { System.out.println("Got another request - returning result!"); return ("Hello World!"); } }

Points to notice:
• •

• •

The class name has "Impl" appended to its name to indicate that this is the server implementation. This is a commonly used naming convention. The class extends UnicastRemoteObject. This is standard for a server that you will start up manually from the command-line (as opposed to one that is started automatically on demand, which is slightly more complex). The class implements HelloWorld. i.e. it implements the remote interface, which implies all of the Java semantics associated with the "implements" keyword. We must declare a default constructor (i.e. one with no arguments) even if you don't need to do anything special, because the constructor method must declare the possibility of throwing a RemoteException. An RemoteException might be thrown by the underlying RMI support library, not by your code itself. In the implementation of our remote method - sayit() - we do two things. The System.out.println statement will cause the server to print a message in its window (on the server machine). The return statement will return a String message back to the client's machine.

Step 3 - Generate the RMI skeletons and stubs

After you have compiled both the remote interface and the implementation class, you can use a tool to automatically generate some of the low-level code that deals with network communication. These are called stubs (client-side) and skeletons (server-side).
134

From the command prompt, run the following command from the build directory ie: where the compiled classes are located.
rmic HelloWorldImpl rmic stands for "RMI compiler". Notice that you specify the name of the implementation class (without any file extension).

After running this command, you will notice some extra files have been generated. Note that the build directory in the Eclipse workshop lab is in the project/build/classes
Step 4 - Write an RMI server registration class

Notice that in the implementation class above, there is no main() method. So how do you run it? The answer is that you don't. The next task is to create a Java class whose purpose is to start the server running. When you go to run your RMI server, it is this class that you execute. Create and compile the following Java source file.
/** This is the server registration class. It has a main method (command-line application) and creates a server instance and registers it with the RMI registry. */

import java.rmi.Naming; public class HelloWorldServer { public static void main (String [] args) { try { // create instance of remote object System.out.println("Creating instance of server object ..."); HelloWorld hw = new HelloWorldImpl(); // bind remote object to naming service System.out.println("Registering object with the RMI registry ..."); Naming.rebind("rmi://localhost:1099/HelloWorldService", hw); System.out.println("Registered!"); } catch (Exception e) { e.printStackTrace(); } } }

Points to notice:

The registration class as a main() method. It is a Java application.
135

• •

It creates an instance of the server implementation class (called "hw"). It registers the instance ("hw") with a name service, and assigns it a human-readable name ("HelloWorldService"). So far we haven't mentioned a name service. The idea is that when a client starts executing, it needs to know how to find where the server is. One way would be to hard-code the server's location into the client's code, but this is not very flexible. You could have the client read the server's location out of a configuration file, but this is not very dynamic (if the server moves to a different machine, someone has to update the configuration file). A name service maps from simple, text-based, human-readable names into Java remote object references (i.e. a reference to a Java object running on a remote server). When a server starts executing, it advertises itself on the name service. When a client starts up, it queries the name service to find out where the server is. This way the client only has to know how to contact the name service, and from there it can find all different kinds of servers.

Exceptions must be handled (try...catch). When you call Naming.rebind(), a number of different exceptions may be thrown - MalformedURLException, RemoteException, AccessException. In this example, we catch all of them at once and just print out a message. Obviously in a real application you would want some better error handling!

Step 5 - Implement an RMI client

Finally, it's time to implement the client application. This could be a GUI client, but to keep it simple, we will just use a command-line client application. Create and compile the following Java source file.
/** The RMI client which looks up the object in the name server, retrieves a reference and invokes the sayit() method. */ import java.rmi.Naming; public class HelloWorldClient { public static void main (String [] args) { try { System.out.println("Looking up service in RMI registry ..."); HelloWorld hw_obj = (HelloWorld) Naming.lookup( "rmi://localhost:1099/HelloWorldService"); System.out.println("Calling remote method ..."); String hw_text = hw_obj.sayit(); System.out.println(hw_text); } catch (Exception e) {

136

e.printStackTrace(); } } }

Points to note:

• • •

When we do a lookup operation on the name service, we pass in a human-readable name (disguised as part of a URL), and what we get back is a Java object reference that we can store in a variable (hw_obj). The type of hw_obj is HelloWorld - i.e. the remote interface. The remote interface contains information that is shared by both the server and client. We can then call the sayit() method on the hw_obj object. Notice that it looks just like a local method call. Exceptions must be handled in the client application as well. In particular, if something goes wrong with the communication, the client may have to handle a RemoteException.

Running the HelloWorld example
As well as needing to run the RMI client and the RMI server, you also need to execute the name service - the "RMI registry". The registry needs to be run first, then the server, and finally the client.

Running the RMI registry

The RMI registry is a simple name service that comes supplied with the J2SE SDK. Rmiregistry MUST be able to locate the interface and implementation and stub/skeleton class files. This means that you should either modify your CLASSPATH to include the compiled classes directory and/or change the current directory to the classes directory. (You may have to also add

.

into your classpath for this to work)

Assuming your CLASSPATH is set correctly, you can run it by typing:
rmiregistry &

rmiregistry will listen at port 1099. You can change this by specifying the port number as an argument to rmiregistry. Note that you can only run ONE copy of rmiregistry per port. This is why setting the CLASSPATH is a better solution.
Running your server

Remember that you run the server registration class, not the server implementation class.
137

Run the server registration class:
java HelloWorldServer

Running your client

In this example, we will run the client and server on the same machine for simplicity. However they will be running in separate Java Virtual Machines, which is the key point. Open a new window, set your environment correctly, and run the client:
java HelloWorldClient

True distribution

In theory, you can run the RMI registry, the server and the client all on different machines. However, note the following:

• •

Both the server registration and the client have the hostname of the RMI registry hardcoded. If you run the registry on a different machine, you need to adjust the code to the new location. The server needs access to the Java classes for the remote interface, the server implementation class, the server registration class and the auto-generated skeleton classes. The client needs access to the Java classes for the remote interface, the client implementation class and the auto-generated stub classes. The RMI registry needs access to the Java class for the remote interface.

Next step ...
Now that you have followed a step-by-step walkthrough, the next step is to be a bit more independent. Modify the example above to include a new remote method that will add together two integers (i.e. it takes two integer arguments, and returns an integer result). This will involve changing the remote interface, and then re-running all the subsequent steps.

138

Module: JNDI
Lab exercise - overview
The laboratory exercise for this module is to query an LDAP server and display a set of attributes from a directory. Level of Difficulty: 1 (easy) Estimated time: 20 minutes Pre-requisites:

none 139

About LDAP and directory structures
Basically Lightweight Directory Access Protocol (LDAP) is a generic method of accessing directory style information eg: address books but can be used for other purposes too, such as Microsoft Active Directory manages all shared objects and security information in a Microsoft Domain. An LDAP-style directory is a hierarchical tree of objects, where the root of the tree normally is what's called a "Base DN" (Base Distinguished Name) Each entry in the tree:
• • •

Is an instance of one or more ObjectClasses (such as Person) Has some attributes. Each attribute has a name and a data type (eg: string, number etc) Has a unique identifier called a Distinguished Name (dn). Often this is a concatenation of attributes such as uid (userid), organisation etc.

All of these ObjectClasses and Attributes are defined in a schema. Luckily there are standards which define some standards for directories such as X.500 compatible address books (which the vast majority of LDAP servers support). Be aware that an LDAP server can manage many independent tree's, each with different Base DN's.
Security and LDAP

LDAP directories are also often used for Authentication. UTS uses a common single signon for email, library access, workstation access etc. To do this you need to 'bind' to the directory server with your userid and password. We can't do this in our lab since this access is restricted but normally you would pass your own "distinguished name" and password to LDAP to authenticate your password. By default, we will use 'anonymous' access.

Accessing an LDAP Directory from the command line
We don't have any LDAP searching tools on the Linux workstations, so you will need to logon to charlie for this exercise You can search for a person using the UTS staff directory. To do this, we will use the following command ldapsearch -h host -p port -b base_dn -s scope filter attributes The parameters are:
host the hostname of the LDAP server

140

port

the TCPIP port - defaults to 389 the "top of the tree" ie: where to start the search from. You must have this option, there is no default. The UTS staff directory base_dn is: o=UTS one of: base, one, sub. Base means only at the top level, one means only 1 level down to search, sub means all subcontexts ("subdirectories"). You can leave this out since this defaults to sub This is the search string. It should meet RFC2254 syntax. eg: (cn=christopher wong) would search for the "Common Name"="christopher wong" (sn-=wong) would search for "Surname"=wong (sn=*wong*) would search for "Surname" containing "wong"

base_dn

scope

The valid operators are: = equal >= bigger than (including alphabetic order eg: c > b) <= less than ~= approximately equal (soundex search so sn~=wong would also return wang, wing, etc) You can have logical "and" "or" and "not" filters by prefixing these criteria with a & | ! character. eg:

filter

(& (sn=wong)(givenName=christopher) ) --> returns all christoper wong's (| (sn=wong)(sn=brookes)) --> returns all wong's & brookes's (& (sn=wong) (! (givenName=christopher) ) ) --> returns all wong's except those whose given names is christopher The hard part is getting the bracketing correct....
This is a list of what attributes to return. The default is to return all.

attributes

rfc2256 has a huge list of what attributes are available. Common ones to use are: cn (common name), dn (distinguished name ie: primary key), sn (surname), givenName, initials, title, description, o (organisation), ou (organisation unit), objectClass, c (country code), street, telephoneNumber

Example search

ldapsearch -h ldap.uts.edu.au -b o=UTS '(sn=wong)' Try do a search for a person by "Common Name" ie: the cn attribute. See if you can find your tutor's name in it.

141

How about restrict the attributes to just sn, givenName, telephoneNumber, mail ? A good tutorial about LDAP can be found at http://edutechwiki.unige.ch/en/LDAP and Introduction to LDAP (SAGE) http://quark.humbug.org.au/publications/ldap/ldap_tut.html

Module: JNDI
Lab exercise - LDAP programming
The laboratory exercise for this module is to query an LDAP server and display a set of attributes from a directory. Level of Difficulty: 1 (easy) Estimated time: 45 minutes Pre-requisites:

LDAP Overview lab
142

Run 'wlenv' to set your environment correctly

An example first
The following Java source code is for a complete JNDI application that queries the main UTS LDAP server (which holds details of all UTS staff). It is a standalone Java application to be compiled and run from the command line. Try it out. Compile it for yourself and run it by typing:
java JNDITest brookes

Then study the source code to understand how it works. Use this as a basis for the exercise below. (note: to do this under eclipse, you need to run the class with a parameter ie: Use Run As -> Run. Then select JNDITest as the Main Class, and on the (x=) Arguments tab, enter the Program Argument as brookes) Source code:

JNDITest.java

Accessing an LDAP Directory from a web application
Write a set of web application components (JSPs and/or servlets) that allow the user to display all the LDAP attributes for a person in the LDAP directory shown below. The user should be able to search based on the person's name ("cn" attribute). To do this, you should create a DirContext and then perform a search operation on it. The LDAP directory to use is shown below: Host name: ldap.uts.edu.au Port: Base DN: 389 o=UTS

No username or password is required (anonymous login).

143

Module: JNDI
Tutorial - Looking up Weblogic LDAP
Weblogic has an embedded LDAP server which provides 2 services 1. A naming services for objects such as data sources and EJB's 2. A directory service for the security domains, such as the default admin userid

Viewing internal LDAP objects
• • •

Go to the Weblogic console: Choose Environment -> servers & select AdminServer Click on the "View JNDI Tree"

This will pop up a new window showing the existing JNDI objects. Notice that your thinOracleDataSource should appear here. Clicking on this would result in viewing the details such as the Binding Name (thinOracleDataSource), the actual class name (something like weblogic.jdbc.common.internal.rmiDataSource) and a ToString representation The neat thing about LDAP and JNDI is that you can bind any serializable Java object to the directory, so in theory, you could bind stuff like java.lang.String 's into the directory & so on.

Setting up Weblogic LDAP for external access
Normally Weblogic is setup not to allow external access to the embedded LDAP directory server - there is a randomly generated bind password and anonymous bind is turned off. We will change this to allow anonymous access.

To allow this, go into the weblogic console, Lock & Edit
144

• • • •

Go to Domain (ie: weblogic) -> Security tab -> Embedded LDAP. In the Credential field, enter a new admin password (eg: weblogic) & confirm Also select Anonymous Bind Allowed ** (not recommended for security reasons) You will have to restart the Weblogic server to update these changes

See managing the Embedded LDAP server (http://edocs.beasys.com/wls/docs100/secmanage/ldap.html) for information

Using the Weblogic Embedded LDAP directory server
Now you can use the weblogic embedded LDAP directory to view users in myrealm The parameters you need to use for LDAP are:
• • • • •

hostname: your weblogic server (if you are running this from charlie, you need to know your workstation host name) port: 7001 base dn: dc=domain (where domain is your weblogic domain). In our labs this is: dc=weblogic bind DN: cn=Admin (this is the -D option on ldapsearch) password: weblogic (you get prompted for this in ldapsearch. You could use the -w option to hard code this)

eg: ldapsearch -h workstation.it.uts.edu.au -p 7001 -D cn=Admin -w weblogic -b dc=weblogic (cn=weblogic) would return details about the user called weblogic You could also use the same information when you write JNDI Java programs. Just set the JNDI environment hashes Context.SECURITY_PRINCIPAL to "cn=Admin" & Context.SECURITY_CREDENTIALS to "weblogic" (or whatever your password is)

If you are using a jndi.properties file to hold this, the property keys are:
java.naming.security.principal=cn=Admin java.naming.security.credentials=weblogic

145

Module: EJB
Lab exercise - Stateless Session Bean - Manual technique
In this lab exercise, we create your first Enterprise JavaBean. It will be a stateless session bean. Level of Difficulty: 2 (moderately easy) Estimated time: 60 minutes Pre-requisites:
• •

Run wlenv to set your environment correctly Start your WebLogic server running in the background

Overview of EJB
146

Enterprise JavaBeans implement the business logic of a J2EE application. Each EJB, or "bean", is a component, i.e. it is treated as a single, logical entity that presents a public interface defining its methods that can be accessed. EJBs are deployed into an application server (in this context, also known as an "EJB container"). In our case, this is WebLogic. Note that WebLogic contains both a web server (for servlets/JSPs) and an application server (for EJBs). Logically they are separate, even though they are implemented in the same product. An application server contains a collection of EJBs. The application server provides a lot of support for the EJBs that it hosts. There are different kinds of EJBs. These are discussed in more detail in the lecture, but for now suffice to say that in this exercise we will be creating an EJB Session Bean. A session bean is a transient kind of EJB that is created when a client requests it, and is destroyed when the client is finished (i.e. it lasts for one "session"). To be more specific, we will be creating a Stateless Session Bean, which means that during a single session with a client, the bean does not maintain any internal state information. The basic model of a stateless session bean is that it is a component with a set of public business-logic methods, and the methods are all independent of each other. One method should not rely upon any other method having previously been called. In this example, the client of our EJB will be a servlet (the presentation tier calling methods on the business-logic tier).

Development Process
Just as there were many steps in developing an RMI application, there are also many steps in developing and deploying an EJB. It is important to follow the correct sequence of steps, as outlined below. 1. Create the Remote interface. The "Remote interface" is where you decide what kind of service(s) your EJB is going to offer to its clients. The remote interface is a Java interface that defines a set of method signatures that the EJB will implement, and that the clients can call. The remote interface defines your business logic methods. The remote interface is shared by both clients and the EJB implementation.
2. Create the Home interface. We have already seen the Remote interface which contains business logic methods. The "Home interface" of an EJB session bean contains methods for creating a new instance of the bean. Clients first obtain a reference to a bean's home interface, and from the home interface, can create one or more instances of the bean itself. 3. Create the EJB implementation class. Naturally you need to create a Java class which provides the implementation of your business-logic methods (and some others, as we will see). 4. Write the EJB deployment descriptor. Recall how web applications (in a WAR file) required an XML deployment descriptor? EJBs also require a deployment descriptor, that provides instructions to the EJB container as to how the EJB should be deployed.

147

5. Package the EJB into a JAR file. Web applications are packaged in WAR files. EJBs are packaged in JAR files. They are basically the same concept. 6. Generate stubs and skeletons. Next we use an "EJB compiler" tool that will take the JAR file created in the previous step, and will generate stubs and skeletons for the EJB, and will also compile all the Java source code. The EJB compiler will also check the syntax of your XML deployment descriptor. This is quite similar to running "rmic" (the RMI compiler) to generate stubs and skeletons when creating pure RMI applications, except now it is a different tool. 7. Deploy the EJB into an application server. The JAR file containing your EJB must be deployed before it can be invoked, in the same way as WAR files must be deployed before your servlets/JSPs can be invoked. 8. Create an EJB client - a servlet. You cannot directly run your EJB and see results immediately. First you need to create a client program that will invoke the business-logic methods on the EJB, and display some results. In this exercise, we will create a servlet as our EJB client, but note that the client could be a servlet, a JSP, a standalone Java application, or even another EJB. 9. Copy EJB stubs + home/remote interface classes to the WEB-INF/classes directory of your WAR file. Recall that in RMI, the client needed access to the Java classes for the interface and the stubs. The same is true for EJB - an EJB client must have access to these classes. In the case of a servlet client, that means we need to copy some of the EJB's class files into the servlet's WAR file. 10. Create the WAR file and deploy. This step is just the normal process of packaging and deploying a Java servlet.

Creating an EJB stateless session bean
Step 0 (Optional)- Using Eclipse/Workshop

You can use Eclipse to create the following files.
1. To do so, create a new EJB Project. 2. Create a new -> project -> , select Show All Wizards, type in EJB in the filter text & select EJB Project 3. Change the configuration from Weblogic EJB Project Facets to Custom & enter a project name 4. When in the Project Facets wizard, ensure Weblogic EJB Extension is not selected. Step 1 - Create the Remote interface

The Remote interface is a Java interface declaration, containing a list of methods (signature only) that you want your clients to be able to invoke. Create and compile the following Java source file.
package myapp; import java.rmi.*; import javax.ejb.*; public interface HelloWorld extends EJBObject {

148

public String hello(String name) throws RemoteException; }

Points to notice:
• • •

Clients will only be able to invoke one method on the server - the method is called hello(), and it takes 1 string argument and returns a String. The interface extends EJBObject (javax.ejb.EJBObject). All EJB remote interfaces must do this. The method declares that it may throw a RemoteException. All methods in a remote interface must declare this. A RemoteException may be thrown by the underlying infrastructure if anything goes wrong with the communication between the client and server. This is the same as for RMI. Although it is not clearly shown here, both the parameters and the return type of remote methods must be Java classes that implement the java.io.Serializable interface.

Step 2 - Create the Home interface

The Home interface is also a Java interface declaration, containing a list of methods (signature only) that your clients can invoke. However the home interface has a special function. Before clients can access the business-logic methods of your EJB (i.e. the ones defined on the Remote interface), they must first obtain a Home interface, and from the Home interface, create an instance of the EJB. Every EJB must have both a Home and a Remote interface. Create and compile the following Java source file.

package myapp; import java.rmi.*; import javax.ejb.*; public interface HelloWorldHome extends EJBHome { public HelloWorld create () throws RemoteException, CreateException; }

Points to notice:
• • • •

To create an instance of the EJB, clients will call a method named create() that takes no arguments, and returns an object whose type is that of the Remote interface. You could define more than one create method if you wish, as long as each one you define takes a different set of arguments. The interface extends EJBHome (javax.ejb.EJBHome). All EJB home interfaces must do this. The method declares that it may throw a RemoteException and/or a CreateException. All "create" methods in a home interface must declare this. Either of these exceptions may be thrown by the underlying infrastructure if anything goes wrong during the creating of the EJB.
149

Step 3 - Create the EJB implementation class

This is the class that actually implements the EJB methods. It must provide public method implementations for all methods defined in the Remote interface. It must also implement all the create methods defined on the Home interface (except they are renamed slightly to ejbCreate()). The EJB implementation class may define other methods, but only the ones listed in the remote interface can be invoked over the network by clients. Create and compile the following Java source file. If using Eclipse, you don't need to compile as this is done automatically.
package myapp; import javax.ejb.*; public class HelloWorldBean implements SessionBean { SessionContext sessionContext; // SessionBean methods public void setSessionContext (SessionContext sc) { this.sessionContext = sc; } // Argument list must match create() method // in HelloWorldHome interface public void ejbCreate() { } public void ejbRemove() { } public void ejbActivate() { } public void ejbPassivate() { }

// Now our business logic methods public String hello(String name) { return ("Hello, " + name); } }

Points to notice:

The class implements SessionBean (javax.ejb.SessionBean). All EJB session beans must do this. Notice though that this class does not implement the Remote interface we defined earlier. This is different to an RMI implementation class. The methods in the bean can be divided into two kinds: o standard session bean methods these include setSessionContext(), plus all the methods whose names start with ejb (ejbCreate(), ejbRemove(), ejbActivate(), ejbPassivate()). These methods are defined by the javax.ejb.SessionBean interface.

150

business logic methods these are the methods you you defined in your Remote interface. In this example there is only one. The EJB container (e.g. application server, i.e. WebLogic) will pass to us a SessionContext object. We store that object in case we later want to access some facilities of the EJB container itself.
o

Step 4 - Write the EJB deployment descriptor

Just like packaged web applications (WAR files) needed a deployment descriptor, so too do packaged EJBs. In fact, EJBs will need two deployment descriptors. One is a J2EE standard deployment descriptor that will be the same regardless of which application server you use (WebLogic, WebSphere, JBoss, etc). This one goes in a file called ejb-jar.xml. The other is a container-specific deployment descriptor - its syntax will be different depending on which product you use to deploy your EJB. This one goes in a file called weblogic-ejb-jar.xml. EJB deployment descriptors are placed into a subdirectory called META-INF. Note that this is different to the directory name you used for WAR files (which was WEB-INF). Create the following file as ejb-jar.xml in a subdirectory called META-INF.
<?xml version="1.0"?> <ejb-jar version="2.1" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd"> <enterprise-beans> <session> <ejb-name>HelloWorld</ejb-name> <home>myapp.HelloWorldHome</home> <remote>myapp.HelloWorld</remote> <ejb-class>myapp.HelloWorldBean</ejb-class> <session-type>Stateless</session-type> <transaction-type>Container</transaction-type> </session> </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>HelloWorld</ejb-name> <method-intf>Remote</method-intf> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar>

151

Secondly, create the following file as weblogic-ejb-jar.xml in the same META-INF directory as your other deployment descriptor.
<?xml version="1.0"?> <!DOCTYPE weblogic-ejb-jar PUBLIC "-//BEA Systems, Inc.//DTD WebLogic 8.1.0 EJB//EN" "http://www.bea.com/servers/wls810/dtd/weblogic-ejb-jar.dtd"> <weblogic-ejb-jar> <weblogic-enterprise-bean> <ejb-name>HelloWorld</ejb-name> <stateless-session-descriptor> <pool> <max-beans-in-free-pool>100</max-beans-in-free-pool> </pool> </stateless-session-descriptor> <jndi-name>ejb/HelloWorld</jndi-name> </weblogic-enterprise-bean> </weblogic-ejb-jar>

Step 5 - Package the EJB into a JAR file

EJBs are packaged in JAR files, which are created using the jar command. The syntax is exactly the same as when you created WAR files. If running Eclipse, you can do the following steps by using the Right Mouse Button -> Export -> EJB Jar file option. Before creating the JAR file, check that the files are in the correct directories. There is one directory for the Java package that the classes are in, and the other directory is META-INF.
/myapp - HelloWorld.class - HelloWorld.java - HelloWorldHome.class - HelloWorldHome.java - HelloWorldBean.class - HelloWorldBean.java / META-INF - ejb-jar.xml - weblogic-ejb-jar.xml

Run the jar command from this directory as follows:
jar cf ../HelloEJB.jar *

152

Step 6 - Generate stubs and skeletons

With RMI, you have to run a tool that generates stubs and skeletons for the RMI application. For EJB you also have to run a tool that generates stubs and skeletons, however it is a different tool. WebLogic uses a tool called appc. This tool takes either a JAR or EAR file as input. The syntax is as follows.
cd .. java weblogic.appc HelloEJB.jar

If you have errors in your JAR file (for example, incorrect directory structure, invalid syntax in the deployment descriptor), appc will usually alert you.

Step 7 - Deploy the EJB into an application server

The process of deploying an EJB is identical to deploying a web application. You just copy the JAR file into the "applications" subdirectory of your WebLogic installation.
cp HelloEJB.jar ~/weblogic/autodeploy

Watch the WebLogic server window to see if there were any errors during deployment. If the EJB was deployed successfully, you will find its name will appear in the JNDI tree of your WebLogic server. Open a management console, and go to "Servers", "myserver", then move to the "Monitoring" tab and choose "View JNDI tree". Your EJB name should appear with a purple dot next to it. This indicates that your EJB is advertising itself in the name service as being available to clients.

Step 8 - Copy EJB stubs + home/remote interface classes to the WEB-INF/classes directory of your WAR file

Just as with RMI, the "client" (in this case a servlet) needs access to the stub files generated by ejbc. Because the client is packaged separately from the EJB, the stubs need to be manually copied from the ejbc-generated output into the servlet's WAR file. Change directory into the WEB-INF/classes directory of your WAR file, and run the following JAR command that will extract the contents of the EJB JAR file into the WEB-INF/classes directory. This will make sure the compiled stubs and compiled home/remote interfaces are available to the client. Note that it will also make other, unnecessary, classes available to the client, but we ignore those now for simplicity.
cd WEB-INF/classes

153

jar xvf /mypath/HelloEJB.jar

You will need to change /mypath/ to represent the directory path of where you have placed your EJB JAR file. ! ALTERNATIVELY could just just copy the entire jar file into the WEB-INF/lib directory

Step 9 - Create an EJB client - a servlet

Here we will use a Java servlet as the client to our EJB. You should create your WAR file directory structure in a different place to where you created the JAR file for your EJB. The WAR file and the JAR file are completely independent. Create and compile the following Java source file.
import myapp.*; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import javax.naming.*; import javax.rmi.PortableRemoteObject; import java.util.*;

public class HelloWorldServlet extends HttpServlet { public void doGet (HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); out.println("----------------------------------------"); try { Context ctx = new InitialContext(); out.println("Got context"); HelloWorldHome hwsh; Object ref = ctx.lookup("ejb/HelloWorld"); hwsh = (HelloWorldHome) PortableRemoteObject.narrow( ref, HelloWorldHome.class); out.println("Got home interface"); HelloWorld hws = hwsh.create(); out.println("Created EJB"); out.println(hws.hello("chris")); } catch (Exception e) { e.printStackTrace(out); } out.println("----------------------------------------"); } }

154

Remember that the compiled servlet class must go in the WEB-INF/classes subdirectory. Also note that the servlet will not compile unless you have the directory "." (which means the current directory) in your CLASSPATH. The WebLogic setEnv.sh script does not automatically put "." in your CLASSPATH, so you may have to add it manually if you have not already. In a text editor, open the file ~/weblogic/bin/setDomainEnv.sh, and search for the line that starts "CLASSPATH=...". In this line, add "." to the list of directories. You could also equally place the EJB lookup & execution code (basically the entire trycatch block!) into a scriptlet in a JSP. This way you do not have to compile the servlet. Regarding the servlet code itself, notice the sequence of operations for the client: 1. Create an InitialContext so we can look up a name service, to find the EJB. No parameters are supplied when we create the InitialContext so we will use the name service supplied by the container (WebLogic), which is what we want in this case. 2. Look up the "JNDI name" of the EJB. Recall that when you created the EJB, you specified its JNDI name in the weblogic-ejb-jar.xml deployment descriptor. That is the name that we use here to perform the lookup. If the lookup is successful, we will be returned with a Java object of type HelloWorldHome - i.e. the EJB's Home interface. 3. Now that we have a reference to the Home interface, we can call the create() method which will give us a reference to the EJB itself (i.e. its Remote interface). 4. Finally, now that we have a reference to the EJB's Remote interface, we can call business logic methods of the EJB as defined on the Remote interface (in this case the method hello()). This may seem a slightly strange process. Just remember that first we obtain a reference to the EJB's Home interface, and from that we create an instance of the EJB which returns an instance of the EJB's Remote interface.

Step 10 - Create the WAR file and deploy

Now that you have created your servlet, and copied the stubs and interfaces so they are accessible to the servlet, you can create the WAR file for the servlet, and deploy it to WebLogic. The process is the same as you have used for creating and deploying WAR files in the past. Note that you will need to create a web.xml file in the WEB-INF directory for the servlet. There is nothing special about this web.xml file - it will be the same as you have created before. To deploy your WAR file, copy it to the "autodeploy" subdirectory of your WebLogic installation.

155

Running the HelloWorld EJB example
To test your application, open a web browser window, and enter the URL of your servlet into the Location field. If all goes well, your servlet will execute, and will make a remote method call to the EJB that is executing in the application server.

Next step ...
Now that you have followed a step-by-step walkthrough, the next step is to be a bit more independent. Modify the example above to include a new remote method that will add together two integers (i.e. it takes two integer arguments, and returns an integer result). This will involve changing the remote interface, and then re-running all the subsequent steps.

Module: EJB
Lab exercise - Using Eclipse + Xdoclet to generate EJB
In this lab exercise, you will use Eclipse + Xdoclet to create an Enterprise JavaBean. Level of Difficulty: 2 (moderately easy) Estimated time: 60 minutes Pre-requisites:
• •

Run wlenv to set your environment correctly Start your WebLogic server running in the background

Rapid code development
One of the biggest complaints about Enterprise JavaBeans as implemented by the J2EE specification is the complexity of generating what seems like fairly straight forward business component development.

156

This issue resulted in the development of competing frameworks such as Spring MVC, Object-Relational Mapping systems such as Hibernate and Java Data Objects, where developers bypass the whole EJB infrastructure entirely. Sun recognised this by creating 2 new standards - the Java Persistence API (which front ends ORM systems such as Hibernate) and the EJB 3.0 specification (which uses Java 5 annotations to 'tag' classes and methods as Enterprise Java Beans) Using EJB 3.0 would be a simpler technique than using EJB 2.1, however, this is not implemented in the J2EE 1.4 specification and is a fundamental part of Java Enterprise Edition 5. Most Java application servers &/or tooling are not yet fully certified at the Java EE 5 spec, so we will concentrate on EJB 2.1 coding. One technique similar to EJB 3.0 is to use Java 5 annotations or Javadoc-style annotations in our code and let code generators create most of the tedious steps required to generate EJB's. In our environment, there are 2 main ways to do this 1. Use the proprietary WebLogic workshop "ejbgen" tool. 2. Use the open source (and popular) Xdoclet tool

Using Weblogic Workshop EJBgen
See the tutorial called "Using EJBGen"

Using Eclipse & XDoclet
Xdoclet ( http://xdoclet.sourceforge.net ) is an open source product designed to remove most of the tedium when developing EJB's. The original product was called ejbdoclet but this tool is now generic and supports many other technologies such as Servlets, Hibernate, Spring & so on and has large support for major Application server vendors such as IBM and BEA WebLogic. XDoclet is designed to be run using Apache ANT, a Java 'make' tool. You normally create a build.xml file with various XDoclet specific 'tasks'. You then create Plain Old Java Object (POJO) classes which implement the business logic. You don't need to create tonnes of extra class files and deployment descriptors, everything is in one source file!! Using Eclipse Web Tools Project reduces the workload significantly further by providing templates and wizards to generate more code. Use the following steps to re-create the previous stateless session bean lab.

157

Step 1: Create the project and settings for Xdoclet development

Create a new EJB project by: new -> select Show All Wizards, , type EJB in the filter text & select EJB Project

In the New EJB Project wizard: enter project name (HelloEJB), & change Configurations (EJB Project with XDoclet)

158

[Next] On the Project Facets wizard, ensure EJBDoclet (Xdoclet) selected & version 1.2.3 (use dropdown on 1.2.3 to get this)

159

[FINISH] You now need to set up the project's XDoclet settings From the project menu, Right Mouse Button -> Properties -> Xdoclet -> ejbdoclet -> select weblogic

160

This will ensure that the Xdoclet generator will execute the weblogic specific tasks. Note that if you are using, say, JBoss, you would also select the JBoss task to generate the JBoss specific deployment descriptors.

Step 2 - Create a new Session Bean
First step is to create a package. Use New -> Package & call the package myapp To create a new EJB, select: New -> Xdoclet Enterprise JavaBean (or you may have to use New -> Other -> EJB -> Xdoclet Enterprise JavaBean) If you get a message "Annotation provider definition is not valid", please select the preferences link

161

You will need to set up Xdoclet provider preferences:
• • •

Make sure Enable xdoclet builder is checked. Xdoclet Home: /pub/ajpcpe/xdoclet, Select version: 1.2.3

You will also have to check the XDoclet settings AGAIN! (this is a known bug in the XDoclet wizard)
• •

Expand the Xdoclet menu on the left & select the ejbdoclet preferences. Ensure the Weblogic task is ticked (you can also select other tasks if you are using nonweblogic application servers such as JBoss)

162

Once you do this step, you should not have to do this again for any further Enterprise Java Bean creation.
Creating the bean

After the previous setup set has been completed, you should be back to Create Enterprise Java Bean wizard.
• •

Ensure Session Bean is selected & press [NEXT] Select or enter a package name eg: myapp Add a class name eg: HelloBean. Leave superclass as Object. & press [NEXT] The next window will display some more parameters for the EJB. Adjust EJB name, description, & display name as necessary. ** IMPORTANT ** Make the JNDI name ejb/Hello (you could leave this as the default, but the standard is to have the ejb beans under the ejb subcontext) Leave State Type = Stateless & Transaction Type: Container Press [FINISH] to build your EJB

163

You should then see the HelloBean.java file in the code editor and some messages in the console about Xdoclet. It runs through various stages such as Init, Ejbdoclet. This is actually generating all the class files and deployment descriptors. Note: if you don't see the "Running <weblogic/>" Generating weblogic-ejb-jar.xml message, you have failed to follow the Weblogic task setup above.

Step 3: Enhancing the Enterprise JavaBean
f you look in the ejbModule folder of your EJB project, you should see in the myapp package the following files
Hello.java HelloBean.java HelloHome.java HelloLocal.java HelloLocalHome.java HelloUtil.java
REMOTE interface Hello IMPLEMENTATION HOME interface LOCAL interface LOCALHOME interface Utility class EJBObject = declarations SessionBean + business methods EJBHome EJBLocalObject = declarations EJBLocalHome helper class eg: getHome()

We will only change HelloBean.java. Everything else is Generated!! To add business methods, edit the HelloBean source file class with the business method like in the session bean lab. Look for the automatically generated method called foo Notice that there is a special javadoc tag in front called @ejn.interface-method viewtype="remote"
/** * * <!-- begin-xdoclet-definition --> * @ejb.interface-method view-type="remote" * <!-- end-xdoclet-definition --> * @generated * * //TODO: Must provide implementation for bean method stub */ public String foo(String param) { return null; }

164

These tags are what XDoclet uses to generate code with. By default, this means XDoclet will generate a declaration of this method (foo()) in the Remote interface. If you change the view-type from remote to both then XDoclet will generate the business method into both the remote and local interfaces. For our exercise, let's change this method to the same as the stateless session lab:
/** * * <!-- begin-xdoclet-definition --> * @ejb.interface-method view-type="both" * <!-- end-xdoclet-definition --> * @generated * */ public String hello(String name) { return ("Hello, " + name); }

Notice that when you change any code in this file, XDoclet will automatically re-build the files.

To stop this behaviour, you need to click on the main toolbar, select Project & de-select Build Automatically. However, be careful, since you will need to build manually if you don't build automatically. Do this via the RMB -> Run XDoclet command.

Step 4: Deploy the bean
There are 4 main ways to do this (assuming the server is running)

(1) From Workshop, right click on the Server (BEA Weblogic Server v10.0 @ localhost) in the Servers view and click "add and remove projects". You then choose the EJB and select Add & [finish] This deploys the bean on the server (2) You can Export the bean to a Jar file. Select the EJB project, RMB -> Export -> Export as EJB Jar file. Copy the resultant JAR file into the weblogic/autodeploy directory (3) From the weblogic console, use the [Lock & Edit] & choose Deployment -> Install option to upload the JAR file from step 2. (4) You can create an EAR project file which has project dependencies on it (containing the lab Web project & the EJB project) You then use step 1 to add the EAR project to weblogic -OR- use Export -> Export as EAR file. This EAR file can then be deployed by copying to the weblogic/autodeploy directory or via the Weblogic console Deployments - install option

Step 5: Creating the client:
165

This is pretty much the same steps as the Stateless Session Bean lab. Let's use a JSP to test this EJB. You need to create a JSP into an existing Dynamic Web project with the following code in it.
<%@page import="myapp.*, javax.naming.*, javax.rmi.*" %> <% Context ctx = new InitialContext(); String jndi_name = "ejb/Hello"; out.println("Got context"); HelloHome hwsh; out.println("Looking for JNDI name " + jndi_name); Object ref = ctx.lookup(jndi_name); hwsh = (HelloHome) PortableRemoteObject.narrow( ref, HelloHome.class); out.println("Got home interface"); Hello hws = hwsh.create(); out.println("Created EJB"); out.println(hws.hello("mate")); %>

A Better way - using the XDoclet xxxutil class
XDoclet generates a utility class called bean_nameUtil.java to make your life easier. This provides a method called getHome() which replaces all the context lookups etc. This code implements a "Service Locator" pattern and can even cache the bean lookups to make your code very efficient.
<% HelloHome h = HelloUtil.getHome(); Hello bean = h.create(); out.println(bean.hello("mate")); %>

A lot simpler eh? Your client code will need to have access to the myapp.Hello & myapp.HelloHome classes. You have 2 options: (1) copy the EJB jar file exported earlier (helloEJB.jar) to WebContent->WEB-INF->lib (The problem with this solution is that you need to update the jar whenever you change the EJB) (2) Set your Dynamic Web Project to have a "J2EE Dependency". You select your Web project (eg: lab) & RMB-> Properties, J2EE Modules Dependencies -> Select (helloejb) Jar module]
166

This will result in the .jar file being placed into the WEB-INF/lib directory at deployment time automatically!!

Note: Normally you only need the Hello, HelloHome (& helloUtil) (& maybe the HelloLocal* equivalents) classes, but we will be lazy and import the whole lot.

Step 6: Running the client
Run as usual. (select the web project , RMB -> Run As -> Run on Server). Normally most changes will get automatically deployed, as long as there is a dependency between the web project and the EJB project. Note: when you look at the web project on the server view, you now see a + symbol next to the web project. Expanding this shows the EJB bean jar

Problems you may encounter
You may need to re-deploy the EJB if you make any changes to the signatures of the bean methods or add new beans into the EJB project. Sometimes you Workshop does not correctly re-deploy changes into the dependent J2EE projects (such as your Web project). To fix this, re-do step 4 above.

Next step ...
Now that you have followed a step-by-step walkthrough, the next step is to be a bit more independent. Modify the example above to include a new remote method that will add together two integers (i.e. it takes two integer arguments, and returns an integer result). This will involve changing the remote interface, and then re-running all the subsequent steps.

167

Module: EJB
Lab exercise - CMP Entity Bean- manually
In this lab exercise, we create an Entity EJB that uses Container Managed Persistence (CMP). Level of Difficulty: 4 (moderately difficult) Estimated time: 90 minutes Pre-requisites:
• • •

Run 'wlenv' to set your environment correctly Start your WebLogic server running in the background Completed Stateless Session Bean exercise

Overview of Entity Beans
In the last exercise, you successfully created a stateless session bean. Recall that session beans are transient beans created to perform some task on behalf of a client. However the goal of this exercise is to create an entity bean. Entity beans represent data in the application. Each instance of an entity bean corresponds to an individual instance of an entity. So for example, if your application has an entity bean called 'Person', and your application knows about 2 people, Mary and Joe, you will have two instances of the Person entity bean. Entity beans must be persistent. That means that an entity bean must survive even if the application server is shut down or crashes. This implies that the data associated with an entity bean must be stored permanently, either in a database, or in a file on disk, or using some other form of persistent storage. Commonly, entity beans map to database records. In a simple example, one entity bean corresponds to one row in a relational database table. There are two ways to implement the persistence requirement of entity beans. One way is to use a relational database for the persistent storage of entity data, and let the container (application server) manage the mapping between attributes in your entity bean and columns in the database table. This is called Container Managed Persistence (CMP). The other alternative is to write the Java code to save and load the entity bean data yourself. This is called Bean Managed Persistence (BMP). CMP is easier to implement (less code to write), but it can only be used in very simple cases. BMP is the more general kind of entity bean, but requires more programming effort. Also note that we will focus entirely on EJB 2.0. Many books and examples on the web may use EJB 1.1. One of the main areas of difference between these versions of the EJB standard is the handling of CMP entity beans. Be careful that you only follow instructions for EJB 2.0!
168

Development Process
The development process for an entity bean is almost identical to that of creating a session bean. The steps are listed below as a reminder, and the differences between session and entity beans noted. 1. Create the Remote interface.
2. Create the Home interface. Provide a create() method if you want users to be able to create new entities (add a new row to the database). Provide a remove() method if you want users to be able to permanently remove entities (delete a row from the database). Provide one or more findXXX() methods, including the mandatory findByPrimaryKey() method. 3. Create the EJB implementation class. You will need to declare abstract get/set methods for each of the CMP fields your bean will use. 4. Write the EJB deployment descriptor. In addition to the ejb-jar.xml and weblogic-ejb-jar.xml deployment descriptors, you will also need to create a third deployment descriptor file for a CMP bean, typically called weblogiccmp-rdbms-jar.xml. 5. Package the EJB into a JAR file. 6. Generate stubs and skeletons. 7. Deploy the EJB into an application server. 8. Create an EJB client for testing - a session bean. Servlets/JSPs should not invoke methods on an entity bean directly, but rather should access entities via session beans. This means that the client of an entity bean should always be a session bean.

Creating an EJB CMP Entity bean

Step 0 - Check your database table

This example assumes that you have an Oracle database table called addressbook as described in the earlier JDBC exercises. If you do not have this table, you will need to create it before continuing.

Step 1 - Create the Remote interface

Create and compile the following Java source file.
package addressbook; import java.rmi.*; import javax.ejb.*; public interface Person extends EJBObject {

169

String summary() throws RemoteException; }

Points to notice:

Here we define one business logic method in addition to the methods that will be used to access the fields of the addressbook (name, address, etc).

Step 2 - Create the Home interface

Create and compile the following Java source file.
package addressbook; import java.rmi.*; import javax.ejb.*; import java.util.Collection; public interface PersonHome extends EJBHome { public Person create (String name, String address, String email, String extn, String birthday) throws RemoteException, CreateException; public Person findByPrimaryKey (String name) throws RemoteException, FinderException; public Collection findByEmail (String email) throws RemoteException, FinderException; }

Points to notice:
• •

We allow clients to create new addressbook entries, but we do not allow them to delete any entries (there is no remove() method defined). We allow clients to search for a person in two ways: by name (the primary key), in which case the finder method returns an instance of the Person object, or by email, in which case the finder method returns a java.util.Collection of primary keys that represent the records that match the search criteria.

Step 3 - Create the EJB implementation class

Create and compile the following Java source file.
package addressbook; import javax.ejb.*; public abstract class PersonBean implements EntityBean { private EntityContext entityContext;

170

// EntityBean methods public void setEntityContext (EntityContext ec) { this.entityContext = ec; } public void unsetEntityContext () { this.entityContext = null; } // Argument list must match create() method // in PersonHome interface public String ejbCreate(String name, String address, String email, String extn, String birthday) throws CreateException { setName(name); setAddress(address); setEmail(email); setExtn(extn); setBirthday(birthday); return null; } public void ejbPostCreate(String name, String address, String email, String extn, String birthday) throws CreateException {} public void ejbRemove() throws RemoveException { } public void ejbActivate() { } public void ejbPassivate() { } public void ejbLoad() { } public void ejbStore() { }

// Now the abstract methods for CMP fields abstract public String getName(); abstract public void setName(String name); abstract public String getAddress(); abstract public void setAddress(String address); abstract public String getEmail(); abstract public void setEmail(String email); abstract public String getExtn(); abstract public void setExtn(String extn); abstract public String getBirthday(); abstract public void setBirthday(String birthday);

// Now our business logic methods public String summary() {

171

String result = getName() + " " + getExtn() + "\n"; return (result); } }

Points to notice:
• • • •

• • •

The class implements EntityBean, not SessionBean. The class has methods setEntityContext() and unsetEntityContext(). The parameter list of ejbCreate() must match the parameter list defined in the Home interface. The ejbCreate() method returns the type of the primary key, but when it actually returns at the end of the function, it returns a null value. Note that the type is different to what is returned by the create() method in the Home interface (the one that the client calls). The create() method on the home interface returns the type of the EJB remote interface (i.e. the EJB type). It seems strange that ejbCreate() returns a different type of value to create(), but it is the correct way to do it, according to the EJB specification! There is now a method called ejbPostCreate() with the same parameter list. ejbPostCreate() is called by the container after the successful creation of a new entity bean. There are abstract method declarations for each of the CMP fields. The whole class itself is also declared abstract because of the abstract methods.

Step 4 - Write the EJB deployment descriptor

Now there are three deployment descriptors. Create the following file as ejb-jar.xml in a subdirectory called META-INF.
<?xml version="1.0"?> <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd"> <ejb-jar> <enterprise-beans> <entity> <ejb-name>Person</ejb-name> <home>addressbook.PersonHome</home> <remote>addressbook.Person</remote> <ejb-class>addressbook.PersonBean</ejb-class> <persistence-type>Container</persistence-type> <prim-key-class>java.lang.String</prim-key-class> <reentrant>False</reentrant> <cmp-version>2.x</cmp-version> <abstract-schema-name>PersonBean</abstract-schema-name> <cmp-field> <field-name>name</field-name> </cmp-field> <cmp-field> <field-name>address</field-name> </cmp-field>

172

<cmp-field> <field-name>email</field-name> </cmp-field> <cmp-field> <field-name>extn</field-name> </cmp-field> <cmp-field> <field-name>birthday</field-name> </cmp-field> <primkey-field>name</primkey-field> <query> <query-method> <method-name>findByEmail</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </query-method> <ejb-ql> <![CDATA[SELECT OBJECT(p) FROM PersonBean AS p WHERE p.email = ?1]]> </ejb-ql> </query> </entity> </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>Person</ejb-name> <method-intf>Remote</method-intf> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor> </ejb-jar>

Secondly, create the following file as weblogic-ejb-jar.xml in the same META-INF directory as your other deployment descriptor.
<?xml version="1.0"?> <!DOCTYPE weblogic-ejb-jar PUBLIC "-//BEA Systems, Inc.//DTD WebLogic 6.0.0 EJB//EN" "http://www.bea.com/servers/wls600/dtd/weblogic-ejb-jar.dtd" >

<weblogic-ejb-jar> <weblogic-enterprise-bean> <ejb-name>Person</ejb-name> <entity-descriptor> <entity-cache> <max-beans-in-cache>1000</max-beans-in-cache> </entity-cache> <persistence> <persistence-type> <type-identifier>WebLogic_CMP_RDBMS</type-identifier>

173

<type-version>6.0</type-version> <type-storage> META-INF/weblogic-cmp-rdbms-jar.xml </type-storage> </persistence-type> <persistence-use> <type-identifier>WebLogic_CMP_RDBMS</type-identifier> <type-version>6.0</type-version> </persistence-use> </persistence> </entity-descriptor> <jndi-name>ejb/Person</jndi-name> </weblogic-enterprise-bean> </weblogic-ejb-jar>

Finally, create the following file as weblogic-cmp-rdbms-jar.xml in the same META-INF directory as your other deployment descriptors.
<?xml version="1.0"?> <!DOCTYPE weblogic-rdbms-jar PUBLIC '-//BEA Systems, Inc.//DTD WebLogic 6.0.0 EJB RDBMS Persistence//EN' 'http://www.bea.com/servers/wls600/dtd/weblogic-rdbms20-persistence-600.dtd'> <weblogic-rdbms-jar> <weblogic-rdbms-bean> <ejb-name>Person</ejb-name> <data-source-name>thinOracleDataSource</data-source-name> <table-name>addressbook</table-name> <field-map> <cmp-field>name</cmp-field> <dbms-column>name</dbms-column> </field-map> <field-map> <cmp-field>address</cmp-field> <dbms-column>address</dbms-column> </field-map> <field-map> <cmp-field>email</cmp-field> <dbms-column>email</dbms-column> </field-map> <field-map> <cmp-field>extn</cmp-field> <dbms-column>extn</dbms-column> </field-map> <field-map> <cmp-field>birthday</cmp-field> <dbms-column>birthday</dbms-column> </field-map> </weblogic-rdbms-bean> </weblogic-rdbms-jar>

Also notice that this XML file refers to details relating to the database. In particular, the table name, and the field names.
174

It also refers to the Data Source that the EJB should use for connecting. The XML file above assumes that you already have a data source created in your WebLogic management console called thinOracleDataSource. If you do not already have this data source, you must create it before trying to deploy or use this EJB.

Remainder ...

The remainder of the steps are the same as for creating a stateless session bean. Before you attempt to deploy your Person EJB, be sure to use the WebLogic management console to set up a JDBC Data Source, and associated Connection Pool. Refer to the JDBC notes to recall how. For now, you can use a servlet as a test client for the entity bean (although in a real application, servlets generally would not call an entity bean directly). If you reuse your servlet from the stateless session bean exercise, you will need to change the following points:
• • • •

the import statement, to specify the correct package name; the class names; the JNDI name to look up - it should match the JNDI name specified in the weblogicejb-jar.xml file; the home interface method used to get a reference to the EJB. In a session bean, the client calls the create() method. In an entity bean, the client probably needs to call the findByPrimaryKey() method with the right type of argument, or another "finder" method. Recall that with entity beans, calling create() will actually add a row to the database; the business logic method (the remote interface method).

Refer to the course notes, the EJB 2.0 specification from Sun Microsystems, and the API documentation for assistance.

Module: EJB
175

Lab exercise - CMP Entity Bean-using Eclipse + XDoclet
In this lab exercise, we create an Entity EJB that uses Container Managed Persistence (CMP). Level of Difficulty: 4 (moderately difficult) Estimated time: 90 minutes Pre-requisites:
• • • •

Run 'wlenv' to set your environment correctly Start your WebLogic server running in the background Completed Stateless Session Bean exercise Complete the Entity Bean exercise

Entity Beans using XDoclet
Unlike the previous exercise, we will use Eclipse WTP and XDoclet to generate most of the code you need to write an entity bean. Even though XDoclet can make writing Entity beans easier, it is still a tedious process to write and annotate a JavaBean which represents your table row.

Development Process
The good news for using rapid development tools is that Eclipse can read your database tables and generate an appropriate xxxBean class with most of the common attributes and annotations pre-set for you. Once we have our xxxBean class generated, we then tailor the class to modify the datasource name, add getData() if you want to use the XDoclet generated value objects, add business methods, add finders and any other customisations that might be needed.

Creating an EJB CMP Entity bean
Check your database table

This example assumes that you have an Oracle database table called addressbook as described in the earlier JDBC exercises. If you do not have this table, you will need to create it before continuing.
Creating the Container Managed Bean

Assuming we are using the existing EJB project, create a new bean by using New -> EJB -> Xdoclet Enterprise Bean * Select Container Managed Bean [Next] * Select the package (myapp), & name "AddressBookBean" [Next]
176

* On the CMP Entity Bean wizard, change the name of the generated Schema from AddressBookSCHEMA to AddressBook & you can choose "usecase:" Import Attributes from table (or you can "Define new Attributes" if you want to do the next part by hand!). (leave the default for the moment)

* Now choose the JDBC Connection that you set up in the Oracle Lab. This would have been called "ell" [Next]

* Assuming that you can connect (or reconnect if prompted with your Oracle userid and password), you can choose the your addressbook table in the CMP Attributes Wizard in the following Step * Select the dropdown in the Table field. You will need to type in your fully qualified table name (normally your oracleuserid.addressbook) to get the correct table name. (I think there is a bug in Eclipse WTP 1.5 which lists ALL the tables in the oracle database, hence the need to filter it down to your own schema)

177

This should result in the list of columns you defined in the JDBC lab, eg:

[FINISH] when complete.

* Note that XDoclet will run and will create many files, hopefully including the weblogicejb-jar.xml & weblogic-cmp-rdbms-jar.xml deployment descriptors. If these don't appear, you should check your XDoclet preferences to ensure that weblogic was selected as a checked task. The files generated should be: AddressBook.java (remote Interface) AddressBookBean.java (The main IMPLEMENTATION) AddressBookCMP.java AddressBookData.java (a Data Transfer/value object/javabean) AddressBookHome.java (home interface) AddressBookLocal.java AddressBookLocalHome.java AddressBookUtil.java (utility classes - in particular, getHome() )

You will need to edit the AddressBookBean.java file to change the various Xdoclet attributes.

For weblogic deployments, you need to change the line with:
178

* @weblogic.data-source-name ${data.source.name} * <!-- end-xdoclet-definition --> * @generated

to
* @weblogic.data-source-name thinOracleDataSource * * @generated

When you save, this should automatically restart xdoclet. Just to check, edit the META-INF/weblogic-cmp-rdbms-jar.xml file to see the data-sourcename is thinkOracleDataSource and that the correct table name is there.

Look at the generated code.

Note that AddressBook is just like an ordinary JavaBean with getters/setters for the properties of an addressbook bean AddressBookBean is similar, except for bean management methods such as ejbCreate(), ejbLoad(), ejbRemove(), ejbStore() & so on. Note that the generator has created a @ejb.finder called findAll() which basically dumps the whole table! AddressBookCMP extends AddressBookBean and adds the method getData(), which is used to obtain the AddressBookData value object. AddressBookData is just a plain old Javabean. However, note that there are 2 methods generated for you - equals() and hashCode(). These are useful if you have a Collection of AddressBookData (especially Sets) or just want to compare beans by content (rather than by reference!) AddressBookHome & AddressBookLocalHome classes contain the methods used to find beans such as findByPrimaryKey() & findAll() as well as the usual create() method. Finally, AddressBookUtil contains utility methods, of which only the getHome() & getLocalHome() methods are useful. You can update AddressBookBean to add any extra business methods you wish. Xdoclet will automatically run when you save these edits.

Creating a custom ejbCreate() method.
* When editing AddressBookBean you will notice that there is a TODO task on the ejbCreate() method code. * It is highly recommended that you COPY this entire create method by adding parameters to populate the fields & leave the default null ejbCreate() method alone. * Add the following code AFTER the existing ejbCreate() method. Note that it is ESSENTIAL to keep the comments in the right spot (ie: before the Javadoc comment before ejbPostCreate()
179

/** * * <!-- begin-user-doc --> * The ejbCreate method. * <!-- end-user-doc --> * * <!-- begin-xdoclet-definition --> * @ejb.create-method * <!-- end-xdoclet-definition --> * @generated */ public java.lang.String ejbCreate( String name, String address, String email, java.math.BigDecimal extn, java.sql.Date birthday ) throws javax.ejb.CreateException { // begin-user-code setName(name); setAddress(address); setEmail(email); setExtn(extn); setBirthday(birthday); // EJB 2.0 spec says return null for CMP ejbCreate methods. return null; // end-user-code }

You could optionally also create yet another ejbCreate() method passing an AddressBookData object as the parameter (since this is the Value Object representing AddressBook objects). This is necessary since when you create an entity bean, you are actually performing an INSERT into TABLE VALUES(... ). Since you need to have the values populated before you can insert into the table, you have to somehow pass the values to the ejbCreate() method!!!!

Creating Other methods in AddressBookBean

You can also add business methods like you did with the Session bean to AddressBean. However, these should be closely related to the purpose of the Entity Bean - related to the business data!!! Add the following to allow you to automatically obtain a JavaBean (AddressBookData) which you can treat as a Data Transfer Object instead of passing tonnes of parameters to various business methods.
/** * Provides access to the generated getData() method of the generated * CMP class. * @ejb.interface-method */ public abstract AddressBookData getData();

180

A very useful debugging method to add is print()
/** * print of a string version of the entity bean * @ejb.interface-method view-type="both" * */ public String print() { return "Name=" + getName() + ",Address=" + getAddress() + ",Email=" + getEmail() + ",Extn=" + getExtn() ",Birthday=" + getBirthday(); }

* Xdoclet should automatically run and re-generate the java files & deployment descriptors. If not, select EJB project & RMB -> Run Xdoclet * Do note that AddressBook.java also lists these 2 methods - getData() & print(). * Finally, the AddressBookData.java bean does not list any of the business methods we just defined (print()). This is because the sole purpose of AddressBookData is to encapsulate data, not business logic. (do note that it does provide a toString() method, which looks very much like our print() method!!)

Deploying it
Since you added this entity bean into the existing helloEJB lab, your bean will be automatically deployed and updated when you run the lab web project. Otherwise, follow the same instructions for session beans * Note: when you update an EJB lab in Workshop, this is rebuilt but not automatically redeployed dynamically. You need to use Run As -> Run on Server on the DEPENDENT web project to force the redeployment. * Note: If there are any problems deploying, sometimes it is best to select the server, RMB -> Add and Remove Projects then to remove the EJB project, and re-add it * Note: if you get a warning about "The web project build path contains classes or jars which are not inside the standard <WebAppRoot>/WEB-INF/classes, you can safely ignore this message since we are using Weblogic Shared Libraries.

Client code.
Your code will look similar to the session Bean exercise except now you can deal with the create(), findByPrimaryKey() & findAll() methods Here is a sample code which looks up a row in the table by primary key (the name field)
<h1>This searchs AddressBook CMP by name</h1> <%

181

AddressBookHome h = AddressBookUtil.getHome(); AddressBook bean = h.findByPrimaryKey("chris"); // does a select %> <ol> <li>Name=<%=bean.getName() %> <li>Address=<%=bean.getAddress() %> <li>Email=<%=bean.getEmail() %> <li>Extn=<%=bean.getExtn() %> <li>Birthday=<%=bean.getBirthday() %> </ol>

It is not good practice to call the Entity bean directly to retrieve the table columns. The better way is to use a Value Object - AddressBookData is appropriate and pre-generated for you. So you should add AddressBookData ab = bean.getData(); & thence refer to this object instead of bean (ie: ab.getName() ) etc. AddressBookData is an ideal object to pass to your JSP and to save in your sessions as an attribute. It can be accessed quite nicely via the JSL EL. Here is a sample code which creates a new row in the database
<% AddressBookHome h = AddressBookUtil.getHome(); try { AddressBook bean = h.create("sam", "Sydney", "sam@uts.edu.au", java.math.BigDecimal.valueOf(1234L), java.sql.Date.valueOf("1990-07-01") ); out.println("Bean created"); out.println("key=" + bean.getName()); } catch (Exception e) { out.println("<b>ERROR: "); out.println(e.getMessage()); // return to JSP e.printStackTrace(); // debug to console }

And here is a sample which lists all records in the database
<% AddressBookHome h = AddressBookUtil.getHome(); AddressBook bean; java.util.Collection list = h.findAll(); // does a select * for (Object i : list) { bean = (AddressBook) i; %> <ol> <li>Name=<%=bean.getName() %> <li>Address=<%=bean.getAddress() %> <li>Email=<%=bean.getEmail() %> <li>Extn=<%=bean.getExtn() %> <li>Birthday=<%=bean.getBirthday() %> </ol> <% } %>

182

More things to do
You can add your own custom Finders, which will be automatically generated for you Edit the AddressBookBean & locate the xdoclet comment that starts with @ejb.finder You can create your own query by adding the following line after it
* @ejb.finder * query="SELECT OBJECT(a) FROM AddressBook as a WHERE a.email like ?1" * signature="java.util.Collection findByEmail(java.lang.String email)" *

Deploy as usual. Create a JSP which uses the above method.

Facade patterns
It's best practice not to have entity beans called in a JSP. This is for both seperation of concerns and the violation of the MVC pattern. The better way is to have a Session bean acting as a facade in front of the entity bean. This allows us to both unit test, seperate the database code from the presentation code and improve efficiency. The simplest way to do this is to just add code to the facade which invokes the entity bean! (much like what you used for a servlet/jsp) Here's an example. In the earlier Session Bean EJB, create a new xdoclet method with the following signature
/** * * <!-- begin-xdoclet-definition --> * @ejb.interface-method view-type="both" * <!-- end-xdoclet-definition --> * @generated * */ public String facade(String param) { try { AddressBookHome h = AddressBookUtil.getHome(); AddressBook bean = h.findByPrimaryKey(param); return bean.print(); } catch (Exception e){ return (e.getMessage()); } }

I'm assuming that the session bean and entity bean are in the same EJB project here. Then to call it just use the session bean as normal (ctx.lookup etc) but call bean.facade() instead to invoke the entity bean via the session bean.
183

What's neat is that the JSP has no idea that they are calling a database lookup. The session bean could actually just cache beans that have already been read. An even better pattern is to use a "Business Delegate" pattern and hide the session bean from the JSP as well. This is just a POJO which hides all references to EJB's (eg: caches the lookup, etc) from the caller. Essentially this is just moving any reference to JNDI, lookups, PortableRemoteObject.narrow(), Home & Bean methods etc into a seperate class &/or method...

What if the EJB's are in seperate projects?
You have to create EJB references in the session bean. This normally exists in the ejb-jar.xml and weblogic-ejb-jar.xml files, but Xdoclet makes this easy to setup. Edit the sessionBean source code and use the @ejb.ejb-ref and @weblogic.ejb-referencedescription tags, for example, in HelloBean.java:
* @ejb.ejb-ref * ejb-name="AddressBook" * * @weblogic.ejb-reference-description * jndi-name="ejb/AddressBook" * ejb-ref-name="ejb/AddressBook" *

This will update the ejb-jar.xml and weblogic-ejb-jar.xml deployment descriptor files with the required references

Refer to the course notes, the EJB 2.0 specification from Sun Microsystems, and the API documentation for assistance.

Module: EJB
Creating EAR files for deployment
An EAR file is an Enterprise Archive. It is used to deploy a whole enterprise application, which may include web components (servlets, JSPs) and EJB components, in a single file.
• •

WAR files - contain web files (servlets, JSP, HTML, images, etc) JAR files - contain EJBs 184

EAR files - contain embedded WAR and JAR files

Directory structure
Like any Java archive, a particular directory structure is necessary, and a new deployment descriptor file - application.xml. The correct directory structure for an EAR file would look like:
- MyEJBs.jar - MyWebApp.war / META-INF - application.xml

application.xml deployment descriptor
The application.xml deployment descriptor is not very complex. Basically, it defines:
• • •

the names of the JAR and WAR files inside your application the root path of the web tree where your web application files should be placed under declaration of any security roles that are global to the whole application

An example is shown below:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE application PUBLIC '-//Sun Microsystems, Inc.//DTD J2EE Application 1.2//EN' 'http://java.sun.com/j2ee/dtds/application_1_2.dtd'> <application> <display-name>Transactional Application Test</display-name> <module> <web> <web-uri>MyWebApp.war</web-uri> <context-root>mywebapp</context-root> </web> </module> <module> <ejb>MyEJBs.jar</ejb> </module> <security-role> <role-name>supplier</role-name> </security-role> </application>

185

Notes about EAR files (and why they are good)
Imagine a simple application that contains one servlet (or JSP) in a WAR file and one stateless session EJB in a JAR file. When you deploy these separately, recall that you had to deploy the EJB first, and then take the stubs and skeleton files that were generated by compiling the EJB, and include a copy of these stubs and skeletons in your WAR file, so the servlet could access them. Obviously it is generally not desirable to have two copies of the same files in two different places (WAR and JAR) if possible, but with separate deployment, it was the only option. One of the main advantages of deploying an application as an EAR file is that this redundancy can be removed. When the application server deploys the EAR file, it extracts the contents of the file, and deploys:
1. JAR files (EJBs) first 2. WAR files (web) second

but more importantly, it arranges the Java classloaders so that Java code contained in the WAR file can access any of the Java class files contained in the JAR file. So, you should create a JAR file for your EJB(s), and in this JAR file put in the EJB stubs and skeletons and any other helper classes you may create. The WAR file now does not need to contain any stubs and skeletons - it can remain "pure" and contain only web components.

Referencing EJBs that your components use
The other thing you should do when creating the deployment descriptors for your web apps and EJBs is declare any EJB references that they make. e.g. if your servlet/JSP calls an EJB session bean, in the web.xml deployment descriptor, it should include an <ejb-ref> tag to declare this to the container. e.g. if your EJB session bean calls an EJB entity bean, in the ejb-jar.xml deployment descriptor, for your session bean you should include an <ejb-ref> tag to declare this to the container. As well as declaring the reference to the container (and to anyone else who may in future reuse your EJBs), it allows you to remove the need for hard-coded JNDI names inside your servlet/JSP/EJB code, when looking up an EJB's home interface. Have a look at the use of the <ejb-ref> tags in the web.xml deployment descriptor in the example below. Also notice the JNDI lookup code in the servlet, and that it now uses a name which maps into the deployment descriptor, not a hard-coded JNDI name. The mapping from the "java:comp/env/ejb/..." name into the actual JNDI name is specified in the weblogic.xml deployment descriptor.

186

In addition, if you have two EJBs in the same JAR file, and one is calling the other, you should use the <ejb-link> tag to indicate to the deployer that the EJB being called is actually in the same JAR file, so the deployer make make some optimisations.

Example: servlet/JSP referencing an EJB

In your servlet/JSP file, the section of code which looks up the EJB is like:
// This is the servlet/JSP file // Lookup the home interface MyEJBHome ejbHome; Object obj = ctx.lookup("java:comp/env/ejb/MyEJB"); ejbHome = (MyEJBHome) javax.rmi.PortableRemoteObject.narrow(obj, MyEJBHome.class);

Notice that this lookup uses the name java:comp/env/ejb/MyEJB. Then in the web.xml deployment descriptor in the WAR file, there should be a declaration of the EJB reference as follows.
<!-- This is the web.xml file --> <ejb-ref> <ejb-ref-name>ejb/MyEJB</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <home>pkg.MySessionHome</home> <remote>pkg.MySession</remote> </ejb-ref>

Then in the weblogic.xml deployment descriptor in the WAR file, there should be a mapping from the name by which the EJB is referenced in the Java source code (java:comp/env/ejb/MyEJB) into the actual JNDI name that the bean is advertised as in the server. In the example below, it assumes that the actual JNDI name of the EJB is "johns-ejb", and that the name by which it is called in the servlet should be mapped into this JNDI name.
<!-- This is the weblogic.xml file --> <reference-descriptor> <ejb-reference-description> <ejb-ref-name>ejb/MyEJB</ejb-ref-name> <jndi-name>johns-ejb</jndi-name> </ejb-reference-description> </reference-descriptor>

Recall that the <jndi-name> of an EJB is configured in that EJB's weblogic-ejb-jar.xml file. In the example above, the weblogic-ejb-jar.xml file would have the JNDI name configured as "johnsejb" even though the class names of the home and remote interface are MySessionHome.class and MySession.class respectively.

187

Example: session bean referencing entity bean

The following example is similar to the one above, but demonstrates specifying an EJB reference from one EJB (session bean) to another (entity bean). First, in the session bean Java code, you would look up the entity bean's home interface as follows:
// This is the session bean Java file // Lookup the home interface MyEntityHome ejbHome; Object obj = ctx.lookup("java:comp/env/ejb/MyEntity"); ejbHome = (MyEntityHome) javax.rmi.PortableRemoteObject.narrow(obj, MyEntityHome.class);

Then in the ejb-jar.xml file, you declare the beans. The declaration, including the reference, might look as follows:
<!-- This is ejb-jar.xml --> <enterprise-beans> <session> <ejb-name>MyFirstSessionBean</ejb-name> <home>pkg.MySessionHome</home> <remote>pkg.MySession</home> <ejb-class>pkg.MySessionBean</ejb-class> ... <ejb-ref> <ejb-ref-name>ejb/MyEntity</ejb-ref-name> <ejb-ref-type>Entity</ejb-ref-type> <home>pkg.MyEntityHome</home> <remote>pkg.MyEntity</remote> <ejb-link>MyFirstEntityBean</ejb-link> </ejb-ref> </session> <entity> <ejb-name>MyFirstEntityBean</ejb-name> <home>pkg.MyEntityHome</home> <remote>pkg.MyEntity</remote> <ejb-class>pkg.MyEntityBean</ejb-class> ... </entity> </enterprise-beans>

Note that this time an <ejb-link> is used which specifies the ejb-name of the bean that is being linked to. This allows the container to recognise that the referenced bean is local, and make some optimisations. Finally, the weblogic-ejb-jar.xml file is used to map from the <ejb-ref-name> into the actual JNDI name by which the beans are advertised.
<!-- This is the weblogic-ejb-jar.xml file --> <weblogic-enterprise-bean> <ejb-name>MyFirstSessionBean</ejb-name> <reference-descriptor> <ejb-reference-description>

188

<ejb-ref-name>ejb/MyEntity</ejb-ref-name> <jndi-name>janes-entity-bean</jndi-name> </ejb-reference-description> </reference-descriptor> <jndi-name>janes-session-bean</jndi-name> </weblogic-enterprise-bean> <weblogic-enterprise-bean> <ejb-name>MyFirstEntityBean</ejb-name> <jndi-name>janes-entity-bean</jndi-name> </weblogic-enterprise-bean>

Steps in deploying a Java application with many parts
1. Compile your EJB code using javac, as normal
cd jar javac mypackage/*.java

2. Create an EJB jar file, using the same jar syntax as normal
jar cvf ../ear/MyEJBs.jar *.*

3. Run the appc compiler on your EJB JAR file to generate the generated stubs and skeletons.
java weblogic.appc MyEJBs.jar

4. Compile your servlet. Note that because the servlet will make references to some of the classes in the EJB, you may need to adjust your Java CLASSPATH while compiling so that the compiler can access the EJB home and remote interface class files.
cd war/WEB-INF/classes javac *.java

5. Create WAR file, as normal.
jar cvf ../ear/webapp.war *.*

6. Make sure the JAR file and WAR file end up in the correct directory structure to make an EAR file, and that you have created your application.xml deployment descriptor. Then use the 'jar' command (same syntax) to create the EAR file.
jar cvf ../myapp.ear *.*

Using Eclipse to generate EAR files
Eclipse WTP/Workshop treats an EAR as a special type of Project - an Enterprise Application Project.

189

You create a new Enterprise Application Project (New -> Project -> Enterprise Application Project) and use the wizard to select the various projects (J2EE Modules :-) which will be part of this EAR. You can later add more by editing the EAR project properties (RMB -> Properties -> J2EE Module Dependencies) and selecting ANY project in the current workspace, but also internal/external JAR files! You will notice that from now on, the component projects (war, ejb etc) will now have a new subfolder called "Enterprise Application Libraries (ear)". This indicates the current projects that depend on your component project. You can directly deploy the EAR file (by adding the project to the server definition) or you can Export the EAR file using RMB -> Export -> EAR file One of the side effects of having an EJB project as part of an EAR is that you can now generate EJB Client jar's - these are files that contain the interfaces & stubs which allow ordinary Java clients (such as applets & AWT/SWING applications) to access the EJB.

An example EAR file
Extract the pieces of the following EAR file to get an idea of the directory structures to use, etc.

190

Module: XML
Lab exercise - Parsing XML in a JSP
XML is the Extensible Markup Language. In this exercise, we create a JSP that reads in and parses an XML file. Level of Difficulty: 1 (easy) Estimated time: 20 minutes Pre-requisites:
• •

Run 'setEnv.sh' to set your environment correctly Start your WebLogic server running in the background

XML
XML is a language for describing structured information. It uses a tag-based syntax like HTML. However, for XML to be useful, it is typically necessary to parse it, or convert it into a different format. This exercise introduces XML parsing. There are three main kinds of XML parsers: SAX, DOM and StAX.

SAX stands for "Simple API for XML" and supports sequential parsing of XML documents. The document is read in, and parsed in the order in which the tags appear. Each time a tag starts or ends, an event is triggered. An application programmer writes a set of event handlers to respond to these events from the parser. DOM stands for "Document Object Model" and when parsing an XML document, builds an in-memory structured representation of the document. The whole document is read in at once, and the DOM tree is created in memory as a Java data structure and can be navigated by calling methods. StAX stands for "Streaming API for XML" and is capable of parsing and writing an XML Document. This API is very resource efficient because it only reads parts of the XML document into memory at once. This way it provides similar capabilities to DOM while maintaining a similar performance to SAX.

In this exercise we use a SAX parser inside a JSP to read in and display an XML file.

Parsing an XML file with SAX
There are three main files required for this exercise: an XML file, a JSP, and a Java class which handles the XML processing. Before beginning, you should set up the directory structure for a WAR file.

XML file 191

The first step is to create the XML file that we will parse. Create the following file as addressbook.xml.
<addressbook> <entry id="1"> <name>Wayne</name> <address>Room 4/130</address> <email>brooks@it.uts.edu.au</email> <phonextn>4469</phonextn> <birthday>2001-01-01</birthday> </entry> <entry id="2"> <name>Maolin</name> <address>Room 4/520</address> <email>maolin@it.uts.edu.au</email> <phonextn>1858</phonextn> <birthday>2001-01-01</birthday> </entry> </addressbook>

JSP file

The next step is to create a JSP file called printout.jsp as shown below.
<%@ page import="javax.xml.parsers.*"%> <%@ page import="org.xml.sax.*"%> <%@ page import="javax.xml.parsers.*"%> <%@ page import="org.xml.sax.helpers.DefaultHandler" %> <H1> Parsed XML document </H1> <% InputStream is = application.getResourceAsStream("/addressbook.xml"); try { SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setValidating(false); SAXParser myParser = spf.newSAXParser(); DefaultHandler h = new handlers.MyHandler(out); myParser.parse(is, h); } catch (Exception e) { } %>

Notice that this JSP has no reference to the structure of the XML file, or what to do with it. All the JSP is responsible for is opening an InputStream to access the XML file, and then

192

creating a SAX parser to read from the XML file. The rules for how to process the XML file are contained in the handler class. In the example above, this is the Java object h, and the class is handlers.MyHandler. Also notice that the example says setValidating(false). This means that the parser will not attempt to validate the XML document against a DTD. If we had requested a validating parser, a DTD file would also be necessary to describe the format/rules of the XML document.

Handler class

The final main section of code required is a Java class that will act as the handler for the SAX parser. It is this file that determines what will happen to the XML. Create the following file as WEB-INF/classes/handlers/MyHandler.java.
package handlers; import org.xml.sax.*; import javax.xml.parsers.*; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.helpers.DefaultHandler; import javax.servlet.jsp.*; public class MyHandler extends DefaultHandler { JspWriter out; public MyHandler(JspWriter out) { this.out = out; } public void startDocument() throws SAXException { try { out.println("<p>Start of document</p>\n<p>"); } catch (Exception e) { } } public void endDocument() throws SAXException { try { out.println("</p>\n<p>End of document</p>"); } catch (Exception e) { } } public void startElement(String uri, String name,String qName, Attributes attrs) throws SAXException { } public void endElement(String uri, String name, String qName)

193

throws SAXException { try { if (name.equals("entry")) { out.println("</p><p>"); } } catch (Exception e) { } } public void characters (char ch[], int start, int length) throws SAXException { try { out.println(new String(ch, start, length) + "<BR/>"); } catch (Exception e) { } } public void processingInstruction(String target, String data) { } public void ignorableWhitespace(char ch[], int start, int length) { } }

Note that this handler class extends DefaultHandler. It has a number of methods that can be implemented as event handlers. As the parser is parsing the XML document, it will trigger events that will call your event handler methods. You will need to compile this file. Change into the WEB-INF/classes directory, and compile the file:
javac handlers/MyHandler.java

Packaging and deployment

The final step is to package and deploy the files as a web application (WAR file). First, create a WEB-INF/web.xml file with no information, as follows.
<?xml version="1.0" ?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 1.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2_2.dtd"> <web-app> </web-app>

Then create the WAR file, and deploy it into WebLogic and test it by opening the JSP in your browser.

Additional Exercise

194

This doesn't present a nice interface to the user. Modify the jsp and handler class to result the results as a table.

Notes

It is never a good idea to embed HTML into a handler class. The best practice would be for the handler class to populate a collection of javabeans which can then be presented via the JSP. Apache Commons Digester (http://jakarta.apache.org/commons/digester) is one example of a popular java library to do this automatically. XMLBeans is another example.

195

Module: XML (DOM)
Lab exercise - Writing XML via DOM
DOM stands for "Document Object Model" and when parsing an XML document, builds an in-memory structured representation of the document. The whole document is read in at once, and the DOM tree is created in memory as a Java data structure and can be navigated by calling methods. In this exercise we use a DOM parser inside a JSP to display an XML file. Level of Difficulty: 3 (medium) Estimated time: 45 minutes Pre-requisites:
• • •

Run 'setEnv.sh' to set your environment correctly Start your WebLogic server running in the background Completed the XML SAX JSP lab

Understanding the code
In the section below, we will walk through the code provided and give an explanation of what is happening. Let's create a file called dom.jsp
<%@ page import="javax.xml.parsers.*" %> <%@ page import="org.w3c.dom.*" %> <%@ page import="java.io.*" %> <html><head> <title>DOM Parser</title> </head> <body> <h1>XML DOM parser test</h1> <hr /> • •

The java.xml.parsers package contains some basic methods for working with XML parsers (either DOM or SAX). The second package, org.w3c.dom, contains DOM-specific objects and methods. There is also a related package, org.w3c.sax that we will use in another exercise.

<% // Create the stream we will read from InputStream is = application.getResourceAsStream("/addressbook.xml"); // Create an instance of the DOM parser and parse the document DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(is); // Begin traversing the document

196

traverseTree(doc, out); %>

This section of code is where we set up the DOM parser to parse the document. The steps involved are: 1. Create a InputStream object that refers to the particular XML file we want to open. getResourceAsStream() will read a file from our war file. 2. Get a reference to a DocumentBuilderFactory and a DocumentBuilder object. The need for this step is because there are potentially many different implementations of DOM parsers available. For example, the implementation that we will be using is called Xerces, and is part of the Apache project. Another implementation of a DOM parser comes from IBM. From an application programmer perspective, you aren't usually interested in which implementation of the DOM parser is being used. You just want to get access to whichever DOM parser happens to be installed on the system you are using. The DocumentBuilderFactory class provides a generic way of locating the "default" DOM parser implementation that is installed on any system. When you call DocumentBuilder.newInstance(), it returns a reference to some implementation of a DOMcompliant parser. The DocumentBuilder object refers to the actual DOM parser itself. 3. Parse the XML file, by calling the parse() method on the DocumentBuilder object. With DOM, whenever you call the parse() method, in return you get back a reference to a Document object that is the starting point for the parsed DOM tree. If there was a syntax error during parsing and the DOM tree could not be built, then a Java exception would be thrown and an error message would appear in the browser. This error message will look like the message generated when testing wellformedness of XML documents in an earlier exercise. 4. Finally, as a result of parsing we have a Document object which represents a DOM tree that we can traverse. In this exercise, there is a specific Java method for performing the traversal, called traverseTree(). We call the traverseTree() method and pass to it a reference to the Document, and also to the pre-defined JSP object called out, which is used for printing data into the HTML code that is sent back to the user's web browser.

Here we declare a Java method that will be used to perform the traversal. We will call this method to handle each node in the DOM tree that has been built in memory by the parser.
<%! /** Handles one node of the tree. It accepts any type of node, and will check the node type before processing it. This function is recursive - if one node contains other "sub-nodes", this function will call itself again to process the sub-nodes. @param currnode the current node @param out where to write the output */ private void traverseTree(Node currnode, JspWriter out) throws Exception {

197

// If the current node is null, do nothing if(currnode == null) { return; } // Find the type of the current node int type = currnode.getNodeType(); // Check the node type, and process it accordingly switch (type) {

Notice that for the current node we are processing, we first find out the node type, and then use a switch statement to branch to a block of code to handle that particular type of node. Now we will examine each of the different handlers in turn.
/* * Handle the top-level document node. * Just print out the word "DOCUMENT", and then get the * root element of the document, and process it using * the traverseTree method */ case Node.DOCUMENT_NODE: { out.println("<p>DOCUMENT</p>"); traverseTree (((Document)currnode).getDocumentElement(), out); break; }

There is only one "document" node for each XML document. In this case, first we just print a message to indicate that we have encountered a document node. Seconly, we call the getDocumentElement() method to retrieve the root node of the document. With that root node, we then call the traverseTree() method to handle it. Note that from within the traverseTree() method, we are calling the same method again. This is an example of recursion in programming.

/* * Handle an element node

198

* This is the most complex type of node dealt with. * First, print out the name of the element, before * processing any other sub-nodes (i.e. a preorder traversal). * Secondly, check if this element has any attributes, and * if it does, process those next, by calling the traverseTree() * method. * Finally, retrieve the children of this node (if any), and * process them one by one using the traverseTree() method. */ case Node.ELEMENT_NODE: { String elementName = currnode.getNodeName(); out.println("<p>ELEMENT: [" + elementName + "]</p>"); if (currnode.hasAttributes()) { NamedNodeMap attributes = currnode.getAttributes(); for (int i=0; i < attributes.getLength(); i++) { Node currattr = attributes.item(i); traverseTree(currattr, out); } } NodeList childNodes = currnode.getChildNodes(); if(childNodes != null) { for (int i=0; i < childNodes.getLength() ; i++) { traverseTree (childNodes.item(i), out); } } break; }

This is the most complex of the handlers. There are three main parts to it: 1. Find out the name of this element (elementName) and print it out. 2. Check to see if this element has any attributes associated with it. If it does, then we retrieve them (attributes) and then loop through them one by one using a for loop. In DOM, every attribute is treated as a Node as well. So in this example, for each attribute, we simply call the traverseTree() method to handle it. 3. The final step in this example is to process any child nodes of this element. We retrieve a list of all the child nodes, and use a for loop to process each one in turn, using the traverseTree() method to do the processing. Note that children of element nodes are typically either text nodes (if the element contains text) or further element nodes (if the element contains other XML elements nested inside it). Note that this is where we decide the traversal algorithm to use. In this case, we are using a preorder traversal, which is the most common kind of traversal for processing documents with DOM.

/* * Handle attribute nodes. * Just print out the word "ATTRIBUTE", and then the name

199

* and value of the attribute itself. */ case Node.ATTRIBUTE_NODE: { String attributeName = currnode.getNodeName(); String attributeValue = currnode.getNodeValue(); out.println("<p>ATTRIBUTE: name=[" + attributeName + "], value=[" + attributeValue + "]</p>"); break; }

In the case of attribute nodes, we just retrieve the attribute name and value, and print them out. Attribute nodes are leaf nodes in the DOM tree. They have no children to process.

/* * Handle text nodes. * Trim whitespace off the beginning and end of the text. * Then check whether there is any real text, and if so, * print it out. This avoids printing out text nodes that * consist of only whitespace characters. */ case Node.TEXT_NODE: { String text = currnode.getNodeValue().trim(); if (text.length() > 0) { out.println("<p>TEXT: [" + text + "]</p>"); } break; } } } %>

In the case of text nodes, we retrieve the value, and "trim" it. Trimming it means that we remove whitespace from either end of the string. If the resulting string has any characters left after trimming, then we print it out. This avoids printing text nodes that consist entirely of whitespace. Text nodes are leaf nodes in the DOM tree. They have no children to process.

Adding indenting to show nesting level
First, copy your dom.jsp file to a new file named dom1.jsp. Make the following changes to

200

dom1.jsp.

At the moment, the sample JSP prints all nodes at the same level of indenting (against the left-hand margin). The first goal of this exercise is to modify the code so that each time the traversal algorithm enters a new level of "depth" in the DOM tree, we indent the output one level further, and each time the traversal algorithm goes up one level in the DOM tree, we remove the indenting. The easiest way to achieve indenting is to use the HTML <blockquote> tag. When you want to increase the indenting by one level, print out the following line of HTML:
<blockquote>

When you want to decrease the indenting by one level, print out the corresponding closing tag:
</blockquote>

Think about how the code works. Each time you process a node, the traverseTree() method is called. Another way to think of it is that the start of the traverseTree() method is the time at which you "enter" (i.e. start processing) a node, and the end of the traverseTree() method is when you "exit" (i.e. finish processing) the node. The solution is quite short - it can be done by adding only two lines of code - but it does require you to think about and understand how the code works (particularly the traverseTree() method).

Formatting the data in a table
The next exercise with the DOM parser is to print out the data from the addressbook.xml file in a HTML table. Your resulting output should look something like the following: Name Address Email Phonextn Birthday 2001-01-01 2001-01-01

Wayne Room 4/536 brookes@it.uts.edu.au 1872 Maolin Room 4/520 maolin@it.uts.edu.au 1858

Copy the original dom.jsp file to become dom2.jsp, and make your changes to dom2.jsp.

Printing a subset of the data
The final exercise is to selectively print data from the DOM tree. Copy the original dom.jsp

201

file to become dom3.jsp, and make your changes to dom3.jsp. Suppose that using the addressbook.xml file, we only want to print out a list of names and email, and none of the other information. Modify the code so that only the <name> and <email> element values are printed. It's not as easy as it sounds - remember that the actual value isn't stored in the DOM "element" node, it is stored in a "text" node that is a child of the element.

Module: XML
Lab exercise - Transforming XML in a JSP
We can use Extensible Stylesheet Language Transformations (XSLT) to transform XML into different formats. We also use XPATH expressions to match elements and attributes. Level of Difficulty: 2 (medium) Estimated time: 40 minutes Pre-requisites:
• • •

Run 'setEnv.sh' to set your environment correctly Start your WebLogic server running in the background Finished SAX and DOM labs.

Creating an XSLT sample file
We will use the existing addressbook.xml file to transform using some XSLT files we will write. First, let's create addressbook1.xsl
<?xml version="1.0" encoding="ISO-8859-1"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"> <xsl:output method='html' version='1.0' encoding='UTF-8' indent='yes'/>

This is the header of our XSLT file:

Since this is an XML document, the first line must start with <?xml

202

We then indicate that this is a stylesheet which will be performing XSLT transformations. Note that there is a synonym called <xsl:transform> instead of <xsl:stylesheet> Finally, the <xsl:output> element tells the XSLT processor what type of output can be expected. In this case, we will be using HTML. This could also equally be 'xml' or 'text' See http://www.w3.org/TR/xslt#output for a definitive syntax of this element.

<xsl:template match="/"> <html> <body> <p><i>Start of document</i></p> <!-- Go and apply all the templates for the root --> <xsl:apply-templates/> <p><i>End of document</i></p> </body> </html> </xsl:template>

This element is called once since XML documents represent a logical tree. When the parser reads in the first, or "root" element, this template is matched.
• •

Note that we display some header/footers around the main body When <xsl:apply-template> is reached, the XSLT processor will attempt to match the next template, in priority order.

The rest of the file is fairly straight forward - for each element we encounter, we emit some boilerplate code
<xsl:template match="addressBook"> <h1>Address Book</h1> <!-- Go and apply all the templates for the root --> <xsl:apply-templates/> </xsl:template> <xsl:template match="entry"> <hr/> <h2>Entry <xsl:value-of select="@id"/></h2> <!-- Go and apply all the templates for the root --> <xsl:apply-templates/> </xsl:template> <xsl:template match="name"> <p>Name: <!-- Go and apply all the templates for the root --> <xsl:apply-templates/> </p> </xsl:template> <xsl:template match="address"> <p>Address: <!-- Go and apply all the templates for the root --> <xsl:apply-templates/> </p> </xsl:template> <xsl:template match="email"> <p>E-mail: <!-- Go and apply all the templates for the root -->

203

<xsl:apply-templates/> </p> </xsl:template> <xsl:template match="phonextn"> <p>Phone: <!-- Go and apply all the templates for the root --> <xsl:apply-templates/> </p> </xsl:template>

</xsl:stylesheet>

Notice that for <entry> node we pick up the attribute id, so if we found <entry id="99">, the <xsl:value-of ..> element would return 99 When the XSLT processor has no more matches, it will then return up the parsing tree and will emit the element text contents. Let's try this out on the command line
java org.apache.xalan.xslt.Process -IN addressbook.xml -XSL addressbook1.xsl

This invokes the Apache Xalan XML processor and returns the result to your terminal. You can use the -OUT addressbook.htm option to save the file, or use standard redirection "> addressbook.htm" to save this to a file. Try the result in a web browser.

Using a web browser to do transformations
Most modern browsers (Internet Explorer 5+, Mozilla/Firefox, Opera) have a built-in XSLT transform engine. If you modify your addressbook.xml file with the following header on the 2nd line after the <?xml > element...
<?xml-stylesheet type="text/xsl" href="addressbook.xsl"?>

If you open this in your browser (either directly or via a web page), you will find that this is also displayed transformed into HTML.

Using Java to do transformations
Here is a JSP that will read in addressbook.xml and addressbook.xsl to use the JAXPack to do XSLT transforms.

<%@ page import="javax.xml.parsers.*" %> <%@ page import="org.w3c.dom.*" %> <%@ page import="javax.xml.transform.*" %> <%@ page import="javax.xml.transform.dom.*" %>

204

<%@ page import="javax.xml.transform.stream.*" %> <%@ page import="java.io.*" %> <html><head> <title>DOM Parser</title> </head> <body> <h1>XML DOM parser test</h1> <hr /> <% // Create the stream we will read from InputStream is = application.getResourceAsStream("/addressbook.xml"); InputStream xsls = application.getResourceAsStream("/addressbook.xsl"); StreamSource xmlSource = new StreamSource(is); StreamSource xsltSource = new StreamSource(xsls); // Create a StreamResult pointing to the output file StreamResult fileResult = new StreamResult(out); // Load a Transformer object and perform the transformation TransformerFactory tfFactory = TransformerFactory.newInstance(); Transformer tf = tfFactory.newTransformer(xsltSource); tf.transform(xmlSource, fileResult); %>

The main method we use is javax.xml.transform.Transformer which is part of the standard J2SE implementation from 1.4 onwards.

More exercises: XSLT functions
XSLT provides some functions such as count(), concat(), substring() and so on. Let's try some. Add this into the main root template (... match="/"... )
<h3>Summary</h3> <p>There are <xsl:value-of select="count(//name)"/> names</p> <p>There are <xsl:value-of select="count(//*)"/> nodes</p>

Here are some quick idioms to remember:
• •

//name means "any <name> element under the root / element" //* means any element

Try it out. Note that this counts the number of names in our addressbook.xml and also the total number of nodes.

Advanced exercises:

205

Printing a subset of the data
How about displaying only <name> elements? HINT: Just removing the match="address" & so on templates won't work - the text contents of the nodes will still be displayed. Try replacing them all with a match="*" template

Formatting the data in a table
The final exercise with XSLT is to convert your results to a table looking somewhat like this: Name Address Email Phonextn Birthday 2001-01-01 2001-01-01

Wayne Room 4/536 brookes@it.uts.edu.au 1872 Maolin Room 4/520 maolin@it.uts.edu.au 1858

Module: Web Services
Lab exercise 1 - Exploring RPC Web Services
In this exercise, we will view a public Web Services registry (http://www.xmethods.com) and then will use the Weblogic universal test client to explore an existing web service, http://cdyne.com/creditcardverify/luhnchecker.asmx Level of Difficulty: 1 (easy) Estimated time: 20 minutes Pre-requisites:

Finding Web services
(from wikipedia) Universal Description, Discovery and Integration (UDDI) is a platform-independent, XMLbased registry for businesses worldwide to list themselves on the Internet. UDDI is an open industry initiative, sponsored by OASIS, enabling businesses to publish service listings and discover each other and define how the services or software applications interact over the Internet. A UDDI business registration consists of three components:
• • •

White Pages — address, contact, and known identifiers; Yellow Pages — industrial categorizations based on standard taxonomies; Green Pages — technical information about services exposed by the business.

206

IBM, Microsoft and SAP supported a publicly accessible Universal Business Registry but closed this down on January 2006. Fortunately, there are 3rd party registries still available on the internet. http://xmethods.com is one such provider.

Using Xmethods.com
Start a browser and navigate to: http://xmethods.com You can browse this list for many publicly available web services. Note that the listing includes a Publisher, Style, ServiceName, Description and Implementation column. Clicking on the service name will reveal a description page of the web service. On this page is:
• • • • • • •

The WSDL address (and alongside this is a "Analyze WSDL" link which you can use to summarise the web service definition file) Owner details Description Informational website link End points (optional) Contributed Clients (where other people have written clients for this webservice in various languages) Usage notes

If you wish, you can download the sample clients other people have written, but for the moment, you can scroll down to the bottom to see a detailed description and usage notes of this service. This information is not usually automatically generated or used by programs. The key information here is the location of the WSDL file.

Using the Weblogic Universal Test Client
Weblogic includes a simplistic test client which you can use to view and try out publically available web services. Start your weblogic server (either via the command line or via Weblogic Workshop) Use the URL http://localhost:7001/wls_utc and enter the following WSDL URL: http://cdyne.com/creditcardverify/luhnchecker.asmx?WSDL

207

You can then press [TEST] and you will see the various operations that this web service supports. In this case, you should see an operation called CheckCC which has a single parameter called CardNumber Enter: 4111111111111111 and press the [CheckCC] button.

You should then get the following results screen

208

Now we can see the XML representation of this transaction. We have our SOAP Envelope and Body for both the request (invocation of the web service) and the response (results returned). As you can see, you provide the parameter as an XML message called <CheckCC> and the response comes back as an XML message called <CheckCCResponse> These are just self-defined XML elements under the namespace "http://ws.cdyne.com".

Alternative testing points
Many web service frameworks (include Weblogic) provide an internal test client. The CDYNE credit card checker is written in Microsoft .NET and this provides an internal test client at the address http://cdyne.com/creditcardverify/luhnchecker.asmx Try this out. Note that this web service supports not only SOAP 1.1 but SOAP 1.2 and a HTTP interface as well.
WSDL file

Now let's look at the WSDL definition of the web service. By convention, most web service frameworks also support returning the WSDL for the web service by using the ?WSDL (or ?wsdl) query string on the endpoint URL

209

So for the CDYNE credit card checker, we use http://cdyne.com/creditcardverify/luhnchecker.asmx?WSDL Try this out. Most browsers will show you the XML returned as a formatted document like:

Let's look at the WSDL in more detail: Firstly, we have some header information: All WSDL documents must have one top level element - the <definitions> tag. This contains the (optional) name of the web service and the target namespace. (note: web browsers sometimes omit the namespace definitions so I added them here)
<wsdl:definitions xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://ws.cdyne.com/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"

targetNamespace="http://ws.cdyne.com/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

We then have the definition of the XML schemas for the messages
<wsdl:types> <s:schema elementFormDefault="qualified" targetNamespace="http://ws.cdyne.com/"> <s:element name="CheckCC"> <s:complexType> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="CardNumber" type="s:string" /> </s:sequence> </s:complexType>

210

</s:element> <s:element name="CheckCCResponse"> <s:complexType> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="CheckCCResult" type="tns:ReturnIndicator" /> </s:sequence> </s:complexType> </s:element> <s:complexType name="ReturnIndicator"> <s:sequence> <s:element minOccurs="0" maxOccurs="1" name="CardType" type="s:string" /> <s:element minOccurs="1" maxOccurs="1" name="CardValid" type="s:boolean" /> </s:sequence> </s:complexType> <s:element name="ReturnIndicator" type="tns:ReturnIndicator" /> </s:schema> </wsdl:types>

This basically defines the following types in pseudocode. Note that the s: prefix represents the standard W3C XML Schema
CheckCC { String CardNumber } CheckCCResponse { ReturnIndicator CheckCCResult } ReturnIndicator { String CardType Boolean CardValid }

Next, we have our SOAP message definitions. Basically, these are the parameters we pass and receive from our operations. The ones displayed below are relevant to SOAP 1.1
<wsdl:message name="CheckCCSoapIn"> <wsdl:part name="parameters" element="tns:CheckCC" /> </wsdl:message> <wsdl:message name="CheckCCSoapOut"> <wsdl:part name="parameters" element="tns:CheckCCResponse" /> </wsdl:message>

Next, our <portType> element. Basically this defines what operations exist on for the given port.
<wsdl:portType name="LUHNCheckerSoap"> <wsdl:operation name="CheckCC"> <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> Enter 4111111111111111 to test a good credit card number.</wsdl:documentation> <wsdl:input message="tns:CheckCCSoapIn" /> <wsdl:output message="tns:CheckCCSoapOut" /> </wsdl:operation> </wsdl:portType>

211

ie: our operation is CheckCC with the input parameter message called CheckCCSoapIn and the return message called CheckCCSoapOut Next, <binding> element. This maps the portType to the specific protocol (in this case, SOAP over HTTP, which is represented by the transport attribute "http://schemas.xmlsoap.org/soap/http").
<wsdl:binding name="LUHNCheckerSoap" type="tns:LUHNCheckerSoap"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" /> <wsdl:operation name="CheckCC"> <soap:operation soapAction="http://ws.cdyne.com/CheckCC" style="document" /> <wsdl:input> <soap:body use="literal" /> </wsdl:input> <wsdl:output> <soap:body use="literal" /> </wsdl:output> </wsdl:operation> </wsdl:binding>

Note that the style is document and the encoding usage is literal. This is the WS-I standard which supplants the traditional RPC SOAP encoding. Finally, we define the service itself. The previous elements defined an abstraction of the web service, we now come to the implementation of the web service itself. This maps the service end point (which is the <port> element here) to a physical address (in this case, "http://cdyne.com/creditcardverify/luhnchecker.asmx" ). If we we using alternative transports such as HTTP, this would be reflected here too. Note that for clarity I have omitted the bindings for SOAP12 and HTTP.
<wsdl:service name="LUHNChecker"> <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> Validates Credit Cards to ensure proper input... </wsdl:documentation> <wsdl:port name="LUHNCheckerSoap" binding="tns:LUHNCheckerSoap"> <soap:address location="http://cdyne.com/creditcardverify/luhnchecker.asmx" /> </wsdl:port> ... omitted other port bindings ... </wsdl:service>

This essentially declares that the service called "LUHNChecker" has a SOAP 1.1 implementation at http://cdyne.com/creditcardverify/luhnchecker.asmx

Lab exercise 2 - Exploring other Web Services
Now that you have tried one web service, why not try other web services from xmethods.com? Another good source of web services is http://www.webservicex.net.

212

Reflection
Whilst fundamentally a simple concept, the Web services standards produce quite verbose XML documents for what could be very simple RPC style services. This complexity is needed to allow web services to be self describing, portable and interoperable between systems and languages. Our next step is to write a client for a web service then we will implement a very simple web service later.

Module: Web Services
Lab exercise 3 - Writing a simple RPC client
In this exercise we will create a simple RPC client
213

Level of Difficulty: 1 (easy) Estimated time: 20 minutes Pre-requisites:
• •

Run 'setEnv.sh' to set your environment correctly Completed Lab exercise 1 - exploring Web services

JAX-RPC Static clients
JAX-RPC is the Java standard for web services. It encapsulates much of the complexity of communicating via SOAP and also maps many Java value classes to the standard XML data types. In this lab, we will use Weblogic to generate client side stubs which will be invoked by our Java class. Note that each JAX-RPC implementation generates different stub classes, so be aware that you will need to re-generate the Stubs for each platform you are developing with (eg: Apache AXIS)

Create new project
First step is to create a new development project ie: New -> Project -> Dynamic Web Project & set the "Annoted Web Service Facets (minimum)" configuration & name the project labws Then configure the build path:
1. Project -> Properties -> Java Build Path 2. Select the Libraries tab & Add External Archives (or go Right Mouse Button -> Build Path -> Add External Archives) 3. Add /opt/bea10/wlserver_10.0/server/lib/wseeclient.jar (or the equivalent path in your configuration)

Generating a static client stub
If you have weblogic 10.3 you can use the ClientGen web service wizard to create a client, however, for the weblogic 10.0 users you will need to have the following ANT build.xml file to build the stubs. File -> New -> XML & call the file build.xml (you can import the build.xml here )
<?xml version="1.0" encoding="UTF-8"?> <project name="webservicesLab" default="build-client" basedir="."> <description>Weblogic JWS builder</description> <target name="init"> <path id="weblogic.class.path"> <pathelement path="${java.class.path}" /> <pathelement path="${env_var:WEBLOGIC_CLASSPATH}" />

214

<fileset dir="/opt/bea10/wlserver_10.0/server/lib"> <include name="weblogic.jar" /> </fileset> </path> </target>

<target name="build-client" depends="init"> <taskdef name="clientgen" classname="weblogic.wsee.tools.anttasks.ClientGenTask"> <classpath refid="weblogic.class.path" /> </taskdef> <clientgen type="JAXRPC" wsdl="http://cdyne.com/creditcardverify/luhnchecker.asmx?wsdl" destDir="src" generateAsyncMethods="false" classpath="${java.class.path}" autoDetectWrapped="true" packageName="ws" /> </target> <target name="build-server" depends="init"> <taskdef name="jwsc" classname="weblogic.wsee.tools.anttasks.JwscTask" > <classpath refid="weblogic.class.path" /> </taskdef> <jwsc srcdir="src" destdir="src"> <jws file="**/*Bean.java" type="JAXRPC" /> <jws file="**/*Service.java" type="JAXRPC" /> </jwsc> </target>

</project>

You then run this ANT build file by selecting build.xml Right Mouse Button -> Run As -> Ant Build You should see the ANT build running in the Workshop Console. Hopefully no errors occur. The following files should be generated
com.cdyne.ws ReturnIndicator.java ws LUHNChecker.java LUHNCheckerSoap.java LUHNCheckerSoap_Stub.java LUHNChecker_Impl.java LUHNChecker_saved_wsdl.wsdl

The main classes we are interested in are:
• •

LUHNChecker.java - this is the web service interface (<wsdl:service>) LUHNCheckerSoap.java - this is the binding (<wsdl:binding> & contains the operations for that port (eg: checkCC(String) ) 215

• • •

LUHNChecker_Impl.java - this is the implementation of the web service interface *** LUHNCheckerSoap_Stub.java - this is stub that does the actual communications/marshalling etc com.cdyne.ws.ReturnIndicator.java - this represents the complexType ReturnIndicator

You will need to do this analysis every time you generate a stub for a web service...
JSP Client

The next step is to create a JSP with the following code fragment in it
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@page import="ws.*" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> Lunh checker: checking 4111111111111 <% LUHNChecker checker = new LUHNChecker_Impl(); LUHNCheckerSoap port = checker.getLUHNCheckerSoap(); com.cdyne.ws.ReturnIndicator ri = port.checkCC("4111111111111111"); out.println(ri.getCardValid()); out.println(ri.getCardType()); %> </body> </html>

Build, deploy and run as usual You can modify this JSP to take the credit card argument as an input field in a form.

Module: Web Services
Lab exercise 5 - Writing a simple web service
In this exercise we will create a simple web service.

216

Level of Difficulty: 3 (medium) Estimated time: 40 minutes Pre-requisites:
• • • •

Run 'setEnv.sh' to set your environment correctly Started the WebLogic server on your workstation Completed Lab exercise 1 - exploring Web services Completed Lab exercise 3 - simple client

Writing the server code
It's actually quite simple to write a Web Service if you have a JSR-181 compliant web service framework. Weblogic 8.1, 9 & 10 all support using Java Annotations to mark web services

Create a new Web Services Project (New -> Project -> Web Services Project, call it "ws" ) Create a new Package (New -> Package -> myapp ) Create a new Weblogic Web service (New -> Other -> Weblogic Web Service). Call this Hello (in the package myapp) By default, the wizard generates a method called void Hello().

Change this to the following:
package myapp; import javax.jws.*; @WebService public class Hello { @WebMethod public String hello(String name) { return "Hello, " + name; } }

Notice the annotations: @WebService tells Java & Weblogic that this is a webservice (the default name is Hello) @WebMethod declares that the following method is a web service Operation. By default, if you dont have this annotation, ALL PUBLIC METHODS are exposed. We will let the wonders of code generation do all the work for us to make this a web service!

Generating the code
217

No need to do any. Workshop will run a builder to do this under the covers for you.
Deploy

As usual, add this to the Server (BEA Weblogic Server v10 [weblogic] -> RMB -> Add and Remove Projects) or just run via highlighting Hello.java -> RMB -> Run As -> Run on Server

Test
Go to http://localhost:7001/ws/Hello This gives you an application test page! Look at the WSDL and the Test Page

Problems
Sometimes when you do changes you need to clean the project, rebuild and also re-publish select the Server (BEA Weblogic server v10 [weblogic] -> RMB -> Publish

Additional Exercise: Java Client (medium)

The next step is to create a JSP client for this service. Follow the instructions in lab 3 and you should be able to write your own JSP client

Module: Web Services
Lab exercise 6 - Adding Basic security to a simple web service
In this exercise we will modify the previous simple web service to add basic HTTP security

218

Level of Difficulty: 3 (medium) Estimated time: 40 minutes Pre-requisites:
• • • • •

Run 'wlenv' to set your environment correctly Started the WebLogic server on your workstation Completed JSP Lab exercise 4 - web authentication Completed Lab exercise 3 - simple client Completed Lab exercise 5 - simple web services

Weblogic (and J2EE in general) define three basic types of web services security. To quote the weblogic documentation at http://edocs.bea.com/wls/docs100/webserv_sec/overview.html , they are::
• • •

Message-level security, in which data in a SOAP message is digitally signed or encrypted. Transport-level security, in which SSL is used to secure the connection between a client application and the Web Service. Access control security, which specifies which roles are allowed to access Web Services.

Message level security is fairly complex and you can read about this independently at http://edocs.bea.com/wls/docs100/webserv_sec/message.html. Basically you can sign and/or encrypt individual SOAP messages according to the WS-security standard - and this could be the entire SOAP message, or just the header or just the body or even just specific elements! You could also include a Token (username, SAML or X.509 based) which represents the user. Transport-level security is basically setting up SSL (or TLS in this case) on the connection between your client and web service. You could use a client based certificates to authenticate the connection. However, this is not the same as USER authentication since this only authorises the network connection. Access control security is the simplest authentication - this re-uses the HTTP basic authentication (which you did in JSP Lab 4 - web authentication) by setting access control security on our web service project. Effectively all you need to do is to pass the username and password on the SOAP call at the client end and the web application server which the web service is running on will handle the security. Again, this could be via simple plain text username/password (like "student", "password") or you could use Digest authentication using a client-side certificate (a lot harder). This lab will use HTTP Basic Authentication and will re-use your existing security setup from the JSP Lab 4 - web authentication.

Setting up usernames & roles
This step has been done in JSP Lab 4 - web authentication. Basically you set up a group called "hellousers" which maps to a role called "hellousers".

219

You then created users who were members of this group. In the lab you created a username "student" with password "password" (or whatever)

Writing the server code
Keep the existing HelloWorld.java file Modify the web.xml and weblogic.xml files. Basically copy the code fragment from the JSP Lab 4 iafter the </welcome-file-list> tag in web.xml
<security-constraint> <web-resource-collection> <web-resource-name>Hello world</web-resource-name> <description>The Hello world application</description> <url-pattern>/*</url-pattern> </web-resource-collection> <auth-constraint> <description>These users can use hello JSP</description> <role-name>hellousers</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>Hello World Application</realm-name> </login-config> <security-role> <description>Hello JSP users</description> <role-name>hellousers</role-name> </security-role>

You can optionally modify the URL pattern (we used /*) to the web service name itself. You also have to modify the weblogic.xml file to add the following:
<wls:security-role-assignment> <wls:role-name>hellousers</wls:role-name> <wls:principal-name>hellousers</wls:principal-name> </wls:security-role-assignment>

Redeploy & Test
Just redeploy as usual. You can test that you now have to enter a userid and password by typing in the URL in a browser (or in the Weblogic test client). Note that if you run your previous client, you should get an 500 error with a message like something like java.rmi.RemoteException: SOAPFaultException - FaultCode [{http://schemas.xmlsoap.org/soap/envelope/}Client.Authentication] FaultString [Failed to receive message weblogic.wsee.util.AccessException: The server at
220

http://localhost:7001/ws/Hello returned a 401 error code (Unauthorized). Please check that username and password are set correctly and that you have permission to access the requested method.The server at http://localhost:7001/ws/Hello returned a 401 error code (Unauthorized). Please check that username and password are set correctly and that you have permission to access the requested method.]

Generating the Client skeleton
You can keep the existing client you wrote the the previous lab and therefore do not need to re-generate the client code. However, if you need to use the Clientgen Ant task, you now have to change the call to add the username and password parameters. To do this change your build.xml clientgen elemnt to the following:
<clientgen type="JAXRPC" wsdl="http://localhost:7001/ws/Hello?wsdl" destDir="src" generateAsyncMethods="false" classpath="${java.class.path}" autoDetectWrapped="true" packageName="ws" > <sysproperty key="javax.xml.rpc.security.auth.username" value="student"/> <sysproperty key="javax.xml.rpc.security.auth.password" value="password"/> </clientgen>

Don't forget to tailor this for your configuration - ie: change the wsdl, student and password values to your configuration!!!
Modifying the client

When you wrote your test JSP to invoke this web service, you needed to locate the port. This was via a method on the service class called getXXXSoapPort() (mine is called getHelloSoapPort() ). The code generated by Weblogic ClientGen includes a variant of this method called getXXXSoapPort(byte[] username, byte[] password) So modify the method call to look like getXXXSoapPort(username.getBytes[], password.getBytes[] ) (assuming that String username contains the username eg: "student", and String password contains the password eg: "password")

Test
Rebuild, and redeploy (if necessary), your client. Check that this now works as expected.

221

Module: Web Services
Lab exercise 7 - Writing a more complex web service
In this exercise we will experiment with different return types from a web service. Level of Difficulty: 3 (medium) Estimated time: 40 minutes Pre-requisites:

222

• • •

Run 'wlenv to set your environment correctly Started the WebLogic server on your workstation Completed Lab exercise 5 - simple web service

Other data types
JAX-RPC defines the following simple Java datatypes to an equivalent in XML schema. See Java Enterprise in a Nutshell, 3rd Ed, chapter 12 for a more complete list. Java Types boolean, java.lang.Boolean byte, java.lang.Byte double, java.lang.Double float, java.lang.Float int, java.lang.Integer long, java.lang.Long short, java.lang.Short java.lang.String java.math.BigDecimal java.math.BigInteger java.net.URI java.util.Calendar java.util.Date java.xml.QName byte[] XML Type: Document-Literal xsd:boolean xsd:byte xsd:double xsd:float xsd:integer xsd:long xsd:short xsd:string xsd:decimal xsd:int xsd:anyURI xsd:dateTime xsd:dateTime xsd:QName xsd:base64Binary

In addition to this, it will map arrays and JavaBeans to an equivalent xsd:ComplexType, xsd:sequence and xsd:element combination.

Lab Exercise: Returning complex types
We will see the impact of returning a simple object array, a and a more complex type as a JavaBean.

Creating a JavaBean
Create a javabean called myapp.HelloBean. This should have the properties String name & int age (hint: create a class in the package myapp called HelloBean, add private String name;

223

private int age; & use source -> Generate getters and setters)

Add new complex methods to your class
Append the following methods into your Hello.java class
@WebMethod public String[] sayHellos (String mate) { String[] list = new String[3]; list[0] = "hi " + mate; list[1] = "hola " + mate; list[2] = "nihao " + mate; return list; } @WebMethod public Vector sayHola (String mate){ Vector<String> v = new Vector<String>(); v.add("hola " + mate); v.add("ciao " + mate); return v; } @WebMethod public HelloBean sayBean (String mate) { HelloBean hb = new HelloBean(); hb.setName(mate); hb.setAge(99); return hb; }

Deploy and look at the WSDL generated. What do you notice? Note that we now have a complexType called "ArrayOfJavaLangstring_literal" - this is the representation of String[]. Ugly isn't it? We also have complexType "HelloBean" - this is the Javabean we created. Note that it has 2 elements, Age and Name of xsd:int and xsd:string respectively. Finally if you look at the "sayHolaResponse" element, we have an anonymous ComplexType with an element called return, with type "java:vector". This is the result of the Vector<String>

Building a client
We can build a client as usual, just do remember to re-run the ant build.xml script in the client project. Modify your existing client to call the new methods added to your web service. You should look at the Hello.java file (the interface).

224

It should contain the method signatures for sayHellos(), sayHola() and sayBean(). Notes: Rather than generating a String[] array, jax-rpc (and in particular, the weblogic implementation of it), generates a holding class, which you then have to call another method (in this case, getJavaLangString() ) to return the String[] array. Rather than generating a vector, java jax-rpc returns an array of Object[]. When you have a Javabean, jax-rpc will return a Javabean back to you.

Module: Security
Lab exercise - Confidentiality
In security terms, "confidentiality" is ensuring that information cannot be accessed by those who do not have permission. It is typically satisfied by encrypting data. This lab exercise looks at how you can use encrypted communication between a client and the presentation tier.

225

Level of Difficulty: 1 (easy) Estimated time: 20 minutes Pre-requisites:
• • •

Run 'wlenv' set your environment correctly Start your WebLogic server running in the background Completed an earlier exercise using servlets or JSPs

Using SSL
The laboratory exercises for this module do not involve writing any new code. It assumes that you have some code from a previous lab, preferably a stateless session EJB, and a Java servlet (or JSP) that calls a business method on the EJB. SSL stands for Secure Sockets Layer, and is also sometimes known as TLS (Transport Layer Security). It is basically a mechanism for encrypting application traffic for transmission over a TCP/IP network. Its most common use is to encrypt HTTP (web) traffic between a web browser and a web server.
• • •

To enable SSL on weblogic 10, go to the Weblogic Console, choose Environment > Servers & select AdminServer You need to click the [Lock and Edit] tab on the top left menu to enable updates Then, on the General tab, select the SSL Listen Port Enabled. Note that the default listen port is 7002. Finally, [Save] and [ACTIVATE CHANGES] to enable SSL.

Try accessing the Weblogic console using SSL: https://localhost:7002/console Try loading one of your earlier web applications (servlet or JSP) using SSL, by using the URL
https://localhost:7002/labs/index.jsp

(change /labs & index.jsp to match your context & JSP

names ) Note that no change was required to the application. You can ignore any messages from your browser about invalid certificates, since effectively we have a 'self-signed' SSL certificate issued from "MyOrganization" to "MyOrganization" !! In a production environment, you would normally purchase an SSL certificate from a commercial vendor such as Verisign or Thawte. You can read your web application server's documentation for the particular process you should follow.

Enforcing SSL
226

Change the web.xml deployment descriptor for the application you just tested, so that it has a <transport-guarantee> tag, specifying that SSL must be used. Insert the following XML into your deployment descriptor after the <welcome-file-list> tag you may have used. You can optionally add <auth-constraints> to enforce login authentication too..
<security-constraint> <web-resource-collection> <web-resource-name>My App</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint>

Then try invoking your application again, first using the SSL URL (starting with https://) as described above. Then try invoking the JSP using a non-SSL URL (use http:// at the start of the URL and use port 7001). What happens (hint: pay close attention to the URL in the browser if you think nothing happens)?

Module: Security
Lab exercise - Web authentication
In a J2EE application, you can require authentication either at the web tier, or at the EJB tier. This lab exercise looks at different ways you can use authentication information in a web application.

227

Level of Difficulty: 1 (easy) Estimated time: 30 minutes Pre-requisites:
• • •

Run 'wlenv' to set your environment correctly Start your WebLogic server running in the background Completed an earlier exercise using servlets or JSPs

Declarative web authentication
The laboratory exercises for this module do not involve writing any new code. It assumes that you have some code from a previous lab, preferably a stateless session EJB, and a Java servlet (or JSP) that calls a business method on the EJB. Declarative web authentication involves adding authentication to a web application without changing the Java source code at all. The authentication requirements are specified purely in the XML deployment descriptor(s). For this exercise, take an existing application, and change the deployment descriptor to require a user to authenticate before being granted access to the application. In the first instance, use HTTP "Basic" authentication. Follow the instructions in the tutorial on using HTTP Basic authentication in web applications.

Programmatic web authentication
Generally, declarative authentication is preferred wherever possible, because it allows the container to manage the authentication process, and reduces the possibility of programmer errors. However, sometimes declarative authentication is not enough. With declarative authentication, the smallest section of an application you can protect is one servlet or JSP. Sometimes, within a single servlet or JSP, you need finer-grained control. With programmatic web authentication, you add some Java code to your servlet/JSP program that checks which user is logged in, and takes appropriate action depending upon the user's identity. For a servlet that you have already created, and set up declarative web security before (previous section), try the following steps for some simple programmatic web authentication. 1. In the servlet's source code, first of all, import the class java.security.Principal (or import java.security.* if you prefer). 2. Somewhere in the doGet() method, add code similar to the following:

228

String username = null; Principal p = req.getUserPrincipal(); if (p != null) { username = p.getName(); } out.println("You are logged in as: " + username);

Module: Transactions
Lab exercise - Transactions
Transactions in J2EE applications are largely managed by the container. That means you can modify the transactional properties of an application by altering values in the deployment descriptor (ejb-jar.xml), so there is not a lot of code to write. This exercise is just to explore an application where a transaction is initiated in a servlet.
229

Level of Difficulty: 1 (easy) Estimated time: 15 minutes Pre-requisites:
• •

Run 'wlenv' to set your environment correctly Start your WebLogic server running in the background

Transactions
There is not much to do, programmatically for transactions. With container-managed transactions, it is an issue of choosing the correct values in the deployment descriptor. Examine an EJB deployment descriptor you created earlier (ejb-jar.xml). You would have created a <container-transaction> declaration like the following.
<assembly-descriptor> <container-transaction> <method> <ejb-name>HelloWorld</ejb-name> <method-intf>Remote</method-intf> <method-name>*</method-name> </method> <trans-attribute>Required</trans-attribute> </container-transaction> </assembly-descriptor>

This example says that for all method-names on the remote interface of EJB HelloWorld, we want to use the transaction attribute "Required". You can change how this EJB method behaves in the context of a transaction by changing the value of the transaction attribute.
Transaction attribute Required Meaning

This method must participate in a transaction. If an existing transaction is already in progress, it will join that one, otherwise a new transaction will be started. This method must participate in a transaction. It will always create a new transaction. If an existing transaction was already in progress, it will suspend that one and create a new one. The new transaction created will have no relationship to the old one.

RequiresNew

NotSupported This method will not participate in a transaction. If an existing transaction was already in progress, it will suspend that one, and execute without a transaction context. Supports This method may or may not participate in a transaction. If an existing transaction is already in progress, it will join that one and run in a transaction. If no transaction is

230

in progress, it will not create a new one, and therefore it will not run in a transaction. Never This method will not participate in a transaction. Further, if an existing transaction was already in progress, it will throw an exception. i.e. it will refuse to run with a transaction. This method must participate in a transaction. Further, if an existing transaction was not already in progress, it will throw an exception. i.e. it will refuse to run without a transaction that is already in progress.

Mandatory

Optional: If you wish to try out some different values, create two different EJBs with one method each. Let's call them EJB1 and EJB2. Set the transaction attribute of EJB1's method to Required, and the transaction attribute of EJB2's method to Never. Make a servlet that invokes EJB1's method. Make EJB1's method invoke EJB2's method. An exception should be thrown.

Starting a transaction in a servlet
So far we have considered transactions only applied to EJB methods. In practice, this is how transactions are used in J2EE applications. However, in rare circumstances, it might be necessary to create a transaction in a servlet or JSP. The following example illustrates how. This lab exercise is merely exploratory - examine the following example of a web application (servlet) that creates a UserTransaction, and then calls a stateless session EJB. The UserTransaction object is created by the application server and is advertised in the JNDI tree, so the servlet merely does a naming lookup to retrieve the transaction context object. Note that using transactions in this way is not usually done in J2EE applications, so you should not try to copy this behaviour in your own applications.
Example application: starting a transaction in a servlet

The application is provided in a separate JAR file and WAR file, for the EJB and servlet components respectively.
• •

TransStatelessSessionEJB.jar TransClient.war

Module: Legacy
Lab exercise - Using CORBA
Many legacy systems use CORBA as their main distributed systems model of programming. This is because CORBA provides an vendor-independent, language-neutral, platform
231

agnostic and open standard. There even exists bridges between proprietary systems such as Microsoft DCOM and CORBA. CORBA can also be more efficient than the J2EE platform - sometimes due to the legacy code such as C being compiled. In the lab environment, a minimal CORBA ORB is provided - this is the open source ORBit and ORBit2 packages under Redhat Linux. Incidentally, this is also required for the GNOME GUI, which uses CORBA to manage the desktop! Level of Difficulty: 3 (medium, extra exercise is hard) Estimated time: 45 minutes Pre-requisites:
• •

Run 'setEnv.sh' to set your environment correctly Ensure . is in your $CLASSPATH

CORBA - C example
We have provided a sample calculator application, written in C, which provides 2 simple functions - add and sub This can be found here as a zip file or alternatively, on /pub/aip/corba/src.zip. For the intrepid, this comes from the orbit documentation package http://www.gnome.org/projects/ORBit2/orbit-docs.tar.gz CORRECTION: There is a bug in Makefile, remove the reference to -llinc in the LDFLAGS= section You can also download the corrected Makefile here. You can also read the Orbit Documentation for this sample at (http://www.gnome.org/projects/ORBit2/orbit-docs/orbit/x478.html) if you are brave (and understand C). Unzip this into a subdirectory. Let's look at the IDL for this application
// // Calculator interface // interface Calculator { double add(in double number1, in double number2); double sub(in double number1, in double number2); };

Basically, this defines 2 functions called add() and sub().

232

Both a server (calculator-server.c) and a client (calculator-client.c) are provided. There is a Makefile available, so you can compile this example.
make

You can test this now by starting up the server in a seperate window and typing
./calculator-server

Let's try the client - run this in your original window..
./calculator-client

Simple eh? 1+2 = 3 Look at the calculator.ref file. This is where the IOR of the server client is temporarily stored. In real life, it would be better to have a lookup mechanism for this object reference, and CORBA 2 provides a human readable naming mechanism based on the URI standard for this very purpose. The IOR is a string that looks something like
IOR:010000001300000049444c3a43616c63756c61746f723a312e3000000300000 00054424f5c0000000101020005000000554e495800000000170000006361747368 61726b2e69742e7574732e6564752e61750000280000002f746d702f6f726269742 d6368772f6c696e632d3431302d302d323730323739383736386434340000000000 caaedfba5400000001010200280000002f746d702f6f726269742d6368772f6c696 e632d3431302d302d3237303237393837363864343400000000001c000000000000 00c0fa8c60a80c68a86b70282828282828010000006f9971a101000000480000000 100000002000000050000001c00000000000000c0fa8c60a80c68a86b7028282828 2828010000006f9971a101000000140000000100000001000105000000000901010 000000000

If you want this decoded, copy this into your clipboard and enter it into the following URL: http://www2.parc.com/istl/projects/ILU/parseIOR/ Note that if you choose Parse(Brief) it shows the NIL object. This is because by default, ORBit does not use IIOP and uses unix domain sockets instead. Let's correct this. You need to create a file called ~/.orbitrc with the following contents
ORBIIOPIPv4=1

Re-run the server, and get the IOR from calculator.ref and try the IOR parser again. You should get a response like
object key is <#00#00#00#00#1C#BCm#FC#A7#D8?#C2#B9#F7#0D#E2#16#FA $#8E#01#00#00#00R#DE#C4#F0>; no trustworthy most-specific-type info; unrecognized ORB; reachable with IIOP 1.2 at host "catshark.it.uts.edu.au", port 34286

Now we can develop CORBA IIOP clients, such as a Java based one.

233

Java CORBA client
We need to generate skeletons for the Java client. Type
idlj calculator.idl

You should get the following files generated
• • • • •

CalculatorHelper.java CalculatorOperations.java Calculator.java CalculatorHolder.java _CalculatorStub.java

We also need to write the client code itself. Create calculator_client.java
import org.omg.CORBA.*; import java.io.*; import java.util.*; class Calculator_client { public static void main( String args[] ) { try{ Properties props = System.getProperties(); System.out.println( "Initializing the orb."); // now get a new instance of an application ORB org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args,props); // read in the IOR reference file BufferedReader in = new BufferedReader( new FileReader("calculator.ref")); String iorString = in.readLine(); // replace above with the following if you are running JDK 1.4.2 // org.omg.IOP.IORHolder ior_holder = new org.omg.IOP.IORHolder(); // String iorString = ior_holder.readIORFile("calculator.ref"); org.omg.CORBA.Object object = orb.string_to_object( iorString ); Calculator calc = CalculatorHelper.narrow( object ); System.out.println("Now calling add"); double res = calc.add((double)1.0,(double)2.0); System.out.println("Call to Corba Calculator="+res); } catch ( org.omg.CORBA.SystemException e ) { System.err.println( "CORBA System Exception "); System.err.println( e ); e.printStackTrace(); } catch (Exception e) { System.err.println("Other java error "+e); e.printStackTrace(); } } }

And compile the lot
javac *.java

(in the supplied Makefile, we have added an extra target called alljava, so you could also type make alljava)

234

If you had errors, correct them, or check that you have '.' in the classpath. Start the calculator-server again, then
java Calculator_client

Hopefully, you should see the correct result come out.

Additional exercises
If you sufficiently skilled in C, you could add extra functions to this application, such as mult or div. Here is the process to follow: 1. Edit calculator.idl file and add the extra definitions. 2. Clear the old code make distclean 3. Edit the calculator-skelimpl.c - you add your methods at the bottom of this file. Use add or sub as a template. 4. Re-generate the code make all 5. You can then also edit the calculator-client.c file to call these extra methods. Don't forget to make all each time you make changes! 6. Finally, you can follow the above steps and modify/compile/run the Java client. One more exercise is to run the client and server on different machines. Since you will be logging onto different machines with the same userid, you should make sure you run the server and client from the same directory, so as to have the same calculator.ref file present.

Module: Legacy
Lab exercise - Using JMS

235

Java Message Service (JMS) provides a Java API for Message Oriented Middleware such as IBM MQseries and integrated JMS providers such as SonicMQ and WebLogic JMS. In this lab, we will experiment with both point-to-point and publish-subscribe messaging patterns. Level of Difficulty: 3 (medium, extra exercise is hard) Estimated time: 45 minutes Pre-requisites:
• • •

Run 'wlenv' to set your environment correctly Ensure . is in your $CLASSPATH Ensure WebLogic server is running

Point-to-Point messaging
Before we can do any programming, we need to setup queues and topics into WebLogic. Enter the WebLogic console.
Part 1: Creating a JMS server and Destinations

Weblogic 9 and 10 have a concept called "JMS Modules". These contain the definitions of all the JMS messaging queues/topics etc. They can be application specific (which requires the creation of a Weblogic-specific XML deployment descriptor) or a System module (which is system wide). We will use the System module in our lab. First we create a JMS Server:
• • • • •

From the weblogic console, press the [Lock & Edit] button to get into edit mode. Choose Services > Messaging > JMS Servers & choose [NEW] Name the server: JMSServer & [Next] Select AdminServer as the Target & [Finish] Choose the [Activate Changes] at the top left menu

Now create the Queue
• • • • • • • •

• • •

From the weblogic console, press the [Lock & Edit] button to get into edit mode. Choose Services > Messaging > JMS module & select [New] Give the new module a name: SystemModule & [Next] Select the AdminServer & [Next] Select the "Would you like to add resources to this JMS System module" checkbox & [Finish] Now we can create the queue for our lab. Select [New] in the "Summary of Resources" table Choose the Queue radio button & [Next] Now enter: name: MyMessageQueue JNDI Name: jms.MyMessageQueue & [Next] Choose [Create a new Subdeployment] - keep the name the system generates & [OK] Choose targets: JMSServer & [Finish] Don't forget to [ACTIVATE] changes (top left menu)

236

Check that the queue exists by going to the Environment > Servers > AdminServer & selecting the "View JNDI tree" link. You should see jms. Expand this and you should see MyMessageQueue appear. We will use the default WebLogic JMS connection factory weblogic.jms.ConnectionFactory. You can optionally create your own connection factory by following the steps when creating a Queue, but choosing Connection factory instead.. We don't need to do this for our lab
Part 2: Create a receiver and sender Java program

Create a subdirectory eg: ~/jms to develop these programs. Note that they are not JSP or servlets, just ordinary Java applications. Here is a simple receiver program called receiver.java
import javax.jms.*; import javax.naming.*; import java.util.Hashtable; public class Receiver implements MessageListener { private QueueConnectionFactory qconFactory; private QueueConnection qcon; private QueueSession qsession; private Queue queue; private QueueReceiver qreceiver;

public static void main (String[] args) throws Exception { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); env.put(Context.PROVIDER_URL,"t3://127.0.0.1:7001"); try { InitialContext ctx = new InitialContext(env); System.out.println("Setting up receiver..."); Receiver r = new Receiver(); r.init(ctx, "jms.MyMessageQueue"); System.out.println("Run init, hit Ctrl-C to stop.."); // loop here if need be. synchronized(r) { r.wait(100000); // wait 100 seconds } System.out.println("Finished waiting, bye..."); } catch (Exception e) { e.printStackTrace(); } } public void init(Context ctx, String queueName) { try { qconFactory = (QueueConnectionFactory) ctx.lookup(

237

"weblogic.jms.ConnectionFactory"); qcon = qconFactory.createQueueConnection(); qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); queue = (Queue) ctx.lookup(queueName); System.out.println("looked up "+queueName); QueueReceiver qreceiver = qsession.createReceiver(queue); System.out.println("Created queueReceiver..."); qreceiver.setMessageListener(this); System.out.println("Starting QueueConnection..."); // start the thread which listens for incoming messages qcon.start(); } catch (Exception e) { e.printStackTrace(); } } //init

public void onMessage(Message msg) { try { String msgText = ((TextMessage)msg).getText(); System.out.println("Message Received: "+ msgText ); } catch (JMSException ex) { ex.printStackTrace(); } } // onMessage }

And here is simple sender program called sender.java
import javax.jms.*; import javax.naming.*; import java.util.Hashtable; public class Sender { public static void main ( String[] args ) throws Exception { try { Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory"); env.put(Context.PROVIDER_URL,"t3://127.0.0.1:7001"); InitialContext ctx = new InitialContext(env); QueueConnectionFactory qconFactory = (QueueConnectionFactory)ctx.lookup( "weblogic.jms.ConnectionFactory"); QueueConnection qcon = qconFactory.createQueueConnection(); QueueSession qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queue = (Queue) ctx.lookup("jms.MyMessageQueue"); QueueSender qsender = qsession.createSender(queue); TextMessage msg = qsession.createTextMessage();

238

qcon.start(); msg.setText ("Hello world"); qsender.send (msg); } catch (Exception e) { e.printStackTrace(); } //catch } // main }

Compile this code. Test by running "java sender" from the shell. NOTE: if you run this from Eclipse/Weblogic Workshop, you will need to add EITHER wljmsclient.jar OR weblogic.jar from your weblogic installation directory (ie: /opt/bea10/wlserver_10.0/server/lib) otherwise you may get a run-time error. Note that you can monitor your queues by using Services-> Messaging > JMS Servers Choose the server (JMSServer) & then choose the Monitoring tab & then "Active Destinations" Note that the name of the queue is actually "SystemModule!MyMessageQueue". Note that the Messages count increases each time you run the "sender". Now let's receive the messages If you run the receiver in a seperate window, you should see the messages get consumed.

Extra work
Develop a publish/subscribe version of the above.
Hints:

Refer to the lecture notes for the different names of the classes, for example, replace Queue with Topic. Also instead of receiving, you subcribe. Instead of sending, you publish.

239

Sign up to vote on this title
UsefulNot useful