48 多言語Coherenceアプリケーションの開発

この章では、CoherenceキャッシュにJavaオブジェクトを移入するJavaアプリケーションを開発し、Oracle GraalVM Enterprise Editionを使用してCoherenceを実行することによって、Coherenceの多言語機能のデモを行います。https://www.oracle.com/graalvmを参照してください。

この機能を使用するには、Oracle GraalVM Enterprise EditionとともにOracle Coherenceをインストールする必要があります。『GraalVM Enterprise EditionでのOracle WebLogic ServerおよびCoherenceの実行』を参照してください。

この章の内容は次のとおりです。

JavaScriptプロジェクトの設定

Coherenceの多言語機能のデモを行うには、CoherenceキャッシュにJavaオブジェクトを移入し、JavaScriptを使用してそれらのキャッシュ・エントリにアクセスし、処理する単純なJavaアプリケーションを開発する必要があります。

Coherenceサーバー側のオブジェクトを含むJavaScriptモジュールをパッケージ化して、記憶域が有効なノードにデプロイする必要があります。最初に、多言語アプリケーションの開発およびパッケージ化に役立つ必要なツールおよびプロジェクト構造を設定します。

この項には次のトピックが含まれます:

webpackおよびwebpack-cliのインストール

webpackおよびwebpack-cliをインストールするには、Node.js (12.6以上)およびノード・パッケージ・マネージャ(npm)がインストールされている必要があります。

  1. プロジェクトにディレクトリを作成し、ディレクトリをこのプロジェクト・ディレクトリに変更します。
    mkdir myapp
    cd myapp
    export PRJ_DIR=`pwd`
    このディレクトリは、シェル変数${PRJ_DIR}によって参照されます。
  2. プロジェクト・ディレクトリで、次のように実行します:
    npm init -y
    このコマンドを実行すると、package.jsonファイルが作成されます。このファイルは後で編集する必要があります。
  3. 次のコマンドを実行して、webpackおよびwebpack-cliをローカルにインストールします。
    npm install --save-dev webpack webpack-cli
    webpackとwebpack-cliをローカルにインストールすると、大幅な変更が行われたときにプロジェクトを個々にアップグレードするのが簡単になります。
  4. package.jsonファイルを編集し、scripts属性を変更します。これにより、npm run buildを実行してアプリケーションをビルドおよびパッケージ化できます。
    {
      "name": "myapp",
      "version": "1.0.0",
      "private": true,
      "scripts": {
        "build": "./node_modules/.bin/webpack --config webpack.config.js --mode production"
      },
      "keywords": [],
      "author": "",
      "devDependencies": {
        "webpack": "^4.41.0",
        "webpack-cli": "^3.3.9"
        }
      }

webpack.config.jsファイルの作成

webpack.config.jsファイルを作成するには:

  1. cdコマンドを使用して、${PRJ_DIR}ディレクトリを開きます。
    cd ${PRJ_DIR}
    
  2. webpack.config.jsというファイルを作成し、次のコードをコピーします。
    const path = require('path');
    module.exports = [
      {
        entry: './src/main.js',
        output: {
          path: path.resolve(__dirname, 'target/scripts/js'),
          filename: 'myapp.js',
          library: 'myapp',
          libraryTarget: 'commonjs2',
        }
      }
    ]
    これは、新規作成されたアプリケーションにmain.jsという単一のJavaScriptモジュールがあり、出力モジュールがtarget/scripts/jsディレクトリにあるmyapp.jsという単一のモジュールであることを示します。

アプリケーション・クラスの実装

アプリケーション・クラスを実装するには、Coherenceキャッシュ内のオブジェクト・エントリにアクセスして更新できるサーバー側のJavaScriptオブジェクトを開発する必要があります。

アプリケーション・クラスの実装例では、firstNamelastNameagegenderなどの属性を持つPersonオブジェクトがキャッシュに移入されることを想定します。

この項には次のトピックが含まれます:

フィルタの使用

