Red Hat

In Relation To

The Hibernate team blog on everything data.

Pagination in Hibernate and EJB3

Posted by    |       |    Tagged as

Just had an interesting discussion on ejb3-feedback@sun.com, started by David Cherryhomes, which saw me stupidly insistingthat something can't be done when in fact, now that I think about it, /I realize I've actually done it before/, and that even the Hibernate AdminApp example uses this pattern!

So, just so I don't forget this pattern again, I'm going to write it down, and also write a reuseable class implementing it.

The basic problem is pagination. I want to display next and previous buttons to the user, but disable them if there are no more, or no previous query results. But I don't want to retrieve all the query results in each request, or execute a separate query to count them. So, here's the correct approach:

public class Page {
   
   private List results;
   private int pageSize;
   private int page;
   
   public Page(Query query, int page, int pageSize) {
       
       this.page = page;
       this.pageSize = pageSize;
       results = query.setFirstResult(page * pageSize)
           .setMaxResults(pageSize+1)
           .list();
   
   }
   
   public boolean isNextPage() {
       return results.size() > pageSize;
   }
   
   public boolean isPreviousPage() {
       return page > 0;
   }
   
   public List getList() {
       return isNextPage() ?
           results.subList(0, pageSize-1) :
           results;
   }

}

You can return this object to your JSP, and use it in Struts, WebWork or JSTL tags. Getting a page in your persistence logic is as simple as:

public Page getPosts(int page) {
    return new Page( 
        session.createQuery("from Posts p order by p.date desc")
        page,
        40
    );
}

The Page class works in both Hibernate and EJB 3.0.

Hibernate3 Events

Posted by    |       |    Tagged as Hibernate ORM

Another major change in Hibernate3 is the evolution to use an event and listener paradigm as its core processing model. This allows very fine-grained hooks into Hibernate internal processing in response to external, application initiated requests. It even allows customization or complete over-riding of how Hibernate reacts to these requests. It really serves as an expansion of what Hibernate tried to acheive though the earlier Interceptor, Lifecycle, and Validatable interafaces.

Note: The Lifecycle and Validatable interfaces have been moved to the new classic package in Hibernate3. Their use is not encouraged, as it introduces dependencies on the Hibernate library into the users domain model and can be handled by a custom Interceptor or through the new event model external to the domain classes. This is nothing new, as the same recomendation was made in Hibernate2 usage.

So what types of events does the new Hibernate event model define? Essentially all of the methods of the org.hibernate.Session interface correlate to an event. So you have a LoadEvent, a FlushEvent, etc (consult the configuration DTD or the org.hibernate.event package for the full list of defined event types). When a request is made of one of these methods, the Hibernate session generates an appropriate event and passes it to the configured event listener for that type. Out-of-the-box, these listeners implement the same processing in which those methods always resulted. However, the user is free to implement a customization of one of the listener interfaces (i.e., the LoadEvent is processed by the registered implemenation of the LoadEventListener interface), in which case their implementation would be responsible for processing any load() requests made of the Session.

These listeners should be considered effectively singletons; meaning, they are shared between requests, and thus should not save any state as instance variables. The event objects themselves, however, do hold a lot of the context needed for processing as they are unique to each request. Custom event listeners may also make use of the event's context for storage of any needed processing variables. The context is a simple map, but the default listeners don't use the context map at all, so don't worry about over-writing internally required context variables.

A custom listener should implement the appropriate interface for the event it wants to process and/or extend one of the convenience base classes (or even the default event listeners used by Hibernate out-of-the-box as these are declared non-final for this purpose). Custom listeners can either be registered programatically through the Configuration object, or specified in the Hibernate configuration XML (declarative configuration through the properties file is not supported). Here's an example of a custom load event listener:

public class MyLoadListener extends DefaultLoadEventListener {
    // this is the single method defined by the LoadEventListener interface
    public Object onLoad(LoadEvent event, LoadEventListener.LoadType loadType) 
            throws HibernateException {
        if ( !MySecurity.isAuthorized( event.getEntityName(), event.getEntityId() ) ) {
            throw MySecurityException("Unauthorized access");
        }
        return super.onLoad(event, loadType);
    }
}

Then we need a configuration entry telling Hibernate to use our listener instead of the default listener:

<hibernate-configuration>
    <session-factory>
        ...
        <listener type="load" class="MyLoadListener"/>
    </session-factory>
</hibernate-configuration>

Or we could register it programatically:

Configuration cfg = new Configuration();
cfg.getSessionEventListenerConfig().setLoadEventListener( new MyLoadListener() );
....

