Skip Headers
Oracle® Coherence Tutorial for Oracle Coherence
Release 3.6

Part Number E15831-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

4 Working with Complex Objects

In this chapter, you work with complex objects residing in the cache. Using JDeveloper, you create a new Contact class, and then store and retrieve Contact objects in the cache using POF serialization.

This chapter contains the following sections:

4.1 Introduction

Until now, you have been putting and getting String objects as the value in a NamedCache. Many of the implementations of the get and put methods in the Coherence Java API define the values and keys to be of type Object. For example:

public java.lang.Object get(java.lang.Object oKey)
public void put(java.lang.Object oKey, java.lang.Object oValue)

Any object can potentially be used as a value or key. This enables you to store complex objects as values in the cache.

Because Coherence might need to send the object across the wire, the object must be serializable. Object serialization is the process of saving an object's state into a sequence of bytes, and then rebuilding (deserializing) them into a live object at some future time. For example, objects that implement the java.io.Serializable interface are serializable.

As an alternative to using the Java Serializable interface, you can improve performance by using Coherence's own class for high-performance serialization, com.tangosol.io.pof.PortableObject. PortableObject is up to six times faster than the standard java.io.Serializable and the serialized result set is smaller.

The PortableObject interface provides two simple methods, readExternal and writeExternal, that permit you explicitly read and write serialized object attributes from the provided PofReader and PofWriter streams respectively. By taking control over the serialization format, Coherence provides a way to dramatically improve the performance of the process. Using POF dramatically reduces the size of the resulting binary. The size of the binary is often 5 to 10x smaller, and the conversion to-or-from the binary can be between 5 and 20 times faster, depending on the size of the object.

4.2 Creating and Caching Complex Objects

In this exercise, you will create a Contact object that contains names, addresses, dates of birth, and telephone numbers for employees. You will also use POF serialization to put the objects in the cache and retrieve them by implementing the PortableObject interface.

  1. Create the Data Objects

  2. Create the Complex Object

  3. Create the Driver Class

  4. Create the Configuration Files and Cache Server Executable

  5. Run the Sample

4.2.1 Create the Data Objects

