Declaring the Component Interface

   

As you saw earlier in Chapter 3, the client's view of an entity or session bean is defined by the bean's component interface, which consists of a local interface, a remote interface, or both. Clients don't access your EJB classes directly, so any functionality you want to make available has to be exposed through the component interface. The methods you declare in a local or remote interface are commonly referred to as a bean's business methods .

When you declare a remote interface, you must declare it to extend javax.ejb.EJBObject . Similarly, a local interface must extend javax.ejb.EJBLocalObject . As a bean provider, this requirement doesn't affect you that much (unless you forget to do it) because you don't have to provide a direct implementation of the component interface yourself. Although your bean class must implement the business methods that you declare in its component interface, the class doesn't have to implement the entire interface. It's up to the container to implement the component interface and delegate calls to the business methods to an instance of your bean class. This means that you don't have to worry about coding EJBObject and EJBLocalObject methods, such as getPrimaryKey or remove , when you implement an entity bean. Be sure you understand this point because it might seem strange at first. An enterprise bean supports its component interface, but it doesn't literally implement it in the way you're accustomed to seeing interfaces used in Java.

You can declare an entity bean class to implement its local or remote interface by including the interface in the bean declaration's implements clause. If so, you should provide empty implementations of the EJBObject or EJBLocalObject methods because the container will never invoke them on your bean (it uses its own implementations). However, declaring a bean to implement its component interface isn't an accepted approach among EJB developers. Chapter 16, "Patterns and Strategies in EJB Design," covers the reasons why in more detail.

For cautions against directly implementing the component interface, see "Using a Business Method Interface," p. 448 .

The Client View of an Entity Bean

Entity beans support a variety of clients. Most often an entity's clients are session beans but they can also be message-driven beans or other entity beans. If an entity bean is remotely accessible, a Java application, applet, JSP, or servlet could also be a client. If you need to access an entity bean from a non-Java client, CORBA offers that possibility for remote clients as well.

A remote client's view of an entity bean is the same regardless of the client type or location. The client view is always defined by the bean's remote interface, and this view is location independent. A JSP running in the Web tier accesses an entity bean using the same API as a remote client session bean running in the same container as the entity. This characteristic is key to a distributed architecture.

Unlike a remote client, a local client must be an enterprise bean located in the same JVM as the entity bean it's accessing. This type of client accesses the bean through the local interface, but its view of the entity isn't location independent. The biggest difference compared to a remote interface is that method arguments passed through the local interface are passed by reference instead of by value. For example, suppose a Customer entity bean provided both a local and a remote interface that each included a getAddress method that returned an Address object comprised of several strings. If a remote client called this method and modified the values held in the returned Address , the Customer entity would be unaffected. The only way to update the Address would be for the entity to provide another method for that purpose. However, any changes made to the Address by a local client would be seen by the Customer entity because they would both be referencing the same local object. This might sound like a pure advantage, but it can be a little dangerous. When an entity exposes an object is this manner, it's potentially giving up control of how that object is modified.

Although an entity bean is allowed to support both local and remote clients, this isn't typical. As a bean provider, you'll more often select a single type of access to support (usually local in the case of an entity bean). Because of the differences in pass- by-value and pass-by-reference behavior, the choice of client type affects the bean implementation and the granularity of methods exposed through the component interface. The choice of client type should be made early in the design because simply converting a local interface to a remote or vice versa would be an oversimplification of an entity's behavior. For example, more would have to be done to make an entity that exposed fine-grained method access to local clients suitable for remote access. Changing the interface type would make the entity remotely accessible, but the overhead associated with many fine-grained remote calls would likely make it a performance nightmare.

Whether you choose to support local or remote clients, the component interface provides the methods they need to work with an entity bean. After a client obtains a reference to an entity's local or remote interface, it can manipulate the entity object in several ways. In particular, a client can

  • Call the entity object's business methods, which is normally what you're most interested in doing

  • Call remove to remove the instance from the container and delete the entity from the database

  • Obtain the entity object's primary key (using getPrimaryKey )

  • Obtain the entity object's handle (only done by remote clients using getHandle )

  • Obtain a reference to the entity's home interface (using getEJBLocalHome or getEJBHome )

  • Pass the reference as a parameter or return value of a method call (limited to local methods when using the local interface)