NamedCacheには、エントリのキーに基づいてエントリにアクセスできるget()およびput()メソッドがあります。ただし、多くの場合、キー以外の属性に基づいてエントリを取得する必要があります。Coherenceでは、このような状況に対してフィルタ・インタフェースを定義します。

たとえば、13-19の年齢グループで、ティーンエイジャに属するすべてのPersonを検索するとします。これを実装する方法の1つは、すべてのエントリを取得して、年齢が13から19の間のエントリのみを選択することですが、この方法は非効率的です。Coherenceは、述語を記憶域ノードに移動する際に役立ちます。これにより、大量のデータ移動が回避されるだけでなく、記憶域ノードに対する述語のパラレル実行も可能になります。

Coherenceでは、記憶域ノードのエントリにアクセスするための組込みフィルタがいくつか提供されます。「キャッシュ内のデータの問合せ」を参照してください。

この項には次のトピックが含まれます:

フィルタ・インタフェースの使用

フィルタ・インタフェースでは、単一のメソッドevaluate(object)が定義されます。このメソッドは、評価するオブジェクトを引数として受け取り、指定されたオブジェクトがフィルタによって定義された条件を満たす場合はtrueを返し、指定されたオブジェクトがフィルタによって定義された条件を満たさない場合はfalseを返します。

フィルタは、次の条件に従う必要があります。
  1. 1つの引数を受け取るevaluateというメソッドを含むクラスを定義してエクスポートする必要があります。
  2. objがフィルタで表される条件を満たす場合、evaluate(obj)trueを返す必要があります。それ以外の場合は、falseを返す必要があります。
フィルタの実装

Personがティーンエイジャであるかどうかをチェックするフィルタを記述するには:

./src/main.jsに移動し、編集ファイルを編集して次のコンテンツを追加します:

ノート:

このファイルは、webpack.config.jsに記載されています
export class IsTeen { // [1]
  evaluate(person) { // [2]
    return person.age >= 13 && person.age <= 19;
  }
}
このサンプルで注目すべき点は以下のとおりです。
  • [1] IsTeenというクラスを定義し、エクスポートします。
  • [2] 単一のパラメータを受け取るevaluateというメソッドを定義します。このメソッドは、age属性が13から19の間にあるかどうかをチェックします。

EntryProcessorsの使用

Coherenceには、キャッシュ・エントリに対してパラレル更新を実行するのに役立つ組込みのEntryProcessorsが用意されています。「エントリ・プロセッサ・エージェントの概要」を参照してください。

すべてのlastName属性が大文字となるように、キャッシュ・エントリ(この章で使用している例のようにPersonオブジェクトで充填したもの)を更新する場合、すべてのエントリを取得して反復処理し、1つずつ更新して、最終的にキャッシュにライトバックする方法があります。これは非効率的な方法です。Coherenceでは、データが存在する処理ロジックをより効率的に送るアプローチが用意されているため、データ移動の必要性がなくなります。キャッシュ・エントリのパラレル更新をより効率的に実行する必要がある場合は、EntryProcessorを使用する必要があります。

この項には次のトピックが含まれます:

EntryProcessorインタフェースの使用
EntryProcessorは、引数として処理するキャッシュ・エントリを取得し、処理結果を返すprocess(entry)という必須メソッドを定義します。JavaScriptでEntryProcessorを実装するには、クラスが次のようになっている必要があります。
  1. 1つの引数(キャッシュ・エントリ)を受け取るprocessという名前のメソッドを使用して、エクスポートしたクラスを定義します。
  2. process(entry)メソッドでキャッシュ・エントリの値を変更する場合は、エントリ値を明示的に更新する必要があります。
EntryProcessorの実装

lastNameをその大文字値に更新するEntryProcessorを記述します。

main.jsファイルを編集し、次のコンテンツを追加します。