This section describes how to create two data objects that will later be incorporated into another data object. An Address object will provide employee address information and a PhoneNumber object will provide telephone contact information.

  1. Create an Address object to store address information for an employee.

    1. Create a new project in JDeveloper called Contacts. See "Creating a New Project in an Existing Application" if you need detailed information.

    2. Name the project Contacts. Ensure that the Default Package is com.oracle.handson, the Java Source Path is C:\home\oracle\labs\Contacts\src and the Output Directory is C:\home\oracle\labs\Contacts\classes.

      Check the Project Properties then Libraries and Classpath value for the Coherence entry. Ensure that the full path is provided for the coherence.jar: C:\oracle\product\coherence\lib\coherence.jar.

      In Run/Debug/Profile, edit the default configuration to disable local storage. Add the following line to the Java Options field:

      -Dtangosol.coherence.distributed.localstorage=false 
      
    3. Create a new Java class called Address. See "Creating a Java Class" if you need detailed information.

      Name the Java class Address. Do not select the Main Method check box.

    4. Write the class to use PortableObject for data serialization. In the JDeveloper code editor, change your generated Address class to implement com.tangosol.io.pof.PortableObject. Add an import statement for the PortableObject class.

    5. Import the com.tangosol.io.pof.PofReader, com.tangosol.io.pof.PofWriter, and java.io.IOException classes required by PortableObject.

    6. Add the default public constructor for Address that is required by PortableObject.

    7. Enter the following private attributes for your Address class. You can add others if you like.

      String Street1

      String Street2

      String City

      String State

      String Country

      At this point, the Address class should look similar to the following

      package com.oracle.handson;
      
      import com.tangosol.io.pof.PofReader;
      import com.tangosol.io.pof.PortableObject;
      import com.tangosol.io.pof.PofWriter;
      
      import java.io.IOException;
      
      public class Address  implements PortableObject 
      {
                 private String Street1;
                 private String Street2;
                 private String City;
                 private String State;
                 private String Zip;
                 private String Country;
          /**
          * Default constructor (necessary for PortableObject implementation).    */ 
          public Address()
              {
              }
      }
      
    8. JDeveloper can generate the default get/set methods for your attributes. From the Source menu, select Generate Accessors. Select the check box next to the Address class. All of the attributes are now automatically selected. Click OK to continue.

      Figure 4-1 Generate Accessors Dialog Box

      Generate Accessors Dialog Box
    9. You can also generate the default constructor and equals methods automatically. From the Source menu, select Generate Constructor from Fields, click Select All, and then click OK.

      Figure 4-2 Generate Constructors Dialog Box

      Generate Constructors Dialog Box

      The generated constructor should look similar to the following:

      public Address(String Street1, String Street2, String City, String State, String Zip, String Country) {
              super();
              this.Street1 = Street1;
              this.Street2 = Street2;
              this.City = City;
              this.State = State;
              this.Zip = Zip;
              this.Country = Country;
          }
      
    10. Implement the readExternal and writeExternal methods as required by the PortableObject interface. For example, the following implementation of readExternal allows the values for the street, city, state, and country to be read as POF objects.

      public void readExternal(PofReader reader)
              throws IOException
           {
           setStreet1(reader.readString(0));
           setStreet2(reader.readString(1));
           setCity(reader.readString(2));
           setState(reader.readString(3));
           setZip(reader.readString(4));
           setCountry(reader.readString(5));
      } 
       
      
    11. Implement the equals, hashCode, and toString object methods.

      Note:

      Cache keys and values must be serializable (for example, java.io.Serializable). Cache keys must also provide an implementation of the hashCode() and equals() methods, and those methods must return consistent results across cluster nodes. This implies that the implementation of hashCode() and equals() must be based solely on the object's serializable state (that is, the object's non-transient fields); most built-in Java types, such as String, Integer and Date, meet this requirement. Some cache implementations (specifically the partitioned cache) use the serialized form of the key objects for equality testing, which means that keys for which equals() returns true must serialize identically; most built-in Java types meet this requirement as well.

      To support these methods, import the com.tangosol.util.Base and com.tangosol.util.HashHelper classes. The following code illustrates a sample implementation of equals:

      public boolean equals(Object oThat)
              {
              if (this == oThat)
                  {
                  return true;
                  }
              if (oThat == null)
                  {
                  return false;
                  }
       
              Address that = (Address) oThat;
              return Base.equals(getStreet1(), that.getStreet1()) &&
                     Base.equals(getStreet2(), that.getStreet2()) &&
                     Base.equals(getCity(),    that.getCity())    &&
                     Base.equals(getState(),   that.getState())   &&
                     Base.equals(getZip(),     that.getZip())     &&
                     Base.equals(getCountry(), that.getCountry());
              }
          
      

      The following code illustrates a sample implementation of hashCode:

      public int hashCode()
              {
              return HashHelper.hash(getStreet1(),
                     HashHelper.hash(getStreet2(),
                     HashHelper.hash(getZip(), 0)));
              }
      

      The following code illustrates a sample implementation of toString:

      public String toString()
              {
              return  getStreet1() + "\n" +
                      getStreet2() + "\n" +
                      getCity() + ", " + getState() + " "  + getZip() + "\n" +
                      getCountry();
              }
      
    12. The resulting class should look similar to the following.

      Example 4-1 Implementation of an Address Class

      package com.oracle.handson;
      
      import com.tangosol.io.pof.PofReader;
      import com.tangosol.io.pof.PortableObject;
      import com.tangosol.io.pof.PofWriter;
       
      import com.tangosol.util.Base;
      import com.tangosol.util.HashHelper;
       
      import java.io.IOException;
       
      public class Address  implements PortableObject 
      {
                 private String Street1;
                 private String Street2;
                 private String City;
                 private String State;
                 private String Zip;
                 private String Country;
          /**
          * Default constructor (necessary for PortableObject implementation).
          */
          public Address() {
              }
       
          public Address(String Street1, String Street2, String City, String State,
                         String Zip, String Country) {
              super();
              this.Street1 = Street1;
              this.Street2 = Street2;
              this.City    = City;
              this.State   = State;
              this.Zip     = Zip;
              this.Country = Country;
          }
        
          //------------ accessors--------------------------------
        
          public void setStreet1(String Street1) {
              this.Street1 = Street1;
          }
       
          public String getStreet1() {
              return Street1;
          }
       
          public void setStreet2(String Street2) {
              this.Street2 = Street2;
          }
       
          public String getStreet2() {
              return Street2;
          }
       
          public void setCity(String City) {
              this.City = City;
          }
       
          public String getCity() {
              return City;
          }
       
          public void setState(String State) {
              this.State = State;
          }
       
          public String getState() {
              return State;
          }
       
          public void setZip(String Zip) {
              this.Zip = Zip;
          }
       
          public String getZip() {
              return Zip;
          }
       
          public void setCountry(String Country) {
              this.Country = Country;
          }
       
          public String getCountry() {
              return Country;
          }
         // -------- PortableObject Interface------------------------------
          
          public void readExternal(PofReader reader)
                  throws IOException
              {
              setStreet1(reader.readString(0));
              setStreet2(reader.readString(1));
              setCity(reader.readString(2));
              setState(reader.readString(3));
              setZip(reader.readString(4));
              setCountry(reader.readString(5));
              }
       
          public void writeExternal(PofWriter writer)
                  throws IOException
              {
              writer.writeString(0, getStreet1());
              writer.writeString(1, getStreet2());
              writer.writeString(2, getCity());
              writer.writeString(3, getState());
              writer.writeString(4, getZip());
              writer.writeString(5, getCountry());
              }
          // ----- Object methods --------------------------------------------------
       
          
          public boolean equals(Object oThat)
              {
              if (this == oThat)
                  {
                  return true;
                  }
              if (oThat == null)
                  {
                  return false;
                  }
       
              Address that = (Address) oThat;
              return Base.equals(getStreet1(), that.getStreet1()) &&
                     Base.equals(getStreet2(), that.getStreet2()) &&
                     Base.equals(getCity(),    that.getCity())    &&
                     Base.equals(getState(),   that.getState())   &&
                     Base.equals(getZip(),     that.getZip())     &&
                     Base.equals(getCountry(), that.getCountry());
              }
       
          
          public int hashCode()
              {
              return HashHelper.hash(getStreet1(),
                     HashHelper.hash(getStreet2(),
                     HashHelper.hash(getZip(), 0)));
              }
       
          
          public String toString()
              {
              return  getStreet1() + "\n" +
                      getStreet2() + "\n" +
                      getCity() + ", " + getState() + " "  + getZip() + "\n" +
                      getCountry();
              }
      }
      
  2. Create a PhoneNumber class to store telephone contact data.

    1. Create a new Java class called PhoneNumber. Do not include a main method.

      See "Creating a Java Class" if you need detailed information.

    2. Use PortableObject for data serialization. In the JDeveloper code editor, change your generated PhoneNumber class to implement com.tangosol.io.pof.PortableObject. Add an import statement for the PortableObject class.

    3. Import the com.tangosol.io.pof.PofReader and com.tangosol.io.pof.PofWriter, and java.io.IOException classes required by PortableObject.

    4. Add the default public constructor for PhoneNumber that is required by PortableObject.

    5. Enter the following private attributes for your PhoneNumber class. You can add others if you like.

      short AccessCode

      short CountryCode

      short AreaCode

      int LocalNumber

    6. JDeveloper can generate the default get/set methods for your attributes. From the Source menu, select Generate Accessors. Select the check box next to the PhoneNumber class. All of the attributes are now automatically selected. Click OK to continue.

    7. You can generate the default constructor automatically. From the Source menu, select Generate Constructor from Fields, click Select All, and then click OK.

      The generated constructor should look similar to the following:

      public PhoneNumber(short AccessCode, short CountryCode, short AreaCode,
                   int LocalNumber) {
          super();
          this.AccessCode = AccessCode;
          this.CountryCode = CountryCode;
          this.AreaCode = AreaCode;
          this.LocalNumber = LocalNumber; 
          }
      
    8. Implement the readExternal and writeExternal methods as required by the PortableObject interface.

    9. Implement the equals, hashCode and toString object methods.

    10. The resulting class should look similar to the following.

      Example 4-2 Implementation of a PhoneNumber Class

      package com.oracle.handson;
       
      import com.tangosol.io.pof.PofReader;
      import com.tangosol.io.pof.PofWriter;
      import com.tangosol.io.pof.PortableObject;
       
      import com.tangosol.util.HashHelper;
       
      import java.io.IOException;
       
      public class PhoneNumber implements PortableObject 
      {
          
          private short AccessCode;
          private short CountryCode;
          private short AreaCode;
          private int LocalNumber;
          
          /**
          * Default constructor (necessary for PortableObject implementation).
          */
          public PhoneNumber() {
          }
       
          public PhoneNumber(short AccessCode, short CountryCode, short AreaCode,
                       int LocalNumber) {
              super();
              this.AccessCode = AccessCode;
              this.CountryCode = CountryCode;
              this.AreaCode = AreaCode;
              this.LocalNumber = LocalNumber;
          }
       
          //------------ accessors--------------------------------
       
          public void setAccessCode(short AccessCode) {
              this.AccessCode = AccessCode;
          }
       
          public short getAccessCode() {
              return AccessCode;
          }
       
          public void setCountryCode(short CountryCode) {
              this.CountryCode = CountryCode;
          }
       
          public short getCountryCode() {
              return CountryCode;
          }
       
          public void setAreaCode(short AreaCode) {
              this.AreaCode = AreaCode;
          }
       
          public short getAreaCode() {
              return AreaCode;
          }
       
          public void setLocalNumber(int LocalNumber) {
              this.LocalNumber = LocalNumber;
          }
       
          public int getLocalNumber() {
              return LocalNumber;
          }
          // -------- PortableObject Interface------------------------------
          
          public void readExternal(PofReader reader)
                  throws IOException
              {
              setAccessCode(reader.readShort(0));
              setCountryCode(reader.readShort(1));
              setAreaCode(reader.readShort(2));
              setLocalNumber(reader.readInt(3));
              }
       
          
          public void writeExternal(PofWriter writer)
                  throws IOException
              {
              writer.writeShort(0, getAccessCode());
              writer.writeShort(1, getCountryCode());
              writer.writeShort(2, getAreaCode());
              writer.writeInt(3, getLocalNumber());
              }   
          // ----- Object methods -------------------------------------------------
       
          /**
          * {@inheritDoc}
          */
          public boolean equals(Object oThat)
              {
              if (this == oThat)
                  {
                  return true;
                  }
              if (oThat == null)
                  {
                  return false;
                  }
       
              PhoneNumber that = (PhoneNumber) oThat;
              return getAccessCode()  == that.getAccessCode()  &&
                     getCountryCode() == that.getCountryCode() &&
                     getAreaCode()    == that.getAreaCode()    &&
                     getLocalNumber() == that.getLocalNumber();
              }
       
          /**
          * {@inheritDoc}
          */
          public int hashCode()
              {
              return HashHelper.hash(getAreaCode(),
                     HashHelper.hash(getLocalNumber(), 0));
              }
       
          /**
          * {@inheritDoc}
          */
          public String toString()
              {
              return "+" + getAccessCode() + " " + getCountryCode() + " "
                         + getAreaCode()   + " " + getLocalNumber();
              }
          
      }
      