Listeners registered declaratively cannot share instances. If the same class name is used in multiple <listener/> elements, each reference will result in a seperate instance of that class. If you need the capability to share listener instances between listener types you must use the programatic registration approach.

Why implement an interface and define the specific type during configuration? Well, a listener implementation could implement multiple event listener interfaces. Having the type additionally defined during registration makes it easier to turn custom listeners on or off during configuration.

Hibernate3 Filters

Posted by    |       |    Tagged as Hibernate ORM

Hibernate3 adds the ability to pre-define filter criteria and attach those filters at both a class and a collection level. What's a pre-defined filter criteria? Well, it's the ability to define a limit clause very similiar to the existing where attribute available on the class and various collection elements. Except these filter conditions can be parameterized! The application can then make the decision at runtime whether given filters should be enabled and what their parameter values should be.

Configuration

In order to use filters, they must first be defined and then attached to the appropriate mapping elements. To define a filter, use the new <filter-def/> element within a <hibernate-mapping/> element:

<filter-def name="myFilter">
    <filter-param name="myFilterParam" type="string"/>
</filter-def>

Then, this filter can be attched to a class:

<class name="myClass" ...>
    ...
    <filter name="myFilter" condition=":myFilterParam = my_filtered_column"/>
</class>

or, to a collection:

<set ...>
    <filter name="myFilter" condition=":myFilterParam = my_filtered_column"/>
</set>

or, even to both (or multiples of each) at the same time!

Usage

In support of this, a new interface was added to Hibernate3, org.hibernate.Filter, and some new methods added to org.hibernate.Session. The new methods on Session are: enableFilter(String filterName), getEnabledFilter(String filterName), and disableFilter(String filterName). By default, filters are not enabled for a given session; they must be explcitly enabled through use of the Session.enabledFilter() method, which returns an instance of the new Filter interface. Using the simple filter defined above, this would look something like:

session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");

Note that methods on the org.hibernate.Filter interface do allow the method-chaining common to much of Hibernate.

Big Deal

This is all functionality that was available in Hibernate before version 3, right? Of course. But before version 3, this was all manual processes by application code. To filter a collection you'd need to load the entity containing the collection and then apply the collection to the Session.filter() method. And for entity filtration you'd have to write stuff that manually modified the HQL string by hand or a custom Interceptor.

This new feature provides a clean and consistent way to apply these types of constraints. The Hibernate team envisions the usefulness of this feature in everything from internationalization to temporal data to security considerations (and even combinations of these at the same time) and much more. Of course it's hard to envision the potential power of this feature given the simple example used so far, so let's look at some slightly more in depth usages.

Temporal Data Example

Say you have an entity that follows the effective record database pattern. This entity has multiple rows each varying based on the date range during which that record was effective (possibly even maintained via a Hibernate Interceptor). An employment record might be a good example of such data, since employees might come and go and come back again. Further, say you are developing a UI which always needs to deal in current records of employment data. To use the new filter feature to acheive these goals, we would first need to define the filter and then attach it to our Employee class:

<filter-def name="effectiveDate">
    <filter-param name="asOfDate" type="date"/>
</filter-def>

<class name="Employee" ...>
    ...
    <many-to-one name="department" column="dept_id" class="Department"/>
    <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
    <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
    ...
    <!--
        Note that this assumes non-terminal records have an eff_end_dt set to a max db date
        for simplicity-sake
    -->
    <filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
</class>

<class name="Department" ...>
    ...
    <set name="employees" lazy="true">
        <key column="dept_id"/>
        <one-to-many class="Employee"/>
        <filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
    </set>
</class>

Then, in order to ensure that you always get back currently effective records, simply enable the filter on the session prior to retrieving employee data:

Session session = ...;
session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
        .setLong("targetSalary", new Long(1000000))
        .list();

In the HQL above, even though we only explicitly mentioned a salary constraint on the results, because of the enabled filter the query will return only currently active employees who have a salary greater than a million dollars (lucky stiffs).

Even further, if a given department is loaded from a session with the effectiveDate filter enabled, its employee collection will only contain active employees.

Security Example

Imagine we have an application that assigns each user an access level, and that some sensitive entities in the system are assigned access levels (way simplistic, I understand, but this is just illustration). So a user should be able to see anything where their assigned access level is greater than that assigned to the entity they are trying to see. Again, first we need to define the filter and apply it:

<filter-def name="accessLevel">
    <filter-param name="userLevel" type="int"/>
