A Simple Coherence C++ Client

Coherence provides native support for C++ clients. Not through JNI or some other C++ wrapper, but pure native C++ integration. The C++ client for Coherence has been written from scratch to support memory management, concurrency and type conversion - across multiple platforms (Windows, Linux, OSX and Solaris). The C++ client for Coherence also supports virtually every feature of the other clients (.NET and Java). So for instance you can:

This post will show you a simple C++ client - targeted for the Windows platform - but in actual fact the only Windows specific resources are the scripts used to build and demonstrate the example. The code could easily be run on the other supported platforms.

The example has been put together to demonstrate how a native C++ client can put objects in a cache - in this case Trade objects - and an atribute aggregated. There is no Java and the C++ data model classes do not include any Coherence specific code. So you can hopefully see how you could easily take your native C++ classes and put objects created from them into Coherence.

Here is the definition of the Trade class (Trade.h):

#ifndef TRADE_H
#define TRADE_H

#include <ostream>
#include <string>

// Constants for POF offsets
#define TRADE_SYMBOL 0
#define TRADE_PRICE 1
#define TRADE_ID 2
#define TRADE_QUANTITY 3

/**
* The Trade class encapsulates common information for a Trade.
*
* This serves as an example data object which does not have direct knowledge
* of Coherence but can be stored in the data grid.
*/
class Trade
{
// ----- data members ---------------------------------------------------

private:
/**
* The trade symbos.
*/
std::string symbol;

/**
* The trade price.
*/
double price;

/**
* The trade id.
*/
int id;

/**
* The trade quantity.
*/
int quantity;

// ----- constructors ---------------------------------------------------

public:
/**
* Create a new ContactInfo object.
*
* @param symbod the trade symbol
* @param price the trade price
* @param id the trade id
* @param quantity the trade quantity
*/
Trade(const std::string& symbol,
   const double price, const int id,
   const int quantity);

/**
* Copy constructor.
*/
Trade(const Trade& that);

protected:
/**
* Default constructor.
*/
Trade();

// ----- accessors ------------------------------------------------------

public:
/**
* Determine the symbol for this Trade object
*
* @return the Trade symbol
*/
std::string getSymbol() const;

/**
* Configure the symbol for a Trade.
*
* @param sName the Trades symbol
*/
void setSymbol(const std::string& symbol);

/**
* Determine the price of a Trade.
*
* @return the price of a Trade
*/
double getPrice() const;

/**
* Configure the price of a Trade.
*
* @param price of a Trade
*/
void setPrice(const double price);

/**
* Determine the id of a Trade.
*
* @return the id of a Rrade
*/
int getId() const;

/**
* Configure the id of a Trade.
*
* @param id of a Trade
*/
void setId(const int id);

/**
* Determine the quantity of a Trade.
*
* @return the quantity of a Trade
*/
int getQuantity() const;

/**
* Configure the quantity of a Trade.
*
* @param quantity of a Trade
*/
void setQuantity(const int quantity);

};

// ----- free functions -----------------------------------------------------

/**
* Output this Trade to the stream
*
* @param out the stream to output to
*
* @return the stream
*/
std::ostream& operator<<(std::ostream& out, const Trade& trade);

/**
* Perform an equality test on two Trade objects
*
* @param infoA the first Trade
* @param infoB the second Trade
*
* @return true if the objects are equal
*/
bool operator==(const Trade& tradeA, const Trade& tradeB);

/**
* Return the has for the Trade.
*
* @param info the Trade to hash
*
* @return the hash for the Trade
*/
size_t hash_value(const Trade& trade);

#endif // TRADE_H

And here is the implementation (Trade.cpp):

#include "Trade.h"

// ----- constructors -------------------------------------------------------

Trade::Trade(const std::string& s,
const double p, const int i,
const int q)

{
setSymbol(s);
setId(i);
setPrice(p);
setQuantity(q);
}

Trade::Trade(const Trade& that)
{
setSymbol(that.getSymbol());
setId(that.getId());
setPrice(that.getPrice());
setQuantity(that.getQuantity());
}

Trade::Trade()
{
}

// ----- accessors ----------------------------------------------------------

std::string Trade::getSymbol() const
{
return symbol;
}

void Trade::setSymbol(const std::string& s)
{
symbol = s;
}

int Trade::getId() const
{
return id;
}

void Trade::setId(const int i)
{
id = i;
}

double Trade::getPrice() const
{
return price;
}

void Trade::setPrice(const double p)
{
price = p;
}

int Trade::getQuantity() const
{
return quantity;
}

void Trade::setQuantity(const int q)
{
quantity = q;
}

// ----- free functions -----------------------------------------------------

std::ostream& operator<<(std::ostream& out, const Trade& trade)
{
out << "Trade("
<< "Symbol=" << trade.getSymbol()
<< ", Price=" << trade.getPrice()
<< ", Id=" << trade.getId()
<< ", Quantity=" << trade.getQuantity()
<< ')';
return out;
}