4.2.2 Create the Complex Object

The Contact object will provide the name, address, and telephone information of employees by incorporating the Address and PhoneNumber data objects.

  1. Create a new Java class called Contact. Do not include a main method.

    See "Creating a Java Class" if you need more information.

  2. Since the class will use PortableObject for data serialization, change your generated Contact class to implement com.tangosol.io.pof.PortableObject in the JDeveloper code editor. Add an import statement for the PortableObject class.

  3. Import the com.tangosol.io.pof.PofReader and com.tangosol.io.pof.PofWriter and java.io.IOException classes required by PortableObject.

  4. Add the default public constructor for Contact that is required by PortableObject.

  5. Enter the following private attributes for your Contact class. You can add others if you like.

    • String FirstName

    • String LastName

    • Address HomeAddress

    • Address WorkAddress

    • Map TelephoneNumbers

    • java.sql.Date BirthDate

  6. JDeveloper can generate the default get/set methods for your attributes. From the Source menu, select Generate Accessors. Select the check box next to the Contact class. All of the attributes are now automatically selected. Click OK to continue.

  7. Create an accessor, getAge, to calculate the age of an employee:

    public int getAge()
            {
            return (int) ((System.currentTimeMillis() - BirthDate.getTime()) /  MILLIS_IN_YEAR);  
            }
    
  8. Add a definition for MILLIS_IN_YEAR.

    public static final long MILLIS_IN_YEAR = 1000L * 60L * 60L * 24L * 365L; 
    
  9. You can generate the default constructor automatically. From the Source menu, select Generate Constructor from Fields, click Select All, and then click OK.

    The generated constructor should look similar to the following:

    public Contact(String FirstName, String LastName, Address HomeAddress,
                   Address WorkAddress, Map TelephoneNumbers, Date BirthDate) {
        super();
        this.FirstName = FirstName;
        this.LastName = LastName;
        this.HomeAddress = HomeAddress;
        this.WorkAddress = WorkAddress;
        this.TelephoneNumbers = TelephoneNumbers;
        this.BirthDate = BirthDate;
    } 
    
  10. Implement the readExternal and writeExternal methods as required by the PortableObject interface.

  11. Implement the equals, hashCode, and toString object methods.

  12. The resulting class should look similar to the following.

    Example 4-3 Sample Contact Class

    package com.oracle.handson;
    
    import com.tangosol.io.pof.PortableObject;
     
    import com.tangosol.io.pof.PofReader;
    import com.tangosol.io.pof.PofWriter;
     
    import java.io.IOException;
     
    import java.sql.Date;
     
    import java.util.Iterator;
    import java.util.Map;
     
    public class Contact implements PortableObject
        {
        
           private String FirstName;
           private String LastName;
           private Address HomeAddress;
           private Address WorkAddress;
           private Map TelephoneNumbers;
           private java.sql.Date BirthDate;
        
        // ----- constructors ---------------------------------------------------
     
        /**
        * Default constructor (necessary for PortableObject implementation).
        */
        public Contact()
            {
            }
     
        public Contact(String FirstName, String LastName, Address HomeAddress,
                       Address WorkAddress, Map TelephoneNumbers, Date BirthDate) {
            super();
            this.FirstName = FirstName;
            this.LastName = LastName;
            this.HomeAddress = HomeAddress;
            this.WorkAddress = WorkAddress;
            this.TelephoneNumbers = TelephoneNumbers;
            this.BirthDate = BirthDate;
        }
        
        // -------- accessors --------------------------------------------
     
        public void setFirstName(String FirstName) {
            this.FirstName = FirstName;
        }
     
        public String getFirstName() {
            return FirstName;
        }
     
        public void setLastName(String LastName) {
            this.LastName = LastName;
        }
     
        public String getLastName() {
            return LastName;
        }
     
        public void setHomeAddress(Address HomeAddress) {
            this.HomeAddress = HomeAddress;
        }
     
        public Address getHomeAddress() {
            return HomeAddress;
        }
     
        public void setWorkAddress(Address WorkAddress) {
            this.WorkAddress = WorkAddress;
        }
     
        public Address getWorkAddress() {
            return WorkAddress;
        }
     
        public void setTelephoneNumbers(Map TelephoneNumbers) {
            this.TelephoneNumbers = TelephoneNumbers;
        }
     
        public Map getTelephoneNumbers() {
            return TelephoneNumbers;
        }
     
        public void setBirthDate(Date BirthDate) {
            this.BirthDate = BirthDate;
        }
     
        public Date getBirthDate() {
            return BirthDate;
        }
        /**
        * Get age.
        *
        * @return age
        */
        public int getAge()
            {
            return (int) ((System.currentTimeMillis() - BirthDate.getTime()) /
                    MILLIS_IN_YEAR);
            }
     
     
        // ----- PortableObject interface ---------------------------------------
     
        /**
        * {@inheritDoc}
        */
        public void readExternal(PofReader reader)
                throws IOException
            {
            setFirstName(reader.readString(0));
            setLastName(reader.readString(1));
            setHomeAddress((Address) reader.readObject(2));
            setWorkAddress((Address) reader.readObject(3));
            setTelephoneNumbers(reader.readMap(4, null));
            setBirthDate(new Date(reader.readLong(5)));
            }
     
        /**
        * {@inheritDoc}
        */
        public void writeExternal(PofWriter writer)
                throws IOException
            {
            writer.writeString(0, getFirstName());
            writer.writeString(1, getLastName());
            writer.writeObject(2, getHomeAddress());
            writer.writeObject(3, getWorkAddress());
            writer.writeMap(4, getTelephoneNumbers());
            writer.writeLong(5, getBirthDate().getTime());
            }
     
     
        // ----- Object methods -------------------------------------------------
     
        /**
        * {@inheritDoc}
        */
        public String toString()
            {
            StringBuffer sb = new StringBuffer(getFirstName())
                    .append(" ")
                    .append(getLastName())
                    .append("\nAddresses")
                    .append("\nHome: ").append(getHomeAddress())
                    .append("\nWork: ").append(getWorkAddress())
                    .append("\nTelephone Numbers");
     
            for (Iterator iter = TelephoneNumbers.entrySet().iterator();
                 iter.hasNext(); )
                {
                Map.Entry entry = (Map.Entry) iter.next();
                sb.append("\n")
                   .append(entry.getKey()).append(": ").append(entry.getValue());
                }
            return sb.append("\nBirth Date: ").append(getBirthDate()).toString();
            }
        /**
        * Approximate number of millis in a year ignoring things such as leap
        * years. Suitable for example use only.
        */
        public static final long MILLIS_IN_YEAR = 1000L * 60L * 60L * 24L * 365L;
     
    }
    

