プライマリ・コンテンツに移動
Oracle® Fusion Middleware Oracle Coherenceリモート・クライアントの開発
12c (12.2.1)
E69907-02
目次へ移動
目次

前
次

11 統合オブジェクトの構築(C++)

この章では、C++クライアント作成時にPortable Object Format (POF)シリアライズ形式を使用する手順を説明します。

注意:

このドキュメントでは、仕様に基づくクラス定義などの高度な概念も含め、CoherenceのC++オブジェクト・モデルに精通していると想定しています。これらのトピックの詳細は、「CoherenceのC++オブジェクト・モデルの使用方法」を参照してください。

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

統合オブジェクトの構築(C++)の概要

C++クライアントを有効にしてCoherenceクラスタにC++ベースのオブジェクトを正しく格納するには、POF (Portable Object Format)という、プラットフォームに依存しないシリアライズ形式が必要です。POFを使用すると、値オブジェクトのプラットフォームおよび元の言語と関係ない方法で、値オブジェクトをバイナリ・ストリームにエンコードできます。このストリームは、類似するPOFベースのクラス定義を使用して、別の言語でデシリアライズできます。POFバイナリ・ストリームの詳細は、『Oracle Coherenceでのアプリケーションの開発』を参照してください。

Coherence C++ APIにはPOFシリアライズ可能クラスがいくつか用意されていますが、カスタムのデータ型ではこの章で説明するようにシリアライズのサポートが必要です。

POFの組込み型

次の型はPOFで内部的にサポートされているので、ユーザー側で特別な処理をする必要はありません。

  • String

  • Integer16 ..Integer64

  • Float32、Float64

  • プリミティブの配列<>

  • ObjectArray

  • Boolean

  • Octet

  • Character16

また、次の一般的なインタフェースを実装するクラスでは自動POFシリアライズが可能です。

  • Map

  • Collection

  • Exception

シリアライズの各オプション

Coherence C++ APIが備えているシリアライズ形式は1つのみ(POF)ですが、クラスをシリアライズ可能にするAPIは多数用意されています。どのようなアプローチを採用しても、最終的には同じバイナリPOF形式が生成されます。クラスをシリアライズ可能にするには、次のアプローチを利用できます。

  • Managed<T>アダプタ・テンプレートを使用して、外部の自由関数シリアライザを追加します。詳細は、「Managed<T>(自由関数シリアライズ)」を参照してください。

  • データ・オブジェクトを変更してObjectを拡張し、PortableObjectインタフェースを実装して、オブジェクトで自己シリアライズができるようにします。詳細は、「PortableObject (自己シリアライズ)」を参照してください。

  • データ・オブジェクトを変更してObjectを拡張し、PofSerializerクラスを作成して外部シリアライズを実行します。詳細は、「PofSerializer (外部シリアライズ)」を参照してください。

表11-1 は、それぞれのアプローチの要件と制限をいくつか示しています。

表11-1 シリアライズの各オプションの要件と制限

アプローチ データ・オブジェクトのCoherenceヘッダー Objectからの派生の必要性 constデータ・メンバーのサポート 外部シリアライズ・ルーチン 引数がないコンストラクタの必要性

Managed<T>

なし

なし

あり

あり

あり

PortableObject

あり

あり

なし

なし

あり

PofSerializer

あり

あり

あり

あり

なし

これらのアプローチにはすべて、次のような共通点があります。

  • データ・アイテムをPOFにエンコードできるようにするシリアライズ・ルーチンを実装する必要があります。

  • データ・オブジェクトのフィールドを特定するには、数値インデックスを使用します。

  • データ・オブジェクト・クラスとシリアライズのメカニズムをCoherenceに登録する必要があります。

  • キャッシュ・キーとして使用するデータ・オブジェクトは、等価比較とハッシュをサポートしている必要があります。

Managed<T>(自由関数シリアライズ)

既存のデータ・オブジェクト・クラスのほとんどでは、Managed<T>を使用すると、最も容易にCoherence for C++に統合できます。