Exposing Business Methods

You don't have to expose every method you plan to implement within your entity bean through its component interface, but you do have to include any methods you want to be accessible from outside the class. At a minimum, you should include get and set methods for the entity's fields that you want clients to be able to access. This is especially true for local interfaces. Remote interfaces work best using methods that group multiple fields into simple data structures. This is a straightforward way to reduce the number of remote calls needed to obtain or set an entity's state. If clients aren't allowed to modify an entity's fields, you can limit the methods in the component interface to get methods. You should also include the business methods that the bean exposes to perform its work in the component interface. Simply put, you should include declarations in the component interface for the methods that make up the public interface you want to expose for your bean.

Because of how a component interface is used, some restrictions are placed on how you declare your methods within it. You can include any type of method that you want ”you just have to live with a few rules. In particular, you must declare your methods such that

  • No method name starts with ejb (as you'll see later, the container uses methods that have names starting with ejb for special purposes).

  • All methods are declared as public (remember that you're in effect declaring the public interface for your bean implementation).

  • No method can be declared as static or final (this is true for any Java interface).

  • All method arguments and return types for methods in a remote interface must be legal RMI-IIOP types.

  • All methods in a remote interface include java.rmi.RemoteException in their throws clauses (these are remote calls that could fail because of an underlying system or communications problem). Local interface methods use javax.ejb.EJBException to report system-level problems instead of RemoteException . This unchecked exception doesn't have to be included in the declarations.

Note

The requirements for legal RMI-IIOP types span five pages in OMG's Java Language to IDL Mapping document. However, in general, the legal RMI-IIOP types include the Java primitives, remote interfaces, Serializable classes, arrays that hold objects of a legal type, and checked exceptions. You can download this document from OMG at http://www.omg.org/cgi-bin/doc?ptc/00-01-06 if you want a more precise description.


Naming Conventions

Because the capability to expose local interfaces is so new to EJB, accepted practices related to them are still in their infancy. One area that comes to the forefront immediately is that of naming conventions. Prior to EJB 2.0, every enterprise bean you created had to have a remote interface, a home interface, and an implementation class. Based on Sun's guidelines in the early EJB specifications, developers quickly standardized how to assign names to each of these elements. To start with, EnglishAuction would be a suitable remote interface name for the central entity bean in the auction example. Because clients use the remote interface to interact with a bean, it's always been given the logical name that represents the bean. Based on this name choice, EnglishAuctionHome would be the name of the corresponding home interface. The implementation class typically would be named EnglishAuctionBean , although some developers prefer a form such as EnglishAuctionEJB instead. Situations in which you need more than one implementation of a particular bean are application-specific, so no standard convention exists for that case.

The fact that a bean can expose both local and remote interfaces complicates your use of the naming convention adopted before EJB 2.0. If you still wanted to name a bean's remote interface EnglishAuction , what would you name the local interface if it needed one? Solutions such as the following are possible:

  • Name the remote interface EnglishAuction (because that's what's always been done) and name the local interface EnglishAuctionLocal to distinguish the two.

  • Name the remote interface EnglishAuctionRemote and the local interface EnglishAuctionLocal to be consistent.

  • Name the local interface EnglishAuction (because that's typically the only interface exposed by an entity bean) and use EnglishAuctionRemote for the less common remote interface. For a session bean, remote interfaces are more common, so reverse the rule and use AuctionHouse and AuctionHouseLocal for examples of remote and local interface names.

You could come up with arguments both for and against each of these proposals, so it will likely take some time before a clear winner emerges. For the examples presented throughout the remainder of the book, the last option in the list was selected. Applying this same convention to the home interface, the auction entity bean will expose its local home as EnglishAuctionHome . Similarly, session beans will use remote home interfaces with names such as AuctionHouseHome .

The Auction Component Interfaces

You saw a simple example of component interfaces back in Chapter 3 when the topic was first introduced. This section goes beyond that to present a set of interfaces applicable to the auction example. To start with, Listing 5.1 declares a local interface for the auction entity bean.

Listing 5.1 EnglishAuction.java “A Local Interface for an Auction Entity Bean
 package com.que.ejb20.auction.model;  /**   * Title:        EnglishAuction<p>   * Description:  Local interface for the EnglishAuction entity bean<p>   */  import java.sql.Timestamp;  import javax.ejb.EJBLocalObject;  import com.que.ejb20.auction.exceptions.InvalidAuctionStatusException;  import com.que.ejb20.auction.exceptions.InvalidBidException;  import com.que.ejb20.auction.view.AuctionDetailView;  import com.que.ejb20.auction.view.BidView;  import com.que.ejb20.item.model.Item;  public interface EnglishAuction extends EJBLocalObject {   public Integer getId();    public void setName(String newName);    public String getName();    public void setDescription(String newDescription);    public String getDescription();    public void setStatus(String newStatus) throws InvalidAuctionStatusException;    public String getStatus();    public void setStartingBid(Double newStartingBid)      throws InvalidAuctionStatusException;    public Double getStartingBid();    public void setMinBidIncrement(Double newMinBidIncrement)      throws InvalidAuctionStatusException;    public Double getMinBidIncrement();    public void setReserveAmount(Double newReserveAmount)      throws InvalidAuctionStatusException;    public Double getReserveAmount();    public void setStartDateTime(Timestamp newStartDateTime)      throws InvalidAuctionStatusException;    public Timestamp getStartDateTime();    public void setScheduledEndDateTime(Timestamp newScheduledEndDateTime)      throws InvalidAuctionStatusException;    public Timestamp getScheduledEndDateTime();    public void setActualEndDateTime(Timestamp newActualEndDateTime);    public Timestamp getActualEndDateTime();    public void assignItem(Item newItem, int newQuantity)      throws InvalidAuctionStatusException;    public Item getItem();    public Integer getQuantity();    public void removeItem() throws InvalidAuctionStatusException;    /**     * Submit a bid to an open auction     *     * @param bidAmount the amount of the bid     * @param bidder the participant submitting the bid     * @return the automatically assigned bid transaction ID     * @throws InvalidBidException if the bid does not meet the criteria for     *   the next acceptable bid     * @throws InvalidAuctionStatusException if the auction is not open     */    public String submitBid(double bidAmount, Bidder bidder)      throws InvalidBidException, InvalidAuctionStatusException;    /**     * Determine the next required bid for an auction     *     * @return the next acceptable bid amount     */    public double computeNextBidAmount()      throws InvalidAuctionStatusException;    public BidView getLeadingBidView();    public BidView getWinningBidView();    public AuctionDetailView getAuctionDetail();    /**     * Get the time remaining before the auction closes     *     * @return the time remaining in msec     */    public long getTimeLeft();    /**     * Report whether or not the current leading bid satisfies the reserve     *     * @return true if the reserve has been met or there is no reserve and     *   at least one bid has been submitted     */    public boolean reserveMet();    /**     * Assign the current leading bid as the auction winner     *     * @throws InvalidAuctionStatusException if the auction is not Open     */    public void assignWinner() throws InvalidAuctionStatusException;  } 

Listing 5.1 shows that EnglishAuction exposes a number of get and set methods and an equal number of business methods related to auction management and bid submission. The declared methods are a subset of what we would be needed in a fully functioning system, but they're adequate for the purposes here. One of the first things to notice about this interface is that it hides the implementation details of the Bid and AuctionOffering dependent objects that were specified as part of the design. Because AuctionOffering contains only a quantity value, it can be managed using business methods that work with an Item reference and an integer value. Bid is slightly more complex and is handled using a different approach. The Bid dependent object isn't exposed by EnglishAuction , but a BidView class is used to report information about leading and winning bids to clients. This allows an auction to report information about its bids without giving up any control of the persistent objects that represent them.

EnglishAuction makes several references to Item , which is the local interface for the entity bean that will be used to represent the items up for auction. The Item local interface appears in Listing 5.2. It consists solely of get methods for the item properties needed by an auction. The simplifying assumption made for the example is that the items available for auction already exist in the system and don't need to be created or modified.

Listing 5.2 Item.java “A Local Interface for an Item Entity Bean
 package com.que.ejb20.item.model;  /**   * Title:        Item<p>   * Description:  Local interface for the Item entity bean<p>   */  import javax.ejb.EJBLocalObject;  public interface Item extends EJBLocalObject {   public Integer getId();    public String getName();    public String getDescription();    public String getImageURL();  } 

Note

Ignoring the appropriateness of the method granularity found in EnglishAuction and Item , you could convert these two interfaces to remote interfaces simply by changing their extends clauses to reference EJBObject and adding throws RemoteException to each method declaration. Because EnglishAuction exposes Item in its component interface (and a remote interface cannot expose a local interface type), changing EnglishAuction to a remote interface would require changing Item as well.


EnglishAuction also references the Bidder local interface to associate a bidder with each submitted bid. This interface appears in Listing 5.3. Similar to Item , it consists of get methods. It includes methods to report a bidder's shipping and billing addresses using an AddressView object in the same way EnglishAuction uses BidView .

Listing 5.3 Bidder.java “A Local Interface for a Bidder Entity Bean
 package com.que.ejb20.auction.model;  /**   * Title:        Bidder<p>   * Description:  Local interface for the Bidder entity bean<p>   */  import java.util.List;  import javax.ejb.EJBLocalObject;  import com.que.ejb20.auction.view.AddressView;  public interface Bidder extends EJBLocalObject {   public Integer getId();    public String getFirstName();    public String getLastName();    public String getEmailAddress();    public String getUsername();    public String getPassword();    public AddressView getShippingAddressView();    public AddressView getBillingAddressView();    /**     * Retrieve all bids submitted by this bidder     *     * @return a List of BidView objects     */    public List getBids();  } 

Listing 5.4 and Listing 5.5 show the source for BidView and AddressView . These classes provide simple data structures that the entity beans can use to report information from their dependent objects. The classes are designated as views to emphasize the fact that manipulating their values has no impact on the underlying persistent data managed by the entity beans. Updates to this type of data are typically done by creating a new instance of one of the view classes with the desired values and passing that to an update method exposed by the associated entity bean. A Bid is immutable (you wouldn't want to change a bid amount or any of the other attributes after it's been submitted), so adding the option to perform updates would only apply to Address objects in this case.

Listing 5.4 BidView.java “View of a Bid
 package com.que.ejb20.auction.view;  /**   * Title:        BidView<p>   * Description:  Value object for an auction bid<p>   */  import java.io.Serializable;  import java.sql.Timestamp;  public class BidView implements Serializable {   private Integer auctionId;    private Integer bidderId;    private Timestamp dateTimeSubmitted;    private String transactionId;    private Double amount;    public BidView(Integer newAuctionId, Integer newBidderId,     Timestamp newDateTimeSubmitted, Double newAmount, String newTransactionId) {     setAuctionId(newAuctionId);      setBidderId(newBidderId);      setDateTimeSubmitted(newDateTimeSubmitted);      setAmount(newAmount);      setTransactionId(newTransactionId);    }    public Integer getAuctionId() {     return auctionId;    }    public void setAuctionId(Integer newAuctionId) {     auctionId = newAuctionId;    }    public Integer getBidderId() {     return bidderId;    }    public void setBidderId(Integer newBidderId) {     bidderId = newBidderId;    }    public Timestamp getDateTimeSubmitted() {     return dateTimeSubmitted;    }    public void setDateTimeSubmitted(Timestamp newDateTimeSubmitted) {     dateTimeSubmitted = newDateTimeSubmitted;    }    public Double getAmount() {     return amount;    }    public void setAmount(Double newAmount) {     amount = newAmount;    }    public String getTransactionId() {     return transactionId;    }    public void setTransactionId(String newTransactionId) {     transactionId = newTransactionId;    }  } 
Listing 5.5 AddressView.java “View of an Address
 package com.que.ejb20.auction.view;  /**   * Title:        AddressView<p>   * Description:  Value object for an address<p>   */  import java.io.Serializable;  public class AddressView implements Serializable {   private String addressLine1;    private String addressLine2;    private String city;    private String state;    private String zipCode;    public AddressView(String newAddressLine1, String newAddressLine2,     String newCity, String newState, String newZipCode) {     setAddressLine1(newAddressLine1);      setAddressLine2(newAddressLine2);      setCity(newCity);      setState(newState);      setZipCode(newZipCode);    }    public String getAddressLine1() {     return addressLine1;    }    public void setAddressLine1(String newAddressLine1) {     addressLine1 = newAddressLine1;    }    public String getAddressLine2() {     return addressLine2;    }    public void setAddressLine2(String newAddressLine2) {     addressLine2 = newAddressLine2;    }    public String getCity() {     return city;    }    public void setCity(String newCity) {     city = newCity;    }    public String getState() {     return state;    }    public void setState(String newState) {     state = newState;    }    public String getZipCode() {     return zipCode;    }    public void setZipCode(String newZipCode) {     zipCode = newZipCode;    }  } 

View objects aren't restricted to dependent objects. EnglishAuction also exposes a method that returns a view of the current state of the auction itself. This option, which is even more important when working with remote clients, provides a convenient way to obtain the state of an entity with a single call. Listing 5.6 defines the object type returned by getAuctionDetail .

Listing 5.6 AuctionDetailView.java “View of an Auction
 package com.que.ejb20.auction.view;  /**   * Title:        AuctionDetailView<p>   * Description:  Detailed view class for an English Auction that presents a   *               complete description of an auction<p>   */  import java.io.Serializable;  import java.sql.Timestamp;  public class AuctionDetailView implements Serializable {   private Integer id;    private String name;    private String description;    private String status;    private Double startingBid;    private Double minBidIncrement;    private Double reserveAmount;    private Timestamp startDateTime;    private Timestamp scheduledEndDateTime;    private Timestamp actualEndDateTime;    private Double leadingBidAmount;    private Double winningBidAmount;    private String itemName;    private String itemDescription;    private Integer quantity;    private String imageURL;    public AuctionDetailView() {   }  public AuctionDetailView(Integer newId, String newName, String newDescription,    String newStatus, Double newStartingBid, Double newMinBidIncrement,    Double newReserveAmount, Timestamp newStartDateTime,    Timestamp newScheduledEndDateTime, Timestamp newActualEndDateTime,    Double newLeadingBidAmount, Double newWinningBidAmount, String newItemName,    String newItemDescription, Integer newQuantity, String newImageURL) {     setId(newId);      setName(newName);      setDescription(newDescription);      setStatus(newStatus);      setStartingBid(newStartingBid);      setMinBidIncrement(newMinBidIncrement);      setReserveAmount(newReserveAmount);      setStartDateTime(newStartDateTime);      setScheduledEndDateTime(newScheduledEndDateTime);      setActualEndDateTime(newActualEndDateTime);      setLeadingBidAmount(newLeadingBidAmount);      setWinningBidAmount(newWinningBidAmount);      setItemName(newItemName);      setItemDescription(newItemDescription);      setQuantity(newQuantity);      setImageURL(newImageURL);    }    public Integer getId() {     return id;    }    public void setId(Integer newId) {     id = newId;    }    public void setName(String newName) {     name = newName;    }    public String getName() {     return name;    }    public void setDescription(String newDescription) {     description = newDescription;    }    public String getDescription() {     return description;    }    public void setStatus(String newStatus) {     status = newStatus;    }    public String getStatus() {     return status;    }    public void setStartingBid(Double newStartingBid) {     startingBid = newStartingBid;    }    public Double getStartingBid() {     return startingBid;    }    public void setMinBidIncrement(Double newMinBidIncrement) {     minBidIncrement = newMinBidIncrement;    }    public Double getMinBidIncrement() {     return minBidIncrement;    }    public void setReserveAmount(Double newReserveAmount) {     reserveAmount = newReserveAmount;    }    public Double getReserveAmount() {     return reserveAmount;    }    public void setStartDateTime(Timestamp newStartDateTime) {     startDateTime = newStartDateTime;    }    public Timestamp getStartDateTime() {     return startDateTime;    }    public void setScheduledEndDateTime(Timestamp newScheduledEndDateTime) {     scheduledEndDateTime = newScheduledEndDateTime;    }    public Timestamp getScheduledEndDateTime() {     return scheduledEndDateTime;    }    public void setActualEndDateTime(Timestamp newActualEndDateTime) {     actualEndDateTime = newActualEndDateTime;    }    public Timestamp getActualEndDateTime() {     return actualEndDateTime;    }    public void setLeadingBidAmount(Double newLeadingBidAmount) {     leadingBidAmount = newLeadingBidAmount;    }    public Double getLeadingBidAmount() {     return leadingBidAmount;    }    public void setWinningBidAmount(Double newWinningBidAmount) {     winningBidAmount = newWinningBidAmount;    }    public Double getWinningBidAmount() {     return winningBidAmount;    }    public void setItemName(String newItemName) {     itemName = newItemName;    }    public String getItemName() {     return itemName;    }    public void setItemDescription(String newItemDescription) {     itemDescription = newItemDescription;    }    public String getItemDescription() {     return itemDescription;    }    public void setQuantity(Integer newQuantity) {     quantity = newQuantity;    }    public Integer getQuantity() {     return quantity;    }    public void setImageURL(String newImageURL) {     imageURL = newImageURL;    }    public String getImageURL() {     return imageURL;    }  } 

You should include exceptions in your method declarations as appropriate to report application errors that might occur. Chapter 13, "Exception Handling," covers the details of exceptions and EJBs, but for now, just note that exception handling is an important part of designing your entity beans and their component interfaces. Listing 5.7 and Listing 5.8 show the two application exceptions referenced by EnglishAuction .

For more information on reporting application errors, see "Application Exceptions," p. 364 .

Listing 5.7 InvalidBidException.java “Application Exception Used to Respond to an Unacceptable Bid
 package com.que.ejb20.auction.exceptions;  /**   * Title:        InvalidBidException   * Description:  Application exception used to report an attempt to submit   *               a bid that does not meet the required bid amount   */  import java.text.NumberFormat;  public class InvalidBidException extends Exception {   /**     * Construct with the relevant bid amounts     *     * @param submittedBid the bid amount that was rejected     * @param requiredBid the minimum acceptable bid     */    public InvalidBidException(double submittedBid, double requiredBid) {    // format using the currency of the default locale to produce a message like     // Submitted bid of .00 does not satisfy required bid amount of .00      super( "Submitted bid of " +        NumberFormat.getCurrencyInstance().format(submittedBid) +        " does not satisfy required bid amount of " +        NumberFormat.getCurrencyInstance().format(requiredBid) );    }    /**     * Construct with a string to display     *     * @param msg the error message to display     */    public InvalidBidException(String msg) {     super(msg);    }  } 
Listing 5.8 InvalidAuctionStatusException.java “Application Exception Used to Respond to Invalid Business Method Calls
 package com.que.ejb20.auction.exceptions;  /**   * Title:        InvalidAuctionStatusException   * Description:  Application exception used to report attempts to perform   *               actions that are inconsistent with the current auction status   */  public class InvalidAuctionStatusException extends Exception {   public InvalidAuctionStatusException(String msg) {     super(msg);    }  } 


Special Edition Using Enterprise JavaBeans 2.0
Special Edition Using Enterprise JavaBeans 2.0
ISBN: 0789725673
EAN: 2147483647
Year: 2000
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net