//------------------------------------------------------------------------------ // Copyright (c) 2011-2017 by European Organization for Nuclear Research (CERN) // Author: Krzysztof Jamrog , // Michal Simon //------------------------------------------------------------------------------ // This file is part of the XRootD software suite. // // XRootD is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // XRootD 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 General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with XRootD. If not, see . // // In applying this licence, CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. //------------------------------------------------------------------------------ #ifndef __XRD_CL_OPERATION_HANDLERS_HH__ #define __XRD_CL_OPERATION_HANDLERS_HH__ #include "XrdCl/XrdClFile.hh" namespace XrdCl { //---------------------------------------------------------------------------- //! Helper class for checking if a given Handler is derived //! from ForwardingHandler //! //! @arg Hdlr : type of given handler //---------------------------------------------------------------------------- template struct IsResponseHandler { //------------------------------------------------------------------------ //! true if the Hdlr type has been derived from ForwardingHandler, //! false otherwise //------------------------------------------------------------------------ static constexpr bool value = std::is_base_of::value; }; //---------------------------------------------------------------------------- //! Helper class for checking if a given Handler is derived //! from ForwardingHandler (overloaded for pointers) //! //! @arg Hdlr : type of given handler //---------------------------------------------------------------------------- template struct IsResponseHandler { //------------------------------------------------------------------------ //! true if the Hdlr type has been derived from ForwardingHandler, //! false otherwise //------------------------------------------------------------------------ static constexpr bool value = std::is_base_of::value; }; //---------------------------------------------------------------------------- //! Lambda wrapper //---------------------------------------------------------------------------- class SimpleFunctionWrapper: public ResponseHandler { public: //------------------------------------------------------------------------ //! Constructor. // //! @param func : function, functor or lambda //------------------------------------------------------------------------ SimpleFunctionWrapper( std::function handleFunction ) : fun( handleFunction ) { } //------------------------------------------------------------------------ //! Callback method. //------------------------------------------------------------------------ void HandleResponse( XRootDStatus *status, AnyObject *response ) { fun( *status ); delete status; delete response; delete this; } private: //------------------------------------------------------------------------ //! user defined function, functor or lambda //------------------------------------------------------------------------ std::function fun; }; //---------------------------------------------------------------------------- //! Lambda wrapper //! //! @arg ResponseType : type of response returned by the server //---------------------------------------------------------------------------- template class FunctionWrapper: public ResponseHandler { public: //------------------------------------------------------------------------ //! Constructor. // //! @param func : function, functor or lambda //------------------------------------------------------------------------ FunctionWrapper( std::function handleFunction ) : fun( handleFunction ) { } //------------------------------------------------------------------------ //! Callback method. //------------------------------------------------------------------------ void HandleResponse( XRootDStatus *status, AnyObject *response ) { ResponseType *res = nullptr; if( status->IsOK() ) response->Get( res ); else res = &nullref; fun( *status, *res ); delete status; delete response; delete this; } private: //------------------------------------------------------------------------ //! user defined function, functor or lambda //------------------------------------------------------------------------ std::function fun; //------------------------------------------------------------------------ //! Null reference to the response (not really but acts as one) //------------------------------------------------------------------------ static ResponseType nullref; }; //---------------------------------------------------------------------------- // Initialize the 'null-reference' //---------------------------------------------------------------------------- template ResponseType FunctionWrapper::nullref; //---------------------------------------------------------------------------- //! Packaged Task wrapper //! //! @arg Response : type of response returned by the server //! @arg Return : type of the value returned by the task //---------------------------------------------------------------------------- template class TaskWrapper: public ResponseHandler { public: //------------------------------------------------------------------------ //! Constructor. // //! @param task : a std::packaged_task //------------------------------------------------------------------------ TaskWrapper( std::packaged_task && task ) : task( std::move( task ) ) { } //------------------------------------------------------------------------ //! Callback method. //------------------------------------------------------------------------ void HandleResponse( XRootDStatus *status, AnyObject *response ) { Response *resp = nullptr; if( status->IsOK() ) response->Get( resp ); else resp = &nullref; task( *status, *resp ); delete status; delete response; delete this; } private: //------------------------------------------------------------------------ //! user defined task //------------------------------------------------------------------------ std::packaged_task task; //------------------------------------------------------------------------ //! Null reference to the response (not really but acts as one) //------------------------------------------------------------------------ static Response nullref; }; //---------------------------------------------------------------------------- // Initialize the 'null-reference' //---------------------------------------------------------------------------- template Response TaskWrapper::nullref; //---------------------------------------------------------------------------- //! Packaged Task wrapper, specialization for requests that have no response //! except for status. //! //! @arg Response : type of response returned by the server //! @arg Return : type of the value returned by the task //---------------------------------------------------------------------------- template class TaskWrapper { public: //------------------------------------------------------------------------ //! Constructor. // //! @param task : a std::packaged_task //------------------------------------------------------------------------ TaskWrapper( std::packaged_task && task ) : task( std::move( task ) ) { } //------------------------------------------------------------------------ //! Callback method. //------------------------------------------------------------------------ void HandleResponse( XRootDStatus *status, AnyObject *response ) { task( *status ); delete status; delete response; delete this; } private: //------------------------------------------------------------------------ //! user defined task //------------------------------------------------------------------------ std::packaged_task task; }; //---------------------------------------------------------------------------- //! Lambda wrapper //---------------------------------------------------------------------------- class ExOpenFuncWrapper: public ResponseHandler { public: //------------------------------------------------------------------------ //! Constructor. // //! @param func : function, functor or lambda //------------------------------------------------------------------------ ExOpenFuncWrapper( File &f, std::function handleFunction ) : f( f ), fun( handleFunction ) { } //------------------------------------------------------------------------ //! Callback method. //------------------------------------------------------------------------ void HandleResponse( XRootDStatus *status, AnyObject *response ) { StatInfo *info = nullptr; if( status->IsOK() ) XRootDStatus st = f.Stat( false, info ); else info = &nullref; fun( *status, *info ); if( info != &nullref ) delete info; delete status; delete response; delete this; } private: File &f; //------------------------------------------------------------------------ //! user defined function, functor or lambda //------------------------------------------------------------------------ std::function fun; //------------------------------------------------------------------------ //! Null reference to the response (not really but acts as one) //------------------------------------------------------------------------ static StatInfo nullref; }; //---------------------------------------------------------------------------- // Initialize the 'null-reference' //---------------------------------------------------------------------------- StatInfo ExOpenFuncWrapper::nullref; //---------------------------------------------------------------------------- //! Pipeline exception, wrapps an XRootDStatus //---------------------------------------------------------------------------- class PipelineException : public std::exception { public: //------------------------------------------------------------------------ //! Constructor from XRootDStatus //------------------------------------------------------------------------ PipelineException( const XRootDStatus &error ) : error( error ) { } //------------------------------------------------------------------------ //! Copy constructor. //------------------------------------------------------------------------ PipelineException( const PipelineException &ex ) : error( ex.error ) { } //------------------------------------------------------------------------ //! Assigment operator //------------------------------------------------------------------------ PipelineException& operator=( const PipelineException &ex ) { error = ex.error; return *this; } //------------------------------------------------------------------------ //! inherited from std::exception //------------------------------------------------------------------------ const char* what() const noexcept { return error.ToString().c_str(); } //------------------------------------------------------------------------ //! @return : the XRootDStatus //------------------------------------------------------------------------ const XRootDStatus& GetError() const { return error; } private: //------------------------------------------------------------------------ //! the XRootDStatus associated with this exception //------------------------------------------------------------------------ XRootDStatus error; }; //---------------------------------------------------------------------------- //! A wrapper handler for a std::promise / std::future. //! //! @arg Response : response type //---------------------------------------------------------------------------- template class FutureWrapperBase : public ResponseHandler { public: //------------------------------------------------------------------------ //! Constructor, initializes the std::future argument from its //! own std::promise //! //! @param ftr : the future to be linked with this handler //------------------------------------------------------------------------ FutureWrapperBase( std::future &ftr ) : called( false ) { ftr = prms.get_future(); } //------------------------------------------------------------------------ //! Destructor //! //! If the handler was not called sets an exception in the promise //------------------------------------------------------------------------ ~FutureWrapperBase() { if( !called ) this->SetException( XRootDStatus( stError, errPipelineFailed ) ); } protected: //------------------------------------------------------------------------ //! Set exception in the std::promise / std::future //! //! @param err : the error //------------------------------------------------------------------------ void SetException( const XRootDStatus &err ) { std::exception_ptr ex = std::make_exception_ptr( PipelineException( err ) ); prms.set_exception( ex ); } //------------------------------------------------------------------------ //! promise that corresponds to the future //------------------------------------------------------------------------ std::promise prms; //------------------------------------------------------------------------ //! true if the handler has been called, false otherwise //------------------------------------------------------------------------ bool called; }; //---------------------------------------------------------------------------- //! A wrapper handler for a std::promise / std::future. //! //! @arg Response : response type //---------------------------------------------------------------------------- template class FutureWrapper : public FutureWrapperBase { public: //------------------------------------------------------------------------ //! Constructor, @see FutureWrapperBase //! //! @param ftr : the future to be linked with this handler //------------------------------------------------------------------------ FutureWrapper( std::future &ftr ) : FutureWrapperBase( ftr ) { } //------------------------------------------------------------------------ //! Callback method. //------------------------------------------------------------------------ void HandleResponse( XRootDStatus *status, AnyObject *response ) { this->called = true; if( status->IsOK() ) { Response *resp = 0; response->Get( resp ); this->prms.set_value( std::move( *resp ) ); } else this->SetException( *status ); delete status; delete response; delete this; } }; //---------------------------------------------------------------------------- //! A wrapper handler for a std::promise / std::future, overload for void type //---------------------------------------------------------------------------- template<> class FutureWrapper : public FutureWrapperBase { public: //------------------------------------------------------------------------ //! Constructor, @see FutureWrapperBase //! //! @param ftr : the future to be linked with this handler //------------------------------------------------------------------------ FutureWrapper( std::future &ftr ) : FutureWrapperBase( ftr ) { } //------------------------------------------------------------------------ //! Callback method. //------------------------------------------------------------------------ void HandleResponse( XRootDStatus *status, AnyObject *response ) { this->called = true; if( status->IsOK() ) { prms.set_value(); } else SetException( *status ); delete status; delete response; delete this; } }; //---------------------------------------------------------------------------- //! A base class for factories, creates ForwardingHandlers from //! ResponseHandler*, ResponseHandler& and std::future //! //! @arg Response : response type //---------------------------------------------------------------------------- template struct RespBase { //------------------------------------------------------------------------ //! A factory method, simply forwards the given handler //! //! @param h : the ResponseHandler that should be wrapped //! @return : a ForwardingHandler instance //------------------------------------------------------------------------ inline static ResponseHandler* Create( ResponseHandler *hdlr ) { return hdlr; } //------------------------------------------------------------------------ //! A factory method, simply forwards the given handler //! //! @param h : the ResponseHandler that should be wrapped //! @return : a ForwardingHandler instance //------------------------------------------------------------------------ inline static ResponseHandler* Create( ResponseHandler &hdlr ) { return &hdlr; } //------------------------------------------------------------------------ //! A factory method //! //! @arg Response : response type //! @param ftr : the std::future that should be wrapped //------------------------------------------------------------------------ inline static ResponseHandler* Create( std::future &ftr ) { return new FutureWrapper( ftr ); } }; //---------------------------------------------------------------------------- //! Factory class, creates ForwardingHandler from std::function, in addition //! to what RespBase provides (@see RespBase) //! //! @arg Response : response type //---------------------------------------------------------------------------- template struct Resp: RespBase { //------------------------------------------------------------------------ //! A factory method //! //! @param func : the function/functor/lambda that should be wrapped //! @return : FunctionWrapper instance //------------------------------------------------------------------------ inline static ResponseHandler* Create( std::function func ) { return new FunctionWrapper( func ); } //------------------------------------------------------------------------ //! A factory method //! //! @param func : the task that should be wrapped //! @return : TaskWrapper instance //------------------------------------------------------------------------ template inline static ResponseHandler* Create( std::packaged_task &task ) { return new TaskWrapper( std::move( task ) ); } //------------------------------------------------------------------------ //! Make the Create overloads from RespBase visible //------------------------------------------------------------------------ using RespBase::Create; }; //---------------------------------------------------------------------------- //! Factory class, overloads Resp for void type //! //! @arg Response : response type //---------------------------------------------------------------------------- template<> struct Resp: RespBase { //------------------------------------------------------------------------ //! A factory method //! //! @param func : the function/functor/lambda that should be wrapped //! @return : SimpleFunctionWrapper instance //------------------------------------------------------------------------ inline static ResponseHandler* Create( std::function func ) { return new SimpleFunctionWrapper( func ); } //------------------------------------------------------------------------ //! A factory method //! //! @param func : the task that should be wrapped //! @return : TaskWrapper instance //------------------------------------------------------------------------ template inline static ResponseHandler* Create( std::packaged_task &task ) { return new TaskWrapper( std::move( task ) ); } //------------------------------------------------------------------------ //! Make the Create overloads from RespBase visible //------------------------------------------------------------------------ using RespBase::Create; }; } #endif // __XRD_CL_OPERATIONS_HANDLERS_HH__