非管理クラスがManaged<T>と互換性を持つようにするには、そのクラスに次のような特性があることが必要です。

  • パラメータのないコンストラクタ(publicまたはprotected): CustomType::CustomType()

  • コピー・コンストラクタ(publicまたはprotected): CustomType::CustomType(const CustomType&)

  • 等価比較の演算子: ブール演算子==(const CustomType&, const CustomType&)

  • std::ostream出力関数: std::ostream& operator<<(std::ostream&, const CustomType&)

  • ハッシュ関数: size_t hash_value(const CustomType&)

次の例は、簡単なAddressクラスを示しています。このクラスは、Coherenceの直接の知識は不要ですが、Managed<T>テンプレートでの使用に適しています。

注意:

見やすさを考慮して、ここではクラス定義の例を宣言の中に記述しています。

例11-1 非管理クラス

#include <iostream>
#include <string>
using namespace std;

class Address
  {
  public:
    Address(const std::string& sCity, const std::string& sState, int nZip)
       : m_sCity(sCity), m_sState(sState), m_nZip(nZip) {}

    Address(const Address& that) // required by Managed<T>
       : m_sCity(that.m_sCity), m_sState(that.m_sState), m_nZip(that.m_nZip) {}

  protected:
    Address() // required by Managed<T>
      : m_nZip(0) {}

  public:
    std::string  getCity()  const {return m_sCity;}
    std::string  getState() const {return m_sState;}
    int          getZip()   const {return m_nZip;}

  private:
    const std::string m_sCity;
    const std::string m_sState;
    const int         m_nZip;
  };

bool operator==(const Address& addra, const Address& addrb) // required by Managed<T>
  {
  return addra.getZip()   == addrb.getZip() &&
         addra.getState() == addrb.getState() &&
         addra.getCity()  == addrb.getCity();
  }

std::ostream& operator<<(std::ostream& out, const Address& addr) // required by Managed<T>
  {
  out << addr.getCity() << ", " << addr.getState() << "  " << addr.getZip();
  return out;
  }

size_t hash_value(const Address& addr) // required by Managed<T>
  {
  return (size_t) addr.getZip();
  }

Managed<T>と組み合せたこの簡単なクラス定義は、真の管理オブジェクトとなり、Coherence C++ APIで使用できるようになります。この定義のみでは、まだシリアライズに対処できません。例11-2 では、シリアライズのサポートが追加されています。

例11-2 シリアライズを使用した管理クラス

#include "coherence/io/pof/SystemPofContext.hpp"

#include "Address.hpp"

using namespace coherence::io::pof;

COH_REGISTER_MANAGED_CLASS(1234, Address); // type ID registration—this must
                                           // appear in the .cpp not the .hpp 

template<> void serialize<Address>(PofWriter::Handle hOut, const Address& addr)
  {
  hOut->writeString(0, addr.getCity());
  hOut->writeString(1, addr.getState());
  hOut->writeInt32 (2, addr.getZip());
  }

template<> Address deserialize<Address>(PofReader::Handle hIn)
  {
  std::string sCity  = hIn->readString(0);
  std::string sState = hIn->readString(1);
  int         nZip   = hIn->readInt32 (2);
  return Address(sCity, sState, nZip);
  }

注意:

このシリアライズ・ルーチンでは、Coherenceの知識が必要です。ただし、クラス定義ファイルの中に記述する必要はありません。独立したソース・ファイルに記述してもかまいません。最終的なアプリケーションでそのファイルをリンクすると、ルーチンとして正常に機能します。

例11-3 は、前述の例を使用して、AddressクラスのインスタンスをManaged<T>でラップしてManaged<Address>とし、Coherence APIに提供することを示しています。

例11-3 Managed<T>でラップしたクラスのインスタンス

// construct the non-managed version as usual
Address office("Redwood Shores", "CA", 94065);

// the managed version can be initialized from the non-managed version
// the result is a new object, which does not reference the original
Managed<Address>::View vOffice = Managed<Address>::create(office);
String::View           vKey    = "Oracle";

// the managed version is suitable for use with caches
hCache->put(vKey, vAddr);
vOffice = cast<Managed<Address>::View>(hCache->get(vKey));

// the non-managed class's public methods/fields remain accessible
assert(vOffice->getCity()  == office.getCity());
assert(vOffice->getState() == office.getState());
assert(vOffice->getZip()   == office.getZip());

// conversion back to the non-managed type may be performed using the
// non-managed class's copy constructor.
Address officeOut = *vOffice;

PortableObject (自己シリアライズ)

