Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

CorbaService.cpp

Go to the documentation of this file.
00001 /***************** <Tweek heading BEGIN do not edit this line> ****************
00002  * Tweek
00003  *
00004  * -----------------------------------------------------------------
00005  * File:          $RCSfile: CorbaService.cpp,v $
00006  * Date modified: $Date: 2004/03/11 00:48:08 $
00007  * Version:       $Revision: 1.11 $
00008  * -----------------------------------------------------------------
00009  ***************** <Tweek heading END do not edit this line> *****************/
00010 
00011 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
00012  *
00013  * VR Juggler is (C) Copyright 1998-2003 by Iowa State University
00014  *
00015  * Original Authors:
00016  *   Allen Bierbaum, Christopher Just,
00017  *   Patrick Hartling, Kevin Meinert,
00018  *   Carolina Cruz-Neira, Albert Baker
00019  *
00020  * This library is free software; you can redistribute it and/or
00021  * modify it under the terms of the GNU Library General Public
00022  * License as published by the Free Software Foundation; either
00023  * version 2 of the License, or (at your option) any later version.
00024  *
00025  * This library is distributed in the hope that it will be useful,
00026  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00027  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00028  * Library General Public License for more details.
00029  *
00030  * You should have received a copy of the GNU Library General Public
00031  * License along with this library; if not, write to the
00032  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00033  * Boston, MA 02111-1307, USA.
00034  *
00035  *************** <auto-copyright.pl END do not edit this line> ***************/
00036 
00037 #include <tweek/tweekConfig.h>
00038 
00039 #include <cstdio>
00040 #include <cstdlib>
00041 #include <string>
00042 #include <boost/concept_check.hpp>
00043 
00044 #include <vpr/vpr.h>
00045 #include <vpr/Util/Assert.h>
00046 #include <vpr/Util/Debug.h>
00047 
00048 #include <tweek/Util/Debug.h>
00049 #include <tweek/Util/Version.h>
00050 #include <tweek/CORBA/CorbaHelpers.h>
00051 #include <tweek/Client/CorbaService.h>
00052 
00053 
00054 namespace tweek
00055 {
00056 
00057 CorbaService::CorbaService(const std::string& nsHost, vpr::Uint16 nsPort,
00058                            const std::string& iiopVersion,
00059                            const std::string& subContextId)
00060    : mOrbFunctor(NULL), mOrbThread(NULL), mNsHost(nsHost), mNsPort(nsPort),
00061      mNameServiceURI("corbaloc:iiop:"), mSubContextId(subContextId)
00062 {
00063    // Why isn't this conversion easier to do with std::string?
00064    char nsPort_str[6];
00065    std::sprintf(nsPort_str, "%hu", nsPort);
00066 
00067    mNameServiceURI += iiopVersion;
00068    mNameServiceURI += std::string("@");
00069    mNameServiceURI += nsHost;
00070    mNameServiceURI += std::string(":");
00071    mNameServiceURI += nsPort_str;
00072    mNameServiceURI += std::string("/NameService");
00073 
00074    vprDEBUG(tweekDBG_CORBA, vprDBG_VERB_LVL)
00075       << "Naming Service URI: " << mNameServiceURI << std::endl
00076       << vprDEBUG_FLUSH;
00077 
00078    std::string tweek_ver = getVersionString();
00079 
00080    // Print out the Tweek version information.
00081    vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00082       << std::string(tweek_ver.length() + 14, '=') << std::endl
00083       << vprDEBUG_FLUSH;
00084    vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00085       << clrOutNORM(clrGREEN, "Tweek Client: ")
00086       << clrOutNORM(clrGREEN, tweek_ver) << clrRESET << std::endl
00087       << vprDEBUG_FLUSH;
00088    vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00089       << std::string(tweek_ver.length() + 14, '=') << std::endl
00090       << vprDEBUG_FLUSH;
00091 }
00092 
00093 vpr::ReturnStatus CorbaService::init(int& argc, char* argv[])
00094 {
00095    vpr::ReturnStatus status;
00096 
00097    try
00098    {
00099       // Initialize the ORB.
00100       vprDEBUG(tweekDBG_CORBA, vprDBG_STATE_LVL)
00101          << "Initializing client ORB (using init string '"
00102          << TWEEK_ORB_VER_STRING << "')\n" << vprDEBUG_FLUSH;
00103       mORB = CORBA::ORB_init(argc, argv, TWEEK_ORB_VER_STRING);
00104 
00105       initRootPOA();
00106 
00107       try
00108       {
00109          mRootContext = tweek::getRootNamingContextByURI(mORB, mNameServiceURI);
00110 
00111          if ( ! CORBA::is_nil(mRootContext) )
00112          {
00113             vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00114                << "Got root context, now binding local context\n"
00115                << vprDEBUG_FLUSH;
00116             mLocalContext =
00117                tweek::bindLocalNamingContext(mRootContext,
00118                                              std::string("tweek"));
00119          }
00120       }
00121       catch (CORBA::ORB::InvalidName& ex)
00122       {
00123          boost::ignore_unused_variable_warning(ex);
00124 
00125          // This should not happen!
00126          vprDEBUG(vprDBG_ALL, vprDBG_CRITICAL_LVL)
00127             << "NameService name invalid in CorbaService::init!\n"
00128             << vprDEBUG_FLUSH;
00129       }
00130 
00131       vprDEBUG(tweekDBG_CORBA, vprDBG_STATE_LVL) << "Starting ORB thread\n"
00132                                                  << vprDEBUG_FLUSH;
00133 
00134       mOrbFunctor = new vpr::ThreadRunFunctor<CorbaService>(this);
00135       mOrbThread  = new vpr::Thread(mOrbFunctor);
00136    }
00137    catch (CORBA::SystemException& sysEx)
00138    {
00139       status.setCode(vpr::ReturnStatus::Fail);
00140       vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00141          << "Caught CORBA::SystemException during initialization\n"
00142          << vprDEBUG_FLUSH;
00143       vprDEBUG_NEXT(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00144          << "Mindor code: " << sysEx.minor() << ", completed: "
00145          << vprDEBUG_FLUSH;
00146 
00147       switch ( sysEx.completed() )
00148       {
00149          case CORBA::COMPLETED_YES:
00150             vprDEBUG_CONT(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00151                << "YES" << std::endl << vprDEBUG_FLUSH;
00152             break;
00153          case CORBA::COMPLETED_NO:
00154             vprDEBUG_CONT(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00155                << "NO" << std::endl << vprDEBUG_FLUSH;
00156             break;
00157          case CORBA::COMPLETED_MAYBE:
00158             vprDEBUG_CONT(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00159                << "MAYBE" << std::endl << vprDEBUG_FLUSH;
00160             break;
00161       }
00162    }
00163    catch (CORBA::Exception&)
00164    {
00165       status.setCode(vpr::ReturnStatus::Fail);
00166       vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00167          << "Caught CORBA::Exception during initialization.\n"
00168          << vprDEBUG_FLUSH;
00169    }
00170    catch (omniORB::fatalException& fe)
00171    {
00172       boost::ignore_unused_variable_warning(fe);
00173 
00174       status.setCode(vpr::ReturnStatus::Fail);
00175       vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00176          << "Caught omniORB::fatalException:\n" << vprDEBUG_FLUSH;
00177       vprDEBUG_NEXT(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00178          << "  file: " << fe.file() << std::endl << vprDEBUG_FLUSH;
00179       vprDEBUG_NEXT(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00180          << "  line: " << fe.line() << std::endl << vprDEBUG_FLUSH;
00181       vprDEBUG_NEXT(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00182          << "  mesg: " << fe.errmsg() << std::endl << vprDEBUG_FLUSH;
00183    }
00184    catch(...)
00185    {
00186       vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00187          << "Caught unknown exception during initialization." << std::endl
00188          << vprDEBUG_FLUSH;
00189    }
00190 
00191    return status;
00192 }
00193 
00194 void CorbaService::shutdown(bool waitForCompletion)
00195 {
00196    if ( ! CORBA::is_nil(mRootPOA) )
00197    {
00198       // We want to etherialize objects (destroy registered servants).  This
00199       // will destroy all descendant POAs, so we do not have to worry about
00200       // them at all.
00201       mRootPOA->destroy(true, waitForCompletion);
00202    }
00203 
00204    if ( ! CORBA::is_nil(mORB) )
00205    {
00206       mORB->shutdown(waitForCompletion);
00207    }
00208 }
00209 
00210 std::list<tweek::SubjectManager_var> CorbaService::getSubjectManagerList()
00211 {
00212    std::list<tweek::SubjectManager_var> mgr_list;
00213 
00214    const CORBA::ULong data_size(100);
00215 
00216    CosNaming::BindingList_var     binding_list;
00217    CosNaming::BindingIterator_var binding_iter;
00218 
00219    mLocalContext->list(data_size, binding_list, binding_iter);
00220 
00221    addSubjectManagers(binding_list, mgr_list);
00222 
00223    if ( ! CORBA::is_nil(binding_iter) )
00224    {
00225       while ( binding_iter->next_n(data_size, binding_list) )
00226       {
00227          addSubjectManagers(binding_list, mgr_list);
00228       }
00229 
00230       binding_iter->destroy();
00231    }
00232 
00233    return mgr_list;
00234 }
00235 
00236 PortableServer::ObjectId_var CorbaService::registerObject(PortableServer::ServantBase* servant,
00237                                                           const std::string& name)
00238 {
00239    // XXX: Why is name unused?  It doesn't seem like it should even be a
00240    // parameter.
00241    boost::ignore_unused_variable_warning(name);
00242 
00243    PortableServer::ObjectId_var obj_id;
00244 
00245    try
00246    {
00247       obj_id = mRootPOA->activate_object(servant);
00248    }
00249    catch (PortableServer::POA::ServantAlreadyActive& activeEx)
00250    {
00251       boost::ignore_unused_variable_warning(activeEx);
00252    }
00253    catch (PortableServer::POA::WrongPolicy& policyEx)
00254    {
00255       boost::ignore_unused_variable_warning(policyEx);
00256    }
00257 
00258    return obj_id;
00259 }
00260 
00261 void CorbaService::unregisterObject(PortableServer::ObjectId_var id)
00262 {
00263    // XXX: Is there a way to verify that the id is valid first?
00264 //   if ( ! PortableServer::is_nil(id) )
00265 //   {
00266       try
00267       {
00268          mRootPOA->deactivate_object(id);
00269       }
00270       catch (PortableServer::POA::ObjectNotActive& activeEx)
00271       {
00272          boost::ignore_unused_variable_warning(activeEx);
00273          vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00274             << "CorbaService::unregisterObject: Tried to deactivate an inactive object\n"
00275             << vprDEBUG_FLUSH;
00276       }
00277       catch (PortableServer::POA::WrongPolicy& policyEx)
00278       {
00279          boost::ignore_unused_variable_warning(policyEx);
00280          vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00281             << "CorbaService::unregisterObject: Wrong POA policy\n"
00282             << vprDEBUG_FLUSH;
00283       }
00284 //   }
00285 //   else
00286 //   {
00287 //      vprDEBUG(tweekDBG_CORBA, vprDBG_WARNING_LVL)
00288 //         << clrOutNORM(clrYELLOW, "WARNING:")
00289 //         << " Tried to unregister null ID in CorbaService::unregisterObject()!"
00290 //         << std::endl << vprDEBUG_FLUSH;
00291 //   }
00292 }
00293 
00294 vpr::ReturnStatus CorbaService::initRootPOA()
00295 {
00296    vpr::ReturnStatus status;
00297 
00298    CORBA::Object_var obj;
00299 
00300    // Obtain a reference to the root POA.  The caller will have to catch any
00301    // thrown exceptions.
00302    vprDEBUG(tweekDBG_CORBA, vprDBG_STATE_LVL) << "Requesting Root POA\n"
00303                                               << vprDEBUG_FLUSH;
00304    obj      = mORB->resolve_initial_references("RootPOA");
00305    mRootPOA = PortableServer::POA::_narrow(obj);
00306 
00307    vprASSERT(! CORBA::is_nil(mRootPOA) && "Failed to get Root POA");
00308 
00309    // We want to allow multiple IDs to the same object and retain the
00310    // references.  The latter is required if we wish to do explict activation.
00311    PortableServer::IdUniquenessPolicy_var uniq_policy =
00312       mRootPOA->create_id_uniqueness_policy(PortableServer::MULTIPLE_ID);
00313    PortableServer::ServantRetentionPolicy_var retain_policy =
00314       mRootPOA->create_servant_retention_policy(PortableServer::RETAIN);
00315    PortableServer::ThreadPolicy_var thread_policy =
00316       mRootPOA->create_thread_policy(PortableServer::ORB_CTRL_MODEL);
00317 
00318    return status;
00319 }
00320 
00321 void CorbaService::addSubjectManagers(const CosNaming::BindingList& bindingList,
00322                                       std::list<tweek::SubjectManager_var>& mgrList)
00323 {
00324    CosNaming::Binding binding;
00325 
00326    for ( CORBA::ULong i = 0; i < bindingList.length(); ++i )
00327    {
00328       binding = bindingList[i];
00329 
00330       // We do not care about anything that is a naming context.
00331       if ( CosNaming::ncontext != binding.binding_type )
00332       {
00333          const std::string subj_mgr_name("SubjectManager");
00334          bool substr_match(false);
00335 
00336 #if defined(__GNUC__) && __GNUC__ == 2
00337          // XXX: This is a hack to deal with GCC 2.96 (and earlier?) having
00338          // a std::string::compare() method that does not match the actual
00339          // STL prototype.
00340          substr_match = (subj_mgr_name.compare(binding.binding_name[0].id, 0,
00341                                                subj_mgr_name.size()) == 0);
00342 #else
00343          substr_match = (subj_mgr_name.compare(0, subj_mgr_name.size(),
00344                                                binding.binding_name[0].id));
00345 #endif
00346 
00347          // Furthermore, we only care about SubjectManager* instances.
00348          if ( substr_match )
00349          {
00350             CosNaming::Name name_comp = binding.binding_name;
00351 
00352             try
00353             {
00354                CORBA::Object_var ref = mLocalContext->resolve(name_comp);
00355                tweek::SubjectManager_var mgr = tweek::SubjectManager::_narrow(ref);
00356 
00357                try
00358                {
00359                   // Filter out any references that we know are not usable.
00360                   if ( ! mgr->_non_existent() )
00361                   {
00362                      mgrList.push_back(mgr);
00363                   }
00364                }
00365                // In the Java equivalent of this method, CORBA::TRANSIENT
00366                // exceptions are sometimes thrown by the call to
00367                // tweek::SubjectManager::_non_existent() above.  I don't know
00368                // if they are also thrown here, but we might as well be safe.
00369                catch (CORBA::TRANSIENT ex)
00370                {
00371                   boost::ignore_unused_variable_warning(ex);
00372                   vprDEBUG(tweekDBG_CORBA, vprDBG_WARNING_LVL)
00373                      << "addSubjectManagers(): Caught CORBA::TRANSIENT "
00374                      << "exception thrown by _non_existent\n"
00375                      << vprDEBUG_FLUSH;
00376                }
00377                // XXX: Figure out what exception(s) can be thrown by
00378                // CORBA::Object::_non_existent()!
00379                catch (...)
00380                {
00381                   vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00382                      << "addSubjectManagers(): Caught unknown exception "
00383                      << "thrown by _non_existent\n"
00384                      << vprDEBUG_FLUSH;
00385                }
00386             }
00387             catch (CosNaming::NamingContext::InvalidName& nameEx)
00388             {
00389                boost::ignore_unused_variable_warning(nameEx);
00390                vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00391                   << "addSubjectManagers(): Tried to resolve invalid name\n"
00392                   << vprDEBUG_FLUSH;
00393             }
00394             catch (CosNaming::NamingContext::CannotProceed& proceedEx)
00395             {
00396                vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00397                   << "addSubjectManagers(): Cannot proceed with resolution of '"
00398                   << proceedEx.rest_of_name[0].id << "'\n" << vprDEBUG_FLUSH;
00399             }
00400             catch (CosNaming::NamingContext::NotFound& notFoundEx)
00401             {
00402                vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00403                   << "addSubjectManagers(): No binding for name '"
00404                   << notFoundEx.rest_of_name[0].id << "' " << vprDEBUG_FLUSH;
00405 
00406                switch ( notFoundEx.why )
00407                {
00408                   case CosNaming::NamingContext::missing_node:
00409                      vprDEBUG_CONT(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00410                         << "(missing node)" << std::endl << vprDEBUG_FLUSH;
00411                      break;
00412                   case CosNaming::NamingContext::not_context:
00413                      vprDEBUG_CONT(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00414                         << "(not a context)" << std::endl << vprDEBUG_FLUSH;
00415                      break;
00416                   case CosNaming::NamingContext::not_object:
00417                      vprDEBUG_CONT(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00418                         << "(not an object)" << std::endl << vprDEBUG_FLUSH;
00419                      break;
00420                }
00421             }
00422          }
00423          else
00424          {
00425             vprDEBUG(tweekDBG_CORBA, vprDBG_CRITICAL_LVL)
00426                << "addSubjectManagers(): Skipping binding with name '"
00427                << binding.binding_name[0].id << "'\n" << vprDEBUG_FLUSH;
00428          }
00429       }
00430    }
00431 }
00432 
00433 void CorbaService::run()
00434 {
00435    vprDEBUG(tweekDBG_CORBA, vprDBG_STATE_LVL) << "Server is running!\n"
00436                                               << vprDEBUG_FLUSH;
00437 
00438 //   PortableServer::POAManager_var pman = mChildPOA->the_POAManager();
00439    PortableServer::POAManager_var pman = mRootPOA->the_POAManager();
00440 
00441    pman->activate();
00442    mORB->run();
00443 //   mORB->destroy();
00444 
00445    vprDEBUG(tweekDBG_CORBA, vprDBG_STATE_LVL) << "Server has shut down\n"
00446                                               << vprDEBUG_FLUSH;
00447 }
00448 
00449 } // End of tweek namespace

Generated on Sun May 2 14:41:03 2004 for Tweek by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002