Using CORBA Compression
The OMG has formal adopted CORBA compression as part of the ZIOP specification in 2010. In 2012 the separate ZIOP specification has been integrated into CORBA v3.3. This article gives an overview of the CORBA compression part of ZIOP. A future article will be dedicated to ZIOP. In that article the ZIOP Policies and the status of the TAO implementation will be explained.
Starting with TAO 1.5.5 there is a partial implementation of the CORBA compression specification. The CORBA compression specification makes it possible to compress and uncompress application data using pluggable compressors. This library was the first step in the development of ZIOP which adds the ability that the ORB compresses all application data transparently.
To perform (de)compressions a so called compressor can be used. For this compressor a compressor factory must be registered with the ORB. The compressor factory is responsible to create the compressor that can be used to (un)compress the data. As part of the TAO distribution zlib, bzip2, and lzo compressors are implemented by default but other compressor factories can be easily added by application developers.
Using compression
In order to use the Compression library you must add the following include to your application code.
#include "tao/Compression/Compression.h"
Then you have to include the compressor factories that are going to be used. The default zlib compressor factory can be included as following.
#include "tao/Compression/zlib/ZlibCompressor_Factory.h"
As in a normal CORBA application you first have to initialize the ORB.
CORBA::ORB_var orb = CORBA::ORB_init (argc, argv);
Then you have to retrieve the CompressionManager using resolve_initial_references().
CORBA::Object_var compression_manager =
orb->resolve_initial_references("CompressionManager");
Compression::CompressionManager_var manager =
Compression::CompressionManager::_narrow (compression_manager.in ());
if (CORBA::is_nil(manager.in ())) {
std::cerr << "Panic: nil compression manager" << std::endl;
return 1;
}
The compression manager has no compressors by default, you have to register the compressor factories that you want to use in your application.
Compression::CompressorFactory_ptr compressor_factory; ACE_NEW_RETURN (compressor_factory, TAO::Zlib_CompressorFactory (), 1); Compression::CompressorFactory_var compr_fact = compressor_factory; manager->register_factory(compr_fact.in ());
Now all the initial setup has been done. When you need to peform (de)compression you need to retrieve a compressor. The number passed into the get_compressor method is the id of the compressor you want. These OMG predefined id's are listed in the table below.
| Compression::COMPRESSORID_GZIP | gzip |
| Compression::COMPRESSORID_BZIP2 | bzip2 |
| Compression::COMPRESSORID_ZLIB | zlib |
| Compression::COMPRESSORID_LZMA | lzma |
| Compression::COMPRESSORID_LZOP | lzo |
| Compression::COMPRESSORID_RZIP | rzip |
| Compression::COMPRESSORID_7X | r7x |
| Compression::COMPRESSORID_XAR | xar |
| Compression::COMPRESSORID_PKZIP | pkzip |
In order to retrieve the zlib compression you can use
Compression::Compressor_var compressor = manager->get_compressor (Compression::COMPRESSORID_ZLIB);
A compressor is capable of compression Compression::Buffer as data which can contain any data as byte array. When compression data you should pass in an out sequence to put the compressed data in. If you want to set a safe size, take the length of the original sequence and multiple it with 1.10, this safe size can be dependent on the compressor you are using. At the moment the size is not large enough a Compression::CompressionException will be thrown.
Compression::Buffer myout; myout.length ((CORBA::ULong)(mytest.length() * 1.1)); compressor->compress (mytest, myout);
To decompress that data you pass in the compressed data and a second Compression::Buffer that can be used to put the decompressed data in, this Compression::Buffer must have a length large enough to contain the decompressed data. At the moment then second Compression::Buffer is not large enough a Compression::CompressionException will be thrown.
The compressed Compression::Buffer doesn't contain the size of the original data, if you need this when decompressing you have to transfer it to the function doing decompression yourself.
Compression::Buffer decompress; decompress.length (1024); compressor->decompress (myout, decompress);
Compression application types can be done using an Any as intermediate
datatype. The Any can then be converted to a OctetSeq using the Codec (short for coder/decoder) support of CORBA. For information how to use the Codec see the TAO Programmers Guide.
Implementing your own compressor
As application developer you can add your own custom compressor. Adding a compressor will require you implement two classes, the CompressorFactory and the Compressor itself.
The CompressorFactory is capable of creating a compressor for a given compression level. To make the implementation of a concret CompressorFactory easier TAO delivers the CompressorFactory base class that implements common functionality.
class My_CompressorFactory : public TAO::CompressorFactory
{
public:
My_CompressorFactory (void);
virtual Compression::Compressor_ptr get_compressor (
Compression::CompressionLevel compression_level);
private:
Compression::Compressor_var compressor_;
};
First, the constructor. We pass our compressor id to the base class and initialize our member to nil. The compressor id must be unique for each compression algorithm, in this case we implement a lzop compressor.
My_CompressorFactory::My_CompressorFactory (void) :
::TAO::CompressorFactory (Compression::COMPRESSORID_LZOP),
compressor_ (::Compression::Compressor::_nil ())
{
}
The factory method that must be implemented is the get_compressor method. For simplicity we ignore the compression_level, we just have one compressor instance for all levels.
Compression::Compressor_ptr
My_CompressorFactory::get_compressor (
Compression::CompressionLevel compression_level)
{
if (CORBA::is_nil (compressor_.in ()))
{
compressor_ = new MyCompressor (compression_level, this);
}
return Compression::Compressor::_duplicate (compressor_.in ());
}
The CompressorFactory is now ready and we start to implement the Compressor itself. For simplifying the implementation we use the BaseCompressor helper base class. Besides the constructor we have to implement the compress and decompress methods
class MyCompressor : public ::TAO::BaseCompressor
{
public:
MyCompressor (Compression::CompressionLevel compression_level,
Compression::CompressorFactory_ptr compressor_factory);
virtual void compress (
const Compression::Buffer &source,
Compression::Buffer &target);
virtual void decompress (
const Compression::Buffer &source,
Compression::Buffer &target);
};
The constructor just passes the values to its base, this compressor is very easy, it doesn't need to store any additional data itself.
MyCompressor::MyCompressor (
Compression::CompressionLevel compression_level,
Compression::CompressorFactory_ptr compressor_factory) :
BaseCompressor (compression_level, compressor_factory)
{
}
Then the compress method, we need to compress the data from the source into the target. At the moment compression fails we must throw a Compression::CompressionException exception.
void
MyCompressor::compress (
const Compression::Buffer &source,
Compression::Buffer &target)
{
// do compression
}
The decompress method should do the opposite work of the compress method. At the moment decompression fails then also a Compression::CompressionException must be thrown.
void
MyCompressor::decompress (
const Compression::Buffer &source,
Compression::Buffer &target)
{
// do decompression
}
If you have implemented a compressor, consider contributing that back to the TAO distribution so that other applications can also benefit from this compressor.


Comments
TAO receives new run-length encoding compressor
One of our users contributed a new run-length encoding compressor. This compressor will be part of the TAO 2.0.9 micro release. This rle compressor is not dependent on any external library and will be enabled by default. Because we now have a compressor that always work we have enabled ZIOP by default. Of course the ORB will only use ZIOP when you set the ZIOP policies.
When the ZIOP policies do get set, the ORB will compress application data before sending it over the wire.