4.2.3 Create the Driver Class

Create a driver class called ContactDriver to put Contact entries into the cache and retrieve them.

  1. Create a new Java class called ContactDriver in the Contacts project. Ensure that it includes a main method.

    See "Creating a Java Class" if you need detailed information.

  2. In the ContactDriver file, create a new NamedCache called contact and put a new instance of the Contact object in it. Get the Contact object from the cache and ensure that the two objects are identical.

    Example 4-4 Sample ContactDriver Class

    package com.oracle.handson;
    
    import com.tangosol.net.CacheFactory;
    import com.tangosol.net.NamedCache;
    
    import java.sql.Date;
    
    import java.util.Map;
    import java.util.HashMap;
    
    public class ContactDriver {
        public ContactDriver() {
        }
    
                
        public static void main(String[] args) {
           NamedCache contact = CacheFactory.getCache("contact");
               
           Address homeAddress = new Address ("4157 Wash Ave", "Suite 4",    
                                        "Burlingame", "CA", "94407", "USA");
           Address workAddress = new Address ("500 Oracle Pkwy", "MS989", 
                                        "Redwood Shores", "CA", "94065", "USA");
           Date date = new Date(2009, 04, 01);
           PhoneNumber phonenumber = new PhoneNumber ((short)11, (short)650, (short)506, 7000);
           Map map = new HashMap();
           map.put("home", phonenumber);
                   
           Contact con1 = new Contact("Tom", "Dunn", homeAddress, workAddress, 
                                          map, date);
    
           contact.put(con1.getFirstName(),con1);
     
           Contact con2 = (Contact)contact.get(con1.getFirstName());
    
           if (con2.getFirstName().equals(con1.getFirstName())) {
           System.out.println("They are the same!!");
           } 
        }
    }
    