PortableObjectインタフェースは、概念の面から見ると、オブジェクトのシリアライズ方法をそのオブジェクト自身で制御できるようにするjava.io.Externalizableに類似しています。coherence::lang::Objectを拡張したクラスであれば、coherence::io::pof::PortableObjectインタフェースを自由に実装してシリアライズのサポートを追加できます。このクラスはObjectを拡張したものであることが必要で、拡張後のクラスのライフサイクルはこのObjectで規定します。

例11-4 では、前述のAddressの例を管理クラスとして書き換え、PortableObjectインタフェースを実装できます。ここでは、このクラスの定義の中でCoherenceオブジェクト・モデル全体を扱うようにしています。たとえば、データ・メンバーに対してstd::stringではなく、coherence::lang::Stringを使用します。

例11-4 PortableObjectを実装する管理クラス

#include "coherence/lang.ns"

#include "coherence/io/pof/PofReader.hpp"
#include "coherence/io/pof/PofWriter.hpp"
#include "coherence/io/pof/PortableObject.hpp"

#include "coherence/io/pof/SystemPofContext.hpp"

using namespace coherence::lang;

using coherence::io::pof::PofReader;
using coherence::io::pof::PofWriter;
using coherence::io::pof::PortableObject;

class Address
  : public cloneable_spec<Address,
      extends<Object>,
      implements<PortableObject> >
  {
  friend class factory<Address>;

  protected: // constructors
    Address(String::View vsCity, String::View vsState, int32_t nZip)
       : m_vsCity(self(), vsCity), m_vsState(self(), vsState), m_nZip(nZip) {}

    Address(const Address& that)
       : super(that), m_vsCity(self(), that.m_vsCity), m_vsState(self(), 
       that.m_vsState), m_nZip(that.m_nZip) {}

    Address() // required by PortableObject
       : m_vsCity(self()),
         m_vsState(self()),
         m_nZip(0) {}

  public: // Address interface   
    virtual String::View  getCity()  const {return m_vsCity;}
    virtual String::View  getState() const {return m_vsState;}
    virtual int32_t       getZip()   const {return m_nZip;}

  public: // PortableObject interface    virtual void writeExternal(PofWriter::Handle hOut) const
      {
      hOut->writeString(0, getCity());
      hOut->writeString(1, getState());
      hOut->writeInt32 (2, getZip());
      }

    virtual void readExternal(PofReader::Handle hIn)
      {
       initialize(m_vsCity, hIn->readString(0));
       initialize(m_vsState, hIn->readString(1));
       m_nZip    = hIn->readInt32 (2);
      }

  public: // Objectinterface    virtual bool equals(Object::View that) const
      {
      if (instanceof<Address::View>(that))
        {
        Address::View vThat = cast<Address::View>(that);

        return getZip() == vThat->getZip() &&
               Object::equals(getState(), vThat->getState()) &&
               Object::equals(getCity(), vThat->getCity());
        }

      return false;
      }

    virtual size32_t hashCode() const
      {
      return (size32_t) m_nZip;
      }

    virtual void toStream(std::ostream& out) const
      {
      out << getCity() << ", " << getState() << "  " << getZip();
      }

  private:
     FinalView<String> m_vsCity;
     FinalView<String> m_vsState;
     int32_t     m_nZip;
  };
COH_REGISTER_PORTABLE_CLASS(1234, Address); // type ID registration—this must
                                            // appear in the .cpp not the .hpp 

例11-5 は、Addressの管理バリアントを示しています。このバリアントは、Managed<T>アダプタの使用を必要とせず、Coherence APIで直接使用できます。

例11-5 Managed<T>を使用しない管理クラス

Address::View vAddr = Address::create("Redwood Shores", "CA", 94065);
String::View  vKey  = "Oracle";

hCache->put(vKey, vAddr);
Address::View vOffice = cast<Address::View>(hCache->get(vKey));

Coherenceオブジェクト・モデルを利用してデータ・オブジェクトを記述することにしているアプリケーションでは、PortableObjectを使用したシリアライズが最適です。PortableObjectの短所として、constデータ・メンバーのサポートが容易ではないという点があります。これは、コンストラクタの実行後にreadExternalメソッドがコールされ、その時点でconstデータ・メンバーの値を割り当てる必要があるためです。

