J2EE Weblogic Documentation
J2EE Weblogic Documentation
Practical Guide
Bea Weblogic
Shree-Technologies
Shrikant
11/29/2008
Table of Contents
DOMAIN: ..................................................................................................................................... 29
2
Packaging your servlet 2: deployment descriptor ......................................................................... 37
Reflection ...................................................................................................................................... 46
SessionCounterServlet .................................................................................................................. 57
URL Rewriting.............................................................................................................................. 57
3
Tutorial - Accessing resources (e.g. relative files) ........................................................................ 60
Reflection ...................................................................................................................................... 66
A HelloWorld JSP......................................................................................................................... 67
4
Module: JSP ...................................................................................................................................... 76
References ......................................................................................................................................... 94
5
Setting up your Oracle account ..................................................................................................... 95
Lab exercise - Oracle Familiarisation - Workshop for Weblogic version .................................. 100
6
A unit test for the JDBC JavaBean ............................................................................................. 109
7
Module: RMI .................................................................................................................................. 131
8
Lab exercise - Using Eclipse + Xdoclet to generate EJB............................................................ 156
9
Creating EAR files for deployment ............................................................................................ 184
Notes about EAR files (and why they are good)......................................................................... 186
XML............................................................................................................................................ 191
10
Lab exercise 1 - Exploring RPC Web Services .......................................................................... 206
Test.............................................................................................................................................. 218
Lab exercise 6 - Adding Basic security to a simple web service ................................................ 218
Test.............................................................................................................................................. 221
11
Lab Exercise: Returning complex types ......................................................................................... 223
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.
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:
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.
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.
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
• '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!
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.
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):
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
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
cd ~/workspace
./workshop4WP
16
You should click on the X on the [Welcome] tab to close this window to get the following
window:
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)
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.
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
Step 4: From the Weblogic Web Module panel: [x] Use Shared Libraries & press [Finish]
The next challenge is to create HTML files for our web site
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.
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
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
23
Domain Home: /home/userid/weblogic & select [finish] button
(note: userid should be your faculty userid)
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.
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.
This lab exercise is designed to help you become familiar with the first two.
____________________________________________________________
• 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.
____________________________________________________________
____________________________________________________________
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 your own WebLogic domain, in which directory is the file 'startWebLogic.sh' located
in?
____________________________________________________________
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!
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. cd ~/weblogic/
5. Start the server running:
6. ./startWebLogic.sh
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.
Once you logon to the WebLogic console, you will see that there are various options to
change and view.
Relevant areas:
28
DOMAIN:
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.
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!
A HelloWorld servlet
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".
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.
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:
When you package your application as a WAR file, it must follow a particular directory
structure like the following.
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 )
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
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.
You should already have a static HTML file called index.html from the previous lab. Modify
this file to link to your new servlet.
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.
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.
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.
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)
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.
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.
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.
• 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.
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.
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);
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.
48
Follow the same steps you used when creating your Hello World servlet to edit and compile
the code.
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>
<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 <url-
pattern>
10. 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.
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.
<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.
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:
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.
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:
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!
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.
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.
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.
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.
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).
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.
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.
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>");
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!!!
• 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!
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.*;
res.setContentType("text/plain");
PrintWriter out = res.getWriter();
out.println("Hello servlet world!");
out.close();
}
61
}
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.
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:
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).
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.
vi WEB-INF/web.xml
(or use the text editor of your choice). Into the web.xml file, copy the following text:
<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>
• 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
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).
<HTML>
<BODY>
<H1>My first WAR file</H1>
<P>
Run my <A HREF="HW">Hello World servlet</A>.
</P>
</BODY>
</HTML>
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
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.
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 *
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.
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.
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.
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:
67
<title>My First JSP page</title>
</head>
<body>
<h1>My first JSP page</h1>
<p>
<% out.println("Hello JSP World"); %>
</p>
</body>
</html>
o The Java code is embedded between the tags <% and %>
This is called a JSP scriptlet.
o 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 PrintWriter out = request.getWriter();
o 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.
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).
68
1. Create a subdirectory (subfolder or subcontext in web terminology) by selecting
webcontent then pressing Right Mouse Button -> New -> Folder
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
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:
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.
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.
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
<%!
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:
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:
Start
JSP block Can contain
tag
declaration <%! Variable and method declarations, nothing else. In particular, the code
71
must not generate any output
Arbitrary Java code. This is the most general of the three, as you can
scriptlet <%
basically put any Java code you wish inside the tags
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:
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.]
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.
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
Java Type Purpose
object
Using the implicit session object is quite similar as its use in servlets, e.g.
73
• Retrieving an object from the session:
• Integer newcounterval = session.getAttribute("sessioncounter");
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.
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.
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
Java Type Purpose
object
Using the implicit session object is quite similar as its use in servlets, e.g.
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.
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.
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.
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 per-
application 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 <security-
constraint>. 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.
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.
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
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.
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.
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
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 Ctrl-
space 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>
<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>
You can have as many security-role elements as you need - one for each different role your
application requires.
<security-constraint>
specifies a set of pages to protect within the web application, and which users
security-constraint
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.
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.
<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:
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..
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
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
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.
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).
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.
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).
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;
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?
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
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
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.
<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>
</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)
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.
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
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>
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
JSP file if
Action Action Class Comments
successful
91
session, if not, sets an error
Struts Configuration
The next step is to create a Struts configuration file to match the above configuration.
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.
Take special note of the ApplicationResource.properties file - this contains the strings which
our struts application uses.
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
You can check the steps by comparing the directory /pub/aip/struts/struts1 and
/pub/aip/struts/struts2
This allows us to cancel even if we fail validation (since this can get you into a loop!)
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.
• None
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
# 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.
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.
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
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).
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.
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;
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 multi-
line editing mode. This is okay, just enter a semi-colon and press enter to finish the
command.
describe addressbook;
start addressbook.sql;
There is also a quick SQL*Plus tutorial which summarises the few commands you will need
to use Oracle in this subject.
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
Oracle Documentation
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.
• None
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
# 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.
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
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
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'.
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.
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.
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).
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.
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.*;
try {
105
ResultSet rs = stmt.getResultSet();
} 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
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 :-).
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.
package myapp;
import java.sql.*;
import java.util.*;
Class.forName(dbDriver);
108
this.conn = DriverManager.getConnection(dbURL, props);
}
}
Notice that this JavaBean has two properties: dbUser and dbPass. These must be set at
runtime before calling the connect() method.
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
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.
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.
<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>
<% } %>
</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.
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 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.
112
Module: JDBC
Lab exercise - Connection Pools and Data Sources
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.
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.
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:
o [NEXT]
o Choose AdminServer & click [Finish] to create the JDBC data source.
o Initial Capacity = 1
o Maximum Capacity = 2
o 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.
oClick "[Save]"
oActivate changes
oClick on the [Activate Changes] on the top left menu to make the changes active
oUsually 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.
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.
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.*;
115
public ResultSet query(String sql) throws SQLException {
Statement s = conn.createStatement();
return (s.executeQuery(sql));
}
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.
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 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 Class Name URL
Name
Oracle
10g
(Thin ojdbc14.jar oracle.jdbc.OracleDriver jdbc:oracle:thin:@server:1521:db
client
Driver)
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
mysql-
MySQ connector- com.mysql.jdbc.Driver
jdbc:mysql://server:port/db
L 5.0.x java- org.gjt.mm.mysql.Driver
commercial
-5.0.x-
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 wlbase.jar,
- -
gic wlutil.jar
type 4
drivers: weblogic.jdbc.db2.DB2Driv
wldb2.jar jdbc:bea:db2://server:port;DatabaseName=db
IBM er
DB2
8.2/9.1, wlinformix. jdbc:bea:informix://server:port;informixServer=s
weblogic.jdbc.informix.In
Informi jar erver;databaseName=db
formixDriver
x, MS
SQL wlsqlserver. weblogic.jdbc.sqlserver.SQL
jdbc:bea:sqlserver://server\\instance
server jar ServerDriver
2000/2
005, weblogic.jdbc.oracle.Oracle
wloracle.jar jdbc:bea:oracle://server:port;SID=db
Oracle Driver
9g,
10g,
Sybase weblogic.jdbc.sybase.Sybase
wlsybase.jar jdbc:bea:sybase://dbserver:port;SID=db
12.5/15 Driver
.1
Built into
JDBC
Java 1.4 & sun.jdbc.odbc.JdbcOdbcDriv
ODBC jdbc:odbc:odbc-dsn-name
later er
bridge
versions.
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
118
sqlite.jar SQLite.JDBCDriver jdbc:sqlite:/:memory:
postgresql-
PostGr
8.3*.jdbc3.j org.postgresql.Driver jdbc:postgresql://server:port/db
es
ar
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.
• 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:
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:
119
• JDBC URL
Oracle: jdbc:oracle:thin:@smaug.it.uts.edu.au:1522:ell
--> eg: Mysql: jdbc:mysql://localhost/mydb
• 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.
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)
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.
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".
• 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.
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.
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.
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).
commit;
will change the autocommit behaviour for the current SQL*Plus session so that changes are
automatically committed after each SQL command.
describe mytable1;
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
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).
Basic queries
General format:
SELECT column-list|*
FROM table-name-list
WHERE condition-list
ORDER BY column-list;
You can retrieve specific columns (but all rows) from a table:
WHERE clause
You can limit which rows are returned according to some criteria:
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:
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:
Here is a different function - maximum value in a column. There are lots of functions
available.
Sorting
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):
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.
2 Johnson Chris
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:
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:
General format:
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:
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!
The INSERT/DELETE statements are for adding and deleting rows in an existing table.
Inserting rows
General format:
An example:
129
'Wayne',
123,
TO_DATE('2001-01-01', 'YYYY-MM-DD'),
NULL
);
Deleting rows
The syntax of the SQL DELETE statement is quite similar to the SELECT statement, except
no column-list is used.
You can selectively delete rows by adding a WHERE clause, with the same syntax as for a
SELECT, e.g.:
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.
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 well-
established 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:
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.
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.
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.
/**
The remote interface - both the client and the
server share a common view of this interface.
*/
import java.rmi.*;
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.
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;
// 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.
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
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.
/**
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;
Points to notice:
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.
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.
/**
The RMI client which looks up the object
in the name server, retrieves a reference
and invokes the sayit() method.
*/
import java.rmi.Naming;
136
e.printStackTrace();
}
}
}
Points to note:
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.
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)
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.
Remember that you run the server registration class, not the server implementation class.
137
Run the server registration class:
java HelloWorldServer
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 hard-
coded. 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.
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.
• none
139
About LDAP and directory structures
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)
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.
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.
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
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
base_dn 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
scope search, sub means all subcontexts ("subdirectories"). You can leave this out since this
defaults to sub
= equal
>= bigger than (including alphabetic order eg: c > b)
<= less than
~= approximately equal (soundex search so sn~=wong would also return wang,
filter
wing, etc)
You can have logical "and" "or" and "not" filters by prefixing these criteria with a
& | ! character. eg:
rfc2256 has a huge list of what attributes are available. Common ones to use are:
attributes
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
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 ?
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.
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.
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
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.
143
Module: JNDI
Tutorial - Looking up Weblogic LDAP
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.
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.
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
Now you can use the weblogic embedded LDAP directory to view users in myrealm
• 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:
You could also use the same information when you write JNDI Java programs.
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.
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.
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.
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.
package myapp;
import java.rmi.*;
import javax.ejb.*;
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.
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.
package myapp;
import java.rmi.*;
import javax.ejb.*;
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.*;
SessionContext sessionContext;
// SessionBean methods
public void setSessionContext (SessionContext sc) {
this.sessionContext = sc;
}
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
o 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.
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.
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).
<?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"?>
<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>
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
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.
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
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.
import myapp.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import java.util.*;
res.setContentType("text/plain");
PrintWriter out = res.getWriter();
out.println("----------------------------------------");
try {
Context ctx = new InitialContext();
out.println("Got context");
HelloWorldHome hwsh;
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 try-
catch block!) into a scriptlet in a JSP.
Regarding the servlet code itself, notice the sequence of operations for the client:
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.
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.
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.
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.
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]
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.
First step is to create a package. Use New -> Package & call the package myapp
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:
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 non-
weblogic 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.
After the previous setup set has been completed, you should be back to Create Enterprise
Java Bean wizard.
• 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.
f you look in the ejbModule folder of your EJB project, you should see in the myapp package
the following files
To add business methods, edit the HelloBean source file class with the business method like
in the session bean lab.
Notice that there is a special javadoc tag in front called @ejn.interface-method view-
type="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.
• (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
165
This is pretty much the same steps as the Stateless Session Bean lab.
You need to create a JSP into an existing Dynamic Web project with the following code in it.
<%
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(hws.hello("mate"));
%>
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"));
%>
Your client code will need to have access to the myapp.Hello & myapp.HelloHome classes.
(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)
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.
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
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).
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).
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.
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.
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.
package addressbook;
import java.rmi.*;
import javax.ejb.*;
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).
package addressbook;
import java.rmi.*;
import javax.ejb.*;
import java.util.Collection;
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.
package addressbook;
import javax.ejb.*;
170
// EntityBean methods
public void setEntityContext (EntityContext ec) {
this.entityContext = ec;
}
171
String result = getName() + " " + getExtn() + "\n";
return (result);
}
Points to notice:
<?xml version="1.0"?>
<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"?>
<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"?>
<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:
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).
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.
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.
Assuming we are using the existing EJB project, create a new bean by using New -> EJB ->
Xdoclet Enterprise Bean
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:
* Note that XDoclet will run and will create many files, hopefully including the weblogic-
ejb-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.
You will need to edit the AddressBookBean.java file to change the various Xdoclet attributes.
178
* @weblogic.data-source-name ${data.source.name}
* <!-- end-xdoclet-definition -->
* @generated
to
* @weblogic.data-source-name thinOracleDataSource
*
* @generated
• Note that AddressBook is just like an ordinary JavaBean with getters/setters for the properties
of an addressbook bean
• 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!)
• 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.
* 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.
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!!!!
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!!!
/**
* 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)
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.
<%
AddressBookHome h = AddressBookUtil.getHome();
try {
AddressBook bean = h.create("sam",
"Sydney",
"[email protected]",
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
}
<%
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)"
*
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.
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-reference-
description 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
• 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
• 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
<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:
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.
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.
In your servlet/JSP file, the section of code which looks up the EJB is like:
Then in the web.xml deployment descriptor in the WAR file, there should be a declaration of
the EJB reference as follows.
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.
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 "johns-
ejb" 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:
Then in the ejb-jar.xml file, you declare the beans. The declaration, including the reference,
might look as follows:
<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.
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>
cd jar
javac mypackage/*.java
2. Create an EJB jar file, using the same jar syntax as normal
3. Run the appc compiler on your EJB JAR file to generate the generated stubs and skeletons.
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
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.
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.
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.
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.
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>[email protected]</email>
<phonextn>4469</phonextn>
<birthday>2001-01-01</birthday>
</entry>
<entry id="2">
<name>Maolin</name>
<address>Room 4/520</address>
<email>[email protected]</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.
<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.
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.*;
JspWriter out;
193
throws SAXException {
try {
if (name.equals("entry")) {
out.println("</p><p>");
}
} catch (Exception e) { }
}
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
The final step is to package and deploy the files as a web application (WAR file).
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.
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.
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
• 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);
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.
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 well-
formedness 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.
197
// If the current node is null, do nothing
if(currnode == null) {
return;
}
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.
/*
* 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);
}
}
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.
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).
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:
Copy the original dom.jsp file to become dom2.jsp, and make your changes to dom2.jsp.
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.
We will use the existing addressbook.xml file to transform using some XSLT files we will
write.
• 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.
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.
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.
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...
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.
Here is a JSP that will read in addressbook.xml and addressbook.xsl to use the JAXPack to
do XSLT transforms.
204
<%@ page import="javax.xml.transform.stream.*" %>
<%
// 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);
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>
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
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
The final exercise with XSLT is to convert your results to a table looking somewhat like this:
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
(from wikipedia)
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
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.
• 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.
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
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".
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:
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").
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
Now that you have tried one web service, why not try other web services from
xmethods.com?
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.
213
Level of Difficulty: 1 (easy)
Estimated time: 20 minutes
Pre-requisites:
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)
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
214
<fileset dir="/opt/bea10/wlserver_10.0/server/lib">
<include name="weblogic.jar" />
</fileset>
</path>
</target>
<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>
</project>
You should see the ANT build running in the Workshop Console. Hopefully no errors occur.
com.cdyne.ws
ReturnIndicator.java
ws
LUHNChecker.java
LUHNCheckerSoap.java
LUHNCheckerSoap_Stub.java
LUHNChecker_Impl.java
LUHNChecker_saved_wsdl.wsdl
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
You can modify this JSP to take the credit card argument as an input field in a form.
216
Level of Difficulty: 3 (medium)
Estimated time: 40 minutes
Pre-requisites:
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
package myapp;
import javax.jws.*;
@WebService
public class Hello {
@WebMethod
public String hello(String name) {
return "Hello, " + name;
}
}
@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!
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
Follow the instructions in lab 3 and you should be able to write your own JSP client
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:
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 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.
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)
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>
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
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.]
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.
<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!!!
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)
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.
222
• Run 'wlenv to set your environment correctly
• Started the WebLogic server on your workstation
• Completed Lab exercise 5 - simple web service
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.
Creating a JavaBean
Create a javabean called myapp.HelloBean. This should have the properties String name &
int age
223
private int age;
& use source -> Generate getters and setters)
@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;
}
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.
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.
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.
When you have a Javabean, jax-rpc will return a Javabean back to you.
Module: Security
Lab exercise - Confidentiality
225
Level of Difficulty: 1 (easy)
Estimated time: 20 minutes
Pre-requisites:
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.
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 )
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"
!!
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:
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.
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.
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:
Transactions
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 Meaning
attribute
RequiresNew 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.
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.
Mandatory 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.
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.
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.
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!
CORBA - C example
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
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).
//
// Calculator interface
//
interface Calculator
{
double add(in double number1, in double number2);
double sub(in double number1, in double number2);
};
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
./calculator-client
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
Now we can develop CORBA IIOP clients, such as a Java based one.
233
Java CORBA client
idlj calculator.idl
You should get the following files generated
• CalculatorHelper.java
• CalculatorOperations.java
• Calculator.java
• CalculatorHolder.java
• _CalculatorStub.java
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);
// 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");
} 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.
java Calculator_client
Additional exercises
If you sufficiently skilled in C, you could add extra functions to this application, such as mult
or div.
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.
Point-to-Point messaging
Before we can do any programming, we need to setup queues and topics into WebLogic.
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.
• 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
• 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.
Create a subdirectory eg: ~/jms to develop these programs. Note that they are not JSP or
servlets, just ordinary Java applications.
import javax.jms.*;
import javax.naming.*;
import java.util.Hashtable;
237
"weblogic.jms.ConnectionFactory");
qcon = qconFactory.createQueueConnection();
qsession = qcon.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
} // onMessage
}
And here is simple sender program called sender.java
import javax.jms.*;
import javax.naming.*;
import java.util.Hashtable;
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");
238
qcon.start();
msg.setText ("Hello world");
qsender.send (msg);
} catch (Exception e) {
e.printStackTrace();
} //catch
} // main
}
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".
If you run the receiver in a seperate window, you should see the messages get consumed.
Extra work
Hints:
Refer to the lecture notes for the different names of the classes, for example, replace Queue
with Topic.
239