4.2.4 Create the Configuration Files and Cache Server Executable

To use POF serialization, you must register your user-defined objects in a POF configuration file. The configuration associates the class of a user-defined object with a numeric value. In addition, you must specify POF serialization and the name of the POF configuration file in the cache configuration file.

  1. Create a POF configuration file for the Contact, Address, and PhoneNumber objects.

    To create a POF configuration file for your data types, use the coherence-pof-config.xml file as a model. You can find a copy of this file in the coherence.jar.

    Define <user-type> elements for the Contact, Address, and PhoneNumber objects, assign type IDs 1001, 1002, and 1003 to them and provide their full class names. The file should include the coherence-pof-config.xml file which reserves the first 1000 IDs for Coherence data types.

    Save the file as contacts-pof-config.xml in the C:\home\oracle\labs directory. Save a copy of the coherence-pof-config.xml file in the labs directory as well. Example 4-5 illustrates a sample contacts-pof-config.xml file.

    Example 4-5 POF Configuration File

    <?xml version="1.0"?>
    
    <!DOCTYPE pof-config SYSTEM "pof-config.dtd">
    
    <pof-config>
      <user-type-list>
    
        <!-- coherence POF user types -->
        <include>coherence-pof-config.xml</include>
    
        <!-- com.tangosol.examples package -->
        <user-type> 
          <type-id>1001</type-id> 
          <class-name>com.oracle.handson.Contact</class-name> 
        </user-type> 
        <user-type> 
          <type-id>1002</type-id> 
          <class-name>com.oracle.handson.Address</class-name> 
        </user-type> 
        <user-type> 
            <type-id>1003</type-id> 
          <class-name>com.oracle.handson.PhoneNumber</class-name> 
        </user-type> 
      </user-type-list>
      <allow-interfaces>true</allow-interfaces>
      <allow-subclasses>true</allow-subclasses>
    </pof-config>
    
  2. Create a cache configuration file. You can use the coherence-cache-config.xml file, which is based on the cache-config.dtd as a model. You can find a copy of coherence-cache-config.xml in the coherence.jar.

    Use ExamplesPartitionedPocScheme as the scheme-name and PartitionedPofCache as the service-name. The serializer section is responsible for mapping a POF serialized object to an appropriate serialization routine which is either a PofSerializer or by calling through the PortableObject interface. In this case, use the com.tangosol.io.pof.ConfigurablePofContext class. The <init-param> section points to the name of the POF configuration file, in this case contacts-pof-config.xml.

    Save the file as contacts-cache-config.xml in the C:\home\oracle\labs directory. Save a copy of the cache-config.dtd file in the labs directory as well. Example 4-6 illustrates a sample contacts-cache-config.xml file.

    Example 4-6 Cache Configuration File

    <?xml version="1.0"?>
    
    <!DOCTYPE cache-config SYSTEM "cache-config.dtd">
    
    <cache-config>
      <caching-scheme-mapping>
        <cache-mapping>
          <cache-name>*</cache-name>
          <scheme-name>ExamplesPartitionedPofScheme</scheme-name>
        </cache-mapping>
      </caching-scheme-mapping>
    
      <caching-schemes>
        <distributed-scheme>
          <scheme-name>ExamplesPartitionedPofScheme</scheme-name> 
          <service-name>PartitionedPofCache</service-name> 
          <serializer>  
            <class-name>com.tangosol.io.pof.ConfigurablePofContext</class-name> 
              <init-params> 
                <init-param> 
                  <param-type>String</param-type>  
                  <param-value>contacts-pof-config.xml</param-value> 
                </init-param> 
              </init-params> 
          </serializer>  
          <backing-map-scheme>
            <local-scheme>
              <!-- each node will be limited to 250MB -->
              <high-units>250M</high-units> 
              <unit-calculator>binary</unit-calculator> 
            </local-scheme>
          </backing-map-scheme>
          <autostart>true</autostart>
        </distributed-scheme>
      </caching-schemes>
    </cache-config>
    
  3. Create an executable to start the cache server.

    Name the file contacts-cache-server.cmd and add the following information:

    • the location of the coherence.jar file to the classpath: %COHERENCE_HOME%\lib\coherence.jar

    • the location of the application class files to the classpath: C:\home\oracle\labs\Contacts\classes

    • the location of the POF configuration file to the classpath: C:\home\oracle\labs

    • the location of the server configuration with -Dtangosol.coherence.cacheconfig

    • the command to start the default cache server: com.tangosol.net.DefaultCacheServer

    Example 4-7 illustrates a sample contacts-cache-server.cmd executable file.

    Example 4-7 Sample Cache Server Executable

    @echo off
    setlocal
    
    if (%COHERENCE_HOME%)==() (
        set COHERENCE_HOME=c:\oracle\product\coherence
    ) 
    
    set CONFIG=c:\home\oracle\labs
    
    set COH_OPTS=%COH_OPTS% -server -cp %COHERENCE_HOME%\lib\coherence.jar;C:\home\oracle\labs\Contacts\classes;C:\home\oracle\labs;
    set COH_OPTS=%COH_OPTS% -Dtangosol.coherence.cacheconfig=%CONFIG%\contacts-cache-config.xml
    
    java %COH_OPTS% -Xms1g -Xmx1g -Xloggc: com.tangosol.net.DefaultCacheServer %2 %3 %4 %5 %6 %7
    
    :exit
    