export class UpperCaseProcessor { // [1]
    process(entry) { // [2]
      let person = entry.value;
      person.lastName = person.lastName.toUpperCase(); // [3]
      entry.value = person; // [4]
      return person.lastName; // [5]
    }
}
このサンプルで注目すべき点は以下のとおりです。
  • [1] UpperCaseProcessorというクラスを定義し、エクスポートします。
  • [2] 単一のパラメータを受け取るprocess()というメソッドを定義します。処理が必要なNamedCacheエントリは、このメソッドに渡されるentry引数を通じてアクセス可能です。
  • [3] 人物のlastNameを大文字に変換します。
  • [4] entryを新しい値で更新します。
  • [5] 更新された(大文字の)姓をプロセッサの実行結果として戻します。

ValueExtractorsの使用

ValueExtractorは、オブジェクトから値を抽出する場合に使用します。「問合せの概念」を参照してください。

この項には次のトピックが含まれます:

ValueExtractorインタフェースの使用

ValueExtractorインタフェースは、extract(value)という1つのメソッドを定義します。これは、値の抽出元となる1つの引数を受け取り、抽出された値を戻します。

ValueExtractorの作成

Personオブジェクトからage属性を抽出するValueExtractorを定義するには:

ディレクトリを${PRJ_DIR}/src/main/jsに変更します。main.jsファイルを編集し、次のコンテンツを追加します。

export class AgeExtractor { // [1]
  extract(value) { // [2]
    return value.age; // [3]
  }
}
このサンプルで注目すべき点は以下のとおりです。
  • [1] AgeExtractorというクラスを定義し、エクスポートします。
  • [2] 単一のパラメータを受け取るextractというメソッドを定義します。
  • [3] valueのage属性を返します。

Aggregatorの使用

Coherence Aggregatorを使用して、特定の基準に基づいて、キャッシュから単一の集計結果を取得できます。

たとえば、この章の前の例で作成したCache内の最も古いPersonのキーを取得します。すべてのエントリを取得し、最大年齢のPersonを探すことができますが、ロット・データがクライアントに移動されることがわかります。Coherenceでは、部分的な結果を計算し、それらの部分的な結果を結合して単一の集計結果を取得できるAggregatorインタフェースを定義します。データ・グリッドの集計の実行を参照してください。

この項には次のトピックが含まれます:

Aggregatorインタフェースの使用

Aggregatorインタフェースでは、次のメソッドを実装する必要があります。

  1. accumulate(entry): すべてのメンバーに対してパラレルに実行し、単一エントリをそのメンバーの部分的な結果に累計します。このメソッドでは、部分的な結果は、エントリの1つ以上の属性を使用して計算されます。このメソッドは、特定のクラスタ・メンバーでの集計用に選択されたエントリごとに1回、Aggregatorに対して複数回呼び出されます。
  2. getPartialResult(): 各メンバーからのパラレル集計の部分的な結果を戻します。
  3. combine(partialResult): 各クラスタ・メンバーから返された部分的な結果を最終結果に結合します。このメソッドでは、部分的な結果は、エントリの1つ以上の属性を使用して計算されます。このメソッドは、各クラスタ・メンバーの部分的な結果について1回ずつ、ルート集計機能インスタンスに対して複数回呼び出されます。
  4. finalizeResult(): 集計の最終結果を計算し、返します。
Aggregatorの記述

最も古いPersonのキーを戻すAggregatorを定義するには、main.jsファイルを編集して、次のコンテンツを追加します。

export class OldestPerson {
  constructor() {
    this.key = -1;
    this.age = 0;
  }
  accumulate(entry) {
    // Compare this entry's age with the result computed so far.    
    if (entry.value.age > this.age) {
      this.key = entry.key;
      this.age = entry.value.age;
    }
    return true;
  }
  getPartialResult() {
    // Return the partial result accumulated / computed so far.
    return JSON.stringify({key:this.key, age:this.age});
  }
  combine(partialResult) {
    // Compute a (possibly) new result from the perviously computed
    // partial result.
    let p = JSON.parse(partialResult);
    if (p.age > this.age) {
      this.key = p.key;
      this.age = p.age;
    }
    return true;
  }
  finalizeResult() {
    // Return the final computed result.
    return this.key;
  }
}

依存関係のインストールおよび使用

