JavaBeat

  • Home
  • Java
    • Java 7
    • Java 8
    • Java EE
    • Servlets
  • Spring Framework
    • Spring Tutorials
    • Spring 4 Tutorials
    • Spring Boot
  • JSF Tutorials
  • Most Popular
    • Binary Search Tree Traversal
    • Spring Batch Tutorial
    • AngularJS + Spring MVC
    • Spring Data JPA Tutorial
    • Packaging and Deploying Node.js
  • About Us
    • Join Us (JBC)
  • Privacy
  • Contact Us

Designing and Developing Secure Java EE Applications using GlassFish Security

October 6, 2010 by itadmin Leave a Comment

GlassFish Security

We are living in a world full of dazzling wonders, and ifor one always enjoy encountering them. Software development is one of the wonders that dazzles me because of its enormously vast domain, including many concerns and subjects of interest. Looking at this domain from any distance, we will see one big and sometimes blurry-edged spot named security.
Security, an orthogonal and inseparable part of software systems, is not for preventing others from accessing some information and system resources but for allowing them access in an appropriate way, by implementing necessary means to precisely check any attempt to access a resource and either allow it to go further or not and record all information related to examining this attempt for further review.

also read:

  • Java EE Tutorials
  • Java EE 7 Tutorials
  • Java EE Interview Questions

Java EE is the platform of choice for developing enormously large-scale applications, and provides plethora of features for implementing security plans for applications, starting from dealing with identity storage and identity solutions up to providing GUI-level support for security concerns and integration with other security providers.

Nowadays, integration is something that we hear in every software development meeting and session independent from what the session is about. Security integration, however, is
a delicate matter compared to all other issues as it deals directly with the organization’s assets. Java EE design allows it to delegate its security requirements to another entity in the enterprise, like a single sign-on solution, which on the other hand can integrate with
other products and platforms in use in the organization. The GlassFish Security book is an attempt to explain this domain considering Java EE, GlassFish, and OpenSSO capabilities and features.

What This Book Covers

Chapter 1, Java EE Security Model, discusses how we can secure different Java applications by using the declarative security model or by using the APiexposed by Java EE containers to access the security enforcement layers programmatically. It also briefly introduces Web modules, EJB modules, and application client module’s security in different levels, including authentication, authorization, and transport security.
Chapter 2, GlassFish Security Realms, discusses JAAS and GlassFish security realm, including File realm, JDBC realm, LDAP realm, and Certificate realm in detail as that will be required to develop a secure enterprise application. It also discusses GlassFish application server interaction with identity storages such as relational databases, Lightweight Directory Access Protocol (LDAP) servers, fl at file storage, and so on.
Chapter 3, Designing and Developing Secure Java EE Applications, covers developing and deploying a secure Java EE application with all standard modules including Web, EJB, and application client modules. It also teaches us how we can secure EJBs using annotation and then use a web frontend to use the secured EJBs after a user provides correct identification information.
Chapter 4, Securing GlassFish Environment, helps you secure your operating system and environment from unprivileged access by applications deployed in GlassFish using the OS features and Java policy management. It also covers network communication security, GlassFish password security, and finally security auditing, which is a complementary function in software security.
Chapter 5, Securing GlassFish, covers GlassFish administration security tasks such as password security and listener security. This chapter will teach you to secure GlassFish by examining the administration security, password protection, and network listener security. It also discusses the benefits of virtual servers for isolating different applications deployed in a single machine with a single IP address.
Chapter 6, Introducing OpenDS: Open Source Directory Service, teaches you about directory service and the set of features OpenDS provides—installing, administrating, and monitoring OpenDS and using OpenDS in embedded mode. This chapter teaches you to set up a replication topology to ensure service and data availability in case of unpredicted disasters.
Chapter 7, OpenSSO, the Single sign-on Solution, covers projects security from an integration point of view. In this chapter you will install and configure OpenSSO and understand different methods of using OpenSSO. It also teaches you how to use OpenSSO RESTful Web Services for authentication, authorization, and acquiring SSO tokens.
Chapter 8, Securing Java EE Applications using OpenSSO, covers OpenSSO Policy Agents that let us as architects, system designers, and developers secure a Java EE application using OpenSSO without changing the application source code. It also discusses about Policy Agents, Policy Agent’s installation, and administration, along with changing our sample application to place it under agent protection instead of using plain Java EE protection.
Chapter 9, Securing Web Services by OpenSSO, covers Web Services security and how we can use OpenSSO and OpenSSO agents to secure our Web Services deployed in GlassFish. It also teaches you to install OpenSSO Web Services Security Provider Agent and develop a simple, secure pair of WSP and WSC.

Designing and Developing Secure Java EE Applications

In previous chapters we discussed how we can utilize Java EE capabilities to secure our Java EE applications. In this chapter, we are going to put what we learned into practice and develop a secure Java EE application with all standard modules including Web, EJB, and application client modules. Security is an orthogonal concern for an application and we should assess it right from the start by reviewing the analysis we receive from business and functional analysts. Assessing the security requirements results in understanding the functionalities we need to include in our architecture to deliver a secure application covering the necessary requirements.

Security necessities can include a wide area of requirements, which may vary from a simple authentication to several sub-systems. A list of these sub-systems includes identity and access management system and transport security, which can include encrypting data as well.
In this chapter we will develop a secure Java EE application based on Java EE and GlassFish capabilities. In course of the chapter we will cover following topics:

  • Analyzing Java EE application security requirements
  • Including security requirements in Java EE application design
  • Developing secure Business layer using EJBs
  • Developing secure Presentation layer using JSP and Servlets
  • Configuring deployment descriptors of Java EE applications
  • Specifying security realm for enterprise applications
  • Developing secure application client module
  • Configuring Application Client Container

Understanding the sample application

The sample application that we are going to develop, converts different length measurement units into each other. Our application converts meter to centimeter, millimeter, and inch. The application also stores usage statistics for later use cases. Guest users who prefer not to log in can only use meter to centimeter conversion, while any company employee can use meter to centimeter and meter to millimeter conversion, and finally any of company’s managers can access meter to inch in addition to two other conversion functionalities. We should show a custom login page to comply with site-wide look and feel. No encryption is required for communication between clients and our application
but we need to make sure that no one can intercept and steal the username and passwords provided by members. All members’ identification information is stored in the company’s wide directory server. The following diagram shows the high-level functionality of the sample application:

We have login action and three conversion actions. Users can access some of them after logging in and some of them can be accessed without logging in.

Analyzing sample application business logic

Before looking at security requirements and factors affecting the software security let’s see what we need to provide in our business layer. Our business logic consists of conversion operations and persistence of the conversion operations usage statistics. We can use a stateless Session Bean with three methods, one for each type of conversion. And for statistics persistence we can use EJB 3 entity beans. After studying the application description we can extract the following security-related requirements which we need to address to comply with the application description:

  • Authentication is required
  • Authentication should happen over a secure channel
  • Authorization is required
  • We need to use LDAP security realm

So far we translated the business analysis to technical requirements and now we are going to check each requirement in further detail to extract the implementation details. For implementing the sample application we can use a simple bottom-up procedure.
The following diagram shows the application blocks down to JSP files, Servlet, and EJBs.

As you can see we have Web module, EJB module, and an application client module. The Web module and the application client module presents a frontend for the EJB layer that performs both business logic, which is the conversion operations, and storing the conversion operation invocation statistics using Entity Beans. GlassFish uses the LDAP realm to authenticate the users against the specified directory server.

Implementing the Business and Persistence layers

The Persistence layer consists of an Entity Bean named Visit; we use this entity bean to store information about each visit. We will use a session bean with three business methods to convert a given length in meter to centimeter, millimeter, and inch.

Implementing the Persistence layer

We are using EJB 3 to develop the Persistence layer so we will only need to implement the entity bean and define the persistence unit. The following listing shows the Visit class.

[code lang=”java”]
Complete code for this class is available in the book’s source code:
https://www.packtpub.com//sites/default/files/
downloads/9386_Code.zip.