PofSerializer (外部シリアライズ)

3番目のシリアライズ・オプションも最低レベルのものです。PofSerializerは、自身以外のクラスにシリアライズ・ロジックを提供するクラスです。たとえば、前述の管理Addressクラスの非PortableObjectバージョンをシリアライズできるAddressSerializerを記述します。前述の2つのアプローチでは、これらは明示的に作成していたのではなく、PofSerializerに委任されていた保護の下で自動的に作成されていました。通常は、Managed<T>PortableObjectのいずれかのアプローチで十分であるため、このアプローチを採用する必要はありません。このアプローチが効果的なのは、constデータ・メンバーを持つ管理オブジェクトを扱う場合です。例11-6 では、非PortableObjectバージョンの管理Addressを検討します。

例11-6 非PortableObjectバージョンの管理クラス

#include "coherence/lang.ns"

using namespace coherence::lang;

class Address
  : public cloneable_spec<Address> // extends<Object> is implied
  {
  friend class factory<Address>;

  protected: // constructors
    Address(String::View vsCity, String::View vsState, int32_t nZip)
       : m_vsCity(self(), vsCity), m_vsState(self(), vsState), m_nZip(nZip) {}


    Address(const Address& that)
       : super(that), m_vsCity(self(), that.getCity()), m_vsState(self(),
         that.getState()), m_nZip(that.getZip()) {}

  public: // Address interface    
    virtual String::View  getCity()  const {return m_vsCity;}
    virtual String::View  getState() const {return m_vsState;}
    virtual int32_t getZip() const {return m_nZip;}

  public: // Objectinterface    
       virtual bool equals(Object::View that) const
      {
      if (instanceof<Address::View>(that))
        {
        Address::View vThat = cast<Address::View>(that);

        return getZip() == vThat->getZip() &&
               Object::equals(getState(), vThat->getState()) &&
               Object::equals(getCity(), vThat->getCity());
        }

      return false;
      }

    virtual size32_t hashCode() const
      {
      return (size32_t) m_nZip;
      }

    virtual void toStream(std::ostream& out) const
      {
      out << getCity() << ", " << getState() << "  " << getZip();
      }

  private:
    const MemberView<String> m_vsCity;
    const MemberView<String> m_vsState;
    const int32_t      m_nZip;
  };

このバージョンはconstデータ・メンバーを使用しているため、PortableObjectには適していません。例11-7 は、Addressインスタンスのシリアライズを担当するものとして登録される外部クラスAddressSerializerを示しています。

例11-7 シリアライズを担当する外部クラス

#include "coherence/lang.ns"

#include "coherence/io/pof/PofReader.hpp"
#include "coherence/io/pof/PofWriter.hpp"
#include "coherence/io/pof/PortableObject.hpp"
#include "coherence/io/pof/PofSerializer.hpp"
#include "coherence/io/pof/SystemPofContext.hpp"

#include "Address.hpp"

using namespace coherence::lang;

using coherence::io::pof::PofReader;
using coherence::io::pof::PofWriter;
using coherence::io::pof::PofSerializer;

class AddressSerializer
  : public class_spec<AddressSerializer,
      extends<Object>,
      implements<PofSerializer> >
  {
  friend class factory<AddressSerializer>;

  protected:
    AddressSerializer();

  public: // PofSerializer interface    virtual void serialize(PofWriter::Handle hOut, Object::View v) const
        {
        Address::View vAddr = cast<Address::View>(v);
        hOut->writeString(0, vAddr->getCity());
        hOut->writeString(1, vAddr->getState());
        hOut->writeInt32 (2, vAddr->getZip());
        hOut->writeRemainder(NULL);
        }

    virtual Object::Holder deserialize(PofReader::Handle hIn) const
      {
      String::View vsCity  = hIn->readString(0);
      String::View vsState = hIn->readString(1);
      int32_t      nZip    = hIn->readInt32 (2);
      hIn->readRemainder();

      return Address::create(vsCity, vsState, nZip);
      }
  };
COH_REGISTER_POF_SERIALIZER(1234, TypedBarrenClass<Address>::create(),AddressSerializer::create()); // This must appear in the .cpp not the .hpp

Addressの使用方法は、次のようにこれまでと同じです。

