Sun Java Solaris Communities My SDN Account Join SDN
 
Enterprise Java Technologies Tech Tips

Writing a Handler in JAX-WS and Inheritance and the Java Persistence API

 
In This Issue

Welcome to the Enterprise Java Technologies Tech Tips for June 24, 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 an open source reference implementation of Java EE 5 called GlassFish. You can download GlassFish from the GlassFish Community Downloads page.

You can view this Tech Tip as simple text.

You can download the sample archive for the tip Writing a Handler in JAX-WS.

You can download the sample archive for the tip Inheritance and the Java Persistence API.

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.

Writing a Handler in JAX-WS
By Rama Pulavarthi  

Handlers are interceptors that can be easily plugged into the Java API for XML-Based Web Services (JAX-WS) 2.0 runtime environment to do additional processing of inbound and outbound messages. JAX-WS defines two types of handlers: protocol handlers and logical handlers. Protocol handlers are specific to a protocol such as SOAP. They can access or change any part of the message, including protocol-specific parts such as the message header. Logical handlers are protocol-agnostic. They cannot change any protocol-specific parts of a message. Logical handlers act only on the payload of the message.

This tip shows you how to write a SOAP protocol handler and a logical handler for use with JAX-WS.

Handler Basics

SOAP handlers are generally used to process SOAP-specific information, such as SOAP headers. For example, a SOAP Handler can process security headers in a message and pass the request to the endpoint if the message has the required credentials. Logical handlers are commonly used if the processing does not need access to SOAP headers, for validation of the payload, and with Representational State Transfer ("REST") style web services. In addition, logical handlers can use Java API for XML Binding (JAXB) for processing the payload. If you have the JAXBContext object, it's simple to alter something in a message with a logical handler. You can get the JAXB objects and call Java methods on them rather than dealing with Source objects or SOAPMessage objects using the SOAP with Attachments API for Java (SAAJ) in a SOAP handler.

Handlers are invoked with a message context, which provides methods that the handler uses to access and modify inbound or outbound messages. The message context also has properties that the handler can process. These properties can be used to communicate additional information or metadata that is not specified in the message. The additional information can be exchanged between a handler and service implementation or between a handler and a web service client. (For more information about message context in JAX-WS, see the article A little bit about Message Context in JAX-WS.)

SOAP handlers extend javax.xml.ws.handler.soap.SOAPHandler. The JAX-WS specification defines the SOAPHandler class for SOAP binding. When a SOAP handler is invoked, a SOAPMessageContext object is specified in the request. The SOAPMessageContext object provides methods to access a SOAPMessage (the class for SOAP messages). Specifically, the method getMessage() in SOAPMesageContext retrieves the SOAPMessage. After getting a SOAPMessage, you can use SAAJ to manipulate it.

Logical handlers extend javax.xml.ws.handler.LogicalHandler. They provide access to the message context and the message payload. If you use SOAP over HTTP for the message exchange, the content of the SOAP body forms the payload. If you use XML over HTTP, the XML content of the primary part of the message forms the payload. When a logical handler is invoked, a LogicalMessageContext object is specified in the request. The method getMessage() in LogicalMessageContext returns a LogicalMessage. The LogicalMessage represents a protocol-neutral XML message and contains methods that provide access to the payload of the message.

The following figure illustrates the relationship between the message contexts, the objects they can be used to retrieve, and the parts of a message those objects cover.

Logical handlers can coexist with SOAP handlers in a handler chain. During runtime, the handler chain is reordered so that for an outbound message the logical handlers execute before the SOAP handlers. For an inbound message, the SOAP handlers execute before the logical handlers.

The following figure shows how logical and SOAP handlers are invoked during a request and response.

Writing a SOAP Message Handler

