|
In This Issue
Welcome to the Enterprise Java Technologies Tech Tips for October 28, 2006. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java Platform, Enterprise Edition (Java EE). This issue covers:These tips were developed using the Java EE 5 SDK. You can download the SDK from the Java EE Downloads page. You can download the sample archive for the Java Persistence Query Language tip . You can download the sample archive for the EJB 3.0 Interceptors tip. Any use of this code and/or information below is subject to the license terms. See the Subscribe/Unsubscribe note at the end of this newsletter to subscribe to Tech Tips that focus on technologies and products in other Java platforms. The JAVA PERSISTENCE QUERY LANGUAGE
by Jie Lin Leng One of the things that the Java Persistence API specifies is a query language that allows you to define queries over entities and their persistent state. The query language, called the Java Persistence Query Language, gives you a way to specify the semantics of queries in a portable way, independent of the particular database you're using in an enterprise environment. This Tech Tip introduces the Java Persistence Query Language and discusses some of its basic features. The tip assumes that you understand the basic terms and concepts of the Java Persistence API. If you don't, see "Chapter 24: Introduction to the Java Persistence API" in the Java EE 5 Tutorial A sample package accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package). The sample uses the Java EE 5 SDK. You can download the Java EE 5 SDK from the Java EE Downloads page A Simple Example
Let's start with a simple example that uses the Java Persistence Query Language. Suppose you have two entities,
@Entity
@Table(name="CUSTOMER_TABLE")
public class Customer implements Serializable{
public enum CustomerStatus
{FULL_TIME, PART_TIME, CONTRACT};
@Id
@Column(name="ID")
private Integer customerId;
@Column(name="CITY")
private String city;
@Column(name="NAME")
private String name;
@Enumerated(ORDINAL)
@Column(name="STATUS")
private CustomerStatus status;
@OneToMany(mappedBy="customer")
private Collection<Order> orders;
...
}
@Entity
@Table(name="ORDER_TABLE")
public class Order implements Serializable {
@Id
@Column(name="ID")
private Integer orderId;
@Column(name="QUANTITY")
private int quantity;
@Column(name="TOTALPRICE")
private float totalPrice;
@ManyToOne()
@JoinColumn(name="CUST_ID")
private Customer customer;
...
}
Here's some client code that creates instances of the entities, creates an entity manager to manage their persistence, and inserts the instances in a database:
// Create an EntityManagerFactory for a persistence unit
// called j2seEnvironment.
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("j2seEnvironment");
// Create an Entity Manager
EntityManager em = emf.createEntityManager();
// get a Transaction
EntityTransaction tx = em.getTransaction();
// create a POJO instance of the Customer class
Customer customer = new Customer();
customer.setCustomerId(new Integer(3));
customer.setName("SUN_SALE");
customer.setCity("SAN JOSE");
customer.setStatus(Customer.CustomerStatus.FULL_TIME);
// create a POJO instance of the Order class
// for this customer
order order = new Order();
order.setOrderId(new Integer(3));
order.setQuantity(new Integer(2));
order.setTotalPrice(new Float(22.30));
order.setCustomer(customer);
// Make the Customer and Order instances persistent
// and insert them into the database
tx.begin();
em.persist(customer);
em.persist(order);
tx.commit();
With persistence established for the entities, you can issue Java Persistence Query Language queries against those entities. For example, here is a simple query that you can add to the
client code to list all the elements in the // run a simple Java Persistence query language query String ejbql = "SELECT c FROM Customer c WHERE c.name = 'SUN_SALE'"; Query query = em.createQuery(ejbql); List result = query.getResultList();
Notice that the syntax of the
The Named Queries You can also predefine queries for an entity. These predefined, static queries are called named queries. A major advantage of using a named query is that you can rerun it multiple times, providing different parameters for each run.
To use a named query, you first define the named query using the
@NamedQuery (
name="findCustomerByName",
query="select c FROM Customer c WHERE c.name = :name"
)
})
public class Customer {
...
}
The named query,
Named queries can also be grouped together using the
@NamedQueries({
@NamedQuery (
name="findCustomerByName",
query="select c FROM Customer c WHERE c.name = :name"
),
@NamedQuery(
name="findCustomerbyOrderId",
query="select c FROM Customer c JOIN c.orders o WHERE
o.orderId = :id"
)
})
public class Customer {
...
}
The second named query,
After you define a named query, you create it in the client code using the
List customers = em.createNamedQuery("findCustomerByName")
.setParameter("name", "SUN_SALE")
.getResultList();
The GROUP BY and HAVING Clauses
The Java Persistence Query Language also supports the
The GROUP BY or HAVING clauses:
// Group the orders by their customer and for each group // return the customer and the average totalPrice String ejbql = "SELECT o.customer, AVG(o.totalPrice) FROM Order o GROUP BY o.customer"; Query query = em.createQuery(ejbql); // Group the customers by their city. For each group return // the city and the number of customers in that group, but // only if there are more than 3 String ejbql = "SELECT c.city, COUNT(c.city) FROM Customer c GROUP BY c.city HAVING COUNT(c.city) > 3"; Query query = em.createQuery(ejbql); // Group the orders with a totalPrice over a certain limit // per the name of their customer, but consider only // customers whose name starts with 'SUN'). For each group // return the customer name, the average, and maximum // totalPrice. String ejbql = SELECT o.customer.name, AVG(o.totalPrice), MAX(o.totalPrice) FROM Order WHERE o.totalPrice > :limit GROUP BY o.customer.name HAVING o.customer.name LIKE 'SUN%'; Query query = em.createQuery(ejbql); There's Much More The Java Persistence Query Language is a full structured query language, and offers many more language features than those covered in this tip. These include language features for bulk update and delete operations, outer join operations, projection, and subqueries. For a more complete description of the language see "Chapter 27: The Java Persistence Query Language" in the Java EE 5 Tutorial. A future tip will cover some common pitfalls in constructing Java Persistence Query Language queries. Running the Sample Code To install and run the sample code that accompanies this tip:
About the Author Jie Lin Leng is a member of the Java Persistence Engineering group at Sun. She is currently involved in the development of the Java Persistence Query Language for EJB 3.0. EJB 3.0 INTERCEPTORS by Mahesh Kannan One of the new features introduced in the EJB 3.0 specification is interceptors. An interceptor is a method that you can interpose in the invocation flow of an enterprise bean. You can define an interceptor to intercept an enterprise bean's business methods -- the interceptor method runs before any of the bean's business methods are invoked. Or you can define an interceptor to intercept lifecycle events for an enterprise bean -- the interceptor method runs as a callback method for the bean's lifecycle events. In essence, interceptors give you a way to add functionality to your business methods without modifying the methods' code. For example, you can use an interceptor to validate parameters before they're passed to a business method, or perform security checks at the time the business method is called. Interceptors are also useful for actions such as logging and profiling that cut across multiple components in an application (these are sometimes called "crosscutting" operations). You also have the flexibility to chain interceptors together. Each interceptor in the chain can perform a specific operation before a business method is invoked or in response to a lifecycle event. This Tech Tip demonstrates using interceptors to gather profiling information about business methods for an enterprise bean. A sample package accompanies the tip. The code examples in the tip are taken from the source code of the sample (which is included in the package). The sample uses the Java EE 5 SDK. You can download the Java EE 5 SDK from the the Java EE 5 SDK Downloads page. An example bean
To demonstrate the interceptors, let's use a simple stateless
session bean that provides a method to reverse a
Here is what
import javax.ejb.Remote;
@Remote
public interface StringServiceRemote {
public String reverse(String str);
}
And here is the StringServiceBean:
import javax.ejb.Stateless
public class StringServiceBean
implements StringServiceRemote {
public String reverse(String str) {
//reverse the string
...
}
}
Defining an interceptor
As mentioned earlier, you can use interceptor methods to intercept either a business method or lifecycle event. An
interceptor that intercepts a business method is typically called an
You can define an Writing an AroundInvoke method
You can define an
Here is an interceptor class that prints the time it takes to run an intercepted business method:
import javax.interceptor.AroundInvoke;
public class MethodProfiler {
public MethodProfiler() {
}
@AroundInvoke
private Object profile(InvocationContext invCtx)
throws Exception {
long t1 = System.nanoTime();
Object result = invCtx.proceed();
long t2 = System.nanoTime();
System.out.println(invCtx.getMethod().getName() +
"(" + invCtx.getParameters()[0] + ") took: " +
((t2 - t1)/ 1000.0) + " nano seconds.");
return result;
}
}
Notice that the interceptor method meets the requirements previously listed.
Although the interceptor method in this example is defined in a separate class, it could have simply been added to the bean
class itself. However, because method profiling has nothing to do with the basic purpose of the Adding an interceptor to a bean
Now that the
import javax.interceptor.Interceptors;
@Stateful
@Interceptors({MethodProfiler.class})
public class StringServiceBean
implements StringServiceRemote {
...
}
Now when the Interceptor chain and InvocationContext
You can chain together multiple interceptors to intercept a bean's methods. Use the
At runtime, before a business method is invoked or a lifecycle event occurs, the container creates an instance of
The Using Interceptor chaining You learned earlier that you can chain together multiple interceptors and use them to intercept a bean's methods. Let's use that capability to perform something interesting.
The
Rather than calling Here is the
import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
public class StringServiceInterceptor {
public StringServiceInterceptor() {
}
@AroundInvoke
private Object validate(InvocationContext invCtx)
throws Exception {
Method m = invCtx.getMethod();
if (m.getName().equals("reverse")) {
String str = (String) invCtx.getParameters()[0];
if ((str == null) || (str.length() < 2)) {
return str;
}
}
return invCtx.proceed();
}
}
Adding chained interceptors to a bean
Now that the
import javax.interceptor.Interceptors;
@Stateless
@Interceptors({MethodProfiler.class,
StringServiceInterceptor.class})
public class StringServiceBean
implements StringServiceRemote {
...
}
Running the Sample Code
Summary EJB 3.0 interceptors give you an elegant way to extend the functionality of enterprise beans. They are especially useful for implementing crosscutting operations in a portable way.
The There are more advanced topics related to EJB interceptors, such as default interceptors, and class-level interceptors and method-level interceptors that allow a list of interceptors to be easily changed. These topics will be covered in a future Tech Tip. You can learn more about EJB 3.0 interceptors in the following sample applications:
About the Author Mahesh Kannan is member of the EJB container team. He has been involved with Java EE development for the last 6 years. TECH TIPS SURVEY
Over the past year we've made some changes in the Enterprise Technologies Tech Tips. We'd like to get your feedback about those changes. Your responses will help us make the Tech Tips better serve your needs. Please go to the questionnaire at and give us your feedback. INTRODUCTION TO SUN'S OPEN-SOURCE JAVA INITIATIVE
Sun Microsystems is open-sourcing its implementations of the Java platform. Find out what the buzz is, and what this means to you and to the future of Java technology. See http://java.sun.com/opensource/ for more details. EJB 3.0 TRAINING
Want to learn more about the Java EE 5 platform and EJB 3.0? Now you can get the latest information directly from experts in the web-based course "Java EE 5 Platform and Enterprise JavaBeans 3.0 - An Expert-to-Engineer Session" . DEVELOPER ASSISTANCE
Need programming advice on Java EE? Try Developer Expert Assistance GLASSFISH CODE SAMPLES
Are you aware of the open source reference implementation of Java EE 5 called GlassFish? You can download GlassFish from the GlassFish Community Downloads page . Sample GlassFish applications are available on the GlassFish Samples page. You can contribute your own GlassFish applications to the set of samples . Please read our Terms of Use and Licensing policies: | |||||||||||
|
| ||||||||||||