Address::View vAddr = Address::create("Redwood Shores", "CA", 94065);
String::View  vKey  = "Oracle";

hCache->put(vKey, vAddr);
Address::View vOffice = cast<Address::View>(hCache->get(vKey));

POFオブジェクト参照の使用

POFでは、POFストリーム内で複数回出現するオブジェクトに、オブジェクトのIDや参照の使用がサポートされています。オブジェクトには、IDが付けられ、同じPOFストリーム内で2回目以降に出現するラベルが付いたオブジェクトは、そのIDで参照されます。

参照を使用することで、同じオブジェクトを複数回エンコーディングすることを防ぎ、データサイズを削減できます。一般に、参照を使用するのは、サイズの大きな多数のオブジェクトが複数回生成されるときや、オブジェクトでネストや循環データ構造が使用されるときです。ただし、大量のデータがあり、繰返しが少ないアプリケーションの場合、オブジェクト参照を使用してもオブジェクトのIDや参照の追跡によって生じるオーバーヘッドのために、最小限の利点しかありません。

オブジェクト・アイデンティティおよび参照の使用には次の制限があります。

  • オブジェクト参照には、ユーザー定義のオブジェクト型のみがサポートされています。

  • Evolvableオブジェクトでは、オブジェクト参照はサポートされていません。

  • キーでは、オブジェクト参照はサポートされていません。

  • 参照をサポートしていないPOFコンテキストによって記述されたオブジェクトは、参照をサポートするPOFコンテキストで読み込むことができません。また、この逆の場合も同様です。

  • POFエクストラクタを使用して、オブジェクト・アイデンティティおよび参照を使用するPOFオブジェクトを問い合せることはできません。かわりに、ValueExtractor APIを使用してオブジェクト値を問い合せるか、またはオブジェクト参照を無効にしてください。

  • PofNavigatorおよびPofValue APIには、オブジェクト参照を使用する際に次の制限があります:

    • 読取り操作のみ許可されます。書込み操作はUnsupportedOperationExceptionとなります。

    • ユーザー・オブジェクトは非共通コレクションでアクセスできますが、共通コレクションではアクセスできません。

    • 読取り操作については、オブジェクトがデータ・ストリームで複数回出現する場合、オブジェクトが最初に出現した場所で読み取られてから、次のデータの部分で読み取られる必要があります。そうでない場合は、IOException: missing identity: <ID>がスローされます。たとえば、リストが3つあり、そのすべてが同じPersonオブジェクトpを含む場合。pオブジェクトは、最初のリストで読み取られてから2番目または3番目のリストで読み取られる必要があります。

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

POFオブジェクト参照の有効化

オブジェクト参照は、デフォルトでは無効になっており、POFコンテキストを作成するときにsetReferenceEnabledを使用して有効にする必要があります。次に例を示します。

SystemPofContext::Handle hCtx = SystemPofContext::getInstance();
hCtx->setReferenceEnabled(true);

循環構造のオブジェクトやネストされたオブジェクトへのPOFオブジェクトIDの登録

循環構造のオブジェクトやネストされたオブジェクトは、オブジェクトの作成時に手動でIDを登録する必要があります。これを行わないと、親を参照する子が、参照マップで親のIDを検出しません。オブジェクトのIDは、PofReader.registerIdentityメソッドを使用し、デシリアライズ・ルーチンでシリアライザから登録できます。

次の例では、循環参照を含んだ2つのオブジェクト(CustomerおよびProduct)と、CustomerオブジェクトのIDを登録するシリアライザ実装を示しています。

Customerオブジェクトの定義は次のとおりです。

class Customer
   : public class_spec<Customer,
      extends<Object> >
   {
   friend class factory<Customer>;
 
   protected:
      Customer()
         : m_vsName(self(), String::null_string),
         m_vProduct(self(), NULL)
         {
         }
 
         Customer(String::View vsName)
            : m_vsName(self(), vsName),
            m_vProduct(self(), NULL)
            {
         }
 
         Customer(String::View vsName, Product::View vProduct)
         : m_vsName(self(), vsName),
         m_vProduct(self(), vProduct)
         {
         }
 
   public:
      String::View getName() const
         {
         return m_vsName;
         }
 
      void setName(String::View vsName)
         {
         m_vsName = vsName;
         }
 
      Product::View getProduct() const
         {
         return m_vProduct;
         }
 
      void setProduct(Product::View vProduct)
         {
         m_vProduct = vProduct;
         }
 
   private:
      MemberView<String> m_vsName;
      MemberView<Product> m_vProduct;
   };