リアルタイム環境では、日時操作にlodashモジュールまたはmomentモジュールを使用できます。npm installを使用して依存関係をインストールする既知のアプローチを使用し、require()関数を使用して依存関係を使用できます。

次に、lodashモジュールの使用例を示します。

const _ = require('lodash')
export class InitCaseProcessor {
  process(entry) {
    let value = entry.value;
    value.firstName = _.startCase(_.toLower(value.firstName));
    value.lastName = _.startCase(_.toLower(value.lastName));
    entry.value = value;
    return value.lastName;
  }
}

lodashモジュールをインストールするには、次のコマンドを使用します。

cd ${PRJ_DIR}/src
npm install lodash

マルチソース・プロジェクトの作成

複雑なプロジェクトでは、クラスを複数のモジュール(ソース・ファイル)に分割できます。複数のソース・ファイルがある場合は、ソース・ファイルをトランスパイルして出力ディレクトリにバンドルできるように、そのソース・ファイルについてwebpackに指示する必要があります。

フィルタおよび集計機能に個別のソース・ファイルを指定するwebpack.config.jsファイルを次に示します。

const path = require('path');
module.exports = [
  {
    entry: {
      filters: './src/filters.js',
      aggregators: './src/aggregators.js'
    }
  },
  output: {
    filename: '<name>.js',
    path: __dirname + '/dist'
    library: '<name>',
    libraryTarget: 'commonjs2',
  }
]

ノート:

この例の<name>エントリを、jsファイルの実際の名前で置き換えます。

JavaScriptモジュールの作成とパッケージ化

JavaScriptモジュールをビルドし、それらの依存関係とともにパッケージ化できます。
次のコマンドを使用して、JavaScriptモジュールを作成およびパッケージ化します:
cd ${PRJ_DIR}
npm run build

単一ソース・プロジェクトとマルチ・ソース・プロジェクトのどちらがあるかに関係なく、「マルチソース・プロジェクトの作成」で説明したwebpack.config.js設定ファイルを使用して、webpackはtarget/scripts/jsディレクトリ内で1つ以上の最適化されたJavaScriptファイルをコンパイル、トランスパイルおよび作成します。target/scripts/jsディレクトリには、JavaScriptモジュールだけでなく、すべての依存関係が含まれます。つまり、target/scripts/js directoryは自己充足的です。

JavaScriptモジュールの自動事前ロード

記憶域が有効なCoherenceメンバーが起動されると、scripts/jsディレクトリ(クラスパス内)の下に存在するすべてのJavaScriptファイルが自動的に評価され、内部マップに登録されます。マップ・キーはクラスのエクスポートされた名前で、マップ値はクラス・オブジェクトです。これらの名前は、対応するクラスを実行するためにscript() APIで使用できます。

ノート:

scripts/jsの親ディレクトリがクラスパスに存在する必要があります。

クラスパスに${PRJ_DIR}/targetを追加するか、またはjarファイルのルートにscriptsディレクトリを含むjarファイルを作成できます。

クラスパスの設定と記憶域が有効なサーバーの起動

クラスパスを設定し、記憶域が有効なサーバーを起動するには、次のコマンドを実行します。

ノート:

scripts/jsの親ディレクトリがクラスパスに存在する必要があります。事前ロードが機能するためにはスクリプト/jsの親ディレクトリがクラスパスに存在する必要があるため、新しいターミナル・ウィンドウで次のコマンドを実行して、Coherenceを起動する必要があります。
CP=${COHERENCE_HOME}/lib/coherence.jar
CP=${PRJ_DIR}/target:/myapp.jar:${CP}
CP=${PRJ_DIR}/target:${CP}
java -cp ${CP} com.tangosol.net.DefaultCacheServer

${COHERENCE_HOME}はCoherenceのインストール・ディレクトリです。必要な数のサーバーを実行できますが、この例では1つのサーバーを実行するだけで十分です。

ノート:

Myapp.jarは、myapp-client Javaプロジェクトのものです。Javaプロジェクトの作成手順は、「JavaアプリケーションでのJavaScriptオブジェクトの使用」を参照してください。この例を使用するには、このファイルをmyapp-client/targetからmyapp/targetにコピーする必要があります。

