2012年9月27日星期四

Glassfish_003:配置ADF Essentials

运行环境:JDeveloper 11.1.2.3.0 + ADF Essentials11.1.2.3.0 + Glassfish3.1.2.2 + Oracle Database 10g Express Edition 10.2.0.1。

ADF Essentials是Oralce推出的ADF精简版,与ADF完整版不同,它是完全免费的。
在Web开发方面,它不包括ADF Security,其它与ADF相同。
另外不包括ADF Desktop,ADF Mobile。

下面介绍一下如何让Glassfish支持ADF Essentials。

1. 为Glassfish添加jar文件
(1)下载adf-essentials.zip
(2)复制到Glassfish的domain的lib目录下,比如C:\Oracle\glassfish-3.1.2.2\glassfish\domains\domain1\lib
(3)在lib目录下运行:unzip -j adf-essentials.zip,会解压出所有需要的jar文件。

2. 启动Glassfish,进行配置
(1)增加JVM Options:-Doracle.mds.cache=simple


(2)增加ConnectionPool:HRConnPool


(3)增加DataSource:jdbc/HRConnDS


3. 开发ADF Web应用
修改AM的Configuration,使用上一步配置的Datasouce。
4. 发布ADF Web应用
右键选择Applicaiton,要发布ear应用,而不能选择ViewController,发布war应用。
说明:发布后发现ear文件超级大,有70多M,其中的war文件的lib中有很多jar文件,不知道是不是能够去掉。

Project 下载:ADF_Essential_Test.7z

参考文献:
1. https://blogs.oracle.com/shay/entry/deploying_oracle_adf_applications_to

JDev_035:与Glassfish集成

运行环境:JDeveloper 11.1.2.3.0 + Glassfish3.1.2.2 + Oracle Database 10g Express Edition 10.2.0.1。

2012年9月24日,JDeveloper 11.1.2.3.0发布,其中一个新特性就是支持集成Glassfish。

1. 为JDeveloper安装Glassfish extension
(1)选中Open Source and Partner Extensions
 (2)选择Glassfish Extension
 (3)重启JDeveloper后,发现多了Glassfish菜单
 (4)配置Glassfish
这里发现了一个Bug,就是最后一项Glassfish Admin URL无法保存设置,永远跟第4项一样。
不过也无所谓了,直接用浏览器访问就是了。

2. 创建Glassfish Server的连接 
(1)新建一个Application Server Connection,选择Glassfish
 (2)管理员
 (3)端口
因为数据库占有了8080端口,所以我把Glassfish的HTTP端口改成了9090。
 (4)测试
虽然第一项失败了,但是不影响发布应用。

3. 创建JavaEEWeb应用,并支持远程Debug
(1)为了能够远程Debug,右键ViewController,设置Run/Debug/Profile,勾上Remote Debugging。

(2)同时,设置监听Glassfish Debug端口,我设置的端口是9009。

4. 启动Debug模式的Glassfish

5. 发布JavaEEWeb应用

6. 远程Debug
(1)右键hello.jsf,选择Debug。
(2)在输入框中,输入一些文字,回车。
(3)JDeveloper停留在断点上

Project 下载:JavaEEWebApp.7z

参考文献:
1. https://blogs.oracle.com/shay/entry/glassfish_extension_for_oracle_jdeveloper

2012年9月25日星期二

Coherence_009:Coherence入门指南之九:与JPA集成

运行环境:JDeveloper 11.1.2.2.0 + Coherence3.7.1 + Oracle Database 10g Express Edition 10.2.0.1。

JPA是数据持久化的标准,Coherence可以作为数据的缓存,如果二者可以结合,岂不完美?
集成的方式有两种:
(1)Coherence在上层,JPA在下层,通过Coherence Cache API 访问和操作数据。
(2)JPA在上层,Coherence在下层,通过Java Persistence API访问和操作数据。
本文介绍的是第一种。

1. 创建JPA
(1)选择Entities from Tables
 (2)选择JPA Entities
  (2)使用默认的Persistence Unit:ConherenceProject
每一个 Persistence Unit定义了JPA Entities、Persistence Provider以及数据库连接信息。
 (3)连接数据库

 (4)选择Employees表
 (5)设置package路径和其它属性,使用默认设置即可

(5)修改persistence.xml
这是改动前的persistence.xml,是JDeveloper帮我们自动生成的。
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
  <persistence-unit name="CoherenceProject">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>java:/app/jdbc/jdbc/HRConnDS</jta-data-source>
    <class>com.oracle.coherence.handson.jpa.Employees</class>
    <properties>
      <property name="eclipselink.target-server" value="WebLogic_10"/>
      <property name="javax.persistence.jtaDataSource" value="java:/app/jdbc/jdbc/HRConnDS"/>
    </properties>
  </persistence-unit>
</persistence>

这是改动后的persistence.xml,为了简单起见,这里我直接使用了JDBC URL的方式连接数据库。
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">
    <persistence-unit name="CoherenceProject">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.oracle.coherence.handson.jpa.Employees</class>
        <properties>
            <property name="eclipselink.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
            <property name="eclipselink.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:XE"/>
            <property name="eclipselink.jdbc.user" value="hr"/>
            <property name="eclipselink.jdbc.password" value="hr"/>
        </properties>
    </persistence-unit>
</persistence>

2. 添加必要的Library
(1)这是添加完成后的样子
(2)在Coherence Library中,添加coherence-jpa.jar
(3)新增Oracle JDBC Library中,添加ojdbc6-g.jar

3.  集成JPA
(1)创建一个XML文件:jpa-cache-config.xml
Coherence是如何与JPA集成的呢?答案就在jpa-cache-config.xml文件中。