4.2.5 Run the Sample

  1. Compile the Contacts project if you have not done so already.

    Right-click the Contacts project and select Make Contacts.jpr.

  2. Stop any cache servers that may be running.

  3. Start the Contacts cache server by executing contacts-cache-server.cmd on the command line.

    Example 4-8 lists sample output from running contacts-cache-server.cmd.

    Example 4-8 Starting the POF Cache Server

    C:\oracle\product\coherence\bin>contacts-cache-server.cmd
    2010-05-27 13:42:18.826/0.297 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational configuration from "jar:file:/C:/oracle/product/coherence/lib/coherence.jar!/tangosol-coherence.xml"
    2010-05-27 13:42:18.826/0.297 Oracle Coherence 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded operational overrides from "jar:file:/C:/oracle/product/coherence/lib/coherence.jar!/tangosol-coherence-override-dev.xml"
    2010-05-27 13:42:18.826/0.297 Oracle Coherence 3.6.0.0 DPR3 <D5> (thread=main, member=n/a): Optional configuration override "/tangosol-coherence-override.xml" is not specified
    2010-05-27 13:42:18.842/0.313 Oracle Coherence 3.6.0.0 DPR3 <D5> (thread=main, member=n/a): Optional configuration override "/custom-mbeans.xml" is not specified
     
    Oracle Coherence Version 3.6.0.0 DPR3 Build 16141
     Grid Edition: Development mode
    Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
     
    2010-05-27 13:42:19.092/0.563 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Loaded cache configuration from "file:/C:/home/oracle/labs/contacts-cache-config.xml"
    2010-05-27 13:42:19.451/0.922 Oracle Coherence GE 3.6.0.0 DPR3 <D4> (thread=main, member=n/a): SystemSocketProvider bound to port 8088
    2010-05-27 13:42:22.904/4.375 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=Cluster, member=n/a): Created a new cluster "cluster:0xC4DB" with Member(Id=1, Timestamp=2010-05-27 13:42:19.467, Address=130.35.99.213:8088, MachineId=49877, Location=site:us.oracle.com,machine:tpfaeffl-lap7,process:5200, Role=CoherenceServer, Edition=Grid Edition, Mode=Development, CpuCount=2, SocketCount=1) UID=0x822363D500000128DB8051CBC2D51F98
    2010-05-27 13:42:22.920/4.391 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=n/a): Started cluster Name=cluster:0xC4DB
     
    Group{Address=224.3.6.0, Port=36000, TTL=4}
     
    MasterMemberSet
      (
      ThisMember=Member(Id=1, Timestamp=2010-05-27 13:42:19.467, Address=130.35.99.213:8088, MachineId=49877, Location=site:us.oracle.com,machine:tpfaeffl-lap7,process:5200, Role=CoherenceServer)
      OldestMember=Member(Id=1, Timestamp=2010-05-27 13:42:19.467, Address=130.35.99.213:8088, MachineId=49877, Location=site:us.oracle.com,machine:tpfaeffl-lap7,process:5200, Role=CoherenceServer)
      ActualMemberSet=MemberSet(Size=1, BitSetCount=2
        Member(Id=1, Timestamp=2010-05-27 13:42:19.467, Address=130.35.99.213:8088, MachineId=49877, Location=site:us.oracle.com,machine:tpfaeffl-lap7,process:5200, Role=CoherenceServer)
        )
      RecycleMillis=1200000
      RecycleSet=MemberSet(Size=0, BitSetCount=0
        )
      )
     
    TcpRing{Connections=[]}
    IpMonitor{AddressListSize=0}
     
    2010-05-27 13:42:23.029/4.500 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=Invocation:Management, member=1): Service Management joined the cluster with senior service member 1
    2010-05-27 13:42:23.279/4.750 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=Cluster, member=1): Loaded POF configuration from "file:/C:/home/oracle/labs/contacts-pof-config.xml"
    2010-05-27 13:42:23.295/4.766 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=Cluster, member=1): Loaded included POF configuration from "jar:file:/C:/oracle/product/coherence/lib/coherence.jar!/coherence-pof-config.xml"
    2010-05-27 13:42:23.373/4.844 Oracle Coherence GE 3.6.0.0 DPR3 <D5> (thread=DistributedCache:PartitionedPofCache, member=1): Service PartitionedPofCac
    he joined the cluster with senior service member 1
    2010-05-27 13:42:23.388/4.859 Oracle Coherence GE 3.6.0.0 DPR3 <Info> (thread=main, member=1):
    Services
      (
      ClusterService{Name=Cluster, State=(SERVICE_STARTED, STATE_JOINED), Id=0, Version=3.6, OldestMemberId=1}
      InvocationService{Name=Management, State=(SERVICE_STARTED), Id=1, Version=3.1, OldestMemberId=1}
      PartitionedCache{Name=PartitionedPofCache, State=(SERVICE_STARTED), LocalStorage=enabled, PartitionCount=257, BackupCount=1, AssignedPartitions=257,
     BackupPartitions=0}
      )
     
    Started DefaultCacheServer...
    
  4. Set up the POF cache server to run in JDeveloper.

    Add additional CLASSPATH entries to the existing project properties. Navigate to Tools then Project Properties then Libraries and Classpath. Click Add JAR/Directory. In your project, add C:\home\oracle\labs to your CLASSPATH. Ensure that coherence.jar is in the classpath.

    Figure 4-3 Adding Labs and Configuration Files to the Classpath

    Adding Labs and Configuration Files to the Classpath
  5. Click Run/Debug/Profile to edit the run-time properties. Ensure that local storage is disabled. Add the path to the contacts-cache-config.xml file in the Java Options field. The should contain the following:

    -Dtangosol.coherence.distributed.localstorage=false -Dtangosol.coherence.cacheconfig=c:\home\oracle\labs\contacts-cache-config.xml
    

    Click OK to save your changes to the run-time configuration and OK again to dismiss the Project Properties dialog box.

  6. Run ContactDriver.java from the JDeveloper IDE to ensure that it works.

    In this example, the Contact object is converted to POF at run time. Using POF should provide significant performance improvements in terms of CPU time and the size of the binary generated.

    Figure 4-4 Contacts Example Output Run from JDeveloper

    PersonExample Output Run from JDeveloper