Orocos Real-Time Toolkit  2.5.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             ms->evaluate();
00091         }
00092     }
00093     };
00094 
00095         boost::shared_ptr<OperationKeeper> mopkeeper;
00096 
00100         OperationInterfacePart* orp;
00101     };
00102 
00103 
00104 
00105     class SendHandleC::D
00106     {
00107     public:
00108         OperationInterfacePart* mofp;
00109         std::string mname;
00110         std::vector<DataSourceBase::shared_ptr> args;
00111         DataSource<SendStatus>::shared_ptr s;
00112         DataSourceBase::shared_ptr msh;
00113         AssignableDataSource<bool>::shared_ptr blocking;
00114 
00115         void checkAndCreate() {
00116             Logger::In in("SendHandleC");
00117             if ( mofp ) {
00118                 size_t sz = mofp->collectArity();
00119                 if ( sz == args.size() ) {
00120                     // insert the send handle first.
00121                     args.insert( args.begin(), msh );
00122                     // may throw or return nill
00123                     s = boost::dynamic_pointer_cast<DataSource<SendStatus> >( mofp->produceCollect(args, blocking ) );
00124                     args.clear();
00125                     if ( !s ) {
00126                         log(Error) << "Failed to produce collector for "<< mname << " with " << sz << " arguments." << endlog();
00127                         return;
00128                     }
00129                 }
00130             }
00131         }
00132 
00133         void newarg(DataSourceBase::shared_ptr na)
00134         {
00135             this->args.push_back( na );
00136             this->checkAndCreate();
00137         }
00138 
00139         D( base::DataSourceBase::shared_ptr sh, OperationInterfacePart* ofp, const std::string& name)
00140             : mofp(ofp), mname(name), s(), msh(sh), blocking( new ValueDataSource<bool>(false) )
00141         {
00142             this->checkAndCreate();
00143         }
00144 
00145         D(const D& other)
00146             : mofp(other.mofp), mname(other.mname),
00147               args( other.args ), s( other.s ), msh(other.msh), blocking(new ValueDataSource<bool>(false))
00148         {
00149         }
00150 
00151         ~D()
00152         {
00153         }
00154 
00155     };
00156 
00157     SendHandleC::SendHandleC()
00158         : d(0), e( new E(0) )
00159     {
00160     }
00161 
00162     SendHandleC::SendHandleC( base::DataSourceBase::shared_ptr op, base::DataSourceBase::shared_ptr sh, OperationInterfacePart* ofp, const std::string& name )
00163         : d( ofp ? new D( sh, ofp, name ) : 0 ), e( new E(op) )
00164     {
00165         if ( d->s ) {
00166             e->s = d->s;
00167             e->b = d->blocking;
00168             e->mopkeeper.reset( new E::OperationKeeper( e->s, e->b) );
00169             delete d;
00170             d = 0;
00171         }
00172         this->e->orp = ofp;
00173     }
00174 
00175     SendHandleC::SendHandleC(const SendHandleC& other)
00176         : d( other.d ? new D(*other.d) : 0 ), e( new E(*other.e) )
00177     {
00178     }
00179 
00180     SendHandleC& SendHandleC::operator=(const SendHandleC& other)
00181     {
00182         if ( &other == this )
00183             return *this;
00184         delete d;
00185         d = ( other.d ? new D(*other.d) : 0 );
00186         e->s = other.e->s;
00187         e->b = other.e->b;
00188         e->mop = other.e->mop;
00189         e->mopkeeper = other.e->mopkeeper;
00190         e->orp = other.e->orp;
00191         return *this;
00192     }
00193 
00194     SendHandleC::~SendHandleC()
00195     {
00196         delete d;
00197         delete e;
00198     }
00199 
00200     SendHandleC& SendHandleC::arg( DataSourceBase::shared_ptr a )
00201     {
00202         if (d)
00203             d->newarg( a );
00204         else {
00205             Logger::log() <<Logger::Warning << "Extra argument discarded for SendHandleC."<<Logger::endl;
00206         }
00207         if ( d && d->s ) {
00208             e->s = d->s;
00209             e->b = d->blocking;
00210             e->orp = d->mofp;
00211             e->mopkeeper.reset( new E::OperationKeeper( e->s, e->b) );
00212             delete d;
00213             d = 0;
00214         }
00215         return *this;
00216     }
00217 
00218     SendStatus SendHandleC::collect() {
00219         if (e->s) {
00220             e->b->set(true); // blocking
00221             e->s->evaluate();
00222             return e->s->value();
00223         }
00224         else {
00225             Logger::log() <<Logger::Error << "collect() called on incomplete SendHandleC."<<Logger::endl;
00226             if (d) {
00227                 size_t sz;
00228                 sz = d->mofp->collectArity();
00229                 Logger::log() <<Logger::Error << "Wrong number of arguments provided for method '"+d->mname+"'"<<Logger::nl;
00230                 Logger::log() <<Logger::Error << "Expected "<< sz << ", got: " << d->args.size() <<Logger::endl;
00231             }
00232         }
00233         return SendFailure;
00234     }
00235 
00236     SendStatus SendHandleC::collectIfDone() {
00237         if (e->s) {
00238             e->b->set(false); // non blocking
00239             // does the send.
00240             e->s->evaluate();
00241             // pass on handle.
00242             return e->s->value();
00243         }
00244         else {
00245             Logger::log() <<Logger::Error << "collectIfDone() called on incomplete SendHandleC."<<Logger::endl;
00246             if (d) {
00247                 size_t sz;
00248                 sz = d->mofp->collectArity();
00249                 Logger::log() <<Logger::Error << "Wrong number of arguments provided for method '"+d->mname+"'"<<Logger::nl;
00250                 Logger::log() <<Logger::Error << "Expected "<< sz << ", got: " << d->args.size() <<Logger::endl;
00251             }
00252         }
00253         return SendFailure;
00254     }
00255 
00256     bool SendHandleC::ready() const
00257     {
00258         return e->s;
00259     }
00260 
00261     void SendHandleC::setAutoCollect(bool on_off) {
00262         if (e->mopkeeper)
00263             e->mopkeeper->autocollect = on_off;
00264     }
00265 
00266     void SendHandleC::check() {
00267         if (d) {
00268             // something went wrong, let producer throw
00269             if (d->mofp)
00270                 DataSourceBase::shared_ptr dummy = d->mofp->produceCollect( d->args, d->blocking );
00271             else
00272                 throw invalid_handle_exception();
00273         }
00274     }
00275 
00276 
00277     DataSourceBase::shared_ptr SendHandleC::getSendHandleDataSource() { return e->s; }
00278 
00279     OperationInterfacePart* SendHandleC::getOrp() { return e->orp; }
00280 }