Productオブジェクトの定義は次のとおりです。

class Product
   : public class_spec<Product,
      extends<Object> >
   {
   friend class factory<Product>;
 
   protected:
      Product()
         : m_vCustomer(self(), NULL)
         {
         }
 
      Product(Customer::View vCustomer)
         : m_vCustomer(self(), vCustomer)
         {
         }
 
   public:
      Customer::View getCustomer() const
         {
         return m_vCustomer;
         }
 
      void setCustomer(Customer::View vCustomer)
         {
         m_vCustomer= vCustomer;
         }
 
   private:
         MemberView<Customer> m_vCustomer;
   };

デシリアライズの間にIDを登録するシリアライザ実装の定義は次のとおりです。

class CustomerSerializer
   : public class_spec<CustomerSerializer,
      extends<Object>,
      implements<PofSerializer> >
   {
   friend class factory<CustomerSerializer>;
 
   public:
      void serialize(PofWriter::Handle hOut, Object::View v) const
         {
         Customer::View vCustomer = cast<Customer::View>(v);
         hOut->writeString(0, vCustomer->getName());
         hOut->writeObject(1, vCustomer->getProduct());
         hOut->writeRemainder(NULL);
         }

      Object::Holder deserialize(PofReader::Handle hIn) const
         {
         String::View vsName = cast<String::View>(hIn->readString(0));
         Customer::Holder ohCustomer = Customer::create(vsName);
 
         hIn->registerIdentity(ohCustomer);
         ohCustomer->setProduct(cast<Product::View>(hIn->readObject(1)));
         hIn->readRemainder();
         return ohCustomer;
         }
   };

カスタムのC++型の登録

シリアライズ可能にすることに加え、各クラスには数値型のIDを関連付ける必要があります。これらのIDはクラスタ全体で既知の状態になっています。クラスタでは、POFユーザー定義型の構成要素を使用して、IDとクラスとのマッピングを構成します。C++では、IDの登録の形式でクラス定義の中にこのマッピングを埋め込みます。これは、クラスの .cppソース・ファイルに記述します。

この登録の手法は、次のようにシリアライズのアプローチごとに少々異なります。

  • COH_REGISTER_MANAGED_CLASS(ID, TYPE): Managed<T>による方法の場合

  • COH_REGISTER_PORTABLE_CLASS(ID, TYPE): PortableObjectによる方法の場合

  • COH_REGISTER_POF_SERIALIZER(ID, CLASS, SERIALIZER): PofSerializerによる方法の場合

これらの登録の例は、前述の例に記載されています。

注意:

登録を記述するファイルは実装ファイル(.cpp)のみとします。POF構成ファイルは、オブジェクトをシリアライズおよびデシリアライズするノードでのみ必要です。

JavaバージョンのC++オブジェクトの実装

POFの使用によって、並列のJava実装を必要とせずに、キーおよび値オブジェクトをクラスタ内に格納できます。これは、基本的なgetとputベースの操作を実行する場合に適しています。さらに、PofExtractorPofUpdater APIにより、Coherenceの非プリミティブ・タイプを使用するときの柔軟性が向上します。多くの拡張クライアントの場合、グリッド内に対応するJavaクラスは不要です。POFエクストラクタとPOFアップデータはバイナリをナビゲートできるため、キーと値全体をオブジェクト形式にデシリアライズしなくても済みます。これは、索引付けする値をPOFエクストラクタを使用してプルするだけで索引付けできることを意味します。

並列のJava実装の組込みが必要になる状況

Javaベースのキャッシュ・サーバーが、データ・オブジェクトのシリアライズ表現を保持するだけでなく、データ・オブジェクトと直接対話する必要がある場合は、並列のJava実装が必要です。たとえば、キャッシュ・ストアを使用するときJavaクラスは必要です。この場合、キーと値のデシリアライズ・バージョンがキャッシュ・ストアに渡され、バックエンドに書き込まれます。さらに、オブジェクトへの直接アクセスが必要な場合、問合せ、フィルタ、入力プロセッサおよびアグリゲータはJava実装が必要です。