</filter-def>

<class name="Opportunity" ...>
    ...
    <many-to-one name="region" column="region_id" class="Region"/>
    <property name="amount" type="Money">
        <column name="amt"/>
        <cloumn name="currency"/>
    </property>
    <property name="accessLevel" type="int" column="access_lvl"/>
    ...
    <filter name="accessLevel"><![CDATA[:userLevel >= access_lvl]]></filter>
</class>

<class name="Region" ...>
    ...
    <set name="opportunities" lazy="true">
        <key column="region_id"/>
        <one-to-many class="Opportunity"/>
        <filter name="accessLevel"><![CDATA[:userLevel >= access_lvl]]></filter>
    </set>
    ...
</class>

Next, our application code would need to enable the filter:

User user = ...;
Session session = ...;
session.enableFilter("accessLevel").setParameter("userLevel", user.getAccessLevel());

At this point, loading a Region would filter its opportunities collection based on the current user's access level:

Region region = (Region) session.get(Region.class, "EMEA");
region.getOpportunities().size(); // <- limited to those accessible by the user's level

Conclusion

These were some pretty simple examples. But hopefully, they'll give you a glimpse of how powerful these filters can be and maybe sparked some thoughts as to where you might be able to apply such constraints within your own application. This can become even more powerful in combination with various interception methods, like web filters, etc. Also a note: if you plan on using filters with outer joining (either through HQL or load fetching) be careful of the direction of the condition expression. Its safest to set this up for left outer joining; in general, place the parameter first followed by the column name(s) after the operator.

Oracle evolution observed

Posted by    |       |    Tagged as

I just cleaned up some of my files and found this snapshot in one of my folders. I made it two weeks ago, as I finally had time to install Oracle 10g. I remember how I was shaking my head in desperation as I realized what they had done. Let me explain.

Back in the days of Oracle8, they decided to write their system installer tools in Java. They apparently had no idea what Java was about, so what we got was the most hated and horrible application installer you can imagine. It required a patched/hacked JDK, which was en vogue at this time, especially in big corporations with mediocre programmers. Usually, some poor guys were forced to use Java, and their CTO/VPs made them suffer. So, naturually, they passed that on to their users. But at least it worked, if you knew the workarounds. At some point, you had a working Oracle installation (the first Linux versions were also quite interesting...).

But this wasn't good enough for Oracle. They had a hacked JRE, their own window and widget toolkit, their own application framework, just for the installer. Hey, why not use this for /all/ Oracle applications? Adminstration tools, wizards, SQL console, all of them! Great idea! I first came in contact with the new Oracle Enterprise Manager in Oracle 8.1.x (I don't even want to know when it first reared it's ugly head in public). It was horrible. Well, actually you could do some useful things on Linux and Solaris which you only could do with 3rd party tools on Windows before, like browsing your database catalog graphically. But it wasn't that useful in practice. Want to have a quick look at a table's content? Sure, fire up the SQL console, there is no Quick select. You need more power in the SQL console than a trivial history of your queries? Autocompletion? PL/SQL editors? Use one of our full blown IDE's or buy a third party tool. But it was OK, in the end. Together with PL/SQL developer, I coded away on a stored procedure app for more than a year. Painful, but interesting.

It even got better with Oracle 9; finally the Oracle Enterprise Manager was a nice (albeit still a hacked JRE and proprietary toolkit) application that you could actually use in your daily work. At this point I had given up on stored procedure business logic and moved to ORM. Long story short, Oracle finally had good GUI management tools. Not perfect, but quite OK. Even the SQL consoles were sometimes usable: they had three different options, each one had different features, and each one had other features missing. Laughable, compared to other vendors, but in the world of Oracle, acceptable.

Fast forward: Oracle 10g. Installed it two weeks ago on a Linux box. It was pain (and I really know how to install Oracle...) and suffering. I didn't realize that they dropped the classic Oracle Enterprise Manager until I had to debug the startup code for the replacement: A web-based database control, that runs in a bastardized Apache/OAS/BC4J environment. Yes, you need a full application server now, just to have some basic management tools for your database (that is, if you don't have the old OEM 9.x around somewhere). Hundreds of megabytes of memory on the server are needed. You might also ask if this new web-based interface is better than the old desktop (client/server concept though) enterprise management tools. A web-based interface for daily work better than a GUI frontend? Surely not.