bool operator==(const Trade& tradeA, const Trade& tradeB)
{
return tradeA.getSymbol() == tradeB.getSymbol() &&
tradeA.getPrice() == tradeB.getPrice() &&
tradeA.getId() == tradeB.getId() &&
tradeA.getQuantity() == tradeB.getQuantity();
}

size_t hash_value(const Trade& trade)
{
return size_t(&trade); // identity hash (note: not suitable for cache keys)
}

As you can see, no Coherence code. All the serialization code is implemented in a seperate file (TradeSerializer.cpp) and linked with the class to serialize using the Portable Object Format (POF) configuration file. The Coherence C++ client libraries locates its configuration files using environment variables.

Finally here is the client console application (cppexample.cpp):

// cppexample.cpp : Defines the entry point for the console application.

#include "Trade.h"

#include "coherence/lang.ns"
#include "coherence/net/CacheFactory.hpp"
#include "coherence/net/NamedCache.hpp"
#include "coherence/util/HashSet.hpp"
#include "coherence/util/aggregator/Integer64Sum.hpp"
#include "coherence/util/filter/EqualsFilter.hpp"
#include "coherence/util/Filter.hpp"
#include "coherence/util/Hashtable.hpp"
#include "coherence/util/ValueExtractor.hpp"
#include "coherence/util/extractor/PofExtractor.hpp"

#include <iostream>
#include <sstream>
#include <ostream>
#include <string>

using namespace coherence::lang;
using coherence::net::CacheFactory;
using coherence::net::NamedCache;
using coherence::util::aggregator::Integer64Sum;
using coherence::util::ValueExtractor;
using coherence::util::extractor::PofExtractor;
using coherence::util::filter::EqualsFilter;
using coherence::util::Filter;
using coherence::util::Hashtable;

#include <stdlib.h>

#define NUM_TRADES 20

int main(int argc, char** argv)
{
// Create/get cache handle
std::cout << "Getting cache..." << std::endl;
NamedCache::Handle hCache = CacheFactory::getCache("test");
std::cout << " OK" << std::endl;

// Put some trades in the cache
std::string symbols[] = { "ORCL", "MSFT", "IBM", "SAP" };
Map::Handle hMap = Hashtable::create();
for(int i = 0; i < NUM_TRADES; i++)
{
  Trade t1 = Trade(symbols[rand() % 4], rand() % 100, i, rand() % 1000);
  hMap->put(Integer32::create(i), Managed<Trade>::create(t1));
}

hCache->putAll(hMap);
std::cout << "Stored: " << NUM_TRADES << " trades" << std::endl;

// Get objects back from cache
std::cout << "Getting objects back from cache..." << std::endl;
int sum = 0;
for(int i = 0; i < NUM_TRADES; i++)
{
  Integer32::Handle hViewKey = Integer32::create(i);
  Managed<Trade>::View vTrade =
  cast<Managed<Trade>::View>(hCache->get(hViewKey));
  std::cout << " The value for " << hViewKey << " is " << vTrade << std::endl;
  if(vTrade->getSymbol() == "ORCL")
  {
   sum += vTrade->getQuantity();
  }
}

std::cout << "Total ORCL trades is: " << sum << std::endl;

// Perform aggregation. Get total number of "ORCL" trades and print results
ValueExtractor::View vQuantityExtractor =   PofExtractor::create(typeid(int32_t), TRADE_QUANTITY);
ValueExtractor::View vSymbolExtractor = PofExtractor::create(typeid(void), TRADE_SYMBOL);
String::View vSymbol = "ORCL";
Filter::View vFilter = EqualsFilter::create(vSymbolExtractor, vSymbol);
Integer64::View vSum = cast<Integer64::View>(
hCache->aggregate(vFilter,
Integer64Sum::create(vQuantityExtractor)));
std::cout << "Total number of ORCL trades agregated is: " << vSum << std::endl;

hCache->release();
std::cout << "Released local resources" << std::endl;

return 0;
}

I hope this example has given you a feel for how simple a C++ Coherence client can be. If you would like try this out for yourself you can download the full example here.

Additional Note

The Coherence C++ shared library requires that the MSVC runtime libraries that correspond to the Visual C++ compiler that was used to build the shared library be installed on the machine where the shared library is being used.

For 3.5 and earlier that means you need the Microsoft Visual C++ 2005 SP1 Redistributable Package (x86 or x64). For 3.6 you need the 2005 package if you are using the Coherence C++ library built with 2005 or the 2010 package if you are using the library built with Visual C++ 2010.

Additionally, if you use a different compiler to build the executable. For example Visual C++ 2008, then you will also need to install the runtime libraries for that compiler.

Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

Views and ideas about Oracle Coherence and other software

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today