@Entity
public class Visit implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Temporal(javax.persistence.TemporalType.DATE)
private Date visitDate;
private String username;
private String operationName;
private int conversionValue;
public Visit() {
}
public Visit(Date visitDate, String username, String Operation,
int conversionValue) {
this.visitDate = visitDate;
this.username = username;
this.operationName = Operation;
this.conversionValue = conversionValue;
}
}
[/code]

Now that our entity bean is ready we can start looking at our session bean that drives the application business logic and also stores information about each invocation using the Visit entity bean. The following listing shows Conversion session bean local interface.

[code lang=”java”]
@ Local
public interface ConversionLocal {
float toInch(int meter);
int toCentimeter(int meter);
int toMillimeter(int meter);
}
[/code]

All of these methods are implemented in Conversion bean implementation which is as follows:

[code lang=”java”]
@ Stateless
public class ConversionBean implements ConversionLocal {
@PersistenceContext(unitName = "chapter3")
private EntityManager em;
@Resource
private SessionContext ctx;
@RolesAllowed({"manager_role"})
public float toInch(int meter) {
persist(meter, "toInch");
return Math.round(meter * 39.37);
}
@PermitAll
public int toCentimeter(int meter) {
persist(meter, "toCentimeter");
return meter * 100;
}
@RolesAllowed("employee_role")
public int toMillimeter(int meter) {
persist(meter, "toInch");
return meter * 1000;
}
private void persist(int value, String operationName) {
String userName = ctx.getCallerPrincipal().getName();
Visit v = new Visit(new Date(), userName, operationName,
value);
em.persist(v);
}
}
[/code]

Starting from the first line we are using @S tateless to mark this class as a stateless Session Bean. Later on we are using @P ersistenceContext to inject an entity manager into the instance. We will use this entity manager to store Visit entities. Then we are using @R esource to inject the current SessionContext into the session bean. Later on we will use it to extract the current principal and username of the invoker. The first security-related annotation is @R olesAllowed({“manager”}), which instructs the application server to only permit an authenticated user with
manager role to invoke this method. After this we have @P ermitAll which instructs the application server to allow anyone, either authenticated or not, to invoke this method. And finally we are using @R olesAllowed(“employee”) to instruct the application server that any authenticated user with employee role can invoke this method.

The persist method stores the invocation information. This information includes the current invoker username, which we extract from SessionContext using the getCallerPrincipal().getName() method. Finally we have a persistence unit that uses sample data source and sample
database which is bundled with GlassFish. The listing shown below contains a snippet of persistence.xml file, which configures a persistence unit for chapter3.

[code lang=”xml”]
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="chapter3" transaction-type="JTA">
<provider>oracle.toplink.essentials.PersistenceProvider
</provider>
<jta-data-source>jdbc/sample</jta-data-source>
<class>book.glassfish.security.chapter3.Visit</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="toplink.ddl-generation"
value="drop-and-create-tables"/>
</properties>
</persistence-unit>
</persistence>
[/code]

Now that we have our Persistence and Business layers ready we can start looking at the Web layer and how the Web layer can complement the inner layer in securing the system.

Developing the Presentation layer

The Presentation layer is the closest layer to end users when we are developing applications that are meant to be used by humans instead of other applications. In our application, the Presentation layer is a Java EE web application consisting of the elements listed in the following table. In the table you can see that different JSP files are categorized into different directories to make the security description easier.

Now that our application building blocks are identified we can start implementing them to complete the application. Before anything else let’s implement JSP files that provides the conversion GUI. The directory layout and content of the Web module is shown in the following figure:

Implementing the Conversion GUI

In our application we have an index.jsp file that acts as a gateway to the entire system and is shown in the following listing:

[code lang=”html”]
<html>
<head><title>Select A conversion</title></head>
<body><h1>Select A conversion</h1>
<a href="auth/login.html">Login</a>
<br/>
<a href="jsp/toCenti.jsp">Convert Meter to Centimeter</a>
<br/>
<a href="jsp/toInch.jsp">Convert Meter to Inch</a>
<br/>
<a href="jsp/toMilli.jsp">Convert to Millimeter</a><br/>
<a href="auth/logout.jsp">Logout</a>
</body>
</html>

[/code]

Implementing the Converter servlet

The Converter servlet receives the conversion value and method from JSP files and calls the corresponding method of a session bean to perform the actual conversion. The following listing shows the Converter servlet content:
[code lang=”java”]
@WebServlet(name="Converter", urlPatterns={"/Converter"})
public class Converter extends HttpServlet {
@EJB
private ConversionLocal conversionBean;
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
System.out.println("POST");
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try{
int valueToconvert =
Integer.parseInt(request.getParameter("meterValue"));
String method = request.getParameter("method");
out.print("<hr/> <center><h2>Conversion Result is: ");
if (method.equalsIgnoreCase("toMilli")) {
out.print(conversionBean.toMillimeter(valueToconvert));
} else if (method.equalsIgnoreCase("toCenti")) {
out.print(conversionBean.toCentimeter(valueToconvert));
} else if (method.equalsIgnoreCase("toInch")) {
out.print(conversionBean.toInch(valueToconvert));
}
out.print("</h2></center>");
}catch (AccessLocalException ale) {
response.sendError(401);
}finally {
out.close();
}
}
}
[/code]

Starting from the beginning we are using annotation to configure the servlet mapping and servlet name instead of using the deployment descriptor for it. Then we use dependency injection to inject an instance of Conversion session bean into the servlet and decide which one of its methods we should invoke based on the conversion type that the caller JSP sends as a parameter. Finally, we catch  javax.ejb.AccessLocalException and send an HTTP 401 error back to inform the client that it does not have the required privileges to perform the requested action. The following figure shows what the result of invocation could look like:

Each servlet needs some description elements in the deployment descriptor or included as deployment descriptor elements.  Implementing the conversion JSP files is the last step in implementing the functional pieces. In the following listing you can see content of the toMilli.jsp file.

[code lang=”html”]
Convert To Millimeter
<html>
<head><title>Convert To Millimeter</title></head>
<body><h1>Convert To Millimeter</h1>
<form method=POST action="../Converter">Enter Value to
Convert: <input name=meterValue>
<input type="hidden" name="method" value="toMilli">
<input type="submit" value="Submit" />
</form>
</body>
</html>

[/code]

The toCenti.jsp and toInch.jsp files look the same except for the descriptive content and the value of the hidden parameter which will be toCentiand toInch respectively for toCenti.jsp and toInch.jsp. Now we are finished with the functional parts of the Web layer; we just need to implement the required GUifor security measures.

Implementing the authentication frontend

For the authentication, we should use a custom login page to have a unified look and feel in the entire web frontend of our application. We can use a custom login page with the FORM authentication method. To implement the F ORM authentication method we need to implement a login page and an error page to redirect the users to that page in case authentication fails. Implementing authentication requires us to go
through the following steps:

  • Implementing login.html and loginError.html
  • Including security description in the web.xml and sun-web.xml or
    sun-application.xml

Implementing a login page

In FORM authentication we implement our own login form to collect username and pa ssword and we then pass them to the container for authentication. We should let the container know which field is username and which field is password by using standard names for these fields. The username field is j_ username and the password field is j_ password. To pass these fields to container for authentication we should use j_security_check as the form action. When we are posting to j_ security_check the servlet container takes action and authenticates the included j_username and j_password against the configured realm. The listing below shows login.html content.
[code lang=”html”]
<form method="POST" action="j_security_check">
Username: <input type="text" name="j_username"><br />
Password: <input type="password" name="j_password"><br />
<br />
<input type="submit" value="Login">
<input type="reset" value="Reset">
</form>

[/code]

The following figure shows the login page which is shown when an unauthenticated user tries to access a restricted resource:

Implementing a logout page

A user may need to log out of our system after they’re finished using it. So we need to implement a logout page. The following listing shows the logout.jsp file:
[code lang=”html”]
<%
session.invalidate();
%>
<body>
<center>
<h1>Logout</h1>
You have successfully logged out.
</center>
</body>

