显示标签为“Coherence”的博文。显示所有博文
显示标签为“Coherence”的博文。显示所有博文

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

2012年9月21日星期五

Coherence_003:Coherence入门指南之三:通过Java程序访问Cache


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

Coherence中的NamedCache Interface扩展了Map Interface,并提供了很多增值功能:locking & synchronization,storage integration,queries,events aggregations,transactions。
因为NamedCache 是一个接口,因此Cache的实现可以任意切换,而不用改变使用者的代码。
这就是面向接口编程的好处。

Coherence中的CacheFactory是Cache的工厂类,通过它可以获得Cache实例。

重点步骤说明:

1. 创建Coherence应用
(1)选择Custom Application

(2)查看Project Properties,发现Library and Classpath中已经有了Coherence Library。
这是因为之前我们设置了Default Project Properties。 
 同样看到Run/Debug/Profile中也有了DefaultCacheServer的Profile。
 (3)新建一个Profile:NoLocalStorage
因为DefaultCacheServer默认是localstorage=true,但Java程序一般都是作为Client进程,因此单独创建一个 localstorage=fasle的Profile。
其中,在Java Options中增加参数:-Dtangosol.coherence.distributed.localstorage=false -Dtangosol.coherence.log.level=3

2. 创建Java类
(1)MyFirstSample.java,向Cache中Put
package com.oracle.coherence.handson;

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


public class MyFirstSample {
    public MyFirstSample() {
    }

    public static void main(String[] args) {

        // ensure we are in a cluser
        CacheFactory.ensureCluster();

        // create or get a named cache called mycache
        NamedCache myCache = CacheFactory.getCache("mycache");

        // put key, value pair into the cache.
        myCache.put("Name", "Tim Middleton");

        System.out.println("Value in cache is " + myCache.get("Name"));

    }
}
(2)MyFirstSampleReader.java 从Cache中读
package com.oracle.coherence.handson;

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

public class MyFirstSampleReader {

    public MyFirstSampleReader() {
    }

    public static void main(String[] args) {
        // ensure we are in a cluser
        CacheFactory.ensureCluster();

        // create or get a named cache called mycache
        NamedCache myCache = CacheFactory.getCache("mycache");

        System.out.println("Value in cache is " + myCache.get("Name"));
    }
}

(3)CacheInfo.java,查看本地的节点成员 
package com.oracle.coherence.handson;


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

import java.util.Iterator;


public class CacheInfo {
    public CacheInfo() {
    }

    public static void main(String[] args) {

        // create or get a named cache called mycache
        NamedCache myCache = CacheFactory.getCache("mycache");

        // get the information about the cluster and local member
        Cluster cluster = CacheFactory.getCluster();
        Member memberThis = cluster.getLocalMember();

        System.out.println("Local member info: " + memberThis);

        // list all the members - highlighting the curret one
        for (Iterator iter = cluster.getMemberSet().iterator(); iter.hasNext(); ) {
            Member member = (Member)iter.next();

            System.out.println(member + (member.equals(memberThis) ? " <-- this node" : ""));
        }
    }
}

3. 运行

(1)选择运行DefaultCacheServer Profile,作为存储数据的Cache。
(2)选择NoLocalStorage Profile,并运行MyFirstSample。
(3)选择NoLocalStorage Profile,并运行MyFirstSampleReader。
(4)选择NoLocalStorage Profile,并运行CacheInfo。

Project 下载:CoherenceApp(Lab3).7z