Orocos Real-Time Toolkit  2.6.0
SendHandleC.cpp
00001 /***************************************************************************
00002   tag: The SourceWorks  Tue Sep 7 00:55:18 CEST 2010  SendHandleC.cpp
00003 
00004                         SendHandleC.cpp -  description
00005                            -------------------
00006     begin                : Tue September 07 2010
00007     copyright            : (C) 2010 The SourceWorks
00008     email                : peter@thesourceworks.com
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00039 #include "SendHandleC.hpp"
00040 #include "../FactoryExceptions.hpp"
00041 #include "DataSourceCommand.hpp"
00042 #include "../Service.hpp"
00043 #include "../Logger.hpp"
00044 #include "Exceptions.hpp"
00045 #include <vector>
00046 
00047 namespace RTT {
00048     using namespace detail;
00049 
00050 
00051     class SendHandleC::E
00052     {
00053     public:
00054         E(base::DataSourceBase::shared_ptr op) : s(), b(), mop(op), orp(0) {}
00055 
00056         ~E() {
00057             // force synchronisation in case we are the last SendHandleC. We may not cleanup mop (holds data!), until the op
00058             // completed or failed.
00059             // Reduce refcount on mopkeeper
00060             mopkeeper.reset();
00061         }
00062 
00067         internal::DataSource<SendStatus>::shared_ptr s;
00071         internal::AssignableDataSource<bool>::shared_ptr b;
00075         base::DataSourceBase::shared_ptr mop;
00076 
00081     struct OperationKeeper
00082     {
00083     DataSource<SendStatus>::shared_ptr ms;
00084     AssignableDataSource<bool>::shared_ptr mb;
00085     bool autocollect;
00086     OperationKeeper(DataSource<SendStatus>::shared_ptr s, AssignableDataSource<bool>::shared_ptr b) : ms(s), mb(b), autocollect(true) {}
00087     ~OperationKeeper() {
00088         if (ms && autocollect) {
00089             mb->set(true); // blocking
00090             try { // the evaluated function may throw
00091                 ms->evaluate();
00092             } catch (std::exception&) {
00093             }
00094         }
00095     }
00096     };
00097 
00098         boost::shared_ptr<OperationKeeper> mopkeeper;
00099 
00103         OperationInterfacePart* orp;
00104     };
00105 
00106 
00107 
00108     class SendHandleC::D
00109     {
00110     public:
00111         OperationInterfacePart* mofp;
00112         std::string mname;
00113         std::vector<DataSourceBase::shared_ptr> args;
00114         DataSource<SendStatus>::shared_ptr s;
00115         DataSourceBase::shared_ptr msh;
00116         AssignableDataSource<bool>::shared_ptr blocking;
00117 
00118         void checkAndCreate() {
00119             Logger::In in("SendHandleC");
00120             if ( mofp ) {
00121                 size_t sz = mofp->collectArity();
00122                 if ( sz == args.size() ) {
00123                     // insert the send handle first.
00124                     args.insert( args.begin(), msh );
00125                     // may throw or return nill
00126                     s = boost::dynamic_pointer_cast<DataSource<SendStatus> >( mofp->produceCollect(args, blocking ) );
00127                     args.clear();
00128                     if ( !s ) {
00129                         log(Error) << "Failed to produce collector for "<< mname << " with " << sz << " arguments." << endlog();
00130                         return;
00131                     }
00132                 }
00133             }
00134         }
00135 
00136         void newarg(DataSourceBase::shared_ptr na)
00137         {
00138             this->args.push_back( na );
00139             this->checkAndCreate();
00140         }
00141 
00142         D( base::DataSourceBase::shared_ptr sh, OperationInterfacePart* ofp, const std::string& name)
00143             : mofp(ofp), mname(name), s(), msh(sh), blocking( new ValueDataSource<bool>(false) )
00144         {
00145             this->checkAndCreate();
00146         }
00147 
00148         D(const D& other)
00149             : mofp(other.mofp), mname(other.mname),
00150               args( other.args ), s( other.s ), msh(other.msh), blocking(new ValueDataSource<bool>(false))
00151         {
00152         }
00153 
00154         ~D()
00155         {
00156         }
00157 
00158     };
00159 
00160     SendHandleC::SendHandleC()
00161         : d(0), e( new E(0) )
00162     {
00163     }
00164 
00165     SendHandleC::SendHandleC( base::DataSourceBase::shared_ptr op, base::DataSourceBase::shared_ptr sh, OperationInterfacePart* ofp, const std::string& name )
00166         : d( ofp ? new D( sh, ofp, name ) : 0 ), e( new E(op) )
00167     {
00168         if ( d->s ) {
00169             e->s = d->s;
00170             e->b = d->blocking;
00171             e->mopkeeper.reset( new E::OperationKeeper( e->s, e->b) );
00172             delete d;
00173             d = 0;
00174         }
00175         this->e->orp = ofp;
00176     }
00177 
00178     SendHandleC::SendHandleC(const SendHandleC& other)
00179         : d( other.d ? new D(*other.d) : 0 ), e( new E(*other.e) )
00180     {
00181     }
00182 
00183     SendHandleC& SendHandleC::operator=(const SendHandleC& other)
00184     {
00185         if ( &other == this )
00186             return *this;
00187         delete d;
00188         d = ( other.d ? new D(*other.d) : 0 );
00189         e->s = other.e->s;
00190         e->b = other.e->b;
00191         e->mop = other.e->mop;
00192         e->mopkeeper = other.e->mopkeeper;
00193         e->orp = other.e->orp;
00194         return *this;
00195     }
00196 
00197     SendHandleC::~SendHandleC()
00198     {
00199         delete d;
00200         delete e;
00201     }
00202 
00203     SendHandleC& SendHandleC::arg( DataSourceBase::shared_ptr a )
00204     {
00205         if (d)
00206             d->newarg( a );
00207         else {
00208             Logger::log() <<Logger::Warning << "Extra argument discarded for SendHandleC."<<Logger::endl;
00209         }
00210         if ( d && d->s ) {
00211             e->s = d->s;
00212             e->b = d->blocking;
00213             e->orp = d->mofp;
00214             e->mopkeeper.reset( new E::OperationKeeper( e->s, e->b) );
00215             delete d;
00216             d = 0;
00217         }
00218         return *this;
00219     }
00220 
00221     SendStatus SendHandleC::collect() {
00222         if (e->s) {
00223             e->b->set(true); // blocking
00224             e->s->evaluate();
00225             return e->s->value();
00226         }
00227         else {
00228             Logger::log() <<Logger::Error << "collect() called on incomplete SendHandleC."<<Logger::endl;
00229             if (d) {
00230                 size_t sz;
00231                 sz = d->mofp->collectArity();
00232                 Logger::log() <<Logger::Error << "Wrong number of arguments provided for method '"+d->mname+"'"<<Logger::nl;
00233                 Logger::log() <<Logger::Error << "Expected "<< sz << ", got: " << d->args.size() <<Logger::endl;
00234             }
00235         }
00236         return SendFailure;
00237     }
00238 
00239     SendStatus SendHandleC::collectIfDone() {
00240         if (e->s) {
00241             e->b->set(false); // non blocking
00242             // does the send.
00243             e->s->evaluate();
00244             // pass on handle.
00245             return e->s->value();
00246         }
00247         else {
00248             Logger::log() <<Logger::Error << "collectIfDone() called on incomplete SendHandleC."<<Logger::endl;
00249             if (d) {
00250                 size_t sz;
00251                 sz = d->mofp->collectArity();
00252                 Logger::log() <<Logger::Error << "Wrong number of arguments provided for method '"+d->mname+"'"<<Logger::nl;
00253                 Logger::log() <<Logger::Error << "Expected "<< sz << ", got: " << d->args.size() <<Logger::endl;
00254             }
00255         }
00256         return SendFailure;
00257     }
00258 
00259     bool SendHandleC::ready() const
00260     {
00261         return e->s;
00262     }
00263 
00264     void SendHandleC::setAutoCollect(bool on_off) {
00265         if (e->mopkeeper)
00266             e->mopkeeper->autocollect = on_off;
00267     }
00268 
00269     void SendHandleC::check() {
00270         if (d) {
00271             // something went wrong, let producer throw
00272             if (d->mofp)
00273                 DataSourceBase::shared_ptr dummy = d->mofp->produceCollect( d->args, d->blocking );
00274             else
00275                 throw invalid_handle_exception();
00276         }
00277     }
00278 
00279 
00280     DataSourceBase::shared_ptr SendHandleC::getSendHandleDataSource() { return e->s; }
00281 
00282     OperationInterfacePart* SendHandleC::getOrp() { return e->orp; }
00283 }