[/code]

Implementing a login error page

And now we should implement LoginError.html, an authentication error page to inform user about its authentication failure.
[code lang=”java”]

<html>
<body>
<h2>A Login Error Occurred</h2>
Please click <a href="login.html">here</a> for another try.
</body>
</html>

[/code]

Implementing an access restricted page

When an authenticated user with no required privileges tries to invoke a session bean method, the EJB container throws a javax.ejb.AccessLocalException. To show a meaningful error page to our users we should either map this exception to an error page or we should catch the exception, log the event for audition purposes, and then use the sen dError() method of the Htt pServletResponse object to send out an error code. We will map the HTTP error code to our custom web pages with meaningful descriptions using the web.xml deployment descriptor. You will see which configuration elements we will use to do the mapping. The following snippet shows AccessRestricted.html file:
[code lang=”html”]
<body>
<center> <p>You need to login to access the requested
resource. To login go to <a href="auth/login.html">Login
Page</a></p></center>
</body>
[/code]

Configuring deployment descriptors

So far we have implemented required files for the FORM-based authentication and we only need to include required descriptions in the web.xml file. L ooking back at the application requirement definitions, we see that anyone can use meter to centimeter conversion functionality and any other functionality that requires the user to login. We use three different HTML pages for different types of conversion. We do not need any constraint on toC entimeter.html therefore we do not need to include any definition for it. Per application description, any employee can access the toMilli.jsp page. Defining security constraint for this page is shown in the following listing:
[code lang=”html”]
<security-constraint>
<display-name>You should be an employee</display-name>
<web-resource-collection>
<web-resource-name>all</web-resource-name>
<description/>
<url-pattern>/jsp/toMillimeter.html</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
<http-method>DELETE</http-method>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>employee_role</role-name>
</auth-constraint>
</security-constraint>

[/code]

We should put enough constraints on the toInch.jsp page so that only managers can access the page. The listing included below shows the security constraint definition for this page.
[code lang=”xml”]

<security-constraint>
<display-name>You should be a manager</display-name>
<web-resource-collection>
<web-resource-name>Inch</web-resource-name>
<description/>
<url-pattern>/jsp/toInch.html</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>manager_role</role-name>
</auth-constraint>
</security-constraint>

[/code]

Finally we need to define any role we used in the deployment descriptor. The following snippet shows how we define these roles in the web.xml page.
[code lang=”xml”]
<security-role>
<description/>
<role-name>manager_role</role-name>
</security-role>
<security-role>
<description/>
<role-name>employee_role</role-name>
</security-role>
[/code]

Looking back at the application requirements, we need to define data constraint and ensure that username and passwords provided by our users are safe during transmission. The following listing shows how we can define the data constraint on the login.html page.
[code lang=”xml”]
<security-constraint>
<display-name>Login page Protection</display-name>
<web-resource-collection>
<web-resource-name>Authentication</web-resource-name>
<description/>
<url-pattern>/auth/login.html</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<user-data-constraint>
<description/>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
[/code]

One more step and our web.xml file will be complete. In this step we define an error page for HTML 401 error code. This error code means that application server is unable to perform the requested action due to negative authorization result. The following snippet shows the required elements to define this error page.
[code lang=”xml”]
<error-page>
<error-code>401</error-code>
<location>AccessRestricted.html</location>
</error-page>
[/code]

Now that we are finished with declaring the security we can create the conversion pages and after creating these pages we can start with Business layer and its security requirements.

Specifying the security realm

Up to this point we have defined all the constraints that our application requires but we still need to follow one more step to complete the application’s security configuration. The last step is specifying the security realm and authentication. We should specify the FORM authentication and per-application description; authentication must happen against the company-wide LDAP server. Here we are going to use the LDAP security realm LDAPRealm which we created in Chapter 2. We need to import a new LDIF file into our LDAP server, which contains groups and users definition required for this chapter. To import the file we can use the following command, assuming that you downloaded the source code bundle from https://www.packtpub.com//sites/default/files/downloads/9386_Code.zip and you have it extracted.
[code lang=”java”]
import-ldif –ldifFile path/to/chapter03/users.ldif
–backendID userRoot –clearBackend –hostname 127.0.0.1 –port 4444 —
bindDN cn=gf\ cn=admin –bindPassword admin –trustAll –noPropertiesFile
[/code]

The following table show users and groups that are defined inside the users.ldif file.

We used OpenDS for the realm data storage and it had two users, one in the employee group and the other one in the manager group. To configure the authentication realm we need to include the following snippet in the web.xml file.

[code lang=”xml”]
<login-config>
<auth-method>FORM</auth-method>
<realm-name>LDAPRealm</realm-name>
<form-login-config>
<form-login-page>/auth/login.html</form-login-page>
<form-error-page>/auth/loginError.html</form-error-page>
</form-login-config>
</login-config>
[/code]

If we look at our Web and EJB modules as separate modules we must specify the role mappings for each module separately using the GlassFish deployment descriptors, which are sun-web.xml and sun-ejb.xml. But we are going to bundle our modules as an Enterprise Application Archive (EAR) file so we can use the GlassFish deployment descriptor for enterprise applications to define the role mapping in one place and let all modules use that definitions. The following listing shows roles and groups mapping in the sun-application.xml file.
[code lang=”xml”]
<sun-application>
<security-role-mapping>
<role-name>manager_role</role-name>
<group-name>manager</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>employee_role</role-name>
<group-name>employee</group-name>
</security-role-mapping>
<realm>LDAPRealm</realm>
</sun-application>

[/code]

The security-role-mapping element we used in sun-application.xml has the same schema as the security-role-mapping element of the sun-web.xml and sun-ejb-jar.xml files. You should have noticed that we have a realm element in addition to role mapping elements. We can use the realm element of the sun-application.xml to specify the default authentication realm for the entire application instead of specifying it for each module separately.

Deploying the application client module in the Application Client Container

The application client module can be a first layer Java SE application which directly communicates with the EJB container and uses services like transaction and security management of EJB container through the Application Client Container. When it comes to software structure an application client is not different from a simple Java SE application. It has a main method, which is the software entry point and we can access different Java EE services simply with annotation or using deployment descriptors. The following listing shows the main method for our application client, which invokes the Conversion Session Bean and prints the result.

[code lang=”java”]
public class Main {
@EJB
private static ConversionRemote conversionBean;
public static void main(String[] args) {
System.out.println(conversionBean.toInch(10));
}
}
[/code]

You may ask how this application can use injection and access an EJB instance. The secret is, as we saw in Chapter 1, hiding in another type of container called the Application Client Container. We deploy an application client module in the ACC and later execute it in the machine either as Java Web Start application or simply using GlassFish-provided scripts. When we run this application the following
procedure takes place:

  1. Application client (launched using Web Start or directly) results in the ACC trying to inject the secured EJB.
  2. The EJB method requires authentication, so GlassFish calls the default CallbackHandler to get user login.
  3. The default CallbackHandler, which is a simple username and password collecting dialog, appears on the client’s screen.
  4. The collected username and password are sent back to application server for authentication and authorization.
  5. After a successful authentication, the method invocation goes through.

This procedure happens even if we do not add any single line of configuration to our EJB module deployment descriptor or Application Client deployment descriptor. The following figure shows more detail about the interaction between different modules when a secure EJB is called from an application client.


The default configuration for application client authentication is summarized in the following table:

All of these measures are configurable either through the Application Client deployment descriptor or the EJB deployment descriptor or the ACC deployment descriptor. The following table shows which attributes are configurable through each one of these deployment descriptors.

Two of the deployment descriptors included in the above table are specific to each vendor and may differ between different application servers. The only standard descriptor is application-client.xml, which is a part of the application client standard. This descriptor is placed inside the META-INF directory of the client application and contains information like which resources our application is using,
how the application is accessing these resources, and finally definitions of the callback handler we want to use to collect user credentials.
The following figure shows default the CallbackHandler, which is fired to collect username and password before the container lets the application invoke a method with security constraint.