JavaアプリケーションでのJavaScriptオブジェクトの使用

JavaScriptオブジェクトを使用するJavaクラスを記述することで、多言語アプリケーションの作成を完了する必要があります。

この項には次のトピックが含まれます:

Javaプロジェクトの作成

前提条件:

Graal VMとmaven-3.5+がインストールされている必要があります。

Javaプロジェクトを作成するには:

  • 新しいターミナル・ウィンドウを開き、新しいディレクトリを作成します。
    mkdir myapp-client
    cd myapp-client
    export JAVA_PRJ_DIR=`pwd`
    cd ${JAVA_PRJ_DIR}
    mkdir -p src/main/java
  • pom.xmlを作成し、次の内容をコピーします。
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.oracle.coherence.example</groupId>
      <artifactId>myapp</artifactId>
      <version>1.0.0-SNAPSHOT</version>
      
      <name>Coherence Graal Demo</name>
      
      <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
        
        <graal.version>19.1.1</graal.version>  
        <coherence.version>14.1.1.-2206-1</coherence.version>
      </properties>
      
      <dependencies>
        <dependency>
          <groupId>${coherence.groupId}</groupId>
          <artifactId>coherence</artifactId>
          <version>${coherence.version}</version>
        </dependency>
       </dependencies>
      
       <build>
        <plugins>
         <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.1</version>
          <configuration>
            <source>1.8</source>
            <target>1.8</target>
          </configuration>
         </plugin>
        </plugins>
       </build>
    
    </project>

キャッシュの移入

NamedCacheを作成して「アプリケーション・クラスの実装」で説明されているPersonオブジェクトを移入するJavaクラスを作成する必要があります。

この項には次のトピックが含まれます:

Person Javaクラスの定義

キャッシュの移入に使用するPersonクラスを定義するには:

cd ${JAVA_PRJ_DIR}/src/main/java
mkdir -p com/oracle/coherence/example

${JAVA_PRJ_DIR}/src/main/java/com/oracle/coherence/exampleディレクトリの下にPerson.javaというファイルを作成し、次のコンテンツを貼り付けます。

package com.oracle.coherence.example;

import java.io.Serializable;

public class Person
  implements Serializable
  {
  Person()
    {
    }

  Person(String firstName, String lastName, String gender, int age)
    {
    m_sFirstName = firstName;
    m_sLastName = lastName;
    m_sGender = gender;
    m_iAge = age;
    }

  public String getLastName()
    {
    return m_sLastName;
    }

  public void setLastName(String sLastName)
    {
    m_sLastName = sLastName;
    }

  public String getFirstName()
    {
    return m_sFirstName;
    }

  public void setFirstName(String sFirstName)
    {
    m_sFirstName = sFirstName;
    }

  public String getGender()
    {
    return m_sGender;
    }

  public void setGender(String sGender)
    {
    m_sFirstName = sGender;
    }

  public int getAge()
    {
    return m_iAge;
    }

  public void setAge(int iAge)
    {
    m_iAge = iAge;
    }

  // ----- Object methods --------------------------------------------------

  @Override
  public String toString()
    {
    return "Person{" +
            "first name='" + m_sFirstName + '\'' +
            "last name='" + m_sLastName + '\'' +
            ", age=" + m_iAge +
            ", gender='" + m_sGender +
            '}';
    }

  private String m_sFirstName;
  private String m_sLastName;
  private String m_sGender;
  private int    m_iAge;
  }
Coherenceキャッシュの移入

Coherenceキャッシュに移入するには:

${JAVA_PRJ_DIR}/src/main/java/com/oracle/coherence/exampleディレクトリの下にMyAppClient.javaというファイルを作成し、次の内容を追加します。

package com.oracle.coherence.example;

