//*****************************************************************************
// RCF - Remote Call Framework
// Copyright (c) 2005. All rights reserved.
// Developed by Jarl Lindrud.
// Contact: jlindrud@hotmail.com .
//*****************************************************************************
#ifndef INCLUDE_RCF_MARSHAL_HPP
#define INCLUDE_RCF_MARSHAL_HPP
#include <RCF/ClientStub.hpp>
#include <RCF/SerializationProtocol.hpp>
#include <RCF/MethodInvocation.hpp>
#include <RCF/Tools.hpp>
#include <RCF/util/Meta.hpp>
#include <SF/Tools.hpp> // FOR_EACH_PRIMITIVE_TYPE
#include <boost/mpl/not.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
// TODO: move code into Marshal.inl
namespace RCF {
// Boost.Serialization treats pointers of primitive types differently than other types,
// hence the following hack, which unfortunately overrides all the serialization protocols,
// not just Boost.Serialization.
#define RCF_DEFINE_PRIMITIVE_POINTER_SERIALIZATION(type) \
inline SerializationProtocolOut &operator<<(SerializationProtocolOut &out, const type *pt) { return out << *pt; } \
inline SerializationProtocolOut &operator<<(SerializationProtocolOut &out, type *const pt) { return out << *pt; } \
inline SerializationProtocolIn &operator>>(SerializationProtocolIn &in, type *&pt) { RCF_ASSERT(pt==NULL); pt = new type(); return in >> *pt; }
SF_FOR_EACH_FUNDAMENTAL_TYPE( RCF_DEFINE_PRIMITIVE_POINTER_SERIALIZATION )
RCF_DEFINE_PRIMITIVE_POINTER_SERIALIZATION(std::string)
#undef RCF_DEFINE_PRIMITIVE_POINTER_SERIALIZATION
// Boost.Serialization handles smart pointers very clumsily, so we'll do those ourselves
//#define RCF_SERIALIZE_REFCOUNTSMARTPTR(RefCountSmartPtr)
#define RefCountSmartPtr boost::shared_ptr
template<typename T>
inline SerializationProtocolOut &operator<<(SerializationProtocolOut &out, const RefCountSmartPtr<T> *spt)
{
return out << *spt;
}
template<typename T>
inline SerializationProtocolOut &operator<<(SerializationProtocolOut &out, RefCountSmartPtr<T> *const spt)
{
return out << *spt;
}
template<typename T>
inline SerializationProtocolIn &operator>>(SerializationProtocolIn &in, RefCountSmartPtr<T> *&spt)
{
spt = new RefCountSmartPtr<T>();
return in >> *spt;
}
template<typename T>
inline SerializationProtocolOut &operator<<(SerializationProtocolOut &out, const RefCountSmartPtr<T> &spt)
{
return out << spt.get();
}
template<typename T>
inline SerializationProtocolIn &operator>>(SerializationProtocolIn &in, RefCountSmartPtr<T> &spt)
{
T *pt = NULL;
in >> pt;
RefCountSmartPtr<T> *pspt =
in.getPointerContext().template get< RefCountSmartPtr<T> * >(pt);
if (pspt == NULL)
{
spt = RefCountSmartPtr<T>(pt);
in.getPointerContext().template set< RefCountSmartPtr<T> * >(&spt, pt);
}
else
{
spt = *pspt;
}
return in;
}
#undef RefCountSmartPtr
struct Void {};
namespace IDL {
class DoRequest
{
public:
DoRequest(ClientStub &stub, bool oneway, const std::string &subInterface, int fnId, SerializationProtocolOut &out)
{
stub.onPreCall();
stub.connectTransport();
out.reset(stub.getSerializationProtocol());
out << RCF::MethodInvocationRequest(stub.getToken(), stub.getServerBindingName(), subInterface, fnId, oneway, false);
}
};
template<typename T>
class InParameter
{
public:
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_pointer<T>::type >::value );
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_reference<T>::type >::value );
InParameter(const T &t, SerializationProtocolOut &out) : t_() { out << t; }
InParameter(SerializationProtocolIn &in) : t_() { in >> t_; }
const T &get() { return t_; }
private:
T t_;
};
template<typename T>
class InParameter<T *>
{
public:
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_pointer<T>::type >::value );
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_reference<T>::type >::value );
typedef typename boost::remove_const<T>::type U;
InParameter(T *pt, SerializationProtocolOut &out)
{
out << pt;
}
InParameter(SerializationProtocolIn &in)
{
U *pu = NULL;
in >> pu;
boost::shared_ptr<U> *ppu = in.getPointerContext().template get< boost::shared_ptr<U>* >(pu);
if (ppu == NULL)
{
pu_ = boost::shared_ptr<U>(pu);
in.getPointerContext().template set< boost::shared_ptr<U>* >(&pu_, pu);
}
else
{
pu_ = *ppu;
}
}
T *get()
{
return pu_.get();
}
private:
boost::shared_ptr<U> pu_;
};
template<typename T>
class InParameter<T &>
{
public:
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_pointer<T>::type >::value );
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_reference<T>::type >::value );
typedef typename boost::remove_const<T>::type U;
InParameter(T &t, SerializationProtocolOut &out)
{
out << &t;
}
InParameter(SerializationProtocolIn &in)
{
U *pu = NULL;
in >> pu;
boost::shared_ptr<U> *ppu = in.getPointerContext().template get< boost::shared_ptr<U>* >(pu);
if (ppu == NULL)
{
pu_ = boost::shared_ptr<U>(pu);
in.getPointerContext().template set< boost::shared_ptr<U>* >(&pu_, pu);
}
else
{
pu_ = *ppu;
}
}
T &get()
{
return *pu_;
}
private:
boost::shared_ptr<U> pu_;
};
template<typename T>
class OutParameter
{
public:
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_pointer<T>::type >::value );
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_reference<T>::type >::value );
OutParameter(const T &, SerializationProtocolIn &, bool)
{}
template<typename V> OutParameter( InParameter< V > &, SerializationProtocolOut &)
{}
};
template<typename T>
class OutParameter<T *>
{
public:
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_pointer<T>::type >::value );
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_reference<T>::type >::value );
OutParameter(const T *t, SerializationProtocolIn &in, bool oneway)
{}
template<typename V> OutParameter( InParameter< V > &v, SerializationProtocolOut &out)
{}
};
template<typename T>
class OutParameter<const T &>
{
public:
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_pointer<T>::type >::value );
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_reference<T>::type >::value );
OutParameter(const T &t, SerializationProtocolIn &in, bool oneway)
{
RCF_UNUSED_VARIABLE(t);
RCF_UNUSED_VARIABLE(in);
RCF_UNUSED_VARIABLE(oneway);
}
template<typename V> OutParameter( InParameter< V > &v, SerializationProtocolOut &out)
{
RCF_UNUSED_VARIABLE(v);
RCF_UNUSED_VARIABLE(out);
}
};
template<typename T>
class OutParameter<T &>
{
public:
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_pointer<T>::type >::value );
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_reference<T>::type >::value );
OutParameter(T &t, SerializationProtocolIn &in, bool oneway)
{
if (!oneway)
{
in >> t;
}
}
template<typename V> OutParameter( InParameter< V > &v, SerializationProtocolOut &out)
{
out << v.get();
}
};
template<typename T = Void>
class OutReturnValue
{
public:
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_pointer<T>::type >::value );
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_reference<T>::type >::value );
OutReturnValue(SerializationProtocolOut &out, const T &t)
{
out << RCF::MethodInvocationResponse(false);
out << t;
}
};
template<>
class OutReturnValue<Void>
{
public:
OutReturnValue(SerializationProtocolOut &out, int t)
{
RCF_UNUSED_VARIABLE(t);
out << RCF::MethodInvocationResponse(false);
}
};
template<typename T = Void>
class InReturnValue
{
public:
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_pointer<T>::type >::value );
BOOST_STATIC_ASSERT( boost::mpl::not_< typename boost::is_reference<T>::type >::value );
InReturnValue(ClientStub &clientStub, SerializationProtocolIn &in, SerializationProtocolOut &out, bool oneway);
T &get();
private:
T t_;
};
template<>
class InReturnValue<Void>
{
public:
InReturnValue(ClientStub &clientStub, SerializationProtocolIn &in, SerializationProtocolOut &out, bool oneway);
Void get() { return Void(); }
};
} // namespace IDL
// ClientMarshal
template<
typename R,
typename A1 = Meta::Null,
typename A2 = Meta::Null,
typename A3 = Meta::Null,
typename A4 = Meta::Null,
typename A5 = Meta::Null,
typename A6 = Meta::Null>
class ClientMarshal;
// NB: using this instead of ScopeGuard,because Borland C++ is not triggering ScopeGuard at all.
// At least with this class, it's triggered in debug builds (but not release apparently).
class ConnectionResetGuard
{
public:
ConnectionResetGuard(ClientStub &clientStub) :
mClientStub(clientStub),
mDismissed()
{}
void dismiss()
{
mDismissed = true;
}
~ConnectionResetGuard()
{
if (!mDismissed)
{
try
{
mClientStub.resetTransport();
}
catch(...)
{}
}
}
private:
ClientStub &mClientStub;
bool mDismissed;
};
template<typename R>
class ClientMarshal<R, Meta::Null, Meta::Null, Meta::Null, Meta::Null, Meta::Null, Meta::Null>
{
public:
R operator()(ClientStub &clientStub, RemoteCallSemantics rcs, const std::string &subInterface, int fnId) const
{
bool oneway = (Oneway == rcs);
ConnectionResetGuard connectionResetGuard(clientStub);
RCF::IDL::DoRequest(clientStub, oneway, subInterface, fnId, clientStub.out);
RCF::IDL::InReturnValue< R > ret(clientStub, clientStub.in, clientStub.out, oneway);
connectionResetGuard.dismiss();
return ret.get();
}
};
template<typename R, typename A1>
class ClientMarshal<R,A1, Meta::Null, Meta::Null, Meta::Null, Meta::Null, Meta::Null>
{
public:
R operator()(ClientStub &clientStub, RemoteCallSemantics rcs, const std::string &subInterface, int fnId, A1 a1) const
{
bool oneway = (Oneway == rcs);
ConnectionResetGuard connectionResetGuard(clientStub);
RCF::IDL::DoRequest(clientStub, oneway, subInterface, fnId, clientStub.out);
RCF::IDL::InParameter< A1 >(a1, clientStub.out);
RCF::IDL::InReturnValue< R > ret(clientStub, clientStub.in, clientStub.out, oneway);
RCF::IDL::OutParameter< A1 >(a1, clientStub.in, oneway);
connectionResetGuard.dismiss();
return ret.get();
}
};
template<typename R, typename A1, typename A2>
class ClientMarshal<R,A1,A2, Meta::Null, Meta::Null, Meta::Null, Meta::Null >
{
public:
R operator()(ClientStub &clientStub, RemoteCallSemantics rcs, const std::string &subInterface, int fnId, A1 a1, A2 a2) const
{
bool oneway = (Oneway == rcs);
ConnectionResetGuard connectionResetGuard(clientStub);
RCF::IDL::DoRequest(clientStub, oneway, subInterface, fnId, clientStub.out);
RCF::IDL::InParameter< A1 >(a1, clientStub.out);
RCF::IDL::InParameter< A2 >(a2, clientStub.out);
RCF::IDL::InReturnValue< R > ret(clientStub, clientStub.in, clientStub.out, oneway);
RCF::IDL::OutParameter< A1 >(a1, clientStub.in, oneway);
RCF::IDL::OutParameter< A2 >(a2, clientStub.in, oneway);
connectionResetGuard.dismiss();
return ret.get();
}
};
template<typename R, typename A1, typename A2, typename A3>
class ClientMarshal<R,A1,A2,A3, Meta::Null, Meta::Null, Meta::Null>
{
public:
R operator()(ClientStub &clientStub, RemoteCallSemantics rcs, const std::string &subInterface, int fnId, A1 a1, A2 a2, A3 a3) const
{
bool oneway = (Oneway == rcs);
ConnectionResetGuard connectionResetGuard(clientStub);
RCF::IDL::DoRequest(clientStub, oneway, subInterface, fnId, clientStub.out);
RCF::IDL::InParameter< A1 >(a1, clientStub.out);
RCF::IDL::InParameter< A2 >(a2, clientStub.out);
RCF::IDL::InParameter< A3 >(a3, clientStub.out);
RCF::IDL::InReturnValue< R > ret(clientStub, clientStub.in, clientStub.out, oneway);
RCF::IDL::OutParameter< A1 >(a1, clientStub.in, oneway);
RCF::IDL::OutParameter< A2 >(a2, clientStub.in, oneway);
RCF::IDL::OutParameter< A3 >(a3, clientStub.in, oneway);
connectionResetGuard.dismiss();
return ret.get();
}
};
template<typename R, typename A1, typename A2, typename A3, typename A4>
class ClientMarshal<R,A1,A2,A3,A4, Meta::Null, Meta::Null>
{
public:
R operator()(ClientStub &clientStub, RemoteCallSemantics rcs, const std::string &subInterface, int fnId, A1 a1, A2 a2, A3 a3, A4 a4) const
{
bool oneway = (Oneway == rcs);
ConnectionResetGuard connectionResetGuard(clientStub);
RCF::IDL::DoRequest(clientStub, oneway, subInterface, fnId, clientStub.out);
RCF::IDL::InParameter< A1 >(a1, clientStub.out);
RCF::IDL::InParameter< A2 >(a2, clientStub.out);
RCF::IDL::InParameter< A3 >(a3, clientStub.out);
RCF::IDL::InParameter< A4 >(a4, clientStub.out);
RCF::IDL::InReturnValue< R > ret(clientStub, clientStub.in, clientStub.out, oneway);
RCF::IDL::OutParameter< A1 >(a1, clientStub.in, oneway);
RCF::IDL::OutParameter< A2 >(a2, clientStub.in, oneway);
RCF::IDL::OutParameter< A3 >(a3, clientStub.in, oneway);
RCF::IDL::OutParameter< A4 >(a4, clientStub.in, oneway);
connectionResetGuard.dismiss();
return ret.get();
}
};
template<typename R, typename A1, typename A2, typename A3, typename A4, typename A5>
class ClientMarshal<R,A1,A2,A3,A4,A5, Meta::Null>
{
public:
R operator()(ClientStub &clientStub, RemoteCallSemantics rcs, const std::string &subInterface, int fnId, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) const
{
bool oneway = (Oneway == rcs);
ConnectionResetGuard connectionResetGuard(clientStub);
RCF::IDL::DoRequest(clientStub, oneway, subInterface, fnId, clientStub.out);
RCF::IDL::InParameter< A1 >(a1, clientStub.out);
RCF::IDL::InParameter< A2 >(a2, clientStub.out);
RCF::IDL::InParameter< A3 >(a3, clientStub.out);
RCF::IDL::InParameter< A4 >(a4, clientStub.out);
RCF::IDL::InParameter< A5 >(a5, clientStub.out);
RCF::IDL::InReturnValue< R > ret(clientStub, clientStub.in, clientStub.out, oneway);
RCF::IDL::OutParameter< A1 >(a1, clientStub.in, oneway);
RCF::IDL::OutParameter< A2 >(a2, clientStub.in, oneway);
RCF::IDL::OutParameter< A3 >(a3, clientStub.in, oneway);
RCF::IDL::OutParameter< A4 >(a4, clientStub.in, oneway);
RCF::IDL::OutParameter< A5 >(a5, clientStub.in, oneway);
connectionResetGuard.dismiss();
return ret.get();
}
};
} // namespace RCF
#include <RCF/Marshal.inl>
#endif // ! INCLUDE_RCF_MARSHAL_HPP