<?xml version="1.0" encoding="UTF-8" ?>
<cache-config>
    <caching-scheme-mapping>
        <cache-mapping>
            <!-- Set the name of the cache to be the entity name  -->
            <cache-name>Employees</cache-name>
            <!-- Configure this cache to use the scheme defined below  -->
            <scheme-name>jpa-distributed</scheme-name>
        </cache-mapping>
    </caching-scheme-mapping>
    <caching-schemes>
        <distributed-scheme>
            <scheme-name>jpa-distributed</scheme-name>
            <service-name>JpaDistributedCache</service-name>
            <backing-map-scheme>
                <read-write-backing-map-scheme>
                    <!-- Define the cache scheme -->
                    <internal-cache-scheme>
                        <local-scheme/>
                    </internal-cache-scheme>
                    <cachestore-scheme>
                        <class-scheme>
                            <class-name>com.tangosol.coherence.jpa.JpaCacheStore</class-name>
                            <init-params>
                                <!-- This param is the entity name
                                     This param is the fully qualified entity class
                                     This param should match the value of the persistence unit name in persistence.xml
                                -->
                                <init-param>
                                    <param-type>java.lang.String</param-type>
                                    <param-value>{cache-name}</param-value>
                                </init-param>
                                <init-param>
                                    <param-type>java.lang.String</param-type>
                                    <param-value>com.oracle.coherence.handson.jpa.{cache-name}</param-value>
                                </init-param>
                                <init-param>
                                    <param-type>java.lang.String</param-type>
                                    <param-value>CoherenceProject</param-value>
                                </init-param>
                            </init-params>
                        </class-scheme>
                    </cachestore-scheme>
                </read-write-backing-map-scheme>
            </backing-map-scheme>
            <autostart>true</autostart>
        </distributed-scheme>
    </caching-schemes>
</cache-config>

(2)修改DefaultCacheServer Profile,增加Java Option:-Dtangosol.coherence.cacheconfig=jpa-cache-config.xml

(3)修改NoLocalStorage Profile,增加Java Option:-Dtangosol.coherence.cacheconfig=jpa-cache-config.xml

4.  代码
(1)Employees.java
这是JPA Entity类,是JDeveloper自动帮我们生成的。
其中定义了很多JPA 批注,用于定义如何从数据库读取和存储Employees对象。

(2) RunEmployeeExample.java 测试类
package com.oracle.coherence.handson.jpa;


import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

import java.math.BigDecimal;

public class RunEmployeeExample {
    public RunEmployeeExample() {
    }

    public static void main(String[] args) {
        BigDecimal empId = new BigDecimal(190); // emp 190 - Timothy Gates

        NamedCache employees = CacheFactory.getCache("Employees");

        Employees emp = (Employees)employees.get(empId);

        System.out.println("Employee " + emp.getFirstName() + " " + emp.getLastName() + ", salary = $" +
                           emp.getSalary());

        // give them a 10% pay rise
        emp.setSalary(emp.getSalary().multiply(new BigDecimal(1.1)));

        employees.put(empId, emp);

        Employees emp2 = (Employees)employees.get(empId);

        System.out.println("New Employee details are " + emp2.getFirstName() + " " + emp2.getLastName() +
                           ", salary = $" + emp2.getSalary());
    }
}
说明:
当调用get()获取数据时,首先访问Coherence缓存,如果有则直接得到,如果没有再通过JPA从数据库中获取。
当调用put()修改数据时,Coherence使用JPA持久化数据到数据库。

5.  运行
(1)选择运行DefaultCacheServer Profile,作为存储数据的Cache。
(2)选择NoLocalStorage Profile,并运行 RunEmployeeExample ,会发现employeeId=190的员工的工资涨了10%,进入数据库中查看,发现数据也修改了。

Project 下载:CoherenceApp(Lab9).7z

2012年9月24日星期一

Coherence_008:Coherence入门指南之八:复合主键和Affinity


运行环境:JDeveloper 11.1.2.2.0 + Coherence3.7.1 + Oracle Database 10g Express Edition 10.2.0.1。

在前面的实验中,我们使用的都是单一属性作为Key,在本实验中我们将定义一个主键类作为Key,并且利用Affinity特性,把具有相同属性值的数据放到同一缓存分区中。

1. 代码
(1)PersonComposited.java 可序列化的Person对象,其中定义了一个内部主键类:Key
package com.oracle.coherence.handson;