public class MyAppClient
  {
  public NamedCache<Integer, Person> getCache()
    {
    return CacheFactory.getTypedCache("DemoCache", TypeAssertion.withTypes(Integer.class, Person.class));
    }
  
  public void populateCache()
    {
    Map<Integer, Person> persons = new HashMap<>();
    persons.put(1, new Person("Ashley", "Jackson", "Female", 84));
    persons.put(2, new Person("John", "Campbell", "Male", 36));
    persons.put(3, new Person("Jeffry", "Trayton", "Male", 95));
    persons.put(4, new Person("Florence", "Campbell", "Female", 35));
    persons.put(5, new Person("Kevin", "Kelvin", "Male", 15));
    persons.put(5, new Person("Jane", "Doe", "Female", 17));
    getCache().putAll(persons);
    System.out.println("Populated cache with " + getCache().size() + " entries");
    }
アプリケーションの実行

アプリケーションを実行するには、まずCoherenceサーバーを起動し、次のコードを使用してキャッシュに少数のPersonオブジェクトを移入する必要があります。

cd ${JAVA_PRJ_DIR}
mvn clean install
cp -rf ${PRJ_DIR}/target/scripts ${CLIENT_PRJ_DIR}/target

CP=${COHERENCE_HOME}/lib/coherence.jar
CP=${PRJ_DIR}/target/myapp-client.jar:${CP}
CP=${PRJ_DIR}/target:${CP}
java -Dstore.storageEnabled=false -cp ${CP} com.tangosol.net.DefaultCacheServer

Javaからのサーバー側JavaScriptオブジェクトの起動

ここで、クライアント・アプリケーションを拡張して、サーバー側のJavaScriptオブジェクトにアクセスする必要があります。更新されたアプリケーションを実行するには、「アプリケーションの実行」を参照してください。

この項には次のトピックが含まれます:

JavaScriptフィルタの起動

JavaScriptで記述されたFilterは、com.tangosol.util.Filtersクラスのscript()メソッドを呼び出すことでインスタンス化できます。次のように定義されます。

public static <V> Filter<V> script(String language,
                                   String filterName,
                                   Object... args);

最初の引数は、スクリプトが実装されている言語を指定するために使用されます。JavaScriptの場合は、jsを使用します。2番目の引数はFilterexported名を指定するために使用し、最後の引数(可変の数の引数)はフィルタにコンストラクタ引数を渡すために使用できます。たとえば、クラスでコンストラクタを定義する場合、使用する引数を渡すことができます。

次をMyAppClient.javaに追加します。

public void displayTeens()
    {
    getCache().getAll(Filters.script("js", "IsTeen")) // Use our "Teen Filter"
              .stream()
              .forEach(System.out::println);
    }
これで、次のようにメイン・メソッドを変更できます。
public static void main(String[] args)
    {
    MyAppClient appClient = new MyAppClient();
    appClient.populateCache();
    appClient.displayTeens();
    }
JavaScript EntryProcessorを使用したパラレル更新の実行

JavaScriptで記述されたEntryProcessorは、com.tangosol.util.Processorsクラスのscript()メソッドを呼び出すことでインスタンス化できます。次のように定義されます。

public static <K, V, R> EntryProcessor<K, V, R> script(String language,
                                                           String processorName,
                                                           Object... args);

次をMyAppClient.javaに追加します。

public void toInitCase()
     {
     // Make Updates using our "InitCaseProcessor"
     getCache().invokeAll(Processors.script("js", "UpperCaseProcessor"));

     // Display updated entries
     getCache().values()
               .forEach(System.out::println);
     }
フィルタでのValueExtractorの使用

ValueExtractorは、汎用フィルタの作成に使用されます。たとえば、BetweenFilterではValueExtractorと2つの値を受け取り、抽出した値がこの2つの値の間にある必要があるかどうかをチェックします。

public static <T, E> ValueExtractor<T, E> script(String language,
                                       String extractorName,
                                       Object... args);

次をMyAppClient.javaに追加します。

public void getPersonsInTeens()
    {
    // Construct a BetweenFilter with our AgeExtractor
    BetweenFilter filter = (BetweenFilter) Filters.between(
            Extractors.script("js", "AgeExtractor"), 13, 19);
    // Retrieve entries using our filter
    getCache().values(filter)
            .forEach(System.out::println);
    }
Aggregatorの実行

JavaScriptで記述されたAggregatorは、com.tangosol.util.Aggregatorsクラスのscript()メソッドを呼び出すことでインスタンス化できます。

最高齢の男性や女性を見つけるには、組込み集計機能とともにOldestPersonフィルタを使用します。

次をMyAppClient.javaに追加します。

public void oldestPersons()
    {
    int oldestMaleKey = getCache().aggregate(Filters.equal("gender", "Male"),
            Aggregators.script("js", "OldestPerson"));
    int oldestFemaleKey = getCache().aggregate(Filters.equal("gender", "Female"),
            Aggregators.script("js", "OldestPerson"));

    System.out.println("Oldest Male : " + getCache().get(oldestMaleKey));
    System.out.println("Oldest Female: " + getCache().get(oldestFemaleKey));
    }

完全なMyAppClient.javaファイルを次に示します:

package com.oracle.coherence.example;

import com.tangosol.net.NamedCache;
import com.tangosol.net.CacheFactory;
import com.tangosol.net.cache.TypeAssertion;
import com.tangosol.util.Aggregators;
import com.tangosol.util.Extractors;
import com.tangosol.util.Filters;
import com.tangosol.util.Processors;
import com.tangosol.util.filter.BetweenFilter;

import java.util.HashMap;
import java.util.Map;

public class MyAppClient
  {
  public NamedCache<Integer, Person> getCache()
    {
    return CacheFactory.getTypedCache("DemoCache", TypeAssertion.withTypes(Integer.class, Person.class));
    }
  
  public void populateCache()
    {
    Map<Integer, Person> persons = new HashMap<>();
    persons.put(1, new Person("Ashley", "Jackson", "Female", 84));
    persons.put(2, new Person("John", "Campbell", "Male", 36));
    persons.put(3, new Person("Jeffry", "Trayton", "Male", 95));
    persons.put(4, new Person("Florence", "Campbell", "Female", 35));
    persons.put(5, new Person("Kevin", "Kelvin", "Male", 15));
    persons.put(5, new Person("Jane", "Doe", "Female", 17));
    getCache().putAll(persons);
    System.out.println("Populated cache with " + getCache().size() + " entries");
    }

  public void displayTeens()
    {
    getCache().values(Filters.script("js", "IsTeen")) // Use our "Teen Filter"
            .stream()
            .forEach(System.out::println);
    }

  public void getPersonsInTeens()
    {
    // Construct a BetweenFilter with our AgeExtractor
    BetweenFilter filter = (BetweenFilter) Filters.between(
            Extractors.script("js", "AgeExtractor"), 13, 19);
    // Retrieve entries using our filter
    getCache().values(filter)
            .forEach(System.out::println);
    }

  public void oldestPersons()
    {
    int oldestMaleKey = getCache().aggregate(Filters.equal("gender", "Male"),
            Aggregators.script("js", "OldestPerson"));
    int oldestFemaleKey = getCache().aggregate(Filters.equal("gender", "Female"),
            Aggregators.script("js", "OldestPerson"));

    System.out.println("Oldest Male : " + getCache().get(oldestMaleKey));
    System.out.println("Oldest Female: " + getCache().get(oldestFemaleKey));
    }

  public void toInitCase()
    {
    // Make Updates using our "InitCaseProcessor"
    getCache().invokeAll(Processors.script("js", "UpperCaseProcessor"));

    // Display updated entries
    getCache().values()
            .forEach(System.out::println);
    }

  // ----- data members ----------------------------------------------------

  public static void main(String[] args)
    {
    MyAppClient appClient = new MyAppClient();
    appClient.populateCache();
    System.out.println("------------ Display Teens    -------------------");
    appClient.displayTeens();
    System.out.println("------------ Get Teens        -------------------");
    appClient.getPersonsInTeens();
    System.out.println("------------ To Upper Case    -------------------");
    appClient.toInitCase();
    System.out.println("------------ Oldest Persons   -------------------");
    appClient.oldestPersons();
    }
  }