We can change the default CallbackHandler in application-client.xml by specifying a new Callbackhandler. The new callback should implement the javax.security.auth.callback.CallbackHandler. The following snippet shows the callback-handler element in application-client.xml.

[code lang=”java”]
<callback-handler>
book.glassfish.security.chapter3.SwingCallbackHandler
</callback-handler>
[/code]

We can use a programmatic way to provide the ACC with username and password instead of using the callback mechanism to have more control over the authentication procedures. To conduct programmatic login we can use com.sun.appserv.security.ProgrammaticLogin class to login before we access any EJB method which has security constraints, defining security measures for communication over IIOP. We can use the GlassFish-specific deployment descriptor for EJB modules to define several types of configuration elements. We can use one set of these elements to define security measures for communication between the EJB container and the clients over IIOP (Internet Inter-Orb Protocol).
The super element for the IOR security is ior-security-config, which includes the following sub elements:

  • The transport-config for specifying transport security
  • The sas-context for specifying the caller propagation options
  • The as-context for specifying the authentication method, the security realm
    we want to use for authentication.

Following snippet shows what we should include in the EJB deployment descriptor to get SSL transport security along with username and password-based authentication using the LDAPRealm we defined in Chapter 2.

[code lang=”xml”]
<ior-security-config>
<transport-config>
<integrity>required</integrity>
<confidentiality>required</confidentiality>
<establish-trust-in-target>Required
</establish-trust-in-target>
<establish-trust-in-client>none</establish-trust-in-client>
</transport-config>
<as-context>
<auth-method>username_password</auth-method>
<realm>LDAPRealm</realm>
<required>true</required>
</as-context>
<sas-context>
<caller-propagation>supported</caller-propagation>
</sas-context>
</ior-security-config>
[/code]

Starting from the top, this snippet instructs the EJB container’s IIOP listener to use SSL for  data transmission to ensure the integrity and confidentiality of data which is transferred between client and server. Other possible values for integrity and confidentiality elements are Supported and None, which means server supports SSL if requested by clients or it does not provide them even if the client asks for data
integrity and confidentiality.
We can have SSL mutual authentication by changing the value of establish-trustin-target and establish-trust-in-client to required. This way the client will authenticate itself to the server using its digital certificate and in the same way the server will authenticate itself to the client using the digital certificate we specified for IIOP listeners.
When using mutual authentication, we should ensure that the trust store of the client trusts the certificate of the server and the trust store of the server trusts the certificate of the client. To achieve this we should:

  1. Add the digital certificate of the client’s certificate issuer to the server
    trust store.
  2. Include the digital certificate of the server’s certificate issuer to the client’s
    trust store.

Later in the code snippet we have the as-context element that we can use to specify which authentication method and security realm we want to use for authenticating clients that need to invoke a secure method of an EJB. The only supported authentication method is USERNAME_PASSWORD. The last element is sas-context. We can use it to specify whether EJB container accepts propagated caller identities or not. Possible values are Supported, Required, and None.

Configuring Application Client Container security

The Application Client Container hosts a Java SE layer application that interacts with the EJB container of the application server using IIOP. Each instance of the container can only host one instance of the client application and can be configured for that client application instance.

When we want to run a client application deployed in GlassFish
we can either use Java Web Start or the script file provided in the
GlassFish bin directory. Command format for using the script file is
as follow:
./appclient -client /opt/dev/Conversion-app-client.
jar -xml /opt/dev/sun-acc.xml
It means that we want to launch the Conversion-app-client.jar
using a configuration file named sun-acc.xml.

The sun-acc.xml structure follows the schema defined in the http://www.sun.com/software/appserver/dtds/sun-application-client-container_1_2.dtd and allows us to configure every aspect of the ACC. The following shows the content of sun-acc.xml, which has both authentication and transport security configured.

[code lang=”xml”]
<client-container>
<target-server name="localhost" address="127.0.0.1" port="3700">
<security>
<ssl cert-nickname="s1as"
ssl2-enabled="false"
ssl2-ciphers="-rc4,-rc4export,-rc2,-rc2export,-des,
-desede3"
ssl3-enabled="true"
ssl3-tls-ciphers="+rsa_rc4_128_md5,
-rsa_rc4_40_md5,+rsa3_des_sha,+rsa_des_sha,
-rsa_rc2_40 _md5,-rsa_null_md5,-rsa_des_56_sha,
-rsa_rc4_56_sha"
tls-enabled="true"
tls-rollback-enabled="true"/>
<cert-db path="ignored" password="ignored"/>
<!– not used –>
</security>
<auth-realm name="LDAPRealm"
classname="com.sun.enterprise.security.auth.realm.ldap.LDAPRealm">
<property name="directory"
value="ldap://127.0.0.1:1389"/>
<property name="base-dn" value=" dc=example,dc=com "/>
<property name="search-bind-password" value="123456"/>
<property name="jaas-context" value="ldapRealm"/>
</auth-realm>
</target-server>
<client-credential user-name="james" password="james"/>
</client-container>
[/code]

Starting from the top, we are instructing the container to use a certificate identified by client nickname. Later on we will see how we can specify which keystore and trust store we want our client container to use when we launch our application. All other properties of the ssl element specify which SSL version and cipher suites are available to the ACC to choose from. During the negotiation between server and
client to establish an SSL session, the strongest cipher suite supported by both server and client is selected. In addition to configuring the transport security we can configure the authentication mechanism for ACC in order to let ACC collect the identification information and
send them back to server when required. Following the security element we have the auth-realm element which specifies the authentication realm that ACC must use to conduct the authentication. You should know all of these properties as we discussed them in great detail
in Chapter 2. The only thing that you should remember is the fact that this configuration has nothing to do with the LDAP realm we configured in the server. This configuration affects only the client container instance running in the client machine and using this particular sun-acc.xml file.

The Application Client Container process exists in the clients machine
and anything we configure using the sun-acc.xml affects the client
machines and has nothing to do with the server or other clients, which
run another instance of the application client.

Next we have the client-credential element which we can use to specify the default client credential that ACC sends to server instead of collecting the username and password. This element ensures that a single principal is used for all invocation without end users knowing about it.
Using SSL always bring out the issue of keystore and trust store which the application requires using during the SSL handshake and SSL session. There is no vendor-specific way to pass the trust and key store information to Java runtime and rather we can use the JVM environment variables to set these values. When JVM starts and needs to use SSL, it looks for some environment variables to
initiate the SSL session. These variables are included in the following table.


In Linux, we can use the following command to export these variables before launching the application client using the appclient script.

[code]
export VMARGS="-Djavax.net.ssl.keyStore=key-store-path -Djavax.net.ssl.
trustStore= trust-store-path -Djavax.net.ssl.keyStorePassword=key-storepassword
-Djavax.net.ssl.trustStorePassword=trust-store-password"
[/code]

For Microsoft Windows we can use the set command to set VMARGS value as follows:

[code]
set VMARGS="-Djavax.net.ssl.keyStore=key-store-path -Djavax.net.ssl.
trustStore=trust-store-path -Djavax.net.ssl.keyStorePassword=key-storepassword
-Djavax.net.ssl.trustStorePassword=trust-store-password"
[/code]

To create a working pair of certification stores we can follow the same steps we followed to create keystore and trust store for GlassFish application server. Using the same certificate issuer will guarantee that GlassFish will accept the certificate provided by the client and the client will accept the certificate provided by GlassFish. Now that we have set the required runtime arguments for JVM we can run the client
application and be assured about data confidentiality and integrity. The sample application for this chapter is included in the source code archive of the book.

Summary

In this chapter we studied Java EE security in action and developed a secure Java EE application with all of standard modules including EJB, Web, and application clients. We studied how we can secure EJBs using annotation and then use a web frontend to use the secure EJBs after the user provides correct identification information. We developed a client application to access the secure EJB and later on we studied how
we can use SSL and mutual authentication between the application client module and EJB container. In the next two chapters we will look at GlassFish security independent of the Java EE security and what measures we should consider to have a safe GlassFish installation.

Filed Under: Java EE Tagged With: Glassfish, Security