Java実装が必要な場合は、実装はキャッシュ・サーバーにある必要があります。JavaバージョンのPOFでシリアライズ可能にする方法は前述の例とほぼ同じです。詳細は、PortableObjectおよびPofSerializerを参照してください。これらのAPIは、C++の3つの方法すべてと互換性があります。

キーの関連付けチェックの遅延

キー・クラスは、クラスタ側Java実装を必要としません。これはKeyAssociationを使用してデータのアフィニティを指定している場合でも同様です。キー・クラスは、クライアント側でチェックされ、修飾されたバイナリがクラスタによって作成および使用されます。ただし、キーの関連付けをJavaキー・クラスに依存している既存のクライアント実装は、Javaキー・クラスの使用を強制するためにdefer-key-association-checkパラメータを設定する必要があります。キーの関連付けを使用する既存クライアント・アプリケーションで、クライアント側のキー・バイナリを利用する場合は、getAssociatedKey()実装を既存のJavaクラスから対応するクライアント・クラスに移植する必要があります。

キーの関連付け処理をExtendクライアントによってではなくクラスタ側で実行するには、クライアント側キャッシュの構成で<remote-cache-scheme>要素の<defer-key-association-check>要素をtrueに設定します。次に例を示します。

<remote-cache-scheme>
   ...
   <defer-key-association-check>true</defer-key-association-check>
</remote-cache-scheme>

注意:

パラメータがtrueに設定されている場合、Javaキー・クラス実装は、キーの関連付けを使用していない場合でも、クラスタに存在する必要があります。

シリアライズのパフォーマンスの理解

Managed<T>PortableObjectは、いずれもバックグラウンドでPofSerializerを使用してシリアライズを実行します。これらのアプローチのそれぞれで独自のオーバーヘッドが発生します。たとえば、Managed<T>によるアプローチでは、デシリアライズの過程で、一時バージョンのデータ・オブジェクトが非管理形式で作成されます。PortableObjectの場合は、constデータ・メンバーに対するサポートがないことから、constデータ・メンバーに対して可能な最適化が回避されるために、余分なコストが発生する可能性があります。全体としてはパフォーマンスの差は無視できますが、可能なかぎり最大のパフォーマンス実現を追求する場合は、PofSerializerを直接使用することも検討に値します。

POF注釈を使用したオブジェクトのシリアライズ

POF注釈は、オブジェクトにシリアライズやデシリアライズ・ルーチンの実装を自動化する方法を提供します。POF注釈は、PofSerializerインタフェースの実装であるPofAnnotationSerializerクラスを使用してシリアライズまたはデシリアライズします。注釈は、Managed<T>アダプタ、PortableObjectインタフェースおよびPofSerializerインタフェースのかわりに使用でき、オブジェクトをシリアライズ可能にするために必要な時間やコードの量を削減します。

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

POFシリアライズでのオブジェクトへの注釈付け

クラスとクラスのメソッドがPOFシリアライズ可能であることを示すために利用できる注釈は2つあります。

  • Portable - クラスをPOFシリアライズ可能とマークします。注釈は、クラス・レベルのみに使用でき、メンバーを含みません。

  • PortableProperty - メソッド・アクセッサをPOFシリアライズ化されたプロパティとしてマークします。注釈が付けられたメソッドは、アクセッサの表記法(getsetis)に従っている必要があります。メンバーを、POF索引や、シリアライズまたはデシリアライズの前後で実行するカスタム・コーデックの指定に使用できます。索引の値は省略可能で、自動的に割り当てられます。カスタム・コーデックを入力しない場合は、デフォルトのコーデックが使用されます。

次の例は、クラスとメソッドへの注釈付けと、プロパティ索引値の明示的な割当てを示しています。クラスはシステム・クラス・ローダーCOH_REGISTER_CLASSとともに登録する必要があります。

class Person
   : public class_spec<Person>
   {
   friend class factory<Person>;

   Public:
      String::View getFirstName() const
         {
         return m_vsFirstName;
         }

      void setFirstName(String::View vsFirstName)
         {
         m_vsFirstName = vsFirstName;
         }

   private: String m_firstName;
      MemberView<String> m_vsFirstName;
      MemberView<String> m_vsLastName;
      int32_t            m_nAge;

   public:
      static const int32_t FIRST_NAME = 0;
      static const int32_t LAST_NAME  = 1;
      static const int32_t AGE        = 2;
   };

