// -*- Mode: C++; -*-
//                              File      : corba_wrappers.h
//                              Package   : omniNotify-Library
//                              Created on: 30-Oct-2000
//                              Authors   : gruber
//
//    Copyright (C) 1998-2001 AT&T Laboratories -- Research
//
//    This file is part of the omniNotify library
//    and is distributed with the omniNotify release.
//
//    The omniNotify library is free software; you can redistribute it and/or
//    modify it under the terms of the GNU Library General Public
//    License as published by the Free Software Foundation; either
//    version 2 of the License, or (at your option) any later version.
//
//    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 GNU
//    Library General Public License for more details.
//
//    You should have received a copy of the GNU Library General Public
//    License along with this library; if not, write to the Free
//    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
//    02111-1307, USA
//
// Description:
//    wrappers hide BOA/POA differences 
 
//////////////////////////////////////////////////////////////////////
//
//                WRAPPER NOTES
//
// NEW: The static state required for WRAPPED_ORB_OA must be declared
// in exactly one .cc file by including corba_wrappers_impl.h.
//
// If you are using the CosNotify library, then this initialization
// is already included in the library and you need not do anything more.
//
// If you are using corba_wrappers.h (and related wrappers files)
// with a stand-alone application then you should include corba_wrappers_impl.h
// in, e.g., the .cc file that contains your main().
//
// Pre-Initialization
// ------------------
// The following calls set configuration parameters of the ORB.
// Not all ORBs will support these calls, so only things that optimize
// performance if they are available should be here.
//
//    WRAPPED_ORB_SETMAXTCP(x);
//
// Sets maximum number of TCP connections to x.
// 
// WRAPPED_ORB_OA Initialization
// -----------------------------
//   Always use this generic init form at top of main:
//          WRAPPED_ORB_OA::init(argc, argv);
//   N.B. This stores some state in static class variables of the
//   class WRAPPED_ORB_OA.  Other calls below rely on this state
//   being set.
//
//   This call initializes an orb and either a boa or a poa.
//   NB: argc, argv are modified to remove any orb-specific arguments
// 
// OBTAINING THE ORB
// -----------------
//  Use 
//       WRAPPED_ORB_OA::orb() 
//  if you need a reference to the orb.  You should *not* release
//  this reference (unless you duplicate it yourself).
//
// WRAPPED_ORB_OA Cleanup
// ----------------------
//          WRAPPED_ORB_OA::cleanup();
//
//   This call cleans up the orb and boa or poa that were
//   initialized via WRAPPED_ORB_OA::init.  None of the
//   calls below should be used after invoking cleanup.
//
// Constructing and registering objects
// ------------------------------------
//      Foo_i* myfoo = new Foo_i(....); // construct a new impl of Foo interface using class Foo_i
//       // returns 1 on error, return 0 on success...
//      CORBA::Boolean failcode = WRAPPED_REGISTER_IMPL(myfoo);
//
//    This will register the object with the boa or poa manager.
//
// Activate *OAs
// -------------
// Call
//      WRAPPED_ORB_OA::activate_oas();
//
// to active the boa or poa.  For boa it does a non-blocking
// impl_is_ready (for some orbs this means spawning a thread, but for
// omniorb there is a nonblocking impl_is_ready option)
//
// Waiting for shutdown
// --------------------
//     WRAPPED_ORB_OA::run();
//
//   This call blocks until a shutdown occurs, due to a failure
//   or to an explicit shutdown...
//
// Causing a shutdown
// ------------------
//     WRAPPED_ORB_OA::shutdown(CORBA::Boolean wait_for_completion);
//
// If the argument wait_for_completion is false, then the actual work of
// carrying out a shutdown will occur in a separate thread and the
// shutdown call will return immediately.  If it is true then the call
// blocks until the shutdown work has been done.
//
// Reference management
// --------------------
// When you have a CORBA object reference, there are standard ways to
// duplicate the reference and release the reference:
//
//     Foo::_duplicate(fooptr); // duplicate an obj reference
//     CORBA::release(fooptr);  // release   an obj reference
//
// However, when you have an implementation reference, there is no
// standard way to do a duplicate or release of the associated
// object reference.  The member function _this() converts from
// the impl reference to the object reference, but it sometimes has
// a reference-duplicating side-effect, and sometimes not.
// For this reason you should avoid using _this() in your code,
// and instead use these macros...
//
// After creating a Foo_i object called myfoo, if you want a
// CORBA object reference, use
//
//   Foo_ptr fooptr = WRAPPED_IMPL2OREF(Foo,myfoo);
//
// This has a side-effect of duplicating the reference.
// ** Remember to release a reference produced by WRAPPED_IMPL2OREF.
//
// Note: with some orbs,
//
//     Foo_ptr fooptr = myfoo->_this();
//
// has a duplicating side-effect, but with some it does not,
// in which case the above wrapper does
//
//     Foo_ptr fooptr = Foo::_duplicate(myfoo->_this());
//
// With the wrapper you know you always get the duplicating side-effect;
// so you can avoid using _this() in your code.
//
// If you have a myfoo and you want to do a release, use
//
//     WRAPPED_RELEASE_IMPL(myfoo);
//
// Safe object disposal
// --------------------
// We use a special helper class, RDIOPlocks, to manage
// safe disposal of objects.  An RDIOplockEntry is allocated
// for each managed object, where the _oplockptr member point
// to this entry.  The entry has an inuse count that, if
// non-zero, is used to defer disposal of the associated
// object until it is safe to do so.  See RDIOplocks.h
// for details.  The following macros are used by the helper class:
//
// WRAPPED_DISPOSEINFO_PTR, WRAPPED_DISPOSEINFO_VAR, WRAPPED_DISPOSEINFO_NIL:
//   the ptr and var types, and the null value, for the information required
//   to dispose an object implementation.  For example, for a POA manager,
//   a PortableServer::ObjectId is needed to deactivate an object implementation.
//   This information is passed to RDIOplocks in a release_entry call.
//   RDIOplocks does the actual disposal once the inuse count is zero.
//
// WRAPPED_IMPL2DISPOSEINFO(implref)
//   Given an impl reference, produce the necessary dispose info.
// 
// WRAPPED_DISPOSE_INFO(info)
//   Dispose the impl associated with info.
// ==> should normally be followed by:
// info = WRAPPED_DISPOSEINFO_NIL
//
// Note that the macro
//     WRAPPED_DISPOSE_IMPL(implref)
//
// is a shorthand for these 2 steps:
//
//    WRAPPED_DISPOSEINFO_VAR info = WRAPPED_IMPL2DISPOSEINFO(implref);
//    WRAPPED_DISPOSE_INFO(info);
//
//
// Implementing the Foo_i class
// ----------------------------
// Let us say there is a module M with interface Foo, and you want
// to define an impl class Foo_i.  You declare the class as follows:
//
// class Foo_i : WRAPPED_SKELETON_SUPER(M, Foo) {
// public:
//    <constructor decl>
//    void foo ( WRAPPED_DECLARG_VOID );
//    void bar ( CORBA::ULong u    WRAPPED_DECLARG );
// protected:
//    <rest of class decl>
// }
//
// And the corresponding method implementations look like:
// 
// void Foo_i::foo ( WRAPPED_IMPLARG_VOID ) { <impl> };
// void Foo_i::bar ( CORBA::ULong u WRAPPED_IMPLARG ) { <impl> };
//
// If the ULong argument u was an out param rather than an in param,
// you should use WRAPPED_OUTARG_TYPE(CORBA::ULong) for both the
// declaration and implementation of the bar method.
//
//
// The WRAPPED_SKELETON_SUPER macro can expand to one or more
// BOA or POA helper classes that together provide the skeleton
// infrastructure for implementing an object that supports
// CORBA interface M::Foo.
//
// WRAPPED_DECLARG_VOID / WRAPPED_IMPLARG_VOID are used
// for methods with no parameters, while 
// WRAPPED_DECLARG / WRAPPED_IMPLARG are used for methods
// with one or more parameters.  Note that there is NO COMMA 
// between the last param and the DECLARG or IMPLARG macro.
// 
//
// Resolving initial references
// ----------------------------
//  Although all ORBs provide an orb->resolve_initial_references function,
//  configuring the ORB do use, say, a different name service, can be a
//  major hassle.  Sometimes it is easier to put special case handling
//  in a macro, which is why we provide the following macro.  Here is
//  an example use:
//
//    CORBA::Object_var nmsv = WRAPPED_RESOLVE_INITIAL_REFERENCE("NameService");
//    CosNaming::NamingContext_var nmcx = CosNaming::NamingContext::_narrow(nmsv);
//    if ( CORBA::is_nil(nmcx) ) { ... something went wrong ... }
//    ... use nmcx (root naming context) ...
//
// Hashing an object reference
//   WRAPPED_OBJREF_HASH(objref, max) :
// returns an unsigned long hash value for objref,
// where max is the max value that should be returned
//
//////////////////////////////////////////////////////////////////////

#ifndef __CORBA_WRAPPERS_H__
#define __CORBA_WRAPPERS_H__

// More ORBs could be supported.  For now we just support OMNIORB3/4
#if !defined(__OMNIORB3__) && !defined(__OMNIORB4__)
#  error "One of the following must be defined : __OMNIORB3__, __OMNIORB4__"
stop_compiling
#endif

#if defined(__OMNIORB3__) 
#  include <omniORB3/CORBA.h>
#  include <omniORB3/Naming.hh>
#else
#  include <omniORB4/CORBA.h>
#  include <omniORB4/Naming.hh>
#endif

#ifdef COS_USES_BOA
#  include "omniorb_boa_wrappers.h"
#else
#  include "omniorb_poa_wrappers.h"
#endif

////////////////////////////////////////////////////////////////////
// Macros that are always the same (combinations of other macros) //
////////////////////////////////////////////////////////////////////

#define WRAPPED_DISPOSE_IMPL(implref) \
  do {\
    WRAPPED_DISPOSEINFO_VAR info = WRAPPED_IMPL2DISPOSEINFO(implref); \
    WRAPPED_DISPOSE_INFO(info); } while (0)


#endif /* __CORBA_WRAPPERS_H__ */