How to Configure Java Messaging Service (JMS) in GlassFish 3 Application Server?

September 10, 2010 by itadmin Leave a Comment

This book begins with the installation of Glassfish 3 and deploying Java applications. It also explains how to develop, configure, package, and deploy servlets. Additionally, we will learn the processing of HTML forms. As we move on, we will develop Java Server Pages and get to know about implicit JSP objects. We will also get to know about all the JSTL (JSP Standard Tag Library) tag libraries. This book gives us a better understanding on how to manage data from a database through the Java Database Connectivity (JDBC) API and the Java Persistence API (JPA). We will also learn more about the newly introduced features of JPA 2.0 and develop JSF 2.0 applications to learn how to customize them. We will then set up Glassfish for the Java Messaging (JMS) API and understand the working of message queues and message topics. Later, we will use the Context and Dependency Injection (CDI) API to integrate application layers and study the SOAP-based web service development using the JAX-WS specification. Finally, we will learn more about the RESTful web service development using the JAX-RS specification.

also read:

  • Java EE Tutorials
  • Java EE 7 Tutorials
  • Java EE Interview Questions

The book covers the various Java EE 6 conventions and annotations that can simplify enterprise Java application development. The latest versions of the Servlet, JSF, JPA, EJB, and JAX-WS specifications are covered, as well as new additions to the specification, such as JAX-RS and CDI.

What This Book Covers

Chapter 1, Getting Started with GlassFish will discuss how to download and install GlassFish. We will look at several methods of deploying a Java EE application through the GlassFish web console, through the asadmin command, and by copying the file to the autodeploy directory. We will cover basic GlassFish administration tasks such as setting up domains and setting up database connectivity by adding connection pools and data sources.

Chapter 2, Servlet Development and Deployment will cover how to develop, configure, package, and deploy servlets. We will also cover how to process HTML form information by accessing the HTTP request object. Additionally, forwarding HTTP requests from one servlet to another will be explained, as well as redirecting the HTTP response to a different server. We will discuss how to persist objects in memory across requests by attaching them to the servlet context and the HTTP session. Finally, we will look at all the major new features of Servlet 3.0, including configuring web applications via annotations, pluggability through web-fragment. xml , programmatic servlet configuration, and asynchronous processing.
Chapter 3, JavaServer Pages will talk about how to develop and deploy simple JSPs. We will cover how to access implicit objects such as request, session, and so on, from JSPs. Additionally, we will look at how to set and get the values of JavaBean properties via the <jsp:useBean> tag. In addition to that, we will find out how to include a JSP into another JSP at runtime via the <jsp:include> tag, and at compilation time via the JSP include directive. We will discuss how to write custom JSP tags by extending javax.servlet.jsp.tagext.SimpleTagSupport or by writing TAG files. We will also discuss how to access JavaBeans and their properties via the Unified Expression Language. Finally, we will cover the JSP XML syntax that allows us to develop XMLcompliant
JavaServer Pages.
Chapter 4, JSP Standard Tag Library will cover all JSP Standard Tag Library tags, including the core, formatting, SQL, and XML tags. Additionally, JSTL functions will be explained. Examples illustrating the most common JSTL tags and functions will be provided; additional JSTL tags and functions will be mentioned and described.
Chapter 5, Database Connectivity will talk about how to access data in a database via both the Java Database Connectivity (JDBC) and through the Java Persistence API (JPA). Defining both unidirectional and bidirectional one-to-one, one-to-many, and many-to-many relationships between JPA entities will be covered. Additionally, we will discuss how to use JPA composite primary keys by developing custom primary key classes. We will also discuss how to retrieve entities from a database by using the Java Persistence Query Language (JPQL). We will look at how to build queries programmatically through the JPA 2.0 Criteria API and automating data validation through JPA 2.0’s Bean Validation support
Chapter 6,JavaServer Faces will cover how to develop web-based applications using JavaServer Faces—the standard component framework for the Java EE 5 platform. We will talk about how to write a simple application by creating JSPs containing JSF tags and managed beans. We will discuss how to validate user input by using JSF’s standard validators and by creating our own custom validators, or by writing validator methods. Additionally, we will look at how to customize standard JSF error messages; both the message text and the message style (font, color, and so on). Finally, we will discuss how to write applications by integrating JSF and the Java Persistence API (JPA).
Chapter 7, Java Messaging Service will talk about how to set up JMS connection factories, JMS message queues, and JMS message topics in GlashFish using the GlashFish web console. We will cover how to send and receive messages to and from a message queue. We will discuss how to send and receive messages to and from a JMS message topic. We will find out how to browse messages in a message queue without
removing the messages from the queue. Finally, we will look at how to set up and interact with durable subscriptions to JMS topics.
Chapter 8, Security will talk about how to use GlashFish’s default realms to authenticate our web applications. We will cover the file realm, which stores user information in a flat file, and the certificate realm, which requires client-side certificates for user authentication. Additionally, we will discuss how to create additional realms that behave just like the default realms, by using the realm classes included with GlashFish.
Chapter 9, Enterprise JavaBeans will cover how to implement business logic via stateless and stateful session beans. Additionally, we will explain the concept of containermanaged transactions and bean-managed transactions. We will look at the life cycles for the different types of Enterprise Java Beans. We will talk about how to have EJB methods invoked periodically by the EJB container, by taking advantage of the EJB timer service. Finally, we will explain how to make sure that EJB methods are only invoked by authorized users.
Chapter 10, Contexts and Dependency Injection will talk about how JSF pages can access CDI named beans as if they were JSF managed beans. We will explain how CDI makes it easy to inject dependencies into our code. We will discuss how we can use qualifiers to determine what specigic implementation of dependency to inject into our code. Finally, we will look at all the scopes that a CDI bean can be placed into.
Chapter 11, Web Services with JAX-WS will cover how to develop web services and web service clients via the JAX-WS API. We will discuss how to send attachments to a web service. We will explain how to expose an EJB’s methods as web services. Finally, we will look at how to secure web services so that they are not accessible to unauthorized clients.
Chapter 12, RESTful Web Services with Jersey and JAX-RS will discuss how to easily develop RESTful web services using JAX-RS—a new addition to the Java EE specification. We will explain how to automatically convert data between Java and XML by taking advantage of the Java API for XML Binding (JAXB). Finally, we will cover how to pass parameters to our RESTful web services via the @PathParam and
@QueryParam annotations.

The Java Messaging API (JMS) provides a mechanism for Java EE applications to send messages to each other. JMS applications do not communicate directly, instead message producers send messages to a destination and message consumers receive the message from the destination.
The message destination is a message queue when the point-to-point (PTP) messaging domain is used, or a message topic when the publish/subscribe (pub/sub) messaging domain is used. In this chapter, we will cover the following topics:

  • Setting up GlashFish for JMS
  • Working with message queues
  • Working with message topics

Setting up GlassFish for JMS

Before we start writing code to take advantage of the JMS API, we need to configure some GlashFish resources. Specifically, we need to set up a JMS connection factory, a message queue, and a message topic.

Setting up a JMS connection factory

The easiest way to set up a JMS connection factory is via GlashFish’s web console. Recall from Chapter 1 that the web console can be accessed by starting our domain, by entering the following command in the command line:

[code lang=”java”]
asadmin start-domain domain1
[/code]

Then point the browser to http://localhost:4848 and log in:


A connection factory can be added by expanding the Resources node in the tree at the left-hand side of the web console, expanding the JMS Resources node and clicking on the Connection Factories node, then clicking on the New… button in the main area of the web console.


For our purposes, we can take most of the defaults. The only thing we need to do is enter a Pool Name and pick a Resource Type for our connection factory.

It is always a good idea to use a Pool Name starting with “jms/” when
picking a name for JMS resources. This way JMS resources can be
easily identified when browsing a JNDI tree.