COH_REGISTER_CLASS(TypedClass<Person>::create()
   ->annotate(Portable::create())
   ->declare(COH_PROPERTY(Person, FirstName, String::View)
      ->annotate(PortableProperty::create(Person::FIRST_NAME)))
   ->declare(COH_PROPERTY(Person, LastName, String::View)
      ->annotate(PortableProperty::create(Person::LAST_NAME)))
   ->declare(COH_PROPERTY(Person, Age, BoxHandle<const Integer32>)
      ->annotate(PortableProperty::create(Person::AGE)))
      );

POF注釈付きオブジェクトの登録

POF注釈付きオブジェクトは、COH_REGISTER_POF_ANNOTATED_CLASSマクロを使用してユーザー定義型として登録する必要があります。次の例では、注釈付きPersonオブジェクトのユーザー定義型を登録します。

COH_REGISTER_POF_ANNOTATED_CLASS(1001, Person);

自動索引付けの有効化

POF注釈では、自動索引付けがサポートされており、明示的な索引値の割当てや管理の必要性を軽減されます。PortableProperty注釈を定義していれば、索引値は省略可能です。明示的に索引値を割り当てるプロパティによって、自動索引値が割り当てられることはありません。自動索引のアルゴリズムを表すと、次のようになります。

名前 明示的な索引 決定された索引

c

1

1

a

省略

0

b

省略

2

注意:

自動索引では、現在、進化可能なクラスがサポートされていません。

自動索引付けを有効にするには、ユーザー定義型を登録するときにCOH_REGISTER_POF_ANNOTATED_CLASS_AIプリプロセッサを使用します。次の例では、自動索引付けを使用する注釈付きPersonオブジェクトのユーザー定義型を登録します。

COH_REGISTER_POF_ANNOTATED_CLASS_AI(1001, Person);

カスタム・コーデックの提供

コーデックによって、シリアライズまたはデシリアライズの前後でコードを実行できます。コーデックでは、PofWriterおよびPofReaderインタフェースを使用して、移植可能なプロパティをエンコードおよびデコードする方法を定義できます。コーデックは、一般に、デシリアライズ中に消失する可能性がある実用的な実装に使用します。または、オブジェクトをシリアライズする前にPofWriterインタフェースで特定のメソッドを明示的にコールするために使用します。

コーデックを作成するには、Codecインタフェースを実装するクラスを作成します。次の例は、リンクされたリスト型の実用的な実装を定義するコーデックを示しています。

class LinkedListCodec
   : public class_spec<LinkedListCodec,
      extends<Object>,
      implements<Codec> >
   {
   friend class factory<LinkedListCodec>;
 
   public:
      void encode(PofWriter::Handle hOut, int32_t nIndex, Object::View ovValue)
         const
         {
            hOut->writeCollection(nIndex, cast<Collection::View>(ovValue));
         }

      Object::Holder decode(PofReader::Handle hIn, int32_t nIndex) const
         {
            LinkedList::Handle hLinkeList = LinkedList::create();
            return hIn->readCollection(nIndex, hLinkeList);
         }
   };
COH_REGISTER_TYPED_CLASS(LinkedListCodec);

コーデックをプロパティに割り当てるには、コーデックをPortableProperty注釈のメンバーとして入力します。コーデックを指定しない場合は、デフォルトのコーデック(DefaultCodec)が使用されます。次の例は、前述のLinkedListCodecコーデックの割当て方法を示しています。

COH_REGISTER_CLASS(TypedClass<Person>::create()
   ->annotate(Portable::create())
   ->declare(COH_PROPERTY(Person, FirstName, String::View)
      ->annotate(PortableProperty::create(Person::FIRST_NAME)))
   ->declare(COH_PROPERTY(Person, LastName, String::View)
      ->annotate(PortableProperty::create(Person::LAST_NAME)))
   ->declare(COH_PROPERTY(Person, Age, BoxHandle<const Integer32>)
      ->annotate(PortableProperty::create(Person::ALIASES,
SystemClassLoader::getInstance()->loadByType(typeid(LinkedListCodec)) )))
);