Let's look at a simple SOAP handler. A sample package accompanies this tip. Download the sample package and extract its contents. You'll see two source files. One of them, SOAPLoggingHandler, is a SOAP handler that logs calls to a web service. Here's a code snippet from SOAPLoggingHandler:

   public class SOAPLoggingHandler implements 
    SOAPHandler<SOAPMessageContext> {
   ... 
   
      public boolean handleMessage(SOAPMessageContext smc) {
          logToSystemOut(smc);
          return true;
      }
       
      public boolean handleFault(SOAPMessageContext smc) {
          logToSystemOut(smc);
          return true;
      }
       
      public void close(MessageContext messageContext) {
      }
      
   ...  

Like all SOAP handlers, SOAPLoggingHandler implements the SOAPHandler interface. Notice that SOAPLoggingHandler also implements three methods: handleMessage(), handleFault(), and close(). The SOAPHandler interface is a subinterface of the Handler interface. The handleMessage(), handleFault(), and close() methods are the three methods defined in the Handler interface, and should be implemented in all basic handlers. Here's how the methods are used:

  • handleMessage() is called for normal processing of inbound and outbound messages.
  • handleFault is called when a message contains a protocol fault.
  • close( ) is called after the completion of message processing by all handlers for each web service invocation, that is, after the completion of a SOAP method exchange pattern (or "MEP").

The logging is done in the handler's logToSystemOut() method that both the handleMessage() and handleFault() methods call:

    private void logToSystemOut(SOAPMessageContext smc) {
        Boolean outboundProperty = (Boolean)
            smc.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        
        if (outboundProperty.booleanValue()) {
            out.println("\nOutbound message:");
        } else {
            out.println("\nInbound message:");
        }
        
        SOAPMessage message = smc.getMessage();
        try {
            message.writeTo(out);
            out.println("");   
        } catch (Exception e) {
            out.println("Exception in handler: " + e);
        }
    }

Notice that the logToSystemOut() method accesses a SOAPMessageContext property, MESSAGE_OUTBOUND_PROPERTY, and uses a SOAPMessageContext method, getMessage(). The value of MESSAGE_OUTBOUND_PROPERTY indicates the message direction. A value of true means that the message is outbound. A value of false indicates an inbound message. Based on the property value, logToSystemOut() prints either "Outbound message" or "Inbound message." It then uses getMessage() to get the SOAP message, and prints it.

Writing a Logical Message Handler

As its name suggests, the LogicalLoggingHandler file in the sample package is a logical message handler. Like the SOAPLoggingHandler, it logs calls to a web service. Here's a code snippet from LogicalLoggingHandler:

   public class LogicalLoggingHandler implements 
    LogicalHandler<LogicalMessageContext> {
   ...
   
       public boolean handleMessage
        (LogicalMessageContext context) {
           return processMessage(context);
       }
       
       public boolean handleFault
        (LogicalMessageContext context) {
           return processMessage(context);
       }
       
       public void close(MessageContext context) {
           // Clean up Resources
       }

Like all logical handlers, LogicalLoggingHandler implements the LogicalHandler interface. And like all handlers it implements the handleMessage(), handleFault(), and close() methods.

The logging is done in the handler's processMessage() method that both the handleMessage() and handleFault() methods call:

   private boolean processMessage
    (LogicalMessageContext context) {
       Boolean outboundProperty = (Boolean)
          context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
   
          if (outboundProperty) {
              out.println("\nOutbound message:");
          } else {
              out.println("\nInbound message:");
          }
          LogicalMessage lm = context.getMessage();
          Source payload = lm.getPayload();
   
          // Process Payload Source
          printSource(payload);
          // ....
          
          // If the payload is modified, 
          // Do lm.setPayload(source) to be safe. Without it, 
          // behavior may vary on the kind of source returned in 
          // lm.getPayload().
          // See LogicalMessage JavaDoc for more details.
          // lm.setPayload(modifiedPayload);
          return true;

The processMessage() method accesses and manipulates the message payload using the logical message context for the logical handler. It calls the LogicalMessage method, getPayload(), to get the payload of the message. The payload is returned as a Source object.

Notice the commented out portion of processMessage(). In some cases, you might need to call the LogicalMessage method, setPayload(), after a modification is made to the payload. The source returned by getPayload() depends on the JAX-WS runtime. If the returned source is DOMSource, a modification to the encapsulated DOM tree changes the message payload in place. In that case, there is no need to subsequently call setPayload(). However, other types of returned source provide only read access to the message. In those cases, you need to call setPayload() after any modifications.

You can also pass a JAXBContext object in the call to getPayload(), to get the payload as a JAXB object. Here's an example:

   LogicalMessage lm = context.getMessage();
   Object jaxbObject = lm.getPayload(jaxbContext);
   // Modify JAXB Object
   lm.setPayload(modifiedJaxbObject,jaxbContext);

Note that there is no connection between the returned object and the message payload -- to change the payload, you need to call setPayload().

Handlers are flexible to plug-in and can be a powerful addition to your application. For another JAX-WS handler example, see Handler example using JAXWS 2.0 in Stephen DiMilla's blog.

About the Author

Rama Pulavarthi is a Member of Technical Staff in the Java Web Services group at Sun Microsystems. He currently works on the development of the JAX-WS Reference Implementation. He previously lead the Software Quality Engineering effort for JAX-RPC.

Inheritance and the Java Persistence API
By Rahul Biswas  

Inheritance, the ability of a subclass to derive state and behavior from its superclass, was not supported previously in Enterprise JavaBeans (EJB) technology. In the EJB 2.1 persistence model, an entity could not derive from another entity. However, the new Java Persistence API, a part of the EJB 3.0 specification (JSR 220), changes that. By supporting inheritance, the Java Persistence API allows you to write more modular, cohesive, and extensible code. It also allows you to take advantage of polymorphism, the ability of an object to take different forms.

This Tech Tip presents some of the features of inheritance supported in the Java Persistence API. A sample package accompanies the Tech Tip. It demonstrates some of the features discussed in the tip. The examples in the tip are taken from the source code for the sample (which is included in the package). The sample uses an open source reference implementation of Java EE 5 called GlassFish. You can download GlassFish from the GlassFish Community Downloads page.

A Simple Example of Inheritance

Let's say you made a resolution this year to be more organized. In particular, you resolved to better organize your financial accounts. Assume you have the following accounts: checking, savings, credit card, brokerage, and margin. All of these are accounts, so you can model them based on a class called Account, which is a Plain Old Java Object (POJO). Here's a snippet of code from the Account class:

   public abstract class Account{

    String name;
    String actNum; 
    String created;
    Status status; //OPEN/CLOSE
    //let's assume we are not that rich yet and stick to float 
    float  balance;      
    String description;

   }
Inheriting from Abstract Entities

Notice that Account is an abstract class, something that can't be directly instantiated as an object. However, in spite of that, the Java Persistence API allows for Account to be an entity. Significantly, this enables you to use Account in polymorphic queries written in the Java Persistence Query Language. Through these queries you can load instances of Account subclasses using only the account number. Also, there are many attributes in Account that can be inherited by more specific entities (the tip will show these entities soon), so making Account an entity allows you to inherit the mapping attributes. To make Account an entity you mark the class with the @Entity annotation. To identify the mapping strategy for the class and its subclasses you mark the class with an @Inheritance annotation. Here's the Account class snippet with @Entity and @Inheritance annotations added:

   @Entity
   @Inheritance(strategy=InheritanceStrategy.SINGLE_TABLE)
   public abstract class Account{

    public enum Status { OPEN, CLOSED }

    @Id
    private  String acctNum;  
    private  String name;
    private  String created;
    private  Status status; //Open/Close
    //let's assume we are not that rich yet and stick to float 
    private  float balance;  
    private  String description;

   }

Notice also, the @Id annotation, which marks the acctNum field as the primary key in the Account entity.

The strategy element value SINGLE_TABLE in the @Inheritance annotation means that the base class Account and any of its subclasses are mapped to a single table.

There is a way to inherit mapping attributes from Account without making it an entity. In that approach you annotate Account with the @MappedSuperclass annotation. But that approach does not allow you to use Account in Java Persistence Query Language queries. Also, depending on the inheritance strategy you choose, it might also result in base class attributes being mapped to separate tables defined for the more specific classes.

Inheriting from Abstract Non-Entities (Mapped Superclass)

Both the checking and savings accounts are bank accounts, so for these two kinds of accounts you can define yet another abstract class, BankAccount. The BankAccount class is abstract because it doesn't need to be instantiated -- its subclasses that model the checking and savings account do. Also, BankAccount inherits its mapping attributes along with the behavior from the Account class.

   public abstract class BankAccount extends Account{

    String bankName;
 
   }

There's no @Entity annotation in BankAccount -- it's defined as an abstract non-entity class. Because more specific classes will be derived from it, you can annotate BankAccount as a mapped superclass:

   @MappedSuperclass
   public abstract class BankAccount extends Account{

    String bankName;
 
   }

You might ask why use that approach if it doesn't allow you to use BankAccount in Java Persistence Query Language queries? In fact, because it's not an entity, BankAccount is not mapped to a database table. However these functions are not needed in this example. The mapped superclass approach does enable you to inherit both behavior and mapping attributes from BankAccount. In a case where you need to use the BankAccount and bank name in a polymorphic query, you would define the class as an abstract entity.

There are two kinds of concrete bank account entities -- SavingsAccount and CheckingAccount. Here are snippets of those classes:

   @Entity
   public class SavingsAccount extends BankAccount{
   
   float savingsRate;
   ...

   }

   @Entity
   public class CheckingAccount extends BankAccount{

   float maintFee;
   ...

   }
 

The attribute bankName maps to ACCOUNT.BANKNAME for InheritanceType.SINGLE_TABLE and SavingsAccount.BANKNAME for InheritanceType.JOINED.

Similarly, for CheckingAccount, bankName maps to ACCOUNT.BANKNAME for InheritanceType.SINGLE_TABLE and CheckingAccount.BANKNAME for InheritanceType.JOINED.

Polymorphic Queries

Because the Java Persistence API supports polymorphic queries, you can find any concrete instance of the Account entity by its account number (acctNum). You can do this using the entity manager's find by primary key method or you can write your own Java Persistence query language query. Here's a statement that runs such a query:

   Account = em.find(Account.class, acctNum);    
 

In the statement, em is an EntityManager instance that is used to find entities by their primary key. An EntityManager is a Java Persistence API class that manages the life cycle of entities within a persistence context, as well as enabling queries to be run on entities.

The query looks up a specific account object instance using the Account class and acctNum, which contains the account number. If the value of acctNum matches an account number of a savings or checking account, the savings or checking account is loaded by the persistence provider. That's true even though you pass an Account class (not a SavingsAccount or CheckingAccount class) in the query. This is a demonstration of polymorphism. When Account is queried, all subclasses that meet the query criteria are returned. If Account was not an entity, but a mapped superclass, you wouldn't be able to run the query as shown above.

Overriding Mapping in Inherited Classes

In an inherited class you can override the mappings that you specified in a mapped superclass. For example, you can override the mapping attribute bankName in the CheckingAccount class as follows:

   @Entity
   @AttributeOverride(
     name="bankName" column=@Column("name="bank_name"))
   public class CheckingAccount extends BankAccount{

     boolean isOverDraftAllowed;

   }

After the override, bankName maps to ACCOUNT.BANK_NAME instead of ACCOUNT.BANKNAME.

Inheritance Strategy

The Java Persistence API allows for three different inheritance strategies that dictate how subclasses are mapped to database tables. The three strategies are single table per class hierarchy, joined subclass, and single table per class.

Single Table Per Class Hierarchy Strategy

This strategy, which is specified by the strategy value "SINGLE_TABLE", means that a class and all of its subclasses are mapped to the same table. If you recall, this is the strategy shown previously in the ACCOUNT class. In a single table per class hierarchy the instances are distinguished by a discriminator value in a discriminator column.

The default name for the discriminator column name is DTYPE, and the default type of the column is STRING. If you don't specify a discriminator value, it defaults to a provider-generated value. For a discriminator column of type STRING, the default discriminator name is the entity name. For example, if you accept all the defaults for Account, the discriminator column value is "ACCOUNT". You can however override the defaults for the discriminator column and value, using the @DiscriminatorColumn and @DiscriminatorValue annotations, respectively. For example:

   @Entity
   @Inheritance(strategy=InheritanceStrategy.SINGLE_TABLE)
   @DiscriminatorColumn(name="DCOL", 
     discriminatorType=DiscriminatorType.STRING)
   @DiscriminatorValue("BaseAccount");
   public abstract class Account{
   ...

   }

   @Entity
   @DiscriminatorValue("Checking_Account");
   public class CheckingAccount extends BankAccount{
   ...
   
   float maintFee;

   }

After these specifications, the discriminator column has the name "DCOL", and records that represent a checking account have a DCOL column value of "Checking_Account".

Here are the column names and their types for the table that would be generated based on specifications for ACCOUNT and its subclasses:

Name                    Null?    Type
---------------------------------------------- 
ACCTNUM                 NOT NULL VARCHAR2(255)
DCOL                             VARCHAR2(31)
CREATED                          VARCHAR2(255)
STATUS                           NUMBER(10)
NAME                             VARCHAR2(255)
BALANCE                          NUMBER(19,4)
DESCRIPTION                      VARCHAR2(255)
TRADEFEES                        NUMBER(19,4)
MAXLOANALLOWED                   NUMBER(19,4)
CREDITCARDNUMBER                 VARCHAR2(255)
ISSUINGBANK                      VARCHAR2(255)
EXPIRESON                        VARCHAR2(255)
BANKNAME                         VARCHAR2(255)
SAVINGSRATE                      NUMBER(19,4)
BANK_NAME                        VARCHAR2(255)
ISOVERDRAFTALLOWED               NUMBER(1)

Table: ACCOUNT

Notice that the table contains all the attributes of the entire class hierarchy. So for an account of type CheckingAccount, there is only one record representing CheckingAccount, BankAccount, and Account instances. This record has a DTYPE value of "Checking_Account" (that's what was specified in the @DiscriminatorValue annotation). If your persistence provider has the ability to create the database tables based on the meta information, you do not have to be concerned about the database schema.

Join Subclass Strategy

In the joined subclass strategy, which is specified by the strategy value "JOINED", the attributes of the base class are stored in a single table, and the attributes of the subclasses are stored in separate tables. So in the code for ACCOUNT, if you changed the inheritance strategy to "JOINED":

 
   @Entity
   @Inheritance(strategy=InheritanceStrategy.JOINED)
   @DiscriminatorColumn(name="DCOL", 
     discriminatorType=DiscriminatorType.STRING)
   @DiscriminatorValue("BaseAccount");
   public abstract class Account{
   ....
   
   }

the database tables would like the following:

Name                    Null?    Type
----------------------------------------------
ACCTNUM                 NOT NULL VARCHAR2(255)
DCOL                             VARCHAR2(31)
CREATED                          VARCHAR2(255)
STATUS                           NUMBER(10)
NAME                             VARCHAR2(255)
BALANCE                          NUMBER(19,4)
DESCRIPTION                      VARCHAR2(255)
 
Table: Account

Name                    Null?    Type
-----------------------------------------------
ACCTNUM                 NOT NULL  VARCHAR2(255)
BANKNAME                          VARCHAR2(255)
SAVINGSRATE                       NUMBER(19,4)

Table: SAVINGSACCOUNT

Name                    Null?    Type 
---------------------------------------------- 
ACCTNUM                 NOT NULL VARCHAR2(255)
BANK_NAME                        VARCHAR2(255)
ISOVERDRAFTALLOWED               NUMBER(1)

Table: CHECKINGACCOUNT

Name                    Null?    Type
---------------------------------------------- 
ACCTNUM                 NOT NULL VARCHAR2(255)
TRADEFEES                        NUMBER(19,4)

Table: BROKERAGEACCOUNT

Name                    Null?    Type
---------------------------------------------- 
ACCTNUM                 NOT NULL VARCHAR2(255)
MAXLOANALLOWED                   NUMBER(19,4)

Table: MARGINACCOUNT

Even though no primary key was specified in the subclasses of Account, each of the tables representing the subclasses has a primary key. The primary key has the same name and type as the primary key defined for the Account entity -- acctNum. The subclasses and the base class are joined on the primary keys when a query is executed to load a subclass entity. Notice how, in the joined subclass strategy, each of the tables representing a subclass has only the attributes that are not contained in the base class.

Single Table Per Class

In single table per class, each class is mapped to a separate table. A persistence provider is not required to support this strategy with this release of the Java Persistence API specification.

Overriding a Join Column

In the joined subclass strategy you saw that the join between the base class and the subclasses happen on the primary keys. The primary key of the subclass has the same type and name as the base class. It is possible to specify a primary key join column in a subclass and override the default. This is demonstrated in the credit card account entity:

 
   @Entity
   @PrimaryKeyJoinColumn(name="cca_id")
   public class CreditCardAccount extends Account{
   
    String issuingBank;
    String creditCardNumber;
    String expiresOn;
   
   }

When the persistence provider does the join between the tables representing the CreditCardAccount and Account entities, to load a CreditCardAccount instance, the join will now happen between cca_id (the primary key column) of CreditCardAccount and the acctNum column of the Account column. If you did not override default primary key join column, the join would happen on the acctNum columns of the tables representing the entities.

Overriding Inheritance Strategy

It's possible for an entity to specify a different inheritance strategy for its subclasses. The BrokerageAccount entity illustrates that.

 

   @Entity
   @Inheritance(strategy=InheritanceStrategy.JOINED)
   public class BrokerageAccount extends Account{
   
    float tradeFees;
   
   }
   
   @Entity
   public class MarginAccount extends BrokerageAccount{
   
    float maxLoanAllowed;
   
   }

Because the Account entity specifies a SINGLE_TABLE per class hierarchy strategy, Account, CheckingAccount, SavingsAccount, CreditCardAccount and BrokerageAccount are stored in the same database table. However the MarginAccount entity's maxLoanAllowed attribute is stored in a separate table because the inheritance strategy was changed to "JOINED" in the BrokerageAccount. A persistence provider does not need to support this feature, but the Java API specification allows for this. So to make sure that your code is portable across vendors, it's best to avoid using this feature.

Notice that MarginAccount is derived from another concrete entity -- BrokerageAccount.

Polymorphic Association

The Java Persistence API allows polymorphic associations. Every account has an owner and an account owner typically has multiple accounts. These accounts do not have to be of the same kind. Also, you don't want to have a member variable in AccountOwner represent each account kind type -- that isn't extensible or efficient. Fortunately you can use a collection of Account entities to represent all the different types of accounts an AccountOwner entity has (just as in POJOs). Note that although you can have a collection of Account objects, you cannot directly instantiate Account. An account owner can have a collection of different kinds of accounts. The ability to have polymorphic associations allows you to have more specific account class instances in the collection of Account.

   @Entity
   public class AccountOwner {
    String name;
    Collection <Account> accounts;
   
   }
 

A mapped superclass cannot be the target of a persistent relationship. So if you made Account a mapped superclass, you wouldn't be able to have a one-to-many relationship between an AccountOwner and Account.

Inheriting From a Non-Entity Class

Typically you inherit an entity from a non-entity to inherit its behavior. The attributes you inherit from a non-entity are not persisted. For example, the BaseAccount class provides the basic functionality of computing the balance, given a principal amount and interest rate. You can extend Account from BaseAccount to inherit this behavior.

   public class BaseAccount {

    public float computeBalance(float principal, float rate){
     return principal * (1.0 + rate/100.0);
    }

   }

   @Entity
   public class Account extends BaseAccount{
   ....
   }
Summary

The new Java Persistence API enables you to write more modular, cohesive, and extensible code through inheritance, polymorphic queries, and polymorphic associations. It benefits both developers who are creating an application data model from scratch and developers who want to migrate their current persistence implementation to move to a standardized persistence API.

Running the Sample Code

To install and run the sample code that accompanies this tip:

  1. If you haven't already done so, download GlassFish from the GlassFish Community Downloads Page, and install it.

  2. Set the following environment variables:
    • GLASSFISH_HOME. This should point to where you installed GlassFish.

    • ANT_HOME. This should point to where ant is installed. Ant is included in the GlassFish bundle that you downloaded. (In Windows, it's in the lib\ant subdirectory.)

    • JAVA_HOME. This should point to the location of JDK 5.0 on your system.

    Add $JAVA_HOME/bin, $ANT_HOME/bin, and $GLASSFISH_HOME/bin to your PATH environment variable.

  3. Download the sample package and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/ttjun2006inheritance, where <sample_install_dir> is the directory in which you installed the sample package. The inherit directory below ttjun2006inheritance contains the source files and other support files for the sample.

  4. Change to the inherit directory and edit the build.properties file as appropriate. For example, if the admin host is remote, change the value of admin.host from the default (localhost) to the appropriate remote host.  Also, make sure that the javaee.server.passwordfile location is correct.

  5. Start GlassFish:
          $GLASSFISH_HOME/bin/asadmin start-domain domain1   
         
  6. Start the database server. From the inherit directory enter the following command:
          ant dbsetup
          

    In response you should see output similar to this:

          ...
          
          start-db:
               [exec] Database started in Network Server mode on host 
               ... and port ...
          
               [exec] Starting database in the background.  Log 
               redirected to ...
               [exec] Command start-database executed successfully.
    		   
  7. Build and deploy the sample application. From the inherit directory enter the following command:
         ant all
         
    In response you should see output similar to this:

          compile:
          
          [javac] Compiling 11 source files to ...
          ...\inherit\build\classes
          
          package-ejb:
          ...
          [jar] Building jar: ...\inherit\build\ejb\sample.jar
          
          package-war:
          ...
          [zip] Building zip: ...\inherit\build\sample.ear
          
          tools:
          
          deploy:
          [exec] Command deploy executed successfully.   
    	  
  8. Start the application. Open your browser to http://<host>:8080/sample/index.html, replacing <host> with your host name (for instance, localhost). You should see the home page of the application.

Try creating a new account and searching for an account. Underlying the functions of the application is the support for inheritance in the Java Persistence API.

About the Author

Rahul Biswas is a member of the Java Performance Engineering group at Sun. He is currently involved in the development of a generic performance benchmark for Java Persistence and the performance improvement of the persistence implementation in GlassFish.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.