In the text field labeled Pool Name, enter jms/GlassFishBookConnectionFactory. Our code examples later in this chapter will use this JNDI name to obtain a reference to this connection factory.
The Resource Type drop-down menu has three options:

  • javax.jms.TopicConnectionFactory – used to create a connection factory that creates JMS topics for JMS clients using the pub/sub messaging domain
  • javax.jms.QueueConnectionFactory – used to create a connection factory that creates JMS queues for JMS clients using the PTP messaging domain
  • javax.jms.ConnectionFactory – used to create a connection factory that creates either JMS topics or JMS queues

For our example, we will select javax.jms.ConnectionFactory. This way we can use
the same connection factory for all our examples, those using the PTP messaging
domain and those using the pub/sub messaging domain.
After entering the Pool Name for our connection factory, selecting a connection
factory type, and optionally entering a description for our connection factory,
we must click on the OK button for the changes to take effect.


We should then see our newly created connection factory listed in the main area of the GlashFish web console.

Setting up a JMS message queue

A JMS message queue can be added by expanding the Resources node in the tree at the left-hand side of the web console, expanding the JMS Resources node and clicking on the Destination Resources node, then clicking on the New… button in the main area of the web console.


In our example, the JNDI name of the message queue is jms/GlassFishBookQueue. The resource type for message queues must be javax.jms.Queue. Additionally, a Physical Destination Name must be entered. In this example, we use GlassFishBookQueue as the value for this field.
After clicking on the New… button, entering the appropriate information for our message queue, and clicking on the OK button, we should see the newly created queue:

Setting up a JMS message topic

Setting up a JMS message topic in GlashFish is very similar to setting up a message queue. In the GlashFish web console, expand the Resources node in the tree at the left hand side, then expand the JMS Resouces node and click on the Destination Resources node, then click on the New… button in the main area of the web console.


Our examples will use a JNDI Name of jms/GlassFishBookTopic. As this is a message topic, Resource Type must be javax.jms.Topic. The Description field is optional. The Physical Destination Name property is required. For our example, we will use GlassFishBookTopic as the value for this property.
After clicking on the OK button, we can see our newly created message topic:


Now that we have set up a connection factory, a message queue, and a message topic, we are ready to start writing code using the JMS API.

Message queues

Like we mentioned earlier, message queues are used when our JMS code uses the point-to-point (PTP) messaging domain. For the PTP messaging domain, there is usually one message producer and one message consumer. The message producer and the message consumer don’t need to run concurrently in order to communicate. The messages placed in the message queue by the message producer will stay in the
message queue until the message consumer executes and requests the messages from the queue.

Sending messages to a message queue

The following example illustrates how to add messages to a mess age queue:

[code lang=”java”]
package net.ensode.glassfishbook;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
public class MessageSender
{
@Resource(mappedName = &quot;jms/GlassFishBookConnectionFactory&quot;)
private static ConnectionFactory connectionFactory;
@Resource(mappedName = &quot;jms/GlassFishBookQueue&quot;)
private static Queue queue;

public void produceMessages()
{
MessageProducer messageProducer;
TextMessage textMessage;
try
{
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageProducer = session.createProducer(queue);
textMessage = session.createTextMessage();
textMessage.setText(&quot;Testing, 1, 2, 3. Can you hear me?&quot;);
System.out.println(&quot;Sending the following message: &quot;
+ textMessage.getText());
messageProducer.send(textMessage);
textMessage.setText(&quot;Do you copy?&quot;);
System.out.println(&quot;Sending the following message: &quot;
+ textMessage.getText());
messageProducer.send(textMessage);
textMessage.setText(&quot;Good bye!&quot;);
System.out.println(&quot;Sending the following message: &quot;
+ textMessage.getText());
messageProducer.send(textMessage);
messageProducer.close();
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new MessageSender().produceMessages();
}
}
[/code]

Before delving into the details of this code, alert readers might have noticed that this class is a standalone Java application as it contains a main method. As this class is standalone, it executes outside the application server. In spite of this, we can see that some resources are injected into it, specifically the connection factory and queue. The reason we can inject resources into this code, even though it runs outside the application server, is because GlashFish includes a utility called appclient. This utility allows us to “wrap” an executable JAR file and allows it to have access to the application server resources. To execute the previous code, assuming it is packaged in an executable JAR file called jmsptpproducer.jar, we would type the following command in the command line:

[code lang=”java”]
appclient -client jmsptpproducer.jar
[/code]

We would then see, after some GlashFish log entries, the following output on the console:

[code lang=”java”]
Sending the following message: Testing, 1, 2, 3. Can you hear me?
Sending the following message: Do you copy?
Sending the following message: Good bye!
[/code]

The appclient executable can be found under [GlashFish installation directory]/GlashFish/bin. The previous example assumes this directory is in your PATH variable. If it isn’t the complete path to the appclient executable, it must be typed in the command line.
With that out of the way, we can now explain the code. The produceMessages() method performs all the necessary steps to send messages
to a message queue. The first thing this method does is obtain a JMS connection by invoking the createConnection() method on the injected instance of javax.jms. ConnectionFactory. Notice that the mappedName attribute of the @Resource annotation decorating the connection factory object matches the JNDI name of the connection factory we set up in the GlashFish web console. Behind the scenes, a JNDI lookup is made using this name to obtain the connection factory object. After obtaining a connection, the next step is to obtain a JMS session from said
connection. This can be accomplished by calling the createSession() method on the Connection object. As can be seen in the previous code, the createSession() method takes two parameters.
The first parameter of the createSession() method is a Boolean indicating if the session is transacted. If this value is true, several messages can be sent as part of a transaction by invoking the commit() method in the session object. Similarly, they can be rolled back by invoking its rollback() method.
The second parameter of the createSession() method indicates how messages are acknowledged by the message receiver. Valid values for this parameter are defined as constants in the javax.jms.Session interface.

