Jakarta EE Programming/Printable version
This is the print version of Jakarta EE Programming You won't see this message or any elements not part of the book's content when you print or preview this page. |
The current, editable version of this book is available in Wikibooks, the open-content textbooks collection, at
https://en.wikibooks.org/wiki/Jakarta_EE_Programming
Frameworks
Most of the Jakarta EE technologies are used with a framework. This is the main difference with the plain old Java programming. So you must become familiar to the framework usage.
Framework vs library
[edit | edit source]A framework or a library is a code that you use but you don't write on your own. Consider the following code:
class MainProgram {
public static void main(String[] args) {
SubProgram.doProcess();
}
}
|
class SubProgram {
public static void doProcess() {
System.out.println("Do the process.");
}
}
|
The code on the left is calling the code on the right. If you use a library, you are writing the code on the left and you don't write the code on the right, so the library is on the right:
class MainProgram {
public static void main(String[] args) {
SubProgram.doProcess();
}
}
|
class SubProgram {
public static void doProcess() {
System.out.println("Do the process.");
}
}
|
If you use a framework, you are writing the code on the right and you don't write the code on the left, so the framework is on the left:
class MainProgram {
public static void main(String[] args) {
SubProgram.doProcess();
}
}
|
class SubProgram {
public static void doProcess() {
System.out.println("Do the process.");
}
}
|
This means that you will not launch your own code. You will launch a product that will read your code and use it. You don't know how your code will be used.
Frameworks in Jakarta EE
[edit | edit source]- When you build a Jakarta EE, you generate a
.ear
or.war
file. This file is respectively executed in an application server or a servlet container. Application servers and servlet containers are frameworks. The most used Jakarta EE application servers are Glassfish, WildFly and Geronimo. The most used Jakarta EE servlet container is Tomcat. - When you write a servlet, it will be executed in a servlet container, which is a framework.
- When you write a
.jsp
, it will be read by the JSP compiler, which is a framework. The Apache Tomcat JSP compiler is Tomcat Jasper.
There are lots of other frameworks that are used in Jakarta EE. They do lots of things you wouldn't be able to write on your own.
Bad practice
[edit | edit source]Do not debug your code as you would debug it with a library. Jakarta EE coding needs other practices than Java coding. Even if you have the source code of the framework, do not try to read it. Most of the time, it is impossible to understand and you will waste your time. You will never find the way the framework is calling your code (a framework often generates some classes at runtime).
When you have an error, you have to read the framework specifications. It is the only way to find a solution. Most of the time, the stacktraces are very long. Only read the part that mentions your own code. If the stacktrace mentions an error code, search the error code in the framework specifications.
Sometimes, the framework specifications are not enough to find the bug. In this case, do not try to understand the error on your own, if the error is in a framework class. The best thing to do is to find someone who already encounters this error and knows the solution. It can be colleagues or people on an internet forum. The most famous is Stack Overflow.
WildFly
WildFly (formerly JBoss) is an open source application server developed by Red Hat. Here is the first steps to use it:
- Download it from the website. You will need a Red Hat account.
- Launch the JAR file with Java. If you're not familiar with an application server, try to keep the default options as much as possible. Note the location where JBoss will be installed.
JBoss should be installed. To verify so, we will create a minimalist application to run.
- Create a file called
index.html
with the following content:
<html> <body> Hello World! </body> </html>
- Open this file with a web browser. It should display "Hello World!".
- Close the browser.
- If you are on Windows or Mac, zip the file (i.e. create an archive).
- If you are on Linux or UNIX, create an archive, compressed or not, like a .tar file.
- Rename the archive file to
helloworld.war
(yes, rename also the file extension). - Put the WAR file in the
standalone\deployments
folder of JBoss (you should have noted where JBoss is installed). - Start JBoss. If you are on Windows, you should find the option to start JBoss in the Windows start menu. Otherwise, you can start JBoss by launching the script
standalone.bat
(on Windows) orstandalone.sh
(on Mac, Linux or UNIX) in thebin
folder of JBoss. In thedeployments
folder, you should see the deployed version of your application:helloworld.war.deployed
. - On a browser, go on
http://localhost:8080/helloworld/
. You should see "Hello World!".
IDE/Eclipse
Eclipse
[edit | edit source]Goals
[edit | edit source]- learn how to set up eclipse
- learn which plugins are available for developing j2ee applications
- develop a basic example, compile it and deploy it
What is Eclipse
[edit | edit source]- Eclipse is an Integrated Development Environment written in Java by IBM
- Eclipse is Open-Source-Software
- Eclipse offers many plugin to use for different tasks
Set Up Eclipse
[edit | edit source]requirements
[edit | edit source]- your installed JDK is working, to check it enter in a shell:
java -version
result should be something like
java version "1.5.0_06" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05) Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)
action
[edit | edit source]- go to http://www.eclipse.org/downloads/ and download the Eclipse which matches your platform
- this book assumes you use version 3.2.1
- untar eclipse-SDK-3.2.1-linux-gtk.tar.gz
- change to directory eclipse
- start eclipse
- if you have never worked with eclipse before, you should do the tutorials
- plugins are installed via Update Manager
- Help->Software Updates->Find and Install
- Select Search for New features
Set Up Plugins
[edit | edit source]- Your needed plugins depend on your project's goal
The Ecplise Web Tools Platform Project
[edit | edit source]- You want to develop a J2EE Web-application
- Consists of source editors for HTML, JavaScript, CSS, JSP, SQL, XML, DTD, XSD, and WSDL; graphical editors for XSD and WSDL
- project homepage: http://www.eclipse.org/webtools/index.html
Requirements
[edit | edit source]- Graphical Editing Framework (GEF)
- url for update manager: http://download.eclipse.org/tools/gef/update-site/releases/site.xml
- documentation: GEF http://wiki.eclipse.org/index.php/GEF_Developer_FAQ#Download_and_Install
- Visual Editor (VE)
Action
[edit | edit source]- url for update manager: http://download.eclipse.org/webtools/updates/
- documentation: http://download.eclipse.org/webtools/updates/
Building an example application
[edit | edit source]Lomboz
[edit | edit source]Building an example application
[edit | edit source]how to build a prg in lomboz.
other plugins
[edit | edit source]Building an example application
[edit | edit source]further reading
[edit | edit source]links
[edit | edit source]
Servlet
A servlet is a Java class that runs on the server side that receives HTTP data and does a processing or more following the constraints of the HTTP protocol.
The servlets
[edit | edit source]Example of servlet
[edit | edit source]package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class Hello
*/
@WebServlet("/Hello")
public class Hello extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public Hello() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("Hello World");
} finally {
out.close();
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request,response);
}
}
Description
[edit | edit source]We notice two methods in this class: doGet()
and doPost()
. The first answers by HTTP to the reception of a GET request, the second to the reception of a POST request. As we want that in the both cases the servlet processes the request, doPost()
forwards to doGet()
.
Deployment on Tomcat
[edit | edit source]- Put the compiled class with its package in the directory
classes
inWEB-INF
of the working web directory (here:webTest
) - Edit
web.xml
inWEB-INF
by adding:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<!-- Beginning here -->
<servlet>
<servlet-name>Hello</servlet-name><!-- Class name -->
<servlet-class>servlet.Hello</servlet-class><!-- Class tree: with the package -->
</servlet>
<servlet-mapping>
<servlet-name>Hello</servlet-name><!-- Class name -->
<url-pattern>/Hello</url-pattern><!-- Class pattern in the URL-->
</servlet-mapping>
<!-- End here -->
<web-app>
So the WEB-INF
contains:
WEB-INF web.xml classes servlet Hello.class
Call of the servlet
[edit | edit source]http://localhost:999/webTest/Hello
Result in the browser:
Hello World
Decomposition of the URL
[edit | edit source][Protocol://][DNS]:[PORT]/[RootEntryDirectory]/[ServletName]
Information methods about the URL
[edit | edit source]// Returns the server name
request.getServerName();
// Returns the server port
request.getServerPort();
// Returns the name of the application hosting the servlet
request.getContextPath();
// Returns the servlet path
request.getServletPath();
// Returns the type of the HTTP request used
request.getMethod();
// Returns the parameters sent in the URL
request.getQueryString();
// Returns the URL used to contact the servlet
request.getRequestURL();
// Returns the local address
request.getLocalAddr();
// Returns the local name
request.getLocalName();
// Returns the local port
request.getLocalPort();
// Returns the remote address
request.getRemoteAddr();
// Returns the remote host
request.getRemoteHost();
Example in the servlet:
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class Hello
*/
@WebServlet("/Hello")
public class Hello extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public Hello() {
super();
// TODO Auto-generated constructor stub
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println(request.getServerName());
out.println("<br/>");
out.println(request.getServerPort());
out.println("<br/>");
out.println(request.getContextPath());
out.println("<br/>");
out.println(request.getServletPath());
out.println("<br/>");
out.println(request.getMethod());
out.println("<br/>");
out.println(request.getQueryString());
out.println("<br/>");
out.println(request.getRequestURL());
out.println("<br/>");
out.println(request.getLocalAddr());
out.println("<br/>");
out.println(request.getLocalName());
out.println("<br/>");
out.println(request.getLocalPort());
out.println("<br/>");
out.println(request.getRemoteAddr());
out.println("<br/>");
out.println(request.getRemoteHost());
} finally {
out.close();
}
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request, response);
}
}
The related call: http://localhost:999/webTest/Hello
localhost 999 /webTest /Hello GET null http://localhost:999/webTest/Hello 127.0.0.1 localhost 999 127.0.0.1 127.0.0.1
Parameter reading methods
[edit | edit source]// Parameter retrieving by the "parameterName"
request.getParameter(parameterName);
// Returns an enumeration of all the parameters of a request
request.getParameterNames();
// Returns all the parameter values of "parameterName"
request.getParameterValues(parameterName);
// Returns an iteration of the parameter names
request.getParameterMap();
Header reading methods
[edit | edit source]// Returns the header names
request.getHeaderNames();
// Returns the headers
request.getHeaders();
// Returns the number of bytes of the request
request.getContentLength();
// Returns the content type of the request
request.getContentType();
// Returns the default language
request.getLocale();
// Returns the list of languages
request.getLocales();
// Returns the header date
request.getDateHeader(String name);
// Returns the header specified by the "name"
request.getHeader(String name);
// Returns the headers specified by the "name"
request.getHeaders(String name);
Request methods for adding information
[edit | edit source]// Store an object in the HttpServletRequest object
request.setAttribute(String name, Object o);
// Returns the stored object "name"
request.getAttribute(String name);
// Returns an enumeration of the attribute names
request.getAttributeNames();
// Remove the attribute "name" the attributes of the request
request.removeAttribute(String name);
Request methods for adding headers
[edit | edit source]The HTTP headers adds complementary informations to the response.
// Indicates the nature of the information put into the response
response.setContentType(String type);
// Indicates the local language
response.setLocale(Locale loc);
// Adds the header "name" with the value "value"
response.addHeader(String name, String value);
Construction of the response body
[edit | edit source](PrintWriter)getWriter()
allows to transfer text into the HTTP response body.(ServletOutputStream)getOutputStream()
allows to transfer binary data into the HTTP response body.
Never use the both at the same time, or you will have an IllegalStateException
exception.
Here is an example of binary sending:
package servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ReponseHttp2
*/
@WebServlet("/HttpResponse2")
public class HttpResponse2 extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public HttpResponse2() {
super();
// TODO Auto-generated constructor stub
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendRedirect("images/toto.jpg");
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request, response);
}
}
In this example, we use processRequest(request, response)
to always get the same process in GET or POST.
Constructing the HTTP response
[edit | edit source]The status codes are splitted into 5 categories:
- 1XX: informative
- 2XX: success
- 3XX: redirection
- 4XX: client error
- 5XX: server error
The details of these codes are available at http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
setStatus(int rc)
sendError(int sc, String message)
...allow to set the error status of the page. As an example, we will generate a server error.
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class ReponseHTTP
*/
@WebServlet("/ReponseHTTP")
public class ReponseHTTP extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ReponseHTTP() {
super();
// TODO Auto-generated constructor stub
}
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "the server is overloaded. Please try later.");
} finally {
out.close();
}
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
processRequest(request, response);
}
}
Other ressources
[edit | edit source]RequestDispatcher
[edit | edit source]include
[edit | edit source]Inclusion of an external resource.
RequestDispatcher rd = null;
rd = getServletContext().getRequestDispatcher("/header.html");
rd.include(request, response);
forward
[edit | edit source]Servlet result transfer to another resource.
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.HttpServlet;
import javax.servlet.HttpServletRequest;
import javax.servlet.HttpServletResponse;
public class Result extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
int result = 10;
RequestDispatcher rd = null;
rd = getServletContext().getRequestDispatcher("/result.jsp");
request.setAttribute("theResult", result);
rd.forward(request, response);
} finally {
out.close();
}
}
}
The destination resource: result.jsp
<%@page contentType="text/html" pageEncoding="UTF-8">
<%@page import="java.text.*" %>
<html>
<body>
<%
theResult = (double) request.getAttribute("theResult");
%>
Result: <%= theResult %>
</body>
</html>
Redirect
[edit | edit source]The server informs the browser to send a HTTP request to the given URL.
location
[edit | edit source]response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // For a 301 HTTP response
response.setHeader("location", "http://www.google.be"); // For a 302 HTTP response
redirect
[edit | edit source]response.sendRedirect("http://www.google.be");
Filters
[edit | edit source]The filters add a process on a HTTP request before it is received by the servlet or on the HTTP response before it is returned.
Its roles are:
- Access control
- Access log
- Data decompression
- Decipherment
- Data conversion
Several responses can be executed successively. The filter class must implement javax.servlet.Filter
.
Events
[edit | edit source]The events inform about the application operations like the instantiation and the destruction of the objects.
- Application-related events: Those triggered by the servlet context.
- Session-related events : Those classes must implement
HttpSessionListener
,HttpSessionAttributeListener
.
Servlet synchronization
[edit | edit source]This synchronization avoids the server to use two threads at the same time, for example, when two instances of the same class call a same method with two different clients. synchronized(this){}
must be applied to the critical processes like counters.
public class ... {
public void method() {
out = response.getWriter();
synchronized(this) {
counter++;
}
out.println("The counter value is " + counter);
}
}
Jakarta Server Pages
Here is a minimalist tutorial to create a JSP using Eclipse.
- If you have not already installed Eclipse, read this page.
- If you have not already installed an application server, read this page.
- Launch Eclipse
- On the Project Explorer view, right-click and select New -> Other...
- Select Web -> Dynamic Web project .
- Type helloworld for the Project name.
- On Target runtime, make sure that you have selected your application server instance.
- Click on Finish .
- Double-click on your new project to open it.
- Right-click on the folder WebContent .
- Select New -> JSP File .
- On File name, type
FirstPage.jsp
. It will be the name of your JSP. - Click on Finish . The new
FirstPage.jsp
file should appear in the folder WebContent . - Locate the text
<body>
in the new JSP file. - After this text, write
Hello World!
. - Right-click on the folder WebContent/WEB-INF .
- Select New -> File .
- On File name, type
web.xml
. This file is used to link our JSP with a URL in order to access to it. It can map many other things. - Click on Finish .
- Double-click on the new file to open it.
- In the file, write the following content:
<?xml version="1.0" encoding="ISO-8859-1" ?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <servlet> <servlet-name>firstpage</servlet-name> <jsp-file>/FirstPage.jsp</jsp-file> </servlet> <servlet-mapping> <servlet-name>firstpage</servlet-name> <url-pattern>/firstpage</url-pattern> </servlet-mapping> </web-app>
- Right-click on the project.
- Select Export -> WAR file . If you don't find the option WAR file, click on Export... instead, select Web -> WAR file and click on Next >. The web project should be named
helloworld
. - Choose a location for the destination. It's the folder where your application containing your JSP will be created. Remember this location.
- Click on Finish .
- Go on the folder where you have created your application. You should see a file named
helloworld.war
. - Copy/paste your WAR file in the deployment folder of your application server.
- Start your application server.
- On a browser, go on
http://localhost:8080/helloworld/firstpage
. You should see "Hello World!".
On the URL, helloworld comes from the name of the WAR file we have created and firstpage comes from the markup <url-pattern>
in the web.xml
file.
Jakarta Server Pages Syntax
The JavaServer Pages is a technology for inserting dynamic content into an HTML or XML page using a Java servlet container. In other word, instead of sending HTML pages to web clients that are always the same for every one, you can send HTML pages that can be different for each client and each time they receive it (using database data for instance). To explain it, let's have a simple HTML page on a web server. The data flow is simple. To put it simply, the client requests a HTML page by sending the page URL and the server returns the given HTML page:
Client | Server | |||
URL | ||||
Retrieve the file | ||||
Here are the HTML file and the display on the client:
The HTML page | The display |
<html>
<body>
<span style="color: blue;">The current time</span>
</body>
</html>
|
The current time |
The returned page is always the same. Now we want to display the current time. To do so, we add a servlet container to the web server. The HTML page will no longer exist on the server. When the page will be requested by a client, a Java class will generate the HTML page and the HTML page will be sent to the client. This Java class is called a servlet:
Client | Web server | Servlet container | |||||
URL | |||||||
Ask to generate the file |
|||||||
Execute the Java class |
|||||||
Here are the Java class, the generated HTML file and the display on the client:
The servlet | The HTML page | The display |
package jsp_servlet;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
class _myservlet implements javax.servlet.Servlet, javax.servlet.jsp.HttpJspPage {
public void _jspService(javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws javax.servlet.ServletException,
java.io.IOException {
javax.servlet.ServletConfig config = …; // Get the servlet config
Object page = this;
PageContext pageContext = …; // Get the page context for this request
javax.servlet.jsp.JspWriter out = pageContext.getOut();
HttpSession session = request.getSession(true);
try {
out.print("<html>\r\n");
out.print("<body>\r\n");
out.print("<span style="color: blue;">");
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Calendar cal = Calendar.getInstance();
out.print(dateFormat.format(cal.getTime()));
out.print("</span>\r\n");
out.print( "</body>\r\n" );
out.print( "</html>\r\n" );
…
} catch (Exception _exception) {
// Clean up and redirect to error page in <%@ page errorPage="myerror.jsp" %>
}
}
}
|
<html>
|
2024/12/08 01:41:39 |
Now the page is dynamic but the servlet is hard to code and to read. So we will use a JavaServer Page (JSP). A JSP is written like a HTML page. It has the file extension .jsp
for HTML page and the file extension .jspx
for an XML markup page. In addition to the HTML syntax, it has embedded scriptlets and jsp tags. A scriptlet is a portion of Java code. The servlet container generates a servlet from the JSP and the servlet will be used to generate HTML pages or XML content. The HTML markups will remains as it is. The embedded scriptlets are inserted into the code of the servlet. The jsp tags are transformed into Java code. So let's use a JSP:
Client | Web server | Servlet container | |||||
URL | |||||||
Ask to generate the file |
|||||||
Generate the servlet | |||||||
Execute the Java class | |||||||
Actually, the servlet is generated by the JSP only for the first request call. The same servlet is reused after then. It is generated again when the JSP will change. Now we have a JSP, that generates a servlet, that generates a HTML page, that will be displayed to the client:
The JSP | The servlet | The HTML page | The display |
<%@ page errorPage="myerror.jsp" %>
<%@ page import="java.text.DateFormat" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.util.Calendar" %>
<html>
<body>
<% DateFormat dateFormat =
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Calendar cal = Calendar.getInstance();
%>
<span style="color: blue;">
<%= dateFormat.format(cal.getTime()) %>
</span>
</body>
</html>
|
package jsp_servlet;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
class _myservlet implements javax.servlet.Servlet,
javax.servlet.jsp.HttpJspPage {
public void _jspService(
javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws javax.servlet.ServletException,
java.io.IOException {
javax.servlet.ServletConfig config = …;
Object page = this;
PageContext pageContext = …;
javax.servlet.jsp.JspWriter out =
pageContext.getOut();
HttpSession session = request.getSession(true);
try {
DateFormat dateFormat =
new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Calendar cal = Calendar.getInstance();
out.print("<html>\r\n");
out.print("<body>\r\n");
out.print("<span style="color: blue;">\r\n");
out.print(dateFormat.format(cal.getTime()));
out.print("\r\n");
out.print("</span>\r\n");
out.print( "</body>\r\n" );
out.print( "</html>\r\n" );
…
} catch (Exception _exception) {
}
}
}
|
<html>
|
2024/12/08 01:41:39 |
Scripting elements
[edit | edit source]There are three basic kinds of scripting elements that allow java code to be inserted directly into the JSP.
- A declaration tag places a variable definition inside the body of the java servlet class. Static data members may be defined as well. Also inner classes can be defined here.
<%! int serverInstanceVariable = 1; %>
Declaration tags also allow methods to be defined.
<%! /** * Converts the Object into a string or if * the Object is null, it returns the empty string. */ public String toStringOrBlank(Object obj) { if (obj != null) { return obj.toString(); } return ""; } %>
- A scriptlet tag places all of the statements contained within it, inside the
_jspService()
method of the java servlet class.
<% int localStackBasedVariable = 1; out.println(localStackBasedVariable); %>
- An expression tag places an expression to be evaluated inside the java servlet class. Expressions should not be terminated with a semi-colon.
<%= "expanded inline data " + 1 %>
- A comment tag does nothing. It is ignored. It lets you document the file. It is different from a HTML comment as a HTML comment (
<!-- -->
) will appear in the generated HTML file.
<%-- This is my first JSP. --%>
Directives
[edit | edit source]JSP directives are added at the top of a JSP page. These directives control how the JSP compiler generates the servlet. The following directives are available:
- include
- The include directive informs the JSP compiler to include a complete file into the current file. It is as if the contents of the included file were pasted directly into the original file. This functionality is similar to the one provided by the C preprocessor. Included files generally have the extension "jspf" (for JSP Fragment):
<%@ include file="somefile.jspf" %>
- page
- The page directive has several attributes:
import |
Results in a Java import statement being inserted into the resulting file.
|
contentType |
Specifies the content that is generated. This should be used if HTML is not used or if the character set is not the default character set. |
errorPage |
Indicates the address of the page that should be shown if an exception occurs while processing the HTTP request. |
isErrorPage |
If set to true, it indicates that this is the error page. Default value is false. |
isThreadSafe |
True if the resulting servlet must be thread safe. |
autoFlush |
To autoflush the contents. A value of true, the default, indicates that the buffer should be flushed when it is full. A value of false, rarely used, indicates that an exception should be thrown when the buffer overflows. A value of false is illegal when also using buffer="none". |
session |
To maintain session. A value of true (the default) indicates that the predefined variable session (of type HttpSession ) should be bound to the existing session if one exists, otherwise a new session should be created and bound to it. A value of false indicates that no sessions will be used, and attempts to access the variable session will result in errors at the time the JSP page is translated into a servlet.
|
buffer |
To set Buffer Size. The default is 8k and it is advisable that you increase it. |
isELIgnored |
Defines whether Expression Language (EL) expressions are ignored when the JSP is translated. |
language |
Defines the scripting language used in scriptlets, expressions and declarations. Right now, the only possible value is "java". |
extends |
Defines the superclass of the class this JSP will become. Don't use this unless you really know what you're doing — it overrides the class hierarchy provided by the Container. |
info |
Defines a String that gets put into the translated page, just so that you can get it using the generated servlet's inherited getServletInfo() method.
|
pageEncoding |
Defines the character encoding for the JSP. The default is "ISO-8859-1" (unless the contentType attribute already defines a character encoding, or the page uses XML document syntax). |
<%@ page import="java.util.*" %> <%-- example import --%> <%@ page contentType="text/html" %> <%-- example contentType --%> <%@ page isErrorPage="false" %> <%-- example for non error page --%> <%@ page isThreadSafe="true" %> <%-- example for a thread safe JSP --%> <%@ page session="true" %> <%-- example for using session binding --%> <%@ page autoFlush="true" %> <%-- example for setting autoFlush --%> <%@ page buffer="20kb" %> <%-- example for setting Buffer Size --%>
- Note: Only the "import" page directive can be used multiple times in the same JSP.
- taglib
- The taglib directive indicates that a JSP tag library is to be used. The directive requires a prefix (much like a namespace in C++) and the URI for the tag library description.
<%@ taglib prefix="myprefix" uri="taglib/mytag.tld" %>
Example
[edit | edit source]Regardless of whether the JSP compiler generates Java source code for a servlet or emits the byte code directly, it is helpful to understand how the JSP compiler transforms the page into a Java servlet. For example, consider the following input JSP and its resulting generated Java Servlet.
Input JSP | Resulting servlet |
<%@ page errorPage="myerror.jsp" %>
<%@ page import="com.foo.bar" %>
<html>
<head>
<%! int serverInstanceVariable = 1;%>
<% int localStackBasedVariable = 1; %>
</head>
<body>
<table>
<%-- This will be ignored. --%>
<tr><td><%= toStringOrBlank( "expanded inline data " + 1 ) %></td></tr>
</table>
</body>
</html>
|
package jsp_servlet;
import java.util.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.*;
import com.foo.bar; // Imported as a result of <%@ page import="com.foo.bar" %>
import …
class _myservlet implements javax.servlet.Servlet, javax.servlet.jsp.HttpJspPage {
// Inserted as a
// result of <%! int serverInstanceVariable = 1;%>
int serverInstanceVariable = 1;
…
public void _jspService(javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response)
throws javax.servlet.ServletException,
java.io.IOException {
javax.servlet.ServletConfig config = …; // Get the servlet config
Object page = this;
PageContext pageContext = …; // Get the page context for this request
javax.servlet.jsp.JspWriter out = pageContext.getOut();
HttpSession session = request.getSession(true);
try {
out.print("<html>\r\n");
out.print("<head>\r\n");
…
// From <% int localStackBasedVariable = 1; %>
int localStackBasedVariable = 1;
…
out.print("</head>\r\n");
out.print("<body>\r\n");
out.print("<table>\r\n");
out.print(" <tr><td>");
// From <%= toStringOrBlank( "expanded inline data " + 1) %>
out.print(toStringOrBlank( "expanded inline data " + 1 ));
out.print(" </td></tr>\r\n");
out.print("</table>\r\n");
out.print("</body>\r\n");
out.print("</html>\r\n");
…
} catch (Exception _exception) {
// Clean up and redirect to error page in <%@ page errorPage="myerror.jsp" %>
}
}
}
|
Implicit objects
[edit | edit source]We have seen that we can declare objects in a scriplet that we can use further. There are also already declared objects that can be used by the programmer. They are called implicit object:
out |
The JspWriter used to write the data to the response stream. |
page |
The servlet itself. |
pageContext |
A PageContext instance that contains data associated with the whole page. A given HTML page may be passed among multiple JSPs. |
request |
The HttpServletRequest object that provides HTTP request information. |
response |
The HttpServletResponse object that can be used to send data back to the client. |
session |
The HttpSession object that can be used to track information about a user from one request to another. |
config |
Provides servlet configuration data. |
application |
Data shared by all JSPs and servlets in the application. |
exception |
Exceptions not caught by application code. |
JSP actions
[edit | edit source]JSP actions are XML tags that invoke built-in web server functionality. They are executed at runtime. Some are standard and some are custom (which are developed by Java developers). The following are the standard ones.
jsp:include
[edit | edit source]Like the include directive, this tag includes a specified jsp into the returned HTML page but it works differently. The Java servlet temporarily hands the request and response off to the specified JavaServer Page. Control will then return to the current JSP, once the other JSP has finished. Using this, JSP code will be shared between multiple other JSPs, rather than duplicated.
<html>
<head></head>
<body>
<jsp:include page="mycommon.jsp" >
<jsp:param name="extraparam" value="myvalue" />
</jsp:include>
name:<%=request.getParameter("extraparam")%>
</body>
</html>
jsp:param
[edit | edit source]Can be used inside a jsp:include
, jsp:forward
or jsp:params
block. Specifies a parameter that will be added to the request's current parameters.
jsp:forward
[edit | edit source]Used to hand off the request and response to another JSP or servlet. Control will never return to the current JSP.
<jsp:forward page="subpage.jsp" >
<jsp:param name="forwardedFrom" value="this.jsp" />
</jsp:forward>
In this forwarding example, the request is forwarded to subpage.jsp
.
jsp:plugin
[edit | edit source]Older versions of Netscape Navigator and Internet Explorer used different tags to embed an applet. This action generates the browser specific tag needed to include an applet. The plugin example illustrates an HTML uniform way of embedding applets in a web page. Before the advent of the <OBJECT>
tag, there was no common way of embedding applets.
<jsp:plugin type=applet height="100%" width="100%"
archive="myjarfile.jar, myotherjar.jar"
codebase="/applets"
code="com.foo.MyApplet" >
<jsp:params>
<jsp:param name="enableDebug" value="true" />
</jsp:params>
<jsp:fallback>
Your browser does not support applets.
</jsp:fallback>
</jsp:plugin>
Currently, the jsp:plugin
tag does not allow for dynamically called applets. For example, jsp:params
cannot be used with a charting applet that requires the data points to be passed in as parameters unless the number of data points is constant. You cannot, for example, loop through a ResultSet to create the jsp:param
tags. Each jsp:param
tag must be hand-coded.
jsp:fallback
[edit | edit source]The content to show if the browser does not support applets.
jsp:getProperty
[edit | edit source]Gets a property from the specified JavaBean.
JSP tag libraries
[edit | edit source]In addition to the pre-defined JSP actions, developers may add their own custom actions using the JSP Tag Extension API. Developers write a Java class that implements one of the Tag interfaces and provide a tag library XML description file that specifies the tags and the java classes that implement the tags.
Consider the following JSP.
<%@ taglib uri="mytaglib.tld" prefix="myprefix" %> … <myprefix:myaction> <%-- The start tag --%> … </myprefix:myaction> <%-- The end tag --%> …
The JSP compiler will load the mytaglib.tld XML file:
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>My taglib</short-name>
<tag>
<name>myaction</name>
<tag-class>org.wikibooks.en.MyActionTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
The JSP compiler will see that the tag myaction
is implemented by the java class MyActionTag
:
public class MyActionTag extends TagSupport {
public MyActionTag() { … }
// Releases all instance variables.
public void release() { … }
// Called for the start tag
public int doStartTag() { … }
// Called at the end tag
public int doEndTag() { … }
}
The first time the tag is used in the file, it will create an instance of MyActionTag
. Then (and each additional time that the tag is used), it will invoke the method doStartTag()
when it encounters the starting tag. It looks at the result of the start tag, and determines how to process the body of the tag. The body is the text between the start tag and the end tag. The doStartTag()
method may return one of the following:
SKIP_BODY |
The body between the tag is not processed. |
EVAL_BODY_INCLUDE |
Evaluate the body of the tag. |
EVAL_BODY_TAG |
Evaluate the body of the tag and push the result onto stream (stored in the body content property of the tag). |
Note: If tag extends the BodyTagSupport
class, the method doAfterBody()
will be called when the body has been processed just prior to calling the doEndTag()
. This method is used to implement looping constructs.
When it encounters the end tag, it invokes the doEndTag()
method. The method may return one of two values:
EVAL_PAGE |
This indicates that the rest of the JSP file should be processed. |
SKIP_PAGE |
This indicates that no further processing should be done. Control leaves the JSP page. This is what is used for the forwarding action. |
If you want to iterate the body a few times, your java class (tag handler) must implement the IterationTag
interface. It returns EVAL_BODY_AGAIN
— which means to invoke the body again.
JSP Standard Tag Library (JSTL)
[edit | edit source]The JavaServer Pages Standard Tag Library (JSTL) is a component of the Java EE Web application development platform. It extends the JSP specification by adding a tag library of JSP tags for common tasks, such as XML data processing, conditional execution, loops and internationalization.
Struts Tag Library
[edit | edit source]The Struts project includes the Struts Tag Library, the bulk of which is useful independently of the Struts architecture.
Internationalization
[edit | edit source]Internationalization in JSP is accomplished the same way as in a normal Java application, that is by using resource bundles.
Expression Language
[edit | edit source]The Expression Language (EL) is a faster/easier way to display parameter values. It is available since JSP 2.0 . For instance, it allows developers to create Velocity-style templates:
Hello, ${param.visitor}
Same as
Hello, <%=request.getParameter("visitor")%>
It also offers a clearer way to navigate nested beans. Consider some beans:
class Person {
String name;
// Person nests an organization bean.
Organization organization;
public String getName() { return this.name; }
public Organization getOrganization() { return this.organization; }
}
class Organization {
String name;
public String getName() { return this.name; }
}
Then, if an instance of Person was to be placed onto a request attribute under the name "person", the JSP would have:
Hello, ${person.name}, of company ${person.organization.name}
Same as.
Hello,
<% Person p = (Person) request.getAttribute("person");
if (p != null) {
out.print(p.getName());
}
%>, of company
<% if ((p != null) && (p.getOrganization() != null)) {
out.print(p.getOrganization().getName());
}
%>
JSP Technology in the Java EE 5 Platform
[edit | edit source]The focus of Java EE 5 has been ease of development by making use of Java language annotations that were introduced by J2SE 5.0. JSP 2.1 supports this goal by defining annotations for dependency injection on JSP tag handlers and context listeners.
Another key concern of the Java EE 5 specification has been the alignment of its webtier technologies, namely JavaServer Pages (JSP), JavaServer Faces (JSF), and JavaServer Pages Standard Tag Library (JSTL).
The outcome of this alignment effort has been the Unified Expression Language (EL), which integrates the expression languages defined by JSP 2.0 and JSF 1.1.
The main key additions to the Unified EL that came out of the alignment work have been: A pluggable API for resolving variable references into Java objects and for resolving the properties applied to these Java objects, Support for deferred expressions, which may be evaluated by a tag handler when needed, unlike their regular expression counterparts, which get evaluated immediately when a page is executed and rendered, and Support for lvalue expression, which appear on the left hand side of an assignment operation. When used as an lvalue, an EL expression represents a reference to a data structure, for example: a JavaBeans property, that is assigned some user input. The Unified EL is defined in its own specification document, which is delivered along with the JSP 2.1 specification.
Thanks to the Unified EL, JSTL tags, such as the JSTL iteration tags, can be used with JSF components in an intuitive way.
JSP 2.1 leverages the Servlet 2.5 specification for its web semantics.
Model-view-controller paradigm
[edit | edit source]A model-view-controller pattern can be used with the JSP files in order to split the presentation from request processing and computer data storage. Either regular servlets or separate JSP files are used to process the request. After the request processing has finished, control is passed to a JSP used only for creating the output. There are several platforms based on Model-view-controller pattern for web tiers (such as Barracuda, Apache Struts, Stripes, and the Spring MVC framework).
Environment
[edit | edit source]Both the Java Server (J2EE specification) and the page scripts and/or extended customised programming added operate by (in the runtime context of being loaded programs used) a special pre-installed base program called a Virtual Machine that integrates with the host Operating System, this type being the Java Virtual Machine (JVM).
Because either, both a Compiler-JVM set (called an SDK or JDK) or the lone JVM (called a JRE, Java Runtime Environment) is made for most computer platform OSs and the compiled programs for the JVM are compiled into special Java Byte code files for the JVM the Byte-code files (compiled Java program .class files) can be effectively transferred between platforms with no requirement to be recompiled excepting versioning compatibility, or special circumstance. The source code for these J2EE servlet or J2EE JSP programs is almost always supplied with J2EE JSP material and J2EE Web Applications because the server must call the compiler when loading them. These small extension programs (custom tags, servlets, beans, page scripting) are variable and likely to be updated or changed either shortly before runtime or intermittently but particularly when sending JSP page requests themselves, it requires the JSP server to have access to a Java compiler (SDK or JDK) and the required source code (not simply the JVM JRE and byte code class files) to successfully exploit the method of serving.
JSP syntax has two basic forms, scriptlet and markup though fundamentally the page is either HTML or XML markup. Scriptlet tagging (called Scriptlet Elements) (delimited) blocks of code with the markup are not effectively markup and allows any java server relevant API (e.g. the servers running binaries themselves or database connections API or java mail API) or more specialist JSP API language code to be embedded in an HTML or XML page provided the correct declarations in the JSP file and file extension of the page are used. Scriptlet blocks do not require to be completed in the block itself only the last line of the block itself being completed syntactically correctly as a statement is required, it can be completed in a later block. This system of split inline coding sections is called step over scripting because it can wrap around the static markup by stepping over it. At runtime (during a client request) the code is compiled and evaluated, but compilation of the code generally only occurs when a change to the code of the file occurs. The JSP syntax adds additional XML-like tags, called JSP actions, to be used to invoke built-in functionality. Additionally, the technology allows for the creation of JSP tag libraries that act as extensions to the standard HTML or XML tags. JVM operated Tag libraries provide a platform independent way of extending the capabilities of a Web server. Note that not all company makes of Java servers are J2EE specification compliant.
Jakarta Enterprise Beans
EJB stands for Enterprise JavaBeans. Freshers should not confuse this with Java Beans of Core Java.
Introduction
[edit | edit source]This page is about Enterprise JavaBeans 2.1. It also covers EJB 2.0, which is still in widespread use. Just as the Java platform has revolutionized the way we think about software development, Enterprise JavaBeans has revolutionized the way we think about developing mission-critical enterprise software. It combines server-side components with distributed object technologies, asynchronous messaging, and web services to greatly simplify the task of application development. It automatically takes into account many of the requirements of business systems, including security, resource pooling, persistence, concurrency, and transactional integrity.
This book shows you how to use Enterprise JavaBeans to develop scalable, portable business systems. But before we can start talking about EJB itself, we'll need a brief introduction to the technologies addressed by EJB, such as component models, distributed objects, asynchronous messaging, and web services. It's particularly important to have a basic understanding of component transaction monitors, the technology that lies beneath EJB.
It is assumed that you're already familiar with Java; if you're not, read Java Programming first. This book also assumes that you're conversant in the JDBC API, or at least in SQL. If you're not familiar with JDBC, see Java JDBC using SQLite.
One of Java's most important features is platform independence. Since it was first released, Java has been marketed as "write once, run anywhere." While the hype has gotten a little heavy-handed at times, code written with Sun's Java programming language is remarkably platform-independent. Enterprise JavaBeans isn't just platform-independent—it's also implementation-independent. If you've worked with JDBC, you know a little about what this means. Not only can the JDBC API run on a Windows machine or on a Unix machine, it can also access relational databases of many different vendors (DB2, Oracle, MySQL, SQLServer, etc.) by using different JDBC drivers. You don't have to code to a particular database implementation—just change JDBC drivers, and you change databases. It's the same with EJB. Ideally, an EJB component—an enterprise bean—can run in any application server that implements the EJB specification. This means that you can develop and deploy your EJB business system in one server, such as BEA's WebLogic, and later move it to a different EJB server, such as Pramati, Sybase EAServer, IBM's WebSphere, or an open source project such as Apache Geronimo, OpenEJB, JOnAS, or JBoss. Implementation independence means that your business components are not dependent on the brand of server, which gives you many more options before, during, and after development and deployment.
In addition to supporting distributed business objects, Enterprise JavaBeans supports asynchronous messaging. EJB 2.1 also allows enterprise beans to be exposed as web services, so that their methods can be invoked by other J2EE applications as well as applications written in other programming languages on a variety of platforms. Web services in EJB 2.1 supports both RPC-style and document-style messaging. Support for web services is based on a new web service API: JAX-RPC.
Server-Side Components
[edit | edit source]Object-oriented languages such as Java, C++, and C# are used to write software that is flexible, extensible, and reusable—the three axioms of object-oriented development. In business systems, object-oriented languages are used to improve development of GUIs, to simplify access to data, and to encapsulate the business logic. The encapsulation of business logic into business objects is a fairly recent focus in the information-technology industry. Business is fluid, which means that a business's products, processes, and objectives evolve over time. If the software that models the business can be encapsulated into business objects, it becomes flexible, extensible, and reusable, and therefore evolves as the business evolves.
A server-side component model may define an architecture for developing distributed business objects that combine the accessibility of distributed object systems with the fluidity of objectified business logic. Server-side component models are used on the middle-tier application servers, which manage the components at runtime and make them available to remote clients. They provide a baseline of functionality that makes it easy to develop distributed business objects and assemble them into business solutions.
Server-side components can also be used to model other aspects of a business system, such as presentation and routing. The Java servlet, for example, is a server-side component that is used to generate HTML and XML data for the presentation layer of a three-tier architecture. EJB 2.1 message-driven beans, which are discussed later in this book, are server-side components that can be used to consume and process asynchronous messages.
Server-side components, like other components, can be bought and sold as independent pieces of executable software. They conform to a standard component model and can be executed without direct modification in a server that supports that component model. Server-side component models often support attribute-based programming, which allows the runtime behavior of the component to be modified when it is deployed, without having to change the programming code in the component. Depending on the component model, the server administrator can declare a server-side component's transactional, security, and even persistence behavior by setting these attributes to specific values.
As an organization's services, products, and operating procedures evolve, server-side components can be reassembled, modified, and extended so that the business system reflects those changes. Imagine a business system as a collection of server-side components that model concepts such as customers, products, reservations, and warehouses. Each component is like a Lego™ block that can be combined with other components to build a business solution. Products can be stored in the warehouse or delivered to a customer; a customer can make a reservation or purchase a product. You can assemble components, take them apart, use them in different combinations, and change their definitions. A business system based on server-side components is fluid because it is objectified, and it is accessible because the components can be distributed.
Enterprise JavaBeans Defined
[edit | edit source]Oracle's definition of Enterprise JavaBeans is:
- "The Enterprise JavaBeans architecture is a component architecture for the development and deployment of component-based distributed business applications. Applications written using the Enterprise JavaBeans architecture are scalable, transactional, and multi-user secure. These applications may be written once, and then deployed on any server platform that supports the Enterprise JavaBeans specification."
That's a mouthful, but it's not atypical of how Sun defines many of its Java technologies—have you ever read the definition of the Java language itself? It's about twice as long. This book offers a shorter definition of EJB:
Enterprise JavaBeans is a standard server-side component model for distributed business applications.
What this means is the EJB offers a standard model for building server-side components that represent both business objects (customers, items in inventory, and the like) and business processes (purchasing, stocking, and so on). Once you have built a set of components that fit the requirements of your business, you can combine them to create business applications. On top of that, as “distributed” components, they don’t all have to reside on the same server: Components can reside wherever it’s most convenient: a Customer component "live" near the Customer database, a Part component can “live” near the inventory database, and a Purchase business-process component can “live” near the user interface: you can do whatever’s necessary for minimizing latency, sharing the processing load, or maximizing reliability.
Distributed Object Architectures
[edit | edit source]To understand EJB, you need to understand how distributed objects work. Distributed object systems are the foundation for modern three-tier architectures. In a three-tier architecture, as shown in Figure 1-1, the presentation logic resides on the client (first tier), the business logic resides on the middle tier (second tier), and other resources, such as the database, reside on the backend (third tier).
Figure 1-1. Three-tier architecture
[edit | edit source]All distributed object protocols are built on the same basic architecture, which is designed to make an object on one computer look like it's residing on a different computer. Distributed object architectures are based on a network communication layer that is really simple. Essentially, there are three parts to this architecture: the business object, the skeleton, and the stub.
The business object resides on the middle tier. It's an instance of an object that models the state and business logic of some real-world concept, such as a person, order, or account. Every business object class has matching stub and skeleton classes built specifically for that type of business object. For example, a distributed business object called Person
would have matching PersonStub
and PersonSkeleton
classes. As shown in Figure 1-2, the business object and skeleton reside on the middle tier, and the stub resides on the client.
The stub and the skeleton are responsible for making the business object on the middle tier look as if it is running locally on the client machine. This is accomplished through some kind of Remote Method Invocation (RMI) protocol. An RMI protocol is used to communicate method invocations over a network. CORBA, Java RMI, and Microsoft .NET all use their own protocols. Every instance of the business object on the middle tier is wrapped by an instance of its matching skeleton class. The skeleton is set up on a port and IP address and listens for requests from the stub, which resides on the client machine and is connected via the network to the skeleton. The stub acts as the business object's surrogate on the client and is responsible for communicating requests from the client to the business object through the skeleton. Figure 1-2 illustrates the process of communicating a method invocation from the client to the server object and back. The stub and the skeleton hide the communication specifics of the RMI protocol from the client and the implementation class, respectively.
Figure 1-2. RMI loop
[edit | edit source]The business object implements a public interface that declares its business methods. The stub implements the same interface as the business object, but the stub's methods do not contain business logic. Instead, the business methods on the stub implement whatever networking operations are required to forward the request to the business object and receive the results. When a client invokes a business method on the stub, the request is communicated over the network by streaming the name of the method invoked, and the values passed in as parameters, to the skeleton. When the skeleton receives the incoming stream, it parses the stream to discover which method is requested, then invokes the corresponding business method on the business object. Any value that is returned from the method invoked on the business object is streamed back to the stub by the skeleton. The stub then returns the value to the client application as if it had processed the business logic locally.
Component Models
[edit | edit source]The term component model has many different interpretations. Enterprise JavaBeans specifies a server-side component model. Using a set of classes and interfaces from the javax.ejb
package, developers can create, assemble, and deploy components that conform to the EJB specification.
The original JavaBeans™ is also a component model, but it's not a server-side component model like EJB. In fact, other than sharing the name "JavaBeans," these two component models are completely unrelated. In the past, a lot of the literature referred to EJB as an extension of the original JavaBeans, but it was a misrepresentation. The two APIs serve very different purposes, and EJB does not extend or use the original.
JavaBeans component model
[edit | edit source]JavaBeans is intended to be used for intra process purposes, while EJB is designed for inter process components. In other words, the original JavaBeans was not intended for distributed components. JavaBeans can be used to solve a variety of problems, but it is primarily used to build clients by assembling visual (GUI) and nonvisual widgets. It's an excellent component model, possibly the best one ever devised for intraprocess development, but it's not a server-side component model. EJB, on the other hand, is explicitly designed to address issues involved with managing distributed business objects in a three-tier architecture.
Given that JavaBeans and Enterprise JavaBeans are completely different, why are they both called component models? In this context, a component model defines a set of contracts between the component developer and the system that hosts the component. The contracts express how a component should be developed and packaged. Once a component is defined, it becomes an independent piece of software that can be distributed and used in other applications. A component is developed for a specific purpose but not a specific application. In the original JavaBeans, a component might be a push button or a spreadsheet that can be used in any GUI application according to the rules specified in the original JavaBeans component model. In EJB, there are several different types of components: components that represent entities in a database (entity beans) have a slightly different contract with their container than components that represent business processes (session beans). For example, a component might be a Customer business object, represented by an entity bean, that can be deployed in any EJB server and used to develop any business application that needs a customer business object. Another type of component might be a MakePurchase
object, represented by a session bean, that models what happens when a customer buys a particular product. (Although the act of making a purchase isn’t itself represented in a database, a purchase involves a complex interaction between a customer, a sales person, inventory, accounts receivable, and possibly other entities). The MakePurchase
object has a different contract with its container than the Customer
object, but it too can still be deployed in any EJB server and used in any business application that needs to support purchases. A third type of EJB, the MessageDrivenBean, has a slightly different contract with its container—but it, too, can be deployed in any EJB server.
Competing Component Models: Microsoft's .NET Framework
[edit | edit source]Enterprise JavaBeans did not appear out of nowhere; it is one of a number of component transaction monitors (CTMs), which in turn have their origin in older transaction processing monitors (such as Tuxedo) and Object Request Brokers. However, the most important competition for EJB is Microsoft’s .NET framework. .NET has its origins in the Microsoft Transaction Server (MTS), which was arguably the first commercially available CTM. MTS was later renamed COM+. Microsoft's COM+ is based on the Component Object Model (COM), originally designed for use on the desktop but eventually pressed into service as a server-side component model. For distributed access, COM+ clients use the Distributed Component Object Model (DCOM).
When MTS was introduced in 1996, it was an exciting development because it provided a comprehensive environment for business objects. With MTS, application developers could write COM components without worrying about system-level concerns. Once a business object was designed to conform to the COM model, MTS (and now COM+) took care of everything else, including transaction management, concurrency, and resource management.
COM+ has become part of Microsoft's new .NET Framework. The core functionality provided by COM+ services remains essentially the same in .NET, but the way it appears to a developer has changed significantly. Rather than writing components as COM objects, .NET Framework developers build applications as managed objects. All managed objects, and in fact all code written for the .NET Framework, depends on a Common Language Runtime (CLR). For Java-oriented developers, the CLR is much like a Java virtual machine (VM), and a managed object is analogous to an instance of a Java class; i.e., to a Java object.
The .NET Framework provides first class support web services via the SOAP (Simple Object Access Protocol) protocol, which enables business components in the .NET world to communicate with applications on any other platform written in any language. This can potentially make business components in .NET universally accessible, a feature that is not easily dismissed. In fact, .NET was the impetus that motivated Sun Microsystems to extend EJB and the rest of the J2EE platform to support web services. Microsoft's .NET platform represents the greatest threat to the dominance of the Java platform since the Java programming language was introduced in 1995.
Although the .NET Framework provides many interesting features, it falls short as an open standard. The COM+ services in the .NET Framework are Microsoft's proprietary CTM, which means that using this technology binds you to the Microsoft platform. If your company plans to deploy server-side components on a non-Microsoft platform, .NET is not a viable solution. In addition, the COM+ services in the .NET Framework are focused on stateless components; there's no built-in support for persistent transactional objects. Although stateless components can offer higher performance, business systems need the kind of flexibility offered by CTMs, which include stateful and persistent components.
Benefits of a Standard Server-Side Component Model
[edit | edit source]What does it mean to be a standard server-side component model? Quite simply, it means that you can develop business objects using the Enterprise JavaBeans component model and expect them to work in any application server that supports the complete EJB specification. This is a pretty powerful statement, because it largely eliminates the biggest problem faced by potential customers of Microsoft .NET products: fear of vendor "lock-in." With a standard server-side component model, customers can commit to using an EJB-compliant application server with the knowledge that they can migrate to a better server if one becomes available. Obviously, care must be taken when using proprietary extensions developed by vendors, but this is nothing new. Even in the relational database industry—which has been using the SQL standard for a couple of decades—optional proprietary extensions abound.
Having a standard server-side component model has benefits beyond implementation independence. A standard component model provides a vehicle for growth in the third-party products. If numerous vendors support EJB, creating add-on products and component libraries is more attractive to software vendors. The IT industry has seen this type of cottage industry grow up around other standards, such as SQL; hundreds of add-on products can now be purchased to enhance business systems with data that is stored in SQL-compliant relational databases. Report-generating tools and data-warehouse products are typical examples. The GUI component industry has also seen the growth of its own third-party products. A healthy market for component libraries already exists for GUI component models such as Sun's original JavaBeans component model.
Many third-party products for Enterprise JavaBeans exist today. Add-on products for credit card processing, legacy database access, and other business services have been introduced for various EJB-compliant systems. These types of products make development of EJB systems simpler and faster than the alternatives, making the EJB component model attractive to corporate IS and server vendors alike. The market for prepackaged EJB components is growing in several domains, including sales, finance, education, web-content management, collaboration, and other areas.
Titan Cruises: An Imaginary Business
[edit | edit source]To make things a little easier, and more fun, we will discuss all the concepts in this book in the context of one imaginary business, a cruise line called Titan. A cruise line makes a particularly interesting example because it incorporates several different businesses: it has ship cabins that are similar to hotel rooms, it serves meals like a restaurant, it offers various recreational opportunities, and it needs to interact with other travel businesses.
This type of business is a good candidate for a distributed object system because many of the system's users are geographically dispersed. Commercial travel agents, for example, who need to book passage on Titan ships will need to access the reservation system. Supporting many—possibly hundreds—of travel agents requires a robust transactional system to ensure that agents have access and that reservations are completed properly. Throughout this book, we will build a fairly simple slice of Titan's EJB system that focuses on the process of making a reservation for a cruise. This exercise will give us an opportunity to develop Ship, Cabin, TravelAgent, ProcessPayment, and other enterprise beans. In the process, you will need to create relational database tables for persisting data used in the example. It is assumed that you are familiar with relational database management systems and that you can create tables according to the SQL statements provided. EJB can be used with any kind of database or legacy application, but relational databases seem to be the most commonly understood database, so I have chosen this as the persistence layer.
What's Next?
[edit | edit source]To develop business objects using EJB, you have to understand the life cycle and architecture of EJB components. This means understanding conceptually how EJB's components are managed and made available as distributed objects.
See Also
[edit | edit source]
EJB-QL
EJB Query Language is used to define what a finder method of an Entity bean should return. The EJB 1.1 specification offered no way to query entity beans. It resulted in different query languages for different application servers. When Sun published the EJB 2.0 specification it added a query language to find entity beans more easily.
Basic Syntax
[edit | edit source]SELECT_CLAUSE FROM_CLAUSE [WHERE_CLAUSE]
Both SELECT_CLAUSE and FROM_CLAUSE must be used but WHERE_CLAUSE is optional.
Finder methods
[edit | edit source]Finder methods are used to return a single or multiple Entities from the storage. The finder method is defined in entity's home interface. The return value of a finder is the beans remote interface or a collection of entity beans implementing the remote interface which were found.
Basic finder method
[edit | edit source]The simplest possible EJB-Query would be one which return all Entities in a given table.
@ejb.finder signature="Collection findAll()" query="SELECT DISTINCT OBJECT(p) FROM Player p"
As you can see, the EJB-Query looks nearly the same as a standard SQL query, although it's not the name of the tables but the name of the EJB classes and it's not the name of the columns but the name of the EJB properties. The only difference is the terminal object(o) which is equivalent to: take all columns of a given row and transform the result into an entity bean instance.
Finder method with WHERE clause
[edit | edit source]Look at the example above. It differs from the finder method above only that a conditional for the players which should be returned is added.
@ejb.finder signature="Collection findByPosition(java.lang.String position)" query="SELECT DISTINCT OBJECT(p) FROM Player p WHERE p.position = ?1"
This finder method returns all Players which play at the position which is entered by parameter one. If you have more than one parameter you can use them in your query with ?2, ?3 and so on.
Finder method which operates on relation
[edit | edit source]EJB Query differs from SQL especially if you want to use different relational tables.
@ejb.finder signature="Collection findByCity(java.lang.String city)" query="SELECT DISTINCT OBJECT(p) FROM Player p, IN (p.teams) AS t WHERE t.city = ?1"
This query return all players whose team plays in the city given with parameter one. In other words: return all Players who play in the team which is situated in a given city.
Select methods
[edit | edit source]In opposite to finder methods select methods might return a persistence field or other entity beans. So it's possible to define a select method which returns a primitive data type instead of a complete object.
Example
[edit | edit source]Stateless Session Beans
Here is a short tutorial to use a stateless session EJB using Eclipse.
- In Eclipse, right-click on the Project Explorer view.
- Select New -> EJB Project. If EJB Project doesn't appear, Select New -> Other, select EJB -> EJB Project and click on Next.
- On "Project name", type
helloworld-ejb
. - Click on Finish.
- Right-click on the Project Explorer view.
- Select New -> Session bean (EJB 3.x). If Session bean (EJB 3.x) doesn't appear, Select New -> Other, select EJB -> Session bean (EJB 3.x) and click on Next.
- On "Java package", type
org.wikibooks.en
. - On "Class name", type
MyFirstEJB
. Leave the other options as it is. - Click on Finish.
- On the same package, create a new interface
MyFirstEJBRemote
. - Add the following method signature inside it:
public String sayHello();
- Add the following annotation above the signature of the interface:
@Remote
- Open the class
MyFirstEJB
. - Remove the annotation
@LocalBean
. - Add the following method inside it:
public String sayHello() { return "Hello World!"; }
- Right-click on the project.
- Select Export -> EJB JAR file . If you don't find the option EJB JAR file, click on Export... instead, select EJB -> EJB JAR file and click on Next >. The web project should be named
helloworld
. - Choose a location for the destination.
- Click on Finish .
- Go on the folder where you have created your JAR.
You should see a JAR file named helloworld-ejb.jar
. You can delete it.
- Right-click on the Project Explorer view.
- Select New -> Enterprise Application project.
- On "Project name", type
helloworld-ear
. - Click on Next .
- Select the project
helloworld-ejb
. - Click on Finish . You should have a new project called
helloworld-ear
. Among other things, it should contain Deployment Descriptor: helloworld-ear/Modules/EJB helloworld-ejb.jar . - Right-click Export -> EAR file, choose a destination and click on Finish.
- Create a copy of the EAR file and change the extension to .zip .
- Explore the content of the ZIP file.
You should see the JAR file named helloworld-ejb.jar
inside. You can delete the ZIP file.
- Copy/paste your EAR file in the deployment folder of your application server.
- Start your application server.
Now your EJB is usable. Unfortunately, we don't know how to use it yet.
- Shutdown your application server.
- Reuse the WAR project that you created in this page.
- Right-click on Java Resources/src .
- Select New -> Package .
- On name, type
org.wikibooks.en
. - Right-click on the new package.
- Select New -> Servlet .
- On Class name, type
EJBServlet
. - Type the following code in the class:
package org.wikibooks.en; import java.io.IOException; import java.io.PrintWriter; import javax.naming.InitialContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class EJBServlet extends HttpServlet { private static final long serialVersionUID = 5847939167723571084L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = new PrintWriter(response.getOutputStream()); out.println("Calling the EJB..."); try { InitialContext initialContext = new InitialContext(); MyFirstEJB myFirstEJB = (MyFirstEJB) initialContext .lookup("java:global/experience4/experience3/MyFirstEJB"); out.println(myFirstEJB.sayHello()); } catch (Exception e) { out.println(e); } out.flush(); out.close(); } }
- If you are using another application server than JBoss, you should have to change the lookup
java:global/experience4/experience3/MyFirstEJB
. - Open the file
web.xml
in WebContent/WEB-INF . - Before the first markup
<servlet>
, type the following code:
<servlet> <servlet-name>servlet</servlet-name> <servlet-class>org.wikibooks.en.EJBServlet</servlet-class> </servlet>
- Before the first markup
<servlet-mapping>
, type the following code:
<servlet-mapping> <servlet-name>servlet</servlet-name> <url-pattern>/servlet</url-pattern> </servlet-mapping>
- Right-click Export -> EAR file.
- For the destination, choose the deployment folder of the application server.
- Click on Finish.
- Start your application server.
- Go on the URL
http://localhost:8080/helloworld/servlet
.
You should see Calling the EJB...
. It means that you manage to call the servlet. You should also see Hello World!
. If you see a text that is a Java exception, it means that the servlet failed to communicate with the EJB. You can verify that the text comes from the EJB by changing the text in the code and redeploy the EAR.
Message Driven Bean
Enterprise JavaBeans integrates the functionality of Message-Oriented Middleware (MOM) into its component model. This integration extends the EJB platform so that it supports both RMI and asynchronous messaging. EJB 2.0 and 2.1 support asynchronous messaging through the Java Message Service (JMS) and a component called the Message-Driven Bean. It can receive and send asynchronous JMS messages, and can easily interact with other EJBs. In addition to JMS, message-driven beans in EJB 2.1 can support other synchronous and asynchronous messaging systems.
EJB 2.1 extends the programming model of the message-driven bean beyond JMS to any messaging system. While vendors must continue to support JMS-based message-driven beans (JMS-MDBs), other types of messaging systems are also allowed. It’s likely that vendors will develop new message-driven bean types to support all kinds of protocols, including SMTP for email, SNMP for device control, peer-to-peer protocols (e.g., BEEP and Jabber) and many other open and proprietary messaging systems. In addition, the message-driven bean has become an elegant option for serving connections to legacy transaction processing systems like CICS, IMS, openUTM, and others.
The expansion of message-driven beans in EJB 2.1 to other protocols is made possible by the new J2EE Connector Architecture (JCA 1.5), which defines a portable programming model for interfacing with enterprise information systems. The use of JCA in J2EE is analogous to the use of USB in computer hardware. A computer that supports USB can interface with just about any USB-compliant device. Similarly, an EJB 2.1 container that supports JCA 1.5 can interface with any JCA 1.5-complaint resource. For example, if a XYZ Vendor creates a new message-driven bean component for their proprietary messaging system based on JCA 1.5, that component will be portable across all EJB 2.1-compliant servers.
Figure 1-1 EJB 2.1 Message-driven beans and JCA 1.5
[edit | edit source]Message-driven beans in EJB 2.1 and 2.0 allow other applications to send messages that can be captured and processed by the EJB application. This feature allows EJB applications to better integrate with legacy and other proprietary systems.
Jakarta Messaging
Asynchronous Messaging
[edit | edit source]An asynchronous messaging system allows two or more applications to exchange information in the form of messages. In this case, a message is a self-contained package of business data and network routing headers. The business data contained in a message can be anything—depending on the business scenario—and usually contains information about some business transaction. In enterprise systems, messages inform an application of some event or occurrence in another system.
Asynchronous messages may be transmitted from one application to another on a network using Message-Oriented Middleware (MOM). MOM products ensure that messages are properly distributed among applications. In addition, MOM usually provides fault-tolerance, load-balancing, scalability, and transactional support for enterprises that need to reliably exchange large quantities of messages. MOM vendors use different message formats and network protocols for exchanging messages, but the basic semantics are the same. An API is used to create a message, give it a payload (application data), assign it routing information, and then send the message. The same API is used to receive messages produced by other applications.
In modern enterprise-messaging systems, applications exchange messages through virtual channels called destinations. When you send a message, it's addressed to a destination, not to a specific application. Any application that subscribes or registers an interest in that destination may receive that message. In this way, the applications that receive messages and those that send messages are decoupled. Senders and receivers are not bound to each other in any way and may send and receive messages as they see fit.
Java Message Service
[edit | edit source]Each MOM vendor implements its own networking protocols, routing, and administration facilities, but the basic semantics of the developer API provided by different MOMs are the same. It's this similarity in APIs that makes the Java Message Service (JMS) possible.
JMS is a vendor-agnostic Java API that can be used with many different MOM vendors. JMS is very similar to JDBC in that an application developer can reuse the same API to access many different systems. If a vendor provides a compliant service provider for JMS, the JMS API can be used to send messages to and receive messages from that vendor. For example, you can use the same JMS API to send messages with Progress's SonicMQ as with IBM's MQSeries.
Web Services
Web services represent the latest wave in distributed computing, and perhaps the most important innovation since the introduction of Java in 1995 and XML in 1998. Although the term "web services" is bantered about quite a bit, arriving at a concrete definition is difficult because web services is, at the highest level, not specific to any particular technology or platform. It's often defined in fairly abstract terms like "a substrate for building distributed applications using software running on different operating systems and devices" or "self-contained, self-describing, modular applications that can be published, located, and invoked across the Web". Of course these quotes are taken out of context, but that's the essential point: You need some kind of context to define web services. Here’s another definition of web services that has meaning in the context of J2EE, EJB, .NET and most other web services platforms:
Web services are network applications that use SOAP and WSDL to exchange information in the form of XML documents.
To understand this definition, you need to understand SOAP and WSDL. Here are brief definitions of these terms.
SOAP 1.1
[edit | edit source]SOAP (Simple Object Access Protocol) is an XML grammar developed by Microsoft, IBM, and others, is currently under the auspices of the W3C. It’s an application protocol used in both RPC and asynchronous messaging. SOAP is very flexible and extensible and, unlike its predecessors (DCE RPC, CORBA IIOP, Java RMI-JRMP, and DCOM), it’s been endorsed and adopted by just about every major vendor.
WSDL 1.1
[edit | edit source]The Web Service Description Language (WSDL) is another XML grammar, developed by Microsoft and IBM under the auspices of the W3C. It is an XML-based IDL (Interface Definition Language) that can be used to describe web services, including the kind of message format expected, the Internet protocol used, and the Internet address of the web service.
Web services are truly platform-independent. Although Java RMI and CORBA IIOP also claim to be platform-independent, in fact these older technologies require their own platforms. To use Java RMI, you need a Java virtual machine and the Java programming language; a program written in Visual Basic or C++ can’t interact with a Java program using RMI. CORBA IIOP is also restrictive, because the IIOP protocol usually requires an elaborate infrastructure like a CORBA ORB, which limits developers to those few vendors that support CORBA, or to the Java environment (which includes built-in support for CORBA IIOP). Web services, on the other hand, are not tied to a specific platform like the JVM or to a technology infrastructure like CORBA because they focus on the protocols used to exchange messages—SOAP and WSDL—not the implementation that supports those protocols. In other words, you can build web services on any platform, using any programming language any way you please.