import com.tangosol.io.ExternalizableLite;
import com.tangosol.net.cache.KeyAssociation;
import com.tangosol.util.ExternalizableHelper;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class PersonComposited implements ExternalizableLite {

    private int id;
    private String surname;
    private String firstname;
    private String address;
    private int age;
    private String gender;

    public static String MALE = "M";
    public static String FEMALE = "F";

    public PersonComposited() {
    }

    public PersonComposited(int id1, String surname1, String firstname1, String address1, int age1, String gender1) {
        super();
        this.id = id1;
        this.surname = surname1;
        this.firstname = firstname1;
        this.address = address1;
        this.age = age1;
        this.gender = gender1;
    }

    public Key getKey() {
        return new Key(this);
    }


    public void setId(int param) {
        this.id = param;
    }

    public int getId() {
        return id;
    }

    public void setSurname(String param) {
        this.surname = param;
    }

    public String getSurname() {
        return surname;
    }

    public void setFirstname(String param) {
        this.firstname = param;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setAddress(String param) {
        this.address = param;
    }

    public String getAddress() {
        return address;
    }

    public void setAge(int param) {
        this.age = param;
    }

    public int getAge() {
        return age;
    }

    public void setGender(String param) {
        this.gender = param;
    }

    public String getGender() {
        return gender;
    }

    public double getAgeDouble() {
        return (double)this.age;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (!(object instanceof PersonComposited)) {
            return false;
        }
        final PersonComposited other = (PersonComposited)object;
        if (id != other.id) {
            return false;
        }
        if (!(surname == null ? other.surname == null : surname.equals(other.surname))) {
            return false;
        }
        if (!(firstname == null ? other.firstname == null : firstname.equals(other.firstname))) {
            return false;
        }
        if (!(address == null ? other.address == null : address.equals(other.address))) {
            return false;
        }
        if (age != other.age) {
            return false;
        }
        if (!(gender == null ? other.gender == null : gender.equals(other.gender))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        final int PRIME = 37;
        int result = 1;
        result = PRIME * result + ((surname == null) ? 0 : surname.hashCode());
        result = PRIME * result + ((firstname == null) ? 0 : firstname.hashCode());
        result = PRIME * result + ((address == null) ? 0 : address.hashCode());
        result = PRIME * result + ((gender == null) ? 0 : gender.hashCode());
        return result;
    }

    public void readExternal(DataInput dataInput) throws IOException {
        this.id = ExternalizableHelper.readInt(dataInput);
        this.surname = ExternalizableHelper.readSafeUTF(dataInput);
        this.firstname = ExternalizableHelper.readSafeUTF(dataInput);
        this.address = ExternalizableHelper.readSafeUTF(dataInput);
        this.gender = ExternalizableHelper.readSafeUTF(dataInput);
        this.age = ExternalizableHelper.readInt(dataInput);
    }

    public void writeExternal(DataOutput dataOutput) throws IOException {
        ExternalizableHelper.writeInt(dataOutput, this.id);
        ExternalizableHelper.writeSafeUTF(dataOutput, this.surname);
        ExternalizableHelper.writeSafeUTF(dataOutput, this.firstname);
        ExternalizableHelper.writeSafeUTF(dataOutput, this.address);
        ExternalizableHelper.writeSafeUTF(dataOutput, this.gender);
        ExternalizableHelper.writeInt(dataOutput, this.age);
    }

    public static class Key implements ExternalizableLite, KeyAssociation {

        // lets define a key of id and version
        private int id;
        private int version;
        private String surname;

        public Key() {
            //for serializble
        }

        public Object getAssociatedKey() {
            return surname;
        }

        public Key(int id, int version) {
            this.id = id;
            this.version = version;
        }

        public Key(PersonComposited p) {
            this.id = p.getId();
            this.version = 1; // default
            this.surname = p.getSurname();  // 运行KeyTest时,这行要注释掉
        }

        public void writeExternal(DataOutput dataOutput) throws IOException {
            ExternalizableHelper.writeInt(dataOutput, this.id);
            ExternalizableHelper.writeInt(dataOutput, this.version);
            ExternalizableHelper.writeSafeUTF(dataOutput, this.surname);
        }

        public void readExternal(DataInput dataInput) throws IOException {
            this.id = ExternalizableHelper.readInt(dataInput);
            this.version = ExternalizableHelper.readInt(dataInput);
            this.surname = ExternalizableHelper.readSafeUTF(dataInput);
        }

        @Override
        public boolean equals(Object object) {
            if (this == object) {
                return true;
            }
            if (!(object instanceof PersonComposited.Key)) {
                return false;
            }
            final PersonComposited.Key other = (PersonComposited.Key)object;
            if (id != other.id) {
                return false;
            }
            if (version != other.version) {
                return false;
            }
            if (surname != other.surname) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            final int PRIME = 37;
            int result = 1;
            return result;
        }
    }
}

(2)KeyTester.java 用于测试复合主键类

package com.oracle.coherence.handson;


import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

public class KeyTester {
    public KeyTester() {
    }

    public static void main(String[] args) {
     
        NamedCache person = CacheFactory.getCache("person");
     
        PersonComposited p = new PersonComposited(1,"Middleton","Tim","Address",29,Person.MALE);
     
        person.put(p.getKey(), p);
     
        //PersonComposited p2 = (PersonComposited)person.get(p.getKey());
        PersonComposited p2 = (PersonComposited)person.get(new PersonComposited.Key(1, 1));
     
        System.out.println("Person is " + p2.getSurname() + " " +  p2.getSurname());
                
    }
}

(3)KeyTester2.java 用于测试Affinity

package com.oracle.coherence.handson;


import com.tangosol.net.CacheFactory;
import com.tangosol.net.DistributedCacheService;
import com.tangosol.net.Member;
import com.tangosol.net.NamedCache;

import java.util.LinkedList;

public class KeyTester2 {
    public KeyTester2() {
    }

    public static void main(String[] args) {
     
        NamedCache person = CacheFactory.getCache("person");
        LinkedList peopleList = new LinkedList();
     
        // build the list
        peopleList.add( new PersonComposited(1,"Flinstone","Fred","Address",29,PersonComposited.MALE));
        peopleList.add( new PersonComposited(2,"Flinstone","Wilma","Address",29,PersonComposited.FEMALE));
        peopleList.add( new PersonComposited(3,"Rubble","Barney","Address",44,PersonComposited.MALE));
        peopleList.add( new PersonComposited(4,"Rubble","Betty","Address",44,PersonComposited.FEMALE));
        peopleList.add( new PersonComposited(5,"Rubble","Dino","Address",44,PersonComposited.FEMALE));
     
        for (java.util.Iterator iterator = peopleList.iterator(); iterator.hasNext();) {
             
                PersonComposited p = (PersonComposited)iterator.next();
                person.put(p.getKey(), p);
         
                Member m = ((DistributedCacheService)person.getCacheService()).getKeyOwner(p.getKey());
                System.out.println("Person " + p.getFirstname() + " " + p.getSurname() +
                                   " is owned by member " + m.getId());
        }
     

    }
}

(4)WhereAreYouProcessor.java 查看数据到底是保存在哪个Cache节点上
package com.oracle.coherence.handson;

import com.tangosol.util.InvocableMap.Entry;
import com.tangosol.util.processor.AbstractProcessor;

public class WhereAreYouProcessor extends AbstractProcessor {
    public WhereAreYouProcessor() {
    }
 
    public Object process(Entry entry ) {
        PersonComposited p = (PersonComposited)entry.getValue();
        System.out.println("\nHello from " + p.getFirstname() + " " + p.getSurname() + "\n");
        return null;
    }
}

(5)EntryProcessorExample.java 执行WhereAreYouProcessor
package com.oracle.coherence.handson;


import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.filter.AlwaysFilter;

import java.util.LinkedList;

public class EntryProcessorExample {
    public EntryProcessorExample() {
    }

    public static void main(String[] args) {
     
        NamedCache person = CacheFactory.getCache("person");
        LinkedList peopleList = new LinkedList();
     
        // build the list
        peopleList.add( new PersonComposited(1,"Flinstone","Fred","Address",29,Person.MALE));
        peopleList.add( new PersonComposited(2,"Flinstone","Wilma","Address",29,Person.FEMALE));
        peopleList.add( new PersonComposited(3,"Rubble","Barney","Address",44,Person.MALE));
        peopleList.add( new PersonComposited(4,"Rubble","Betty","Address",44,Person.FEMALE));
        peopleList.add( new PersonComposited(5,"Rubble","Dino","Address",44,Person.FEMALE));
     
        for (java.util.Iterator iterator = peopleList.iterator(); iterator.hasNext();) {
             
                PersonComposited p = (PersonComposited)iterator.next();
                person.put(p.getKey(), p);          
        }
     
        // now run the entry processor to display where they are!
        person.invokeAll(AlwaysFilter.INSTANCE, new WhereAreYouProcessor());
    }
}

2. 运行
(1)选择运行DefaultCacheServer Profile,作为存储数据的Cache。
(2)选择NoLocalStorage Profile,并运行KeyTester,根据复合主键获取对象。
(3)选择运行DefaultCacheServer Profile,再增加一个Cache节点。
(4)选择NoLocalStorage Profile,并运行KeyTester2,会发现surname相同的数据在同一个Cache节点上。
(5)选择NoLocalStorage Profile,并运行EntryProcessorExample,会发现surname相同的数据在同一个Cache Console中输出。

Project 下载:CoherenceApp(Lab8).7z

Coherence_007:Coherence入门指南之七:并行计算

运行环境:JDeveloper 11.1.2.2.0 + Coherence3.7.1 + Oracle Database 10g Express Edition 10.2.0.1。

在前面的实验中,我们感受了Coherence的缓存特性,在本实验中我们将体验Coherence的并行计算特性。

EntryProcessor是执行计算的代理,它可以对每个Entry执行诸如增加、修改、删除以及计算的操作。
如果同一个Entry上有多个EntryProcessors等待执行,那么其上的操作将排队执行。
Coherence的缓存实现了InvocableMap Interface,包含如下方法:
(1)Object invoke(Object oKey, InvocableMap.EntryProcessor processor),针对某个Key执行Entry Processor,并返回结果。
(2)Map invokeAll(Collection keys, InvocableMap.EntryProcessor processor),针对集合中的Key执行Entry Processor,并返回结果。
(3)Map invokeAll(Filter filter, InvocableMap.EntryProcessor processor),针对满足Filter的Entries执行Entry Processor,并返回结果。

1. 代码
(1)Employee.java 可序列化的员工对象
package com.oracle.coherence.handson;

import com.tangosol.io.ExternalizableLite;
import com.tangosol.util.ExternalizableHelper;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import java.math.BigDecimal;


public class Employee implements  ExternalizableLite {
    private int empId;
    private String surname;
    private String firstname;
    private double salary;
 
     
    public Employee() {
    }

    public Employee(int empId1, String surname1, String firstname1,
                    double salary1) {
        super();
        this.empId = empId1;
        this.surname = surname1;
        this.firstname = firstname1;
        this.salary = salary1;
    }

    public void setEmpId(int param) {
        this.empId = param;
    }

    public int getEmpId() {
        return empId;
    }

    public void setSurname(String param) {
        this.surname = param;
    }

    public String getSurname() {
        return surname;
    }

    public void setFirstname(String param) {
        this.firstname = param;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setSalary(double param) {
        this.salary = param;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (!(object instanceof Employee)) {
            return false;
        }
        final Employee other = (Employee)object;
        if (empId != other.empId) {
            return false;
        }
        if (!(surname == null ? other.surname == null : surname.equals(other.surname))) {
            return false;
        }
        if (!(firstname == null ? other.firstname == null : firstname.equals(other.firstname))) {
            return false;
        }
        if (Double.compare(salary, other.salary) != 0) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        final int PRIME = 37;
        int result = 1;
        result = PRIME * result + ((surname == null) ? 0 : surname.hashCode());
        result = PRIME * result + ((firstname == null) ? 0 : firstname.hashCode());
        long temp = Double.doubleToLongBits(salary);
        result = PRIME * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
 
    public void readExternal(DataInput dataInput) throws IOException {
        this.empId = ExternalizableHelper.readInt(dataInput);  
        this.surname = ExternalizableHelper.readSafeUTF(dataInput);
        this.firstname = ExternalizableHelper.readSafeUTF(dataInput);
        this.salary  = ExternalizableHelper.readBigDecimal(dataInput).doubleValue();

    }

    public void writeExternal(DataOutput dataOutput) throws IOException {
        ExternalizableHelper.writeInt(dataOutput, this.empId);
        ExternalizableHelper.writeSafeUTF(dataOutput, this.surname);
        ExternalizableHelper.writeSafeUTF(dataOutput, this.firstname);
        ExternalizableHelper.writeBigDecimal(dataOutput, new BigDecimal(this.salary));
     
    }
}

(2)RaiseSalary.java 为员工涨10%的Processor操作

package com.oracle.coherence.handson;

import com.tangosol.util.processor.AbstractProcessor;
import com.tangosol.util.InvocableMap.Entry;

import java.util.Map;

public class RaiseSalary extends AbstractProcessor {
    public RaiseSalary() {
    }
 
    public Object process(Entry entry ) {
        Employee emp = (Employee)entry.getValue();
        emp.setSalary(emp.getSalary() * 1.10);
        entry.setValue(emp);
        return null;
    }
}

(3)InvokeTest.java 执行RaiseSalary Processor

package com.oracle.coherence.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.filter.AlwaysFilter;

public class InvokeTest {
    public InvokeTest() {
    }

    public static void main(String[] args) {
     
        NamedCache empCache = CacheFactory.getCache("employees");
     
        Employee e1 = new Employee(1,"Middleton","Tim",5000);
        empCache.put(e1.getEmpId(), e1);
     
        Employee e2 = new Employee(2,"Jones","Chris",10000);
        empCache.put(e2.getEmpId(), e2);
     
        empCache.invokeAll(AlwaysFilter.INSTANCE, new RaiseSalary());
     
        e1 = (Employee)empCache.get(e1.getEmpId());
        e2 = (Employee)empCache.get(e2.getEmpId());
     
        System.out.println("Salary for emp 1 is now: " + e1.getSalary());
        System.out.println("Salary for emp 2 is now: " + e2.getSalary());
     
    }
}

(4)SayHelloProcessor.java 查看数据到底是保存在哪个Cache节点上
package com.oracle.coherence.handson;

import com.tangosol.util.InvocableMap.Entry;
import com.tangosol.util.processor.AbstractProcessor;

public class SayHelloProcessor extends AbstractProcessor {
    public SayHelloProcessor() {

    }

    public Object process(Entry entry) {
        Employee emp = (Employee)entry.getValue();
        System.out.println("\nHello from " + emp.getFirstname() + " " + emp.getSurname() + "\n");
        return null;
    }
}

(5)WhereAreMyEmployees.java 执行SayHelloProcessor
package com.oracle.coherence.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.filter.AlwaysFilter;

public class WhereAreMyEmployees {
    public WhereAreMyEmployees() {
    }

    public static void main(String[] args) {

        NamedCache empCache = CacheFactory.getCache("employees");

        empCache.invokeAll(AlwaysFilter.INSTANCE, new SayHelloProcessor());
    }
}

2. 运行
(1)选择运行DefaultCacheServer Profile,作为存储数据的Cache。
(2)选择NoLocalStorage Profile,并运行InvokeTest,会发现所有员工的工资涨了10%。
(3)选择运行DefaultCacheServer Profile,再增加一个Cache节点。
(4)选择NoLocalStorage Profile,并运行WhereAreMyEmployees,会发现在两个DefaultCacheServer Console中都有员工信息的输出。

Project 下载:CoherenceApp(Lab7).7z

Coherence_006:Coherence入门指南之六:监听器和触发器

运行环境:JDeveloper 11.1.2.2.0 + Coherence3.7.1 + Oracle Database 10g Express Edition 10.2.0.1。

1. MapListener
Coherence的缓存提供了ObservableMap接口用于监听数据,当数据发生变化时,可以采取相应操作。
监听的方法有三个:
(1)void addMapListener(MapListener listener),监听所有的数据对象。
(2)void addMapListener(MapListener listener, Filter filter, boolean fLite),监听满足Filter的数据对象。
(3)void addMapListener(MapListener listener, Object oKey, boolean fLite),监听指定Key的数据对象。
其中,第三个参数fLite=true,表示在MapEvent中是否包括新值和旧值。
监听的事件类型可以通过MapListener来定义:
namedCache.addMapListener(new MapListener() {
    public void entryDeleted(MapEvent mapEvent) {
        //TODO... handle deletion event
    }

    public void entryInserted(MapEvent mapEvent) {
       //TODO... handle inserted event
    }

    public void entryUpdated(MapEvent mapEvent) {
       //TODO... handle updated event
    }
});

1.1 监听器例子代码

(1)ListenForNewPerson.java

package com.oracle.coherence.handson;


import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.MapEvent;
import com.tangosol.util.MapListener;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class ListenForNewPerson {
    public ListenForNewPerson() {
    }

    public static void main(String[] args) throws IOException {
        // connect to named cache
        NamedCache person = CacheFactory.getCache("person");

        // listen for insert events on Person
        // This can be done in an easier way by using a new AbstractMapListener()
        // and then overriding only the method you want to
        //
        person.addMapListener(new MapListener() {
            public void entryDeleted(MapEvent mapEvent) {
                // ignore
            }

            public void entryInserted(MapEvent mapEvent) {
                Person p = (Person)mapEvent.getNewValue();
                System.out.println("New person added: " + p.getFirstname() + " " + p.getSurname());
            }

            public void entryUpdated(MapEvent mapEvent) {
                // ignore
            }
        });


        System.out.println("waiting for events");
        BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
        String text = console.readLine();

    }
}
说明:为了不让程序进程不退出,这里使用了一个“土招”:监听控制台的输入。
如果没有输入,则一直不退出;如果在控制台输入了字符,则立即退出。
注意,为了能够运行时出现Input输入框,需要在NoLocalStorage Profile中,选中Allow Program Input选项。
(2)ListenForUpdatedPerson.java

package com.oracle.coherence.handson;


import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.AbstractMapListener;
import com.tangosol.util.MapEvent;
import com.tangosol.util.filter.EqualsFilter;
import com.tangosol.util.filter.MapEventFilter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class ListenForUpdatedPerson {
    public ListenForUpdatedPerson() {
    }

    public static void main(String[] args) throws IOException {
        // connect to named cache
        NamedCache person = CacheFactory.getCache("person");

        // listen for insert events on Person
        // This can be done in an easier way by using a new AbstractMapListener()
        // and then overriding only the method you want to
        //
        person.addMapListener(new AbstractMapListener() {
                public void entryUpdated(MapEvent mapEvent) {
                    Person oldPerson = (Person)mapEvent.getOldValue();
                    Person newPerson = (Person)mapEvent.getNewValue();

                    // better to implement toString() on the person object to display it.. :)
                    System.out.println("Old person is " + oldPerson.getFirstname() + " " + oldPerson.getSurname());
                    System.out.println("New person is " + newPerson.getFirstname() + " " + newPerson.getSurname());
                }
            }, new MapEventFilter(MapEventFilter.E_UPDATED, new EqualsFilter("getGender", Person.MALE)),
                false) // not a lite event
            ;


        System.out.println("waiting for events");
        BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
        String text = console.readLine();


    }
}

(3)PersonEventTester.java

package com.oracle.coherence.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

public class PersonEventTester {
    public PersonEventTester() {
    }

    public static void main(String[] args) {

        NamedCache person = CacheFactory.getCache("person");

        Person p1 = new Person(1, "Middleton", "Tim", "Level 2, 66 Kings Park Road, West Perth", 39, Person.MALE);

        System.out.println("put person");
        person.put(p1.getId(), p1);

        Person p2 = (Person)person.get(p1.getId());
        p2.setFirstname("Timothy");

        System.out.println("Update person");
        person.put(p2.getId(), p2);
    }
}

1.2 运行监听器例子
(1)选择运行DefaultCacheServer Profile,作为存储数据的Cache。
(2)选择NoLocalStorage Profile,并运行ListenForNewPerson。
(3)选择NoLocalStorage Profile,并运行ListenForUpdatedPerson。
(4)选择NoLocalStorage Profile,并运行PersonEventTester。

2. MapTrigger
MapListener与MapTrigger的区别在于:MapListener是事前行为,即数据发生变化之后的操作。而MapListener是事前行为,即数据发生变化之前的操作。
比如我们可以使用触发器来自动把小写改成大写。

2.1 触发器器例子代码

(1)UppercaseMapTrigger.java

package com.oracle.coherence.handson;

import com.tangosol.util.MapTrigger;

public class UppercaseMapTrigger implements MapTrigger {
    public UppercaseMapTrigger() {
    }


    public void process(MapTrigger.Entry entry) {
        Person person = (Person)entry.getValue();
        String sName = person.getSurname();
        String sNameUC = sName.toUpperCase();

        if (!sNameUC.equals(sName)) {
            person.setSurname(sNameUC);

            System.out.println("Changed last name of [" + sName + "] to [" + person.getSurname() + "]");

            entry.setValue(person);
        }
    }

    // ---- hashCode() and equals() must be implemented

    public boolean equals(Object o) {
        return o != null && o.getClass() == this.getClass();
    }

    public int hashCode() {
        return getClass().getName().hashCode();
    }


}

(2)RunMapTrigger.java

package com.oracle.coherence.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.MapTrigger;
import com.tangosol.util.MapTriggerListener;

public class RunMapTrigger {
    public RunMapTrigger() {
    }

    public static void main(String[] args) {

        NamedCache person = CacheFactory.getCache("person");

        MapTrigger trigger = new UppercaseMapTrigger();
        person.addMapListener(new MapTriggerListener(trigger));

        Person p1 = new Person(1, "jones", "Tom", "Address1", 60, Person.MALE);
        person.put(p1.getId(), p1);

        Person p2 = (Person)person.get(p1.getId());

        System.out.println("Person id = " + p2.getId() + ", surname= " + p2.getSurname());

    }
}

2.2 运行触发器例子
(1)选择运行DefaultCacheServer Profile,作为存储数据的Cache。
(2)选择NoLocalStorage Profile,并运行UppercaseMapTrigger。
(3)选择NoLocalStorage Profile,并运行RunMapTrigger。

3. 一个简单的聊天室例子
通过MapListener,我们可以实现一个简单的聊天室。
基本设计如下:
(1)创建一个Cache,用来监听哪些用户进入或离开了聊天室。
(2)创建另一个Cache,用来监听用户输入的信息。
当然,这样实现的聊天室是一个公共的聊天室,每个人的发言都可以被聊天室中的所有人看到。
你可以在这个例子的基础上,增加聊天用户列表和私聊的功能。

3.1 聊天室代码
(1)ChatMessage.java

package com.oracle.coherence.handson.chat;

import java.io.Serializable;

public class ChatMessage implements Serializable {

    private String from;
    private long entryTime;
    private String message;

    public ChatMessage() {
    }

    public ChatMessage(String from, String message) {
        this.from = from;
        this.message = message;
        this.entryTime = System.currentTimeMillis();
    }


    public void setFrom(String from) {
        this.from = from;
    }

    public String getFrom() {
        return from;
    }

    public void setEntryTime(long entryTime) {
        this.entryTime = entryTime;
    }

    public long getEntryTime() {
        return entryTime;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}

(2)ChatClient.java

package com.oracle.coherence.handson.chat;

import com.tangosol.net.*;

import java.io.*;

import com.tangosol.util.UUID;
import com.tangosol.util.filter.*;
import com.tangosol.util.MapEvent;
import com.tangosol.util.AbstractMapListener;

import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class ChatClient {

    public static void main(String[] args) {
        String userName = null;
        String message;
        NamedCache chatmembers = null;

        try {

            System.out.println("Welcome to the Coherence Chat Client");
            System.out.println("------------------------------------");

            BufferedReader console = new BufferedReader(new InputStreamReader(System.in));

            System.out.print("User Name:");
            userName = console.readLine();

            // join the chatroom named cache as storage enabled = true
            NamedCache cache = CacheFactory.getCache("chatroom");
            chatmembers = CacheFactory.getCache("chatmembers");

            chatmembers.put(userName, userName);

            // register a listener to display the messages
            cache.addMapListener(new AbstractMapListener() {
                    public void entryInserted(MapEvent event) {
                        ChatMessage msg = (ChatMessage)event.getNewValue();

                        System.out.println("From: " + msg.getFrom());
                        System.out.println("Time: " + new Date(msg.getEntryTime()));
                        System.out.println("Mesg: " + msg.getMessage());

                        System.out.println();
                    }
                }, new MapEventFilter(MapEvent.ENTRY_INSERTED, new NotEqualsFilter("getFrom", userName)), false);

            chatmembers.addMapListener(new AbstractMapListener() {
                public void entryDeleted(MapEvent event) {
                    String who = (String)event.getOldValue();
                    System.out.println(who + " has left the chat");
                }

                public void entryInserted(MapEvent event) {
                    String who = (String)event.getNewValue();
                    System.out.println(who + " has entered the chat");
                }
            });

            do {
                System.out.print("\nEnter message or bye to quit: ");
                message = console.readLine();

                if ("bye".equals(message))
                    break;
                // else add this to the chat
                else if ("help".equals(message)) {
                    System.out.println("HELP:");
                    System.out.println("bye - quit");
                    System.out.println("who - list of users in the chat\n");
                } else if ("who".equals(message)) {
                    System.out.println("Current chat memebers");
                    System.out.println("=====================");
                    Set s = chatmembers.entrySet();
                    for (Iterator entries = chatmembers.entrySet().iterator(); entries.hasNext(); ) {
                        Map.Entry entry = entries.next();
                        String member = (String)entry.getValue();

                        System.out.println(member);
                    }
                } else {

                    cache.put(new UUID(), new ChatMessage(userName, message));

                }

            } while (true);

            System.out.println("Bye");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            chatmembers.remove(userName);
        }

    }
}

3.2 运行聊天室例子
(1)选择运行DefaultCacheServer Profile,作为存储数据的Cache。
(2)选择NoLocalStorage Profile,并运行ChatClient。
(3)选择NoLocalStorage Profile,再启动一个ChatClient。
(4)分别在第1和第2个Console输入姓名,然后输入聊天内容,开始聊天。

Project 下载:CoherenceApp(Lab6).7z

Coherence_005:Coherence入门指南之五:查询与统计

运行环境:JDeveloper 11.1.2.2.0 + Coherence3.7.1 + Oracle Database 10g Express Edition 10.2.0.1。

1. 查询
Coherence的缓存提供了QueryMap Interface用于查询,它提供了如下方法:
(1)Set entrySet(Filter filter), 返回Map中满足Filter条件的Entries。
(2)addIndex(ValueExtractor extractor, boolean fOrdered, Comparator comparator) ,增加索引。
被索引的字段不会被序列化,因此可以提高访问速度。
(3)Set keySet(Filter filter) ,与(1)类似,只不过返回的是Keys,而不是values。
说明:Filter是作用在Cache Entry Owner上的,即作用在主分区上,这意味着可以Filter操作并行运行在多个Coherence缓存节点。

2. 统计
Coherence的缓存提供了aggregate方法用于统计,它提供了如下方法:
(1)Object aggregate(Collection keys, InvocableMap.entryAggregator agg),根据集合中的Keys做统计。
(2)Object aggregate(Filter filter, InvocableMap.entryAggregator agg),针对满足Filter条件的Entries做统计。
本实验使用的是(2)。
说明:aggregate操作可以并行运行在多个Coherence缓存节点。

3. 代码
(1)PopulatePeople.java,向Cache中随机存储1000个People对象(不同的年龄、性别)。

package com.oracle.coherence.handson;


import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.extractor.ReflectionExtractor;

import java.io.IOException;

import java.util.Random;


public class PopulatePeople {
    public PopulatePeople() {
    }

    public static void main(String[] args) throws IOException {

        System.setProperty("tangosol.coherence.distributed.localstorage", "false");
        NamedCache person = CacheFactory.getCache("person");

        // add indexes
        person.addIndex(new ReflectionExtractor("getGender"), true, null);
        person.addIndex(new ReflectionExtractor("getAgeDouble"), false, null);

        Random generator = new Random();

        for (int i = 1; i <= 10000; i++) {
            Person p =
                new Person(i, "Surname" + i, "Firstname" + i, "Address" + i, generator.nextInt(100) + 1, (generator.nextInt(2) ==
                                                                                                          1 ?
                                                                                                          Person.FEMALE :
                                                                                                          Person.MALE));
            person.put(p.getId(), p);

        }

        System.out.println(person.entrySet().size());

    }
}

(2)QueryExample.java

package com.oracle.coherence.handson;


import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.filter.AndFilter;
import com.tangosol.util.filter.EqualsFilter;
import com.tangosol.util.filter.GreaterEqualsFilter;

import java.util.Set;

public class QueryExample {
    public QueryExample() {
    }

    public static void main(String[] args) {

        NamedCache person = CacheFactory.getCache("person");

        // get a set of all males
        Set males = person.entrySet(new EqualsFilter("getGender", Person.MALE));

        Set malesOver35 =
            person.entrySet(new AndFilter(new EqualsFilter("getGender", Person.MALE), new GreaterEqualsFilter("getAge",
                                                                                                              35)));

        System.out.println("Total number of males is " + males.size());
        System.out.println("Total number of males > 35 " + malesOver35.size());
    }
}

(3)AggregationExample.java

package com.oracle.coherence.handson;


import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;
import com.tangosol.util.Filter;
import com.tangosol.util.aggregator.DoubleAverage;
import com.tangosol.util.aggregator.DoubleMax;
import com.tangosol.util.filter.AlwaysFilter;
import com.tangosol.util.filter.EqualsFilter;

public class AggregationExample {
    public AggregationExample() {
    }

    public static void main(String[] args) {
        Double averageAgeMales = null;
        Double averageAgeFemales = null;
        Double maxAge = null;
        Double averageAge = null;
        int max = 100;

        NamedCache person = CacheFactory.getCache("person");

        // create a new query

        averageAgeMales =
                (Double)person.aggregate(new EqualsFilter("getGender", Person.MALE), new DoubleAverage("getAge"));

        averageAgeFemales =
                (Double)person.aggregate(new EqualsFilter("getGender", Person.FEMALE), new DoubleAverage("getAge"));

        maxAge = (Double)person.aggregate((Filter)null, // new AlwaysFilter()
                    new DoubleMax("getAge"));

        averageAge = (Double)person.aggregate(new AlwaysFilter(), new DoubleAverage("getAge"));


        System.out.println("Average age of males is " + averageAgeMales);
        System.out.println("Average age of females is " + averageAgeFemales);
        System.out.println("Max age is " + maxAge);
        System.out.println("Average age  " + averageAge);
    }
}

说明:如果想要Filter所有对象,可以使用new AlwaysFilter(),或让Filter=null。

4. 运行
(1)选择运行DefaultCacheServer Profile,作为存储数据的Cache。
(2)选择NoLocalStorage Profile,并运行PopulatePerson。
(3)选择NoLocalStorage Profile,并运行 QueryExample 。
(4)选择NoLocalStorage Profile,并运行 AggregationExample。
(5)选择 DefaultCacheServer Profile,再启动一个Cache节点。
(6)选择NoLocalStorage Profile,再次运行 AggregationExample,统计时间应该快了很多。
注意,如果你的机器是双核CPU,运行(6)才能看出变化比较明显。

Project 下载:CoherenceApp(Lab5).7z

2012年9月23日星期日

Coherence_004:Coherence入门指南之四:访问复杂对象

运行环境:JDeveloper 11.1.2.2.0 + Coherence3.7.1 + Oracle Database 10g Express Edition 10.2.0.1。

上一个实验放到Cache中的是最普通的String类型的对象,在这个实验中将向Cache中放复杂一些的对象。

由于Coherence集群需要通过网络传输对象,并且涉及到读写操作,因此要求对象必须Serializable。
所谓序列化,就是把内存中对象的状态保存在硬盘上的一个二进制的byte序列中,而反序列化则是把该byte序列重新构建为内存中的对象。

1. Person.java

package com.oracle.coherence.handson;


import java.io.Serializable;

public class Person implements Serializable {
 
    private int id;
    private String surname;
    private String firstname;
    private String address;
    private int age;
    private String gender;
 
    public static String MALE = "M";
    public static String FEMALE = "F";
 
    public Person() {
    }

    public Person(int id1, String surname1, String firstname1, String address1,
                  int age1, String gender1) {
        super();
        this.id = id1;
        this.surname = surname1;
        this.firstname = firstname1;
        this.address = address1;
        this.age = age1;
        this.gender = gender1;
    }

    public void setId(int param) {
        this.id = param;
    }

    public int getId() {
        return id;
    }

    public void setSurname(String param) {
        this.surname = param;
    }

    public String getSurname() {
        return surname;
    }

    public void setFirstname(String param) {
        this.firstname = param;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setAddress(String param) {
        this.address = param;
    }

    public String getAddress() {
        return address;
    }

    public void setAge(int param) {
        this.age = param;
    }

    public int getAge() {
        return age;
    }

    public void setGender(String param) {
        this.gender = param;
    }

    public String getGender() {
        return gender;
    }

    public double getAgeDouble() {
        return (double)this.age;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (!(object instanceof Person)) {
            return false;
        }
        final Person other = (Person)object;
        if (id != other.id) {
            return false;
        }
        if (!(surname == null ? other.surname == null : surname.equals(other.surname))) {
            return false;
        }
        if (!(firstname == null ? other.firstname == null : firstname.equals(other.firstname))) {
            return false;
        }
        if (!(address == null ? other.address == null : address.equals(other.address))) {
            return false;
        }
        if (age != other.age) {
            return false;
        }
        if (!(gender == null ? other.gender == null : gender.equals(other.gender))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        final int PRIME = 37;
        int result = 1;
        result = PRIME * result + id;
        result = PRIME * result + ((surname == null) ? 0 : surname.hashCode());
        result = PRIME * result + ((firstname == null) ? 0 : firstname.hashCode());
        result = PRIME * result + ((address == null) ? 0 : address.hashCode());
        result = PRIME * result + age;
        result = PRIME * result + ((gender == null) ? 0 : gender.hashCode());
        return result;
    }
}

2. PersonCache.java

package com.oracle.coherence.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

public class PersonCache {
    public PersonCache() {
    }

    public static void main(String[] args) {

        long startTime = System.currentTimeMillis();

        NamedCache person = CacheFactory.getCache("person");

        Person p1 = new Person(1, "Middleton", "Tim", "Level 2, 66 Kings Park Road, West Perth", 39, Person.MALE);

        person.put(p1.getId(), p1);

        Person p2 = (Person)person.get(p1.getId());

        if (p2.equals(p1)) {
            System.out.println("They are the same!!");
        }

        long endTime = System.currentTimeMillis();

        System.out.println("### Time spend: " + (endTime - startTime));
    }
}

3. PersonAdvanced.java
Coherence特别提供了一个序列化/反序列化的工具类,据说比Java默认的实现速度高6倍。
要使用该工具类,需要实现ExternalizableLite接口,并且重写方法readExternal和writeExternal。

package com.oracle.coherence.handson;


import com.tangosol.io.ExternalizableLite;
import com.tangosol.util.ExternalizableHelper;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

public class PersonAdvanced implements ExternalizableLite {

    private int id;
    private String surname;
    private String firstname;
    private String address;
    private int age;
    private String gender;

    public static String MALE = "M";
    public static String FEMALE = "F";

    public PersonAdvanced() {
    }

    public PersonAdvanced(int id1, String surname1, String firstname1, String address1, int age1, String gender1) {
        super();
        this.id = id1;
        this.surname = surname1;
        this.firstname = firstname1;
        this.address = address1;
        this.age = age1;
        this.gender = gender1;
    }

    public void setId(int param) {
        this.id = param;
    }

    public int getId() {
        return id;
    }

    public void setSurname(String param) {
        this.surname = param;
    }

    public String getSurname() {
        return surname;
    }

    public void setFirstname(String param) {
        this.firstname = param;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setAddress(String param) {
        this.address = param;
    }

    public String getAddress() {
        return address;
    }

    public void setAge(int param) {
        this.age = param;
    }

    public int getAge() {
        return age;
    }

    public void setGender(String param) {
        this.gender = param;
    }

    public String getGender() {
        return gender;
    }

    public double getAgeDouble() {
        return (double)this.age;
    }

    @Override
    public boolean equals(Object object) {
        if (this == object) {
            return true;
        }
        if (!(object instanceof PersonAdvanced)) {
            return false;
        }
        final PersonAdvanced other = (PersonAdvanced)object;
        if (id != other.id) {
            return false;
        }
        if (!(surname == null ? other.surname == null : surname.equals(other.surname))) {
            return false;
        }
        if (!(firstname == null ? other.firstname == null : firstname.equals(other.firstname))) {
            return false;
        }
        if (!(address == null ? other.address == null : address.equals(other.address))) {
            return false;
        }
        if (age != other.age) {
            return false;
        }
        if (!(gender == null ? other.gender == null : gender.equals(other.gender))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        final int PRIME = 37;
        int result = 1;
        result = PRIME * result + ((surname == null) ? 0 : surname.hashCode());
        result = PRIME * result + ((firstname == null) ? 0 : firstname.hashCode());
        result = PRIME * result + ((address == null) ? 0 : address.hashCode());
        result = PRIME * result + ((gender == null) ? 0 : gender.hashCode());
        return result;
    }

    public void readExternal(DataInput dataInput) throws IOException {
        this.id = ExternalizableHelper.readInt(dataInput);
        this.surname = ExternalizableHelper.readSafeUTF(dataInput);
        this.firstname = ExternalizableHelper.readSafeUTF(dataInput);
        this.address = ExternalizableHelper.readSafeUTF(dataInput);
        this.gender = ExternalizableHelper.readSafeUTF(dataInput);
        this.age = ExternalizableHelper.readInt(dataInput);
    }

    public void writeExternal(DataOutput dataOutput) throws IOException {
        ExternalizableHelper.writeInt(dataOutput, this.id);
        ExternalizableHelper.writeSafeUTF(dataOutput, this.surname);
        ExternalizableHelper.writeSafeUTF(dataOutput, this.firstname);
        ExternalizableHelper.writeSafeUTF(dataOutput, this.address);
        ExternalizableHelper.writeSafeUTF(dataOutput, this.gender);
        ExternalizableHelper.writeInt(dataOutput, this.age);
    }
}

4. PersonAdvancedCache.java

package com.oracle.coherence.handson;

import com.tangosol.net.CacheFactory;
import com.tangosol.net.NamedCache;

public class PersonAdvancedCache {
    public PersonAdvancedCache() {
    }

    public static void main(String[] args) {

        long startTime = System.currentTimeMillis();

        NamedCache person = CacheFactory.getCache("person");

        PersonAdvanced p1 = new PersonAdvanced(1, "Middleton", "Tim", "Level 2, 66 Kings Park Road, West Perth", 39, PersonAdvanced.MALE);

        person.put(p1.getId(), p1);

        PersonAdvanced p2 = (PersonAdvanced)person.get(p1.getId());

        if (p2.equals(p1)) {
            System.out.println("They are the same!!");
        }
     
        long endTime = System.currentTimeMillis();

        System.out.println("### Time spend: " + (endTime - startTime));
    }
}

5. 运行
(1)选择运行DefaultCacheServer Profile,作为存储数据的Cache。
(2)选择NoLocalStorage Profile,并运行PersonCache。
(3)选择NoLocalStorage Profile,并运行PersonAdvancedCache。

Project 下载:CoherenceApp(Lab4).7z