  • Session.AUTO_ACKNOWLEDGE: indicates that the session will automatically acknowledge the receipt of a message.
  • Session.CLIENT_ACKNOWLEDGE: indicates that the message receiver must explicitly call the acknowledge() method on the message.
  • Session.DUPS_OK_ACKNOWLEDGE: indicates that the session will lazily acknowledge the receipt of messages. Using this value might result in some messages being delivered more than once.

After obtaining a JMS session, an instance of javax.jms.MessageProducer is obtained by invoking the createProducer() method on the session object. The MessageProducer object is the one that will actually send messages to the message queue. The injected Queue instance is passed as a parameter to the createProducer() method . Again, the value of the mappedName attribute for the @Resource annotation decorating this object must match the JNDI name we gave our message queue when setting it up in the GlashFish web console.
After obtaining an instance of MessageProducer, the code creates a series of text messages by invoking the createTextMessage() method on the session object. This method returns an instance of a class implementing the javax.jms.TextMessage interface. This interface defines a method called setText() , which is used to set the actual text in the message. After creating each text message and setting its text, they are
sent to the queue by invoking the send() method on the MessageProducer object. After sending the messages, the code disconnects from the JMS queue by invoking the close() method on the MessageProducer object , on the Session object , and on the Connection object.
Although the previous example sends only text messages to the queue, we are not limited to this type of message. The JMS API provides several types of messages that can be sent and received by JMS applications. All message types are defined as interfaces in the javax.jms package. The following table lists all the available message types:


For more information on all of these message types, consult their JavaDoc documentation at http://java.sun.com/javaee/6/docs/api/.

Retrieving messages from a message queue

There is no point in sending messages from a queue if nothing is going to receive them. The following example illustrates how to retrieve messages from a JMS message queue:

[code lang=”java”]
package net.ensode.glassfishbook;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

public class MessageReceiver
{
@Resource(mappedName = &quot;jms/GlassFishBookConnectionFactory&quot;)
private static ConnectionFactory connectionFactory;
@Resource(mappedName = &quot;jms/GlassFishBookQueue&quot;)
private static Queue queue;

public void getMessages()
{
Connection connection;
MessageConsumer messageConsumer;
TextMessage textMessage;
boolean goodByeReceived = false;
try
{
connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageConsumer = session.createConsumer(queue);
connection.start();
while (!goodByeReceived)
{
System.out.println(&quot;Waiting for messages…&quot;);
textMessage = (TextMessage) messageConsumer.receive();
if (textMessage != null)
{
System.out.print(&quot;Received the following message: &quot;);
System.out.println(textMessage.getText());
System.out.println();
}
if (textMessage.getText() != null
&amp;&amp; textMessage.getText().equals(&quot;Good bye!&quot;))
{
goodByeReceived = true;
}
}
messageConsumer.close();
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new MessageReceiver().getMessages();
}
}
[/code]

Just like in the previous example, an instance of javax.jms.ConnectionFactory and an instance of javax.jms.Queue are injected by using the @Resource annotation. Getting a connection and a JMS session is exactly the same as in the previous example.  In this example, we obtain an instance of javax.jms.MessageConsumer by calling the createConsumer() method on the JMS session object. When we are ready to
start receiving messages from the message queue, we need to invoke the start() method on the JMS connection object.

Code not receiving messages?
A common mistake when writing JMS messages is to fail to call the
start() method on the JMS connection object. If our code is not
receiving messages it should be receiving, we need to make sure we
didn’t forget to call this method.

Messages are received by invoking the receive() method on the instance of MessageConsumer obtained from the JMS session. This method returns an instance of a class implementing the javax.jms.Message interface. It must be casted to the appropriate type in order to obtain the actual message. In this particular example, we placed this method call in a while loop, as we are expecting a message that will let us know that no more messages are coming. Specifically, we are looking for a message containing the text “Good bye!”. Once we receive said message, we break out of the loop and continue processing. In this particular case, there is no more processing to do. Therefore, all we do is call the
close() method on the message consumer object, on the session object, and on the connection object.
Just like in the previous example, using the appclient utility allows us to inject resources into the code and prevents us from having to add any libraries to the CLASSPATH. After executing the code through the appclient utility, we should see the following output in the command line:

[code lang=”java”]
appclient -client target/jmsptpconsumer.jar
Waiting for messages…
Received the following message: Testing, 1, 2, 3. Can you hear me?

Waiting for messages…
Received the following message: Do you copy?

Waiting for messages…
Received the following message: Good bye!
[/code]

This of course assumes that the previous example was already executed and it placed the messages in the message queue.

Asynchronously receiving messages from a message queue

The MessageConsumer.receive() method has a disadvantage—it blocks execution until a message is received from the queue. We can avoid this disadvantage by receiving messages asynchronously via an implementation of the javax.jms.MessageListener interface. The javax.jms.MessageListener interface contains a single method called onMessage. It takes an instance of a class implementing the javax.jms.Message interface as its sole parameter. The following example illustrates a typical implementation of this interface:

[code lang=”java”]
package net.ensode.glassfishbook;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
public class ExampleMessageListener implements MessageListener
{
@Override
public void onMessage(Message message)
{
TextMessage textMessage = (TextMessage) message;
try
{
System.out.print(&quot;Received the following message: &quot;);
System.out.println(textMessage.getText());
System.out.println();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
}
[/code]

In this case, the onMessage() method simply outputs the message text to the console. Our main code can now delegate message retrieval to our custom MessageListener implementation:

[code lang=”java”]
package net.ensode.glassfishbook;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
public class AsynchMessReceiver
{
@Resource(mappedName = &quot;jms/GlassFishBookConnectionFactory&quot;)
private static ConnectionFactory connectionFactory;
@Resource(mappedName = &quot;jms/GlassFishBookQueue&quot;)
private static Queue queue;
public void getMessages()
{
Connection connection;
MessageConsumer messageConsumer;
try
{
connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageConsumer = session.createConsumer(queue);
messageConsumer.setMessageListener(new
ExampleMessageListener());
connection.start();
System.out.println(&quot;The above line wil l allow the &quot;
+ &quot;MessageListener implementation to &quot;
+ &quot;receiving and processing messages from the queue.&quot;);
Thread.sleep(1000);
System.out.println(&quot;Our code does not have to block &quot;
+ &quot;while messages are received.&quot;);
Thread.sleep(1000);
System.out.println(&quot;It can do other stuff &quot;
+ &quot;(hopefully something more useful than sending &quot;
+ &quot;silly output to the console. :)&quot;);
Thread.sleep(1000);
messageConsumer.close();
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new AsynchMessReceiver().getMessages();
}
}
[/code]

The only relevant difference between this example and the one in the previous section is that in this case, we are calling the setMessageListener() method on the instance of javax.jms.MessageConsumer obtained from the JMS session. We pass an instance of our custom implementation of javax.jms.MessageListener to this method. Its onMessage() method is automatically called whenever there is a message waiting in the queue. By using this approach, the main code does not block while waiting to receive messages. Executing the previous example (using of course GlashFish’s appclient utility) results in the following output:

[code]
appclient -client target/jmsptpasynchconsumer.jar
The above line will allow the MessageListener implementation to receiving
and processing messages from the queue.
Received the following message: Testing, 1, 2, 3. Can you hear me?

Received the following message: Do you copy?

Received the following message: Good bye!

Our code does not have to block while messages are received.
It can do other stuff (hopefully something more useful than sending silly
output to the console. 🙂
[/code]

Notice how the messages were received and processed while the main thread was executing. We can tell this is the case because the output of the onMessage() method of our MessageListener can be seen between calls to System.out.println() in the primary class.

Browsing message queues

JMS provides a way to browse message queues without actually removing the messages from the queue. The following example illustrates how to do this:

[code lang=”java”]
package net.ensode.glassfishbook;
import java.util.Enumeration;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueBrowser;
import javax.jms.Session;
import javax.jms.TextMessage;
public class MessageQueueBrowser
{
@Resource(mappedName = &quot;jms/GlassFishBookConnectionFactory&quot;)
private static ConnectionFactory connectionFactory;
@Resource(mappedName = &quot;jms/GlassFishBookQueue&quot;)
private static Queue queue;
public void browseMessages()
{
try
{
Enumeration messageEnumeration;
TextMessage textMessage;
Connection connection = connectionFactory.createConnection();

Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
QueueBrowser browser = session.createBrowser(queue);
messageEnumeration = browser.getEnumeration();
if (messageEnumeration != null)
{
if (!messageEnumeration.hasMoreElements())
{
System.out.println(&quot;There are no messages &quot; + &quot;in the
queue.&quot;);
}
else
{
System.out.println(&quot;The following messages are in the
queue:&quot;);
while (messageEnumeration.hasMoreElements())
{
textMessage =
(TextMessage) messageEnumeration.nextElement();
System.out.println(textMessage.getText());
}
}
}
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new MessageQueueBrowser().browseMessages();
}
}
[/code]

As we can see, the procedure to browse messages in a message queue is straightforward. We obtain a JMS connection and a JMS session the usual way, then invoke the createBrowser() method on the JMS session object. This method returns an implementation of the javax.jms.QueueBrowser interface. This interface contains a getEnumeration() method that we can invoke to obtain an enumeration containing all messages in the queue. To examine the messages in the queue, we simply traverse this enumeration and obtain the messages one by one. In the previous example, we simply invoke the getText() method of each message in the queue.

Message topics

Message topics are used when our JMS code uses the publish/subscribe (pub/sub) messaging domain. When using this messaging domain, the same message can be sent to all subscribers of the topic.

Sending messages to a message topic

The following example illustrates how to send messages to a message topic: [code lang=”java”]
[code lang=&quot;java&quot;] package net.ensode.glassfishbook;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
public class MessageSender
{
@Resource(mappedName = &quot;jms/GlassFishBookConnectionFactory&quot;)
private static ConnectionFactory connectionFactory;
@Resource(mappedName = &quot;jms/GlassFishBookTopic&quot;)
private static Topic topic;
public void produceMessages()
{
MessageProducer messageProducer;
TextMessage textMessage;
try
{
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageProducer = session.createProducer(topic);
textMessage = session.createTextMessage();
textMessage.setText(&quot;Testing, 1, 2, 3. Can you hear me?&quot;);
System.out.println(&quot;Sending the following message: &quot;
+ textMessage.getText());
messageProducer.send(textMessage);
textMessage.setText(&quot;Do you copy?&quot;);
System.out.println(&quot;Sending the following message: &quot;
+ textMessage.getText());
messageProducer.send(textMessage);
textMessage.setText(&quot;Good bye!&quot;);
System.out.println(&quot;Sending the following message: &quot;
+ textMessage.getText());
messageProducer.send(textMessage);
messageProducer.close();
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new MessageSender().produceMessages();
}
}
[/code]

As we can see, this code is nearly identical to the MessageSender class we saw when we discussed point-to-point messaging. As a matter of fact, the only lines of code that are different are the ones that are highlighted. The JMS API was designed this way so that application developers do not have to learn two different APIs for the PTP and pub/sub domains. As the code is nearly identical to the corresponding example in the Message queues section, we will only explain the differences between the two examples. In this example, instead of declaring an instance of a class implementing javax.jms. Queue, we declare an instance of a class implementing javax.jms.Topic. Just like in the previous examples, we use dependency injection to initialize the Topic object. After obtaining a JMS connection and a JMS session, we pass the Topic object to the createProducer() method in the Session object. This method returns an instance of javax.jms.MessageProducer that we can use to send messages to the JMS topic.

Receiving messages from a message topic

Just as sending messages to a message topic is nearly identical to sending messages to a message queue, receiving messages from a message topic is nearly identical to receiving messages from a message queue.

[code lang=”java”]
package net.ensode.glassfishbook;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
public class MessageReceiver
{
@Resource(mappedName = &quot;jms/GlassFishBookConnectionFactory&quot;)
private static ConnectionFactory connectionFactory;
@Resource(mappedName = &quot;jms/GlassFishBookTopic&quot;)
private static Topic topic;
public void getMessages()
{
Connection connection;
MessageConsumer messageConsumer;
TextMessage textMessage;
boolean goodByeReceived = false;
try
{
connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageConsumer = session.createConsumer(topic);
connection.start();
while (!goodByeReceived)
{
System.out.println(&quot;Waiting for messages…&quot;);
textMessage = (TextMessage) messageConsumer.receive();
if (textMessage != null)
{
System.out.print(&quot;Received the following message: &quot;);
System.out.println(textMessage.getText());
System.out.println();
}
if (textMessage.getText() != null
&amp;&amp; textMessage.getText().equals(&quot;Good bye!&quot;))
{
goodByeReceived = true;
}
}
messageConsumer.close();
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new MessageReceiver().getMessages();
}
}
[/code]

Once again, the differences between this code and the corresponding code for PTP are trivial. Instead of declaring an instance of a class implementing javax.jms.Queue, we declare a class implementing javax.jms.Topic. We use the @Resource annotation to inject an instance of this class into our code using the JNDI name we used when creating it in the GlashFish web console. After obtaining a JMS connection and a JMS session, we pass the Topic object to the createConsumer() method in the Session object. This method returns an instance of javax.jms.MessageConsumer that we can use to receive messages from the JMS topic. Using the pub/sub messaging domain as illustrated in this section has the advantage that messages can be sent to several message consumers. This can be easily tested by concurrently executing two instances of the MessageReceiver class we developed in this section, then executing the MessageSender class we developed in the previous section. We should see console output for each instance, indicating that both instances received all messages. Just like with message queues, messages can be retrieved asynchronously from a message topic. The procedure to do this is so similar to the message queue version that we will not show an example. To convert the asynchronous example shown earlier in this chapter to use a message topic, simply replace the javax.jms.Queue variable with an instance of javax.jms.Topic and inject the appropriate instance by using “jms/GlassFishBookTopic” as the value of the mappedName attribute of the @Resource annotation decorating the instance of javax.jms.Topic.

Creating durable subscribers

The disadvantage of using the pub/sub messaging domain is that message consumers must be executing when messages are sent to the topic. If the message consumer is not executing at the time, it will not receive the messages, whereas in PTP, messages are kept in a queue until the message consumer executes. Fortunately, the JMS API provides a way to use the pub/sub messaging domain and keep messages in the topic until all subscribed message consumers execute and receive the message. This can be accomplished by creating durable subscribers to a JMS topic. In order to be able to service durable subscribers, we need to set the ClientId property of our JMS connection factory. Each durable subscriber must have a unique client id, therefore a unique connection factory must be declared for each potential durable subscriber.

InvalidClientIdException?
Only one JMS client can connect to a topic for a specific client id. If more
than one JMS client attempts to obtain a JMS connection using the same
connection factory, a JMSException stating that the client id is already in
use will be thrown. The solution is to create a connection factory for each
potential client that will be receiving messages from the durable topic.

Like we mentioned before, the easiest way to add a connection factory is through the GlashFish web console. Recall that to add a JMS connection factory through the GlashFish web console, we need to expand the Resources node on the left hand side, then expand the JMS Resources node, click on the Connection Factories node, and click on the New… button in the main area of the page. Our next example will use the settings displayed in the following screenshot:


Before clicking on the OK button, we need to scroll to the bottom of the page, click on the Add Property button, and enter a new property named ClientId. Our example will use ExampleId as the value for this property.


Now that we have set up GlashFish to be able to provide durable subscriptions, we are ready to write some code to take advantage of them:

[code lang=”java”]
package net.ensode.glassfishbook;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
public class MessageReceiver
{
@Resource(mappedName = &quot;jms/GlassFishBookDurableConnectionFactory&quot;)
private static ConnectionFactory connectionFactory;
@Resource(mappedName = &quot;jms/GlassFishBookTopic&quot;)
private static Topic topic;
public void getMessages()
{
Connection connection;
MessageConsumer messageConsumer;
TextMessage textMessage;
boolean goodByeReceived = false;
try
{
connection = connectionFactory.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
messageConsumer = session.createDurableSubscriber(topic,
&quot;Subscriber1&quot;);
connection.start();
while (!goodByeReceived)
{
System.out.println(&quot;Waiting for messages…&quot;);
textMessage = (TextMessage) messageConsumer.receive();
if (textMessage != null)
{
System.out.print(&quot;Received the following message: &quot;);
System.out.println(textMessage.getText());
System.out.println();
}
if (textMessage.getText() != null
&amp;&amp; textMessage.getText().equals(&quot;Good bye!&quot;))
{
goodByeReceived = true;
}
}
messageConsumer.close();
session.close();
connection.close();
}
catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
new MessageReceiver().getMessages();
}
}
[/code]

As we can see, this code is not much different from the previous examples whose purpose was to retrieve messages. There are only two differences from the previous examples: the instance of ConnectionFactory to which we are injecting is the one we set up earlier in this section to handle durable subscriptions, and instead of calling the createSubscriber() method on the JMS session object, we are calling createDurableSubscriber() . The createDurableSubscriber() method takes two arguments: a JMS Topic object to retrieve messages from and a string designating a name for this subscription. This second parameter must be unique between all subscribers to the durable topic.

Summary

In this chapter, we covered how to set up JMS connection factories, JMS message queues, and JMS message topics in GlashFish using the GlashFish web console. We also covered how to send messages to a message queue via the javax.jms.MessageProducer interface.
Additionally, we covered how to receive messages from a message queue via the javax.jms.MessageConsumer interface. We also covered how to asynchronously receive messages from a message queue by implementing the javax.jms.MessageListener interface. We also saw how to use these interfaces to send and receive messages to and from a JMS message topic. We covered how to browse messages in a message queue without removing the messages from the queue via the javax.jms.QueueBrowser interface. Finally, we saw how to set up and interact with durable subscriptions to JMS topics.

Filed Under: Java EE Tagged With: Glassfish, JMS

Follow Us

  • Facebook
  • Pinterest

As a participant in the Amazon Services LLC Associates Program, this site may earn from qualifying purchases. We may also earn commissions on purchases from other retail websites.

JavaBeat

FEATURED TUTORIALS

Answered: Using Java to Convert Int to String

What is new in Java 6.0 Collections API?

The Java 6.0 Compiler API

Copyright © by JavaBeat · All rights reserved