2005/5/9

     
 

Marshaler.h

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/dmi/Marshaler.h,v 1.11 2005/03/06 11:57:19 kommer Exp $
#ifndef acdk_lang_dmi_Marshaler_h
#define acdk_lang_dmi_Marshaler_h

#include <acdk.h>
#include <acdk/lang/sys/RefHolderExt.h>

namespace acdk {
namespace lang {
namespace dmi {

/**
  Abstract base class for general purpose marshaling.

  @see StandardMarshaler For local standard marshaling  
*/
foreign 
class ACDK_CORE_PUBLIC Marshaler
{
public:
  /**
    The marshalign code passes this to the un/marshaler method
    to indicate, on what communcation side for which purpose the 
    argument should be marshaled.
  */
  enum MarshalMode
  {
    Unknown = 0,
    /** The client sends data */
    SendClient,
    /** The Server send data to the client */
    SendServer,
    /** The client receives data */
    ReceiveClient,
    /** The server receives Data */
    ReceiveServer,
    /** Client in and out data */
    SendReceiveClient,
    /** Server in and out data */
    SendReceiveServer
  };
  
  virtual ~Marshaler() {} 
  /**
    Marshals the given obj on basis of given class into the outstore.
    @param cls The Class, which should be used to marshal
    @param obj the acdk::lang::Object instance, which should be marshaled.
    @param outstore the streamed storage
    @param mode On which side and for which purpose the method will be called
    @throw ObjectStreamException
  */
  virtual void marshal(IN(RClass) cls, IN(acdk::lang::Object) obj, byteArray& outstore, MarshalMode mode = Unknown) = 0;
  /**
    Unmarshals the on basis of given Class an object using instore.
    @param cls The template to use
    @param instore the buffer, from home to read
    @param mode On which side and for which purpose the method will be called
    @param cachedObject If the interface cache the object, it may can be reused by the marshaler
    @return The acdk::lang::Object 
    @throw ObjectStreamException
  */
  virtual acdk::lang::Object unmarshal(IN(RClass) cls, byteArray& instore, MarshalMode mode = Unknown, IN(acdk::lang::Object) cachedObject = Nil) = 0;
  
};

/**
  If a BYVAL-call is used locally, the standard marshaler is used to make copies of the 
  objects.
*/
foreign 
class ACDK_CORE_PUBLIC StandardMarshaler
: public Marshaler
{
  acdk::lang::Object _obj;
public:
  
	virtual void marshal(IN(RClass) cls, IN(acdk::lang::Object) obj, byteArray& outstore, MarshalMode mode = Unknown);
	virtual acdk::lang::Object unmarshal(IN(RClass) cls, byteArray& instore, MarshalMode mode = Unknown, IN(acdk::lang::Object) cachedObject = Nil);
  static StandardMarshaler gInstance;
};

/**
  
*/
template <class T>
class TMarshaler
{
protected:
  byteArray _data;
  Marshaler& _marshaler;
  
public:
  TMarshaler(Marshaler& marshaler = StandardMarshaler::gInstance)
	: _data(0)
  , _marshaler(marshaler)
	{
	}
protected:
	~TMarshaler()
	{
	}
	RClass getTClass()
  {
    return ::acdk::lang::Class::getSingeltonClass(T::clazzInfo());
  }
};


/**
  Marshal Holder for sending data from Client to Server.
  T is type of the RefHolder family
  and contains and Objects which supports 
  serialization.
*/
 
template <class T>
class TSendMarshaler
: public TMarshaler<T>
{
  T _rh;
public:
  TSendMarshaler(Marshaler& marshaler = StandardMarshaler::gInstance)
  : TMarshaler<T>(marshaler)
  {
  }
	TSendMarshaler(const T& rh, Marshaler& marshaler = StandardMarshaler::gInstance)
  : TMarshaler<T>(marshaler)
  , _rh() // don't take copy, because otherwise it will not copied.
  {
    TSendMarshaler<T>::_marshaler.marshal(TSendMarshaler<T>::getTClass(), (::acdk::lang::RObject)rh, TSendMarshaler<T>::_data, Marshaler::SendClient);
	}
	~TSendMarshaler()
	{
		// nothing here
	}
  T getT()
  {
    if (_rh != Nil)
      return _rh;
    _rh = (T)TSendMarshaler<T>::_marshaler.unmarshal(TSendMarshaler<T>::getTClass(), TSendMarshaler<T>::_data, Marshaler::SendServer);
    return _rh;
  }
  T operator ()()
  {
    return TSendMarshaler<T>::getT(); 
  }
	operator T () 
	{ 
		return TSendMarshaler<T>::getT();
	}
  T operator->() { return operator T(); }
};



/**
  Marshal Holder for receiving data from server
  T is type of RefHolder family
*/
template <class T>
class TReceiveMarshaler
: public TMarshaler<T>
{
  T _serverObject;
  T& _clientObject;
public:	
  TReceiveMarshaler(T& rh, Marshaler& marshaler = StandardMarshaler::gInstance)
  : TMarshaler<T>(marshaler)
  , _serverObject()
  , _clientObject(rh)
  {
		
	}
// gcc 3.1 doesn't like this?
// private:
  TReceiveMarshaler(const TReceiveMarshaler<T>& other);
public:
	~TReceiveMarshaler()
	{
    if (_serverObject != Nil)
      TReceiveMarshaler<T>::_marshaler.marshal(TReceiveMarshaler<T>::getTClass(), (::acdk::lang::RObject)_serverObject, TReceiveMarshaler<T>::_data, Marshaler::ReceiveServer);
    else
      _clientObject = (T)TReceiveMarshaler<T>::_marshaler.unmarshal(TReceiveMarshaler<T>::getTClass(), TReceiveMarshaler<T>::_data, Marshaler::ReceiveClient, (::acdk::lang::RObject)_clientObject);
	}
  TReceiveMarshaler<T>& operator=(const T& other)
  {
    TReceiveMarshaler<T>::_marshaler.marshal(TReceiveMarshaler<T>::getTClass(), (::acdk::lang::RObject)other, TReceiveMarshaler<T>::_data, Marshaler::ReceiveServer);
    return *this;
  }
};


/**
  Marshal Holder for sending data from client to server and back
  T is type of RefHolder family
*/
template <class T>
class TSendReceiveMarshaler
: public TMarshaler<T>
{
  T& _rrh;
public:
  TSendReceiveMarshaler(T& rh, Marshaler& marshaler = StandardMarshaler::gInstance)
  : TMarshaler<T>(marshaler)
  , _rrh(rh)
  {
    TSendReceiveMarshaler<T>::_marshaler.marshal(TSendReceiveMarshaler<T>::getTClass(), (::acdk::lang::RObject)_rrh, TSendReceiveMarshaler<T>::_data, Marshaler::SendReceiveClient);
	}
private:
  TSendReceiveMarshaler(const TReceiveMarshaler<T>& other)
  : TMarshaler<T>()
  ,  _rrh(other._rrh)
  {
  }
public:
	~TSendReceiveMarshaler()
	{
    _rrh = (T)TSendReceiveMarshaler<T>::_marshaler.unmarshal(TSendReceiveMarshaler<T>::getTClass(), TSendReceiveMarshaler<T>::_data, Marshaler::SendReceiveClient, (::acdk::lang::RObject)_rrh);
	}
  operator T ()
  {
    return (T)TSendReceiveMarshaler<T>::_marshaler.unmarshal(TSendReceiveMarshaler<T>::getTClass(), TSendReceiveMarshaler<T>::_data, Marshaler::SendReceiveClient, (::acdk::lang::RObject)_rrh);
  }
  TSendReceiveMarshaler<T>& operator=(const T& other)
  {
    TSendReceiveMarshaler<T>::_marshaler.marshal(TSendReceiveMarshaler<T>::getTClass(), (::acdk::lang::RObject)other, TSendReceiveMarshaler<T>::_data, Marshaler::SendReceiveServer);
    return *this;
  }
};




} // namespace dmi
} // namespace lang
} // namespace acdk
#endif // acdk_lang_dmi_Marshaler_h