But wait, it gets worse. Remember that screenshot I have found? It shows isqlplus, the newest incarnation of the never-dying SQLplus console. Yes, it's primary use is to execute SQL. The old CLI-based sqlplus tool had some real good value in the early days, like flexible formatting control of the result printout for reporting, etc. The two graphical tools we got with Oracle 8 and 9 have been really bad, but at least they are quick to start and use. Now look at this new isqlplus. A textarea, a submit button, some primitive history functionality. This is a standalone product now with all the bells and whistles. It looks like it even has its own instance of the application server (at least it has its own TCP port). It probably even has it's own development group and VPs.

This is called progress. Thanks Oracle.

(I didn't have time to check if the Oracle 10g Grid Manager Foo is actually the rebranded old Enterprise Manager. There is still hope...)

The Lie Of Simplicity

Posted by    |       |    Tagged as

Simple is a seductive notion. We all want to make things simple. But when we talk about software, simple could mean at least two different things.

There are always two ways of looking at nontrivial software: the implementation view, and the user view. I have always gotten the impression (I may be wrong) that many people who say that J2EE is too complex confuse the second view for the first. So, just in case I'm right about this, I think we should rephrase. Perhaps we should say J2EE is too /inconvenient/.

A simple framework is very often /not/ the best solution to a difficult problem. Making life easy for developers does not mean giving us simple tools. The problem with J2EE development is not that the J2EE stack provides too much complex functionality; it is that the functionality is not exposed to the user in a convenient way.

For example, Hibernate is /much/ more complex (implementation-wise) than a CMP 2.1 entity bean container. Arguably, some of Hibernate's user-visible functionality is also more complex. For example, HQL has many more features than EJBQL and could therefore be said to be more complex. Likewise, Hibernate's support for multiple inheritance mapping strategies is a complex feature, not visible in CMP 2.1.

But it is that very complexity that makes Hibernate powerful, and, perhaps paradoxically, simplifies life for people using Hibernate to write applications. By contrast, CMP 2.1 is simultaneously too simple (featurewise) and too complex (from the point of view of the user).

The best frameworks are /powerful/, not simple. But they do try to get their internal complexity out of the face of the user, as far as possible. Sometimes it is possible, other times not. If you try to oversimplify a difficult problem, you end up making life more difficult for your users, who are then forced to work around your framework's limitations, instead of working with it.

There are very, very few simple solutions to difficult problems. Be very sceptical when someone claims to have found one.

My 2c on annotation overriding.

Posted by    |       |    Tagged as

Cedric and Bill have proposed solutions. My preference is basically similar to Bill's, but here's how I would write it:

<class name="org.hibernate.Item">
    @Entity
    @Table(name="AUCTION_ITEM")
    <method sig="getBar()">@Transient</method>
    <method sig="doSomething(int, String)">
        @Tx(REQUIRES_NEW)
    </method>
</class>

I like this, because the same approach can be used outside of the context of J2EE. I /really/ wish something like this would have been included in JSR-175.

EJB3, the new JavaBeans?

Posted by    |       |    Tagged as

This item is a prediction about the future. Predicting the future is a dangerous business, and exposes the author to ridicule in both the future and present. Nevertheless, articulating a /nice/ vision of the future can help bring about that future.

My prediction is that the EJB3 programming model will eventually be to Java development what JavaBeans is now.

That's a big call, and somewhat hubristic. JavaBeans is such a wildly successful component model that we now barely think about using it. We don't say I'm going to write a JavaBean to do blah; we usually just say I'm going to write a class to do blah, and then unconsciously follow the JavaBeans conventions. We long ago forgot the original definition of a JavaBeans container (BeanBox, anyone?), and use JavaBeans just about everywhere. The JavaBeans definition is part of Java culture more than it is part of any JCP specification.

I'm really interested in what makes a programming model successful. So I've tried to put together a list of reasons why I think JavaBeans was so successful.

JavaBeans components are:

  • easy to write and easy to change
  • object oriented
  • somewhat self-documenting
  • sufficiently general - the component model does not really assume much about the nature of the bean container, nor about the purpose of the component
  • fine grained
  • executable completely outside /any/ container

These attributes make it easy to use the JavaBeans model for things that were /unanticipated by the designers/. JavaBean containers now have a much different shape to what was expected by the creators of the programming model. Meanwhile, we use the JavaBeans themselves to build all kinds of things, not just GUI components!

EJB before JSR-220 failed on most of the above points. I'm not going to rehash the problems with the current EJB model, for this is by now an incredibly boring topic. I'll focus on one particular part of the model, which I think is key: the deployment descriptor.

An EJB 2.x deployment descriptor is neither useful for documentation purposes nor sufficiently general. It's too noisy to help document the component and too specific to the EJB container environment - as understood by the EJB spec designers - to be reusable by other containers.

Interestingly, the annotation-based metadata defined by JSR-220 does /not/ seem to suffer from these problems. Annotations make excellent self-documentation, and the nature of the annotations is somewhat general. Annotations like @Stateful, @Stateless, @Entity, @Table, @Remote, @ManyToOne, etc, say much more about the semantics of the component itself than they say about the container! This is a huge break from the deployment descriptor approach, which I think implicitly assumes that the behavior defined in metadata is /independant/ of - and external to - the semantics of the component.

The generality of these new EJB3-style annotations means that when I write my EJB, I am always expressing my solution to the business problem, not the requirements of the container. And, critically, it means that a container that is not a JSR-220 complaint EJB3 container will be able to consume these annotations, and do useful things with them.

Sure, there are certain annotations and annotation attributes which are pretty specific to the wording of the specification, but I think they are the exception rather than the rule.

I think the other provisions of the EJB3 component model are equally general. Actually, they don't go far beyond the JavaBeans conventions. And so, like JavaBeans, the EJB3 model satisfies each point item of the list above. So I'm inclined to interpret the EJB3 component model as an enhancement to JavaBeans: JavaBeans with extra semantics, defined by these general-purpose annotations.

Hopefully, people who are not building EJB containers will be able to re-use the EJB3 annotations and component programming model.

Here's a concrete example of the kind of thing I expect to see happen. I think session beans make perfect web framework actions! Currently, if we want to call into the EJB container from Struts, we have to write an Action and explicitly look up and invoke the session bean. But imagine if the action were /itself/ a local, stateless session bean: we'd get all the services of the EJB container, right there in the web tier. It gets better. If our actions are session beans, then instead of keeping state associated with the user in that demon-spawned-son-of-HashMap, the HttpSession (I usually need a shower after touching that thing), we could keep the session state in stateful beans (one per application transaction, of course). I know you're thinking oh but I don't want to have to write a whole EJB just to get a web action. Back up: it's not a whole EJB; it's just an EJB. Remember, in EJB3, a session bean is just a JavaBean with maybe two or three annotations. In fact, you won't even be thinking about writing an EJB; you'll just be writing a @Stateless class.

What You Can Do With EJB3 (part one)

Posted by    |       |    Tagged as

Now that the EJB 3.0 early draft is out there, it's definitely time to move on from all the recent politics, and start thinking about what we can actually /do/ with this stuff. EJB is the only Java standard which addresses server-side /business logic/, and is thus central to J2EE. The EJB spec committee recognizes that EJB has fallen short of achieving some of its ambitious goals, and is in need of an overhaul. This overhaul has focused very much upon ease of use, primarily via simplification of the requirements upon bean implementors. However, the spec committe also identified a number of critical functional enhancements that facilitate ease of use and the elimination of certain J2EE anti-patterns.

Fortunately, the Java community now knows much more about the problems involved in building web and enterprise applications than it did five years ago. We have been learning by doing. A powerful, easy to use, standard approach to building server-side business objects is now well within our grasp!

The spec committee thought very hard about how to simplify certain extremely common use cases, expecially two cases that I'll canonicalize as follows:

/Updating data/

1. retrieve an item of data

2. display on screen

3. accept user input

4. update the data

5. report success to the user

/Entering new data/

1. retrieve an item of data

2. display on screen

3. accept user input

4. create a new item of data, with an association to the first item

5. report success to the user

Each of these cases involves two full application request/response cycles. Both demonstrate that optimistic locking is essential in an application that requires high concurrency (both cases would need to be implemented as a single conversation spanning two distinct ACID database/JTA transactions).

A further common use case, that is especially difficult to do in EJB 2.1, given the limitations of the query language is the following:

/Listing and reporting data/

1. retrieve an aggregated or summarized list of data

2. display it to the user

Finally, we considered two canonical physical architectures. The /colocated/ case - which we considered most important, at least for typical web apps - has a presentation layer acting as a local client of the business layer. The /remote case/ has a remote client (for example, a servlet engine or swing client running in a different physical tier) accessing the business layer.

First we need data. Interaction with relational data is central to almost every web or enterprise application. Applications that implement nontrivial business logic benefit from an object-oriented representation of the data (a /domain model/) that takes full advantage of object oriented techniques like inheritance and polymorphism. For various reasons (I won't repeat the arguments we made at length in Hibernate in Action), applications which use fully object oriented domain models need an automated solution to the OR mismatch problem. EJB3 incorporates a very sophisticated ORM specification that draws heavily upon the experience of CMP 2.1, Hibernate and Oracle's TopLink.

Our auction application has Users, Items and Bids. Let's implement these as 3.0-style entity beans. We'll start with Item:

@Entity 
public class Item {
    private Long id;
    private User seller;
    private Collection<Bid> bids = new ArrayList<Bid>();
    private String description;
    private String shortDescription;
    private Date auctionEnd;
    private int version;
    
    public Item(User seller, String desc, String shortDesc, Date end) {
        this.seller = seller;
        this.description = desc;
        this.shortDescription = shortDesc;
        this.auctionEnd = end;
    }
    
    protected Item() {}
    
    @Id(generate=AUTO)
    public Long getId() {
        return id;
    }
    protected void setId(Long id) {
        this.id = id;
    }
    
    @Column(length=500)
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    
    public Date getAuctionEnd() {
        return auctionEnd;
    }
    protected void setAuctionEnd(Date end) {
        this.auctionEnd = end;
    }
    
    @Column(length=100)
    public String getShortDescription() {
        return shortDescription;
    }
    public void setShortDescription(String shortDescription) {
        this.shortDescription = shortDescription;
    }
    
    @JoinColumn(nullable=false, updatable=false)
    public User getSeller() {
        return seller;
    }
    protected void setSeller(User seller) {
        this.seller = seller;
    }
    
    @OneToMany(cascade=ALL)
    protected Collection<Bid> getBids() {
        return bids;
    }
    protected void setBids(Collection<Bid> bids) {
        this.bids = bids;
    }
    
    @Version
    public int getVersion() {
        return version;
    }
    protected void setVersion(int version) {
        this.version = version;
    }
    
    public Bid bid(BigDecimal amount, User bidder) {
        Bid newBid = new Bid(this, amount, bidder);
        bids.add(newBid);
        return bid;
    }
    
}

The most striking thing, initially, is the annotations. No deployment descriptor is required! EJB 3.0 will let you choose between the use of annotations and XML deployment descriptors, but we expect that annotations will be the most common case.

The @Entity annotation tells the container that this class is a CMP entity bean. The optional @Column annotations define the column mappings for persistent properties (if we were mapping legacy data, we would define column names in these annotations). The @Id annotations selects the primary key property of the entity bean. In this case, the entity bean has a generated primary key. The optional @OneToMany annotations defines a one to many association, and specifies a /cascade style/ of ALL. The optional @JoinColumn annotation defines a column mapping for an association. In this case, it constrains the association to be required and immutable. The @Version annotation defines the property used by the container for optimistic locking.

Perhaps the most important thing to notice here is that almost all of the annotations are optional. EJB3 uses /configuration by exception/, meaning that the specification defines natural, useful defaults so that you do /not/ need to specify an annotation in the common case. For example, we have not included any annotation at all on one of the persistent properties.

Also striking is that, apart from the annotations, Item has no dependency to classes or interfaces in javax.ejb. This was a major goal of EJB3, and helps to significantly reduce noise.

Entity beans do not require a local or remote interface, which also reduces noise.

It's time to implement Bid:

@Entity
public class Bid {
    private Long id;
    private Item item;
    private BigDecimal amount;
    private Date datetime;
    private User bidder;
    private boolean approved;
    
    protected Bid() {}
    
    public Bid(Item item, BigDecimal amount, User bidder) {
        this.item = item;
        this.amount = amount;
        this.bidder = bidder;
        this.datetime = new Date();
    }
    
    @Id(generate=AUTO)
    public Long getId() {
        return id;
    }
    protected void setId(Long id) {
        this.id = id;
    }
    
    @Column(nullable=false) 
    public BigDecimal getAmount() {
        return amount;
    }
    protected void setAmount(BigDecimal amount) {
        this.amount = amount;
    }
    
    @Column(nullable=false) 
    public Date getDatetime() {
        return datetime;
    }
    protected void setAmount(Date datetime) {
        this.datetime = datetime;
    }
    
    @JoinColumn(nullable=false)
    public User getBidder() {
        return bidder;
    }
    protected void setBidder(User bidder) {
        this.bidder = bidder;
    }
    
    @JoinColumn(nullable=false)
    public Item getItem() {
        return item;
    }
    protected void setItem(Item item) {
        this.item = item;
    }
    
    public boolean isApproved() {
        return approved;
    }
    public void setApproved(boolean approved) {
        this.approved = approved;
    }
    
    
}

I'll leave it to you to write the User entity bean!

Notice that our domain model classes are now simple JavaBeans. This means that they are testable outside the EJB container.

What about the home interfaces? Well, the requirement for home interfaces has been eliminated by EJB3, so we won't be needing them.

Now, let's look at our first use case, updating an Item. We'll assume a colocated architecture, and implement our business logic in a stateless session bean with a local business interface. A business interface defines operations visible to the client (your session beans may have as many business interfaces as you like). We'll define the Auction local interface as follows:

public interface Auction {
    public Item getItemById(Long itemId);
    public void updateItem(Item item);
}

Business interfaces are local by default, so no @Local annotation is required.

Since our Item entity bean is also a JavaBean, we can pass it directly to a JSP (for example). We do not need any DTOs, or complex method signatures.

The AuctionImpl bean class implements this interface:

@Stateless
public class AuctionImpl implements Auction {
    @Inject public EntityManager em;
    
    public Item getItemById(Long itemId) {
        return em.find(Item.class, itemId);
    }
    
    public void updateItem(Item item) {
        em.merge(item);
    }
}

Wow. That was easy!

The @Inject annotation is used to indicate that a field of a session bean is set by the container. In EJB 3.0, session beans do not need to use JNDI to obtain references to resources or other EJBs. In this case, the container /injects/ a reference to the EntityManager, the interface for persistence-related operations on entity beans.

Notice that the container handles optimistic locking transparently.

Suppose our client was a servlet. The code to display an Item might look something like this:

Long itemId = new Long( request.getParameter("itemId") );

Auction auction = (Auction) new InitialContext().lookup("Auction");

Item item = auction.getItemById(itemId);

session.setAttribute("item", item);

Since the Item entity bean is also just a simple JavaBean, the JSP can use it directly. The second request, which updates the Item, might look like this:

Item item = (Item) session.getAttribute("item");

item.setDescription( request.getParameter("description") );
item.setShortDescription( request.getParameter("shortDescription") );

Auction auction = (Auction) new InitialContext().lookup("Auction");
    
auction.updateItem(item);

Note that other expert groups are exploring ways to eliminate JNDI lookups, such as these lookups for the session bean.

Now let's turn to the second use case, creating a new Bid. We'll add a new method to Auction:

public interface Auction {
    public Item getItemById(Long itemId);
    public void updateItem(Item item);
    public Bid bidForItem(Item item, BigDecimal amount, User bidder)
        throws InvalidBidException;
    public void approveBid(Long bidId);
}

We must implement these new methods in AuctionImpl, of course:

@Stateless
public class AuctionImpl implements Auction {
    @Inject public EntityManager em;
    @Inject QueueConnectionFactory bidQueue;
    
    ...
    
    public void approveBid(Long bidId) {
        Bid bid = em.find(Bid.class, bidId);
        bid.setApproved(approved);
    }
    
    public Bid bidForItem(Item item, BigDecimal amount, User bidder)
        throws InvalidBidException {
        
        String query = "select max(bid.amount) from Bid bid where "
            + "bid.item.id = :itemId and bid.approved = true";
        
        BigDecimal maxApprovedBid = 
            (BigDecimal) em.createNamedQuery(query)
                .setParameter( "itemId", item.getId() )
                .getUniqueResult();
        
        if ( amount.lessThan(maxApprovedBid) ) {
            throw new InvalidBidException();
        }
        
        Bid bid = item.createBid(amount, bidder);
        
        em.create(bid);
        
        requestApproval(bid, bidQueue);
        
        return bid;            
        
    }
    
    
    private static void requestApproval(Bid bid, Queue queue) {
        ...
    }
}

The bidForItem() method executes an EJB QL query that determines the current maximum approved Bid. If the amount of the new bid is larger, we instantiate a new Bid and make it persistent by calling EntityManager.create().

The requestApproval() method sends a message to the queue, asking a backend system to verify the bidder's ability to pay. The session bean gets a reference to a JMS QueueConnectionFactory by dependency injection.

We need a message driven bean, BidApprovalListener, to receive the reply from the backend system. When the reply is received, we'll send an email to the bidder, and mark the Bid approved.

@MessageDriven 
public class BidApprovalListener implements MessageListener {
    @Inject javax.mail.Session session;
    @Inject Auction auction;
    
    public void onMessage(Message msg) {
    
        MapMessage mapMessage = (MapMessage) msg;
        boolean approved = mapMessage.getBoolean("approved");
        long bidId = mapMessage.getLong("bidId");
        
        auction.approveBid(bidId);
                    
        notifyApproval(bid, session);
        
    }
    
    private static void notifyApproval(Bid bid, Session session) {
        ...
    }
}

Notice that the message driven bean gets its JavaMail Session and a reference to the Auction session bean by dependency injection.

Our final use case is easy. We add one more method to Auction:

public interface Auction {
    public Item getItemById(Long itemId);
    public void updateItem(Item item);
    public Bid bidForItem(Item item, BigDecimal amount, User bidder)
        throws InvalidBidException;
    public void approveBid(Long bidId);
    public List<ItemSummary> getItemSummaries();
}

And implement it in AuctionImpl:

@Stateless
public class AuctionImpl implements Auction {
    ...
    
    public List<ItemSummary> getItemSummaries() {
        String query = "select new "
        + "ItemSummary(item.shortDescription, item.id, max(bid.amount)) "
        + "from Item item left outer join item.bids bid";
        
        return (List<ItemSummary>) em.createQuery(query)
            .listResults();
    }
}

ItemSummary is just a simple JavaBean, with an appropriate constructor, so we don't need to show it here.

The EJB QL query demonstrates how easy it is to do outer joins, projection and aggregation in EJB3. These (and other) new features make the Fast Lane Reader antipattern pretty much obsolete.

Well, that's the end of part one. We've seen the following simplifications:

  • Annotations replace complex XML deployment descriptors
  • Elimination of home interfaces
  • Elimination of dependencies to classes and interfaces in javax.ejb
  • Entity beans are simple JavaBeans, with no local or remote interfaces
  • Dependency injection replaces JNDI lookups
  • Elimination of DTOs
  • Elimination of Fast Lane Reader antipattern

In the next installment, we'll consider remote clients...

The Importance of Being P-less

Posted by    |       |    Tagged as

Another blogger, who will remain unmentionable, is upset that some of the guys at JBoss are beginning to throw the term AO around. According to him, the AOP community is just terribly attached to their P, and quite concerned that JBoss might be about to dominate the world with their P-less aspects.

Strangely, this blogger, along with every Java developer I know, is quite comfortable with the term OO. So, here's how we see it: Object Orientation (OO) is an approach to understanding and modelling a certain class of problems; Object Oriented Programming (OOP) is the act of writing code in an object oriented language like Java. Likewise, AO is a way of thinking about a (different) class of problems, while AOP is the mechanical act of actually implementing aspects in an aspect oriented language like AspectJ.

I fully expect that at some stage someone will want to start talking about AOD (Aspect Oriented Design) and AOA (Aspect Oriented Analysis), just as some people talk about OOD and OOA today. But I don't want JBoss to be held responsible when that happens!

It seems quite undeniable that aspect orientation is a useful way for middleware and framework developers to think about the cross-cutting problems we often meet. Whether /application developers/ will ever need to switch from Java to an aspect oriented language, in order to implement their own aspects, is unclear. (Only time will tell.) I guess we are trying to say that /aspect orientation/ is useful, even if application developers never end up using AOP day-to-day.

Finally final review

Posted by    |       |    Tagged as

I finally got the comments from our Hibernate in Action reviewers back, so it's time to give everyone an update on the current state. First, thanks to all of you guys for your feedback. We really appreciate the many hours you spent reading and commenting on the book. As one of you said: A good book is only possible with excellent reviewers.

Your feedback (and the overall response so far) was very positive, so we soon have a great Hibernate manual for everyone. Some of the minor things you found will be fixed immediately, as we go now in copyedit and typesetting (and then, finally to press).

The current schedule is to have Chapter 1 on the Manning Early Access Program next week. For all of you that don't know the process: With MEAP, you can get the chapters of a Manning book while it's finalized. This means you get PDFs just after typesetting and after some weeks, when all chapters are ready to print (remember that at the same time the copyeditor has to proofread everything), you will get a hardcopy of the finished book too. I'll give you an update as soon as we have something to show.

I'm still busy fixing code bugs in our examples and most importantly, finishing the example application. We also use this example app in our Hibernate public training , so expect some very interesting mapping techniques and Hibernate tricks. I'll have to add some kind of presentation layer on top, but I wasn't really happy with the WebWork2/Hibernate demo app we built earlier this year (WW2 needs documentation). I have to get back into web frameworks now (poor me), an area I successfully avoided for more than a year. I think I should give Tapestry a look, as it is at least properly documented. Any recommendations? No, not Struts!

back to top