diff --git a/src/XrdCl/XrdClFileOperations.hh b/src/XrdCl/XrdClFileOperations.hh index 54430c62074..0bec146a5bf 100644 --- a/src/XrdCl/XrdClFileOperations.hh +++ b/src/XrdCl/XrdClFileOperations.hh @@ -395,7 +395,7 @@ namespace XrdCl //! Factory for creating StatImpl objects (as there is another Stat in //! FileSystem there would be a clash of typenames). //---------------------------------------------------------------------------- - StatImpl Stat( File *file, Arg force ) + inline StatImpl Stat( File *file, Arg force ) { return StatImpl( file, std::move( force ) ); } @@ -404,7 +404,7 @@ namespace XrdCl //! Factory for creating StatImpl objects (as there is another Stat in //! FileSystem there would be a clash of typenames). //---------------------------------------------------------------------------- - StatImpl Stat( File &file, Arg force ) + inline StatImpl Stat( File &file, Arg force ) { return StatImpl( file, std::move( force ) ); } @@ -561,7 +561,7 @@ namespace XrdCl //! Factory for creating TruncateImpl objects (as there is another Stat in //! FileSystem there would be a clash of typenames). //---------------------------------------------------------------------------- - TruncateImpl Truncate( File *file, Arg size ) + inline TruncateImpl Truncate( File *file, Arg size ) { return TruncateImpl( file, std::move( size ) ); } @@ -570,7 +570,7 @@ namespace XrdCl //! Factory for creating TruncateImpl objects (as there is another Stat in //! FileSystem there would be a clash of typenames). //---------------------------------------------------------------------------- - TruncateImpl Truncate( File &file, Arg size ) + inline TruncateImpl Truncate( File &file, Arg size ) { return TruncateImpl( file, std::move( size ) ); } @@ -835,6 +835,526 @@ namespace XrdCl } }; typedef VisaImpl Visa; + + //---------------------------------------------------------------------------- + //! SetXAttr operation (@see FileOperation) + //---------------------------------------------------------------------------- + template + class SetXAttrImpl: public FileOperation, + Arg, Arg> + { + public: + + //------------------------------------------------------------------------ + //! Inherit constructors from FileOperation (@see FileOperation) + //------------------------------------------------------------------------ + using FileOperation, + Arg, Arg>::FileOperation; + + //------------------------------------------------------------------------ + //! Argument indexes in the args tuple + //------------------------------------------------------------------------ + enum { NameArg, ValueArg }; + + //------------------------------------------------------------------------ + //! @return : name of the operation (@see Operation) + //------------------------------------------------------------------------ + std::string ToString() + { + return "SetXAttrImpl"; + } + + protected: + + //------------------------------------------------------------------------ + //! RunImpl operation (@see Operation) + //! + //! @param params : container with parameters forwarded from + //! previous operation + //! @return : status of the operation + //------------------------------------------------------------------------ + XRootDStatus RunImpl() + { + try + { + std::string name = std::get( this->args ).Get(); + std::string value = std::get( this->args ).Get(); + // wrap the arguments with a vector + std::vector attrs; + attrs.push_back( xattr_t( std::move( name ), std::move( value ) ) ); + // wrap the PipelineHandler so the response gets unpacked properly + UnpackXAttrStatus *handler = new UnpackXAttrStatus( this->handler.get() ); + XRootDStatus st = this->file->SetXAttr( attrs, handler ); + if( !st.IsOK() ) delete handler; + return st; + } + catch( const PipelineException& ex ) + { + return ex.GetError(); + } + catch( const std::exception& ex ) + { + return XRootDStatus( stError, ex.what() ); + } + } + }; + + //---------------------------------------------------------------------------- + //! Factory for creating SetXAttrImpl objects (as there is another SetXAttr in + //! FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline SetXAttrImpl SetXAttr( File *file, Arg name, Arg value ) + { + return SetXAttrImpl( file, std::move( name ), std::move( value ) ); + } + + //---------------------------------------------------------------------------- + //! Factory for creating SetXAttrImpl objects (as there is another SetXAttr in + //! FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline SetXAttrImpl SetXAttr( File &file, Arg name, Arg value ) + { + return SetXAttrImpl( file, std::move( name ), std::move( value ) ); + } + + //---------------------------------------------------------------------------- + //! SetXAttr bulk operation (@see FileOperation) + //---------------------------------------------------------------------------- + template + class SetXAttrBulkImpl: public FileOperation>, Arg>> + { + public: + + //------------------------------------------------------------------------ + //! Inherit constructors from FileOperation (@see FileOperation) + //------------------------------------------------------------------------ + using FileOperation>, + Arg>>::FileOperation; + + //------------------------------------------------------------------------ + //! Argument indexes in the args tuple + //------------------------------------------------------------------------ + enum { AttrsArg }; + + //------------------------------------------------------------------------ + //! @return : name of the operation (@see Operation) + //------------------------------------------------------------------------ + std::string ToString() + { + return "SetXAttrBulkImpl"; + } + + + protected: + + //------------------------------------------------------------------------ + //! RunImpl operation (@see Operation) + //! + //! @param params : container with parameters forwarded from + //! previous operation + //! @return : status of the operation + //------------------------------------------------------------------------ + XRootDStatus RunImpl() + { + try + { + std::vector attrs = std::get( this->args ).Get(); + return this->file->SetXAttr( attrs, this->handler.get() ); + } + catch( const PipelineException& ex ) + { + return ex.GetError(); + } + catch( const std::exception& ex ) + { + return XRootDStatus( stError, ex.what() ); + } + } + }; + + //---------------------------------------------------------------------------- + //! Factory for creating SetXAttrBulkImpl objects (as there is another SetXAttr + //! in FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline SetXAttrBulkImpl SetXAttr( File *file, Arg> attrs ) + { + return SetXAttrBulkImpl( file, std::move( attrs ) ); + } + + //---------------------------------------------------------------------------- + //! Factory for creating SetXAttrBulkImpl objects (as there is another SetXAttr + //! in FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline SetXAttrBulkImpl SetXAttr( File &file, Arg> attrs ) + { + return SetXAttrBulkImpl( file, std::move( attrs ) ); + } + + //---------------------------------------------------------------------------- + //! GetXAttr operation (@see FileOperation) + //---------------------------------------------------------------------------- + template + class GetXAttrImpl: public FileOperation, + Arg> + { + public: + + //------------------------------------------------------------------------ + //! Inherit constructors from FileOperation (@see FileOperation) + //------------------------------------------------------------------------ + using FileOperation, + Arg>::FileOperation; + + //------------------------------------------------------------------------ + //! Argument indexes in the args tuple + //------------------------------------------------------------------------ + enum { NameArg }; + + //------------------------------------------------------------------------ + //! @return : name of the operation (@see Operation) + //------------------------------------------------------------------------ + std::string ToString() + { + return "GetXAttrImpl"; + } + + protected: + + //------------------------------------------------------------------------ + //! RunImpl operation (@see Operation) + //! + //! @param params : container with parameters forwarded from + //! previous operation + //! @return : status of the operation + //------------------------------------------------------------------------ + XRootDStatus RunImpl() + { + try + { + std::string name = std::get( this->args ).Get(); + // wrap the argument with a vector + std::vector attrs; + attrs.push_back( std::move( name ) ); + // wrap the PipelineHandler so the response gets unpacked properly + UnpackXAttr *handler = new UnpackXAttr( this->handler.get() ); + XRootDStatus st = this->file->GetXAttr( attrs, handler ); + if( !st.IsOK() ) delete handler; + return st; + } + catch( const PipelineException& ex ) + { + return ex.GetError(); + } + catch( const std::exception& ex ) + { + return XRootDStatus( stError, ex.what() ); + } + } + }; + + //---------------------------------------------------------------------------- + //! Factory for creating GetXAttrImpl objects (as there is another GetXAttr in + //! FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline GetXAttrImpl GetXAttr( File *file, Arg name ) + { + return GetXAttrImpl( file, std::move( name ) ); + } + + //---------------------------------------------------------------------------- + //! Factory for creating GetXAttrImpl objects (as there is another GetXAttr in + //! FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline GetXAttrImpl GetXAttr( File &file, Arg name ) + { + return GetXAttrImpl( file, std::move( name ) ); + } + + //---------------------------------------------------------------------------- + //! GetXAttr bulk operation (@see FileOperation) + //---------------------------------------------------------------------------- + template + class GetXAttrBulkImpl: public FileOperation>, + Arg>> + { + public: + + //------------------------------------------------------------------------ + //! Inherit constructors from FileOperation (@see FileOperation) + //------------------------------------------------------------------------ + using FileOperation>, + Arg>>::FileOperation; + + //------------------------------------------------------------------------ + //! Argument indexes in the args tuple + //------------------------------------------------------------------------ + enum { NamesArg }; + + //------------------------------------------------------------------------ + //! @return : name of the operation (@see Operation) + //------------------------------------------------------------------------ + std::string ToString() + { + return "GetXAttrBulkImpl"; + } + + + protected: + + //------------------------------------------------------------------------ + //! RunImpl operation (@see Operation) + //! + //! @param params : container with parameters forwarded from + //! previous operation + //! @return : status of the operation + //------------------------------------------------------------------------ + XRootDStatus RunImpl() + { + try + { + std::vector attrs = std::get( this->args ).Get(); + return this->file->GetXAttr( attrs, this->handler.get() ); + } + catch( const PipelineException& ex ) + { + return ex.GetError(); + } + catch( const std::exception& ex ) + { + return XRootDStatus( stError, ex.what() ); + } + } + }; + + //---------------------------------------------------------------------------- + //! Factory for creating GetXAttrBulkImpl objects (as there is another GetXAttr in + //! FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline GetXAttrBulkImpl GetXAttr( File *file, Arg> attrs ) + { + return GetXAttrBulkImpl( file, std::move( attrs ) ); + } + + //---------------------------------------------------------------------------- + //! Factory for creating GetXAttrBulkImpl objects (as there is another GetXAttr in + //! FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline GetXAttrBulkImpl GetXAttr( File &file, Arg> attrs ) + { + return GetXAttrBulkImpl( file, std::move( attrs ) ); + } + + //---------------------------------------------------------------------------- + //! DelXAttr operation (@see FileOperation) + //---------------------------------------------------------------------------- + template + class DelXAttrImpl: public FileOperation, + Arg> + { + public: + + //------------------------------------------------------------------------ + //! Inherit constructors from FileOperation (@see FileOperation) + //------------------------------------------------------------------------ + using FileOperation, Arg>::FileOperation; + + //------------------------------------------------------------------------ + //! Argument indexes in the args tuple + //------------------------------------------------------------------------ + enum { NameArg }; + + //------------------------------------------------------------------------ + //! @return : name of the operation (@see Operation) + //------------------------------------------------------------------------ + std::string ToString() + { + return "DelXAttrImpl"; + } + + protected: + + //------------------------------------------------------------------------ + //! RunImpl operation (@see Operation) + //! + //! @param params : container with parameters forwarded from + //! previous operation + //! @return : status of the operation + //------------------------------------------------------------------------ + XRootDStatus RunImpl() + { + try + { + std::string name = std::get( this->args ).Get(); + // wrap the argument with a vector + std::vector attrs; + attrs.push_back( std::move( name ) ); + // wrap the PipelineHandler so the response gets unpacked properly + UnpackXAttrStatus *handler = new UnpackXAttrStatus( this->handler.get() ); + XRootDStatus st = this->file->DelXAttr( attrs, handler ); + if( !st.IsOK() ) delete handler; + return st; + } + catch( const PipelineException& ex ) + { + return ex.GetError(); + } + catch( const std::exception& ex ) + { + return XRootDStatus( stError, ex.what() ); + } + } + }; + + //---------------------------------------------------------------------------- + //! Factory for creating DelXAttrImpl objects (as there is another DelXAttr in + //! FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline DelXAttrImpl DelXAttr( File *file, Arg name ) + { + return DelXAttrImpl( file, std::move( name ) ); + } + + //---------------------------------------------------------------------------- + //! Factory for creating DelXAttrImpl objects (as there is another DelXAttr in + //! FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline DelXAttrImpl DelXAttr( File &file, Arg name ) + { + return DelXAttrImpl( file, std::move( name ) ); + } + + //---------------------------------------------------------------------------- + //! DelXAttr bulk operation (@see FileOperation) + //---------------------------------------------------------------------------- + template + class DelXAttrBulkImpl: public FileOperation>, Arg>> + { + public: + + //------------------------------------------------------------------------ + //! Inherit constructors from FileOperation (@see FileOperation) + //------------------------------------------------------------------------ + using FileOperation>, + Arg>>::FileOperation; + + //------------------------------------------------------------------------ + //! Argument indexes in the args tuple + //------------------------------------------------------------------------ + enum { NamesArg }; + + //------------------------------------------------------------------------ + //! @return : name of the operation (@see Operation) + //------------------------------------------------------------------------ + std::string ToString() + { + return "DelXAttrBulkImpl"; + } + + + protected: + + //------------------------------------------------------------------------ + //! RunImpl operation (@see Operation) + //! + //! @param params : container with parameters forwarded from + //! previous operation + //! @return : status of the operation + //------------------------------------------------------------------------ + XRootDStatus RunImpl() + { + try + { + std::vector attrs = std::get( this->args ).Get(); + return this->file->DelXAttr( attrs, this->handler.get() ); + } + catch( const PipelineException& ex ) + { + return ex.GetError(); + } + catch( const std::exception& ex ) + { + return XRootDStatus( stError, ex.what() ); + } + } + }; + + //---------------------------------------------------------------------------- + //! Factory for creating DelXAttrBulkImpl objects (as there is another DelXAttr + //! in FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline DelXAttrBulkImpl DelXAttr( File *file, Arg> attrs ) + { + return DelXAttrBulkImpl( file, std::move( attrs ) ); + } + + //---------------------------------------------------------------------------- + //! Factory for creating DelXAttrBulkImpl objects (as there is another DelXAttr + //! in FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline DelXAttrBulkImpl DelXAttr( File &file, Arg> attrs ) + { + return DelXAttrBulkImpl( file, std::move( attrs ) ); + } + + // TODO + + //---------------------------------------------------------------------------- + //! ListXAttr bulk operation (@see FileOperation) + //---------------------------------------------------------------------------- + template + class ListXAttrImpl: public FileOperation>> + { + public: + + //------------------------------------------------------------------------ + //! Inherit constructors from FileOperation (@see FileOperation) + //------------------------------------------------------------------------ + using FileOperation>>::FileOperation; + + //------------------------------------------------------------------------ + //! @return : name of the operation (@see Operation) + //------------------------------------------------------------------------ + std::string ToString() + { + return "ListXAttrImpl"; + } + + + protected: + + //------------------------------------------------------------------------ + //! RunImpl operation (@see Operation) + //! + //! @param params : container with parameters forwarded from + //! previous operation + //! @return : status of the operation + //------------------------------------------------------------------------ + XRootDStatus RunImpl() + { + return this->file->ListXAttr( this->handler.get() ); + } + }; + + //---------------------------------------------------------------------------- + //! Factory for creating ListXAttrImpl objects (as there is another ListXAttr + //! in FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline ListXAttrImpl ListXAttr( File *file ) + { + return ListXAttrImpl( file ); + } + + //---------------------------------------------------------------------------- + //! Factory for creating ListXAttrImpl objects (as there is another ListXAttr + //! in FileSystem there would be a clash of typenames). + //---------------------------------------------------------------------------- + inline ListXAttrImpl ListXAttr( File &file ) + { + return ListXAttrImpl( file ); + } } #endif // __XRD_CL_FILE_OPERATIONS_HH__ diff --git a/src/XrdCl/XrdClOperationHandlers.hh b/src/XrdCl/XrdClOperationHandlers.hh index 75762d9b2ab..06b659c8637 100644 --- a/src/XrdCl/XrdClOperationHandlers.hh +++ b/src/XrdCl/XrdClOperationHandlers.hh @@ -28,6 +28,9 @@ #include "XrdCl/XrdClFile.hh" +#include +#include + namespace XrdCl { //---------------------------------------------------------------------------- @@ -62,10 +65,121 @@ namespace XrdCl static constexpr bool value = std::is_base_of::value; }; + //---------------------------------------------------------------------------- + //! Helper class for unpacking single XAttrStatus from bulk response + //---------------------------------------------------------------------------- + class UnpackXAttrStatus : public ResponseHandler + { + public: + + UnpackXAttrStatus( ResponseHandler *handler ) : handler( handler ) + { + } + + //------------------------------------------------------------------------ + //! Callback method. + //------------------------------------------------------------------------ + void HandleResponse( XRootDStatus *status, AnyObject *response ) + { + // status is always OK for bulk response + + std::vector *bulk = nullptr; + response->Get( bulk ); + *status = bulk->front().status; + handler->HandleResponse( status, nullptr ); + delete response; + delete this; + } + + private: + + ResponseHandler *handler; + }; + + //---------------------------------------------------------------------------- + //! Helper class for unpacking single XAttr from bulk response + //---------------------------------------------------------------------------- + class UnpackXAttr : public ResponseHandler + { + public: + + UnpackXAttr( ResponseHandler *handler ) : handler( handler ) + { + } + + //------------------------------------------------------------------------ + //! Callback method. + //------------------------------------------------------------------------ + void HandleResponse( XRootDStatus *status, AnyObject *response ) + { + // status is always OK for bulk response + + std::vector *bulk = nullptr; + response->Get( bulk ); + *status = bulk->front().status; + std::string *rsp = new std::string( std::move( bulk->front().value ) ); + response->Set( rsp ); + handler->HandleResponse( status, response ); + delete this; + } + + private: + + ResponseHandler *handler; + }; + + //---------------------------------------------------------------------------- + // Helper class for creating null references for particular types + // + // @arg Response : type for which we need a null reference + //---------------------------------------------------------------------------- + template + struct NullRef + { + static Response value; + }; + + //---------------------------------------------------------------------------- + // Initialize the 'null-reference' + //---------------------------------------------------------------------------- + template + Response NullRef::value; + + //---------------------------------------------------------------------------- + //! Unpack response + //! + //! @param rsp : AnyObject holding response + //! @return : the response + //---------------------------------------------------------------------------- + template + inline Response* GetResponse( AnyObject *rsp ) + { + Response *ret = nullptr; + rsp->Get( ret ); + return ret; + } + + //---------------------------------------------------------------------------- + //! Unpack response + //! + //! @param rsp : AnyObject holding response + //! @param status : + //! @return : the response + //---------------------------------------------------------------------------- + template + inline Response* GetResponse( XRootDStatus *status, AnyObject *rsp ) + { + if( !status->IsOK() ) return &NullRef::value; + return GetResponse( rsp ); + } + //---------------------------------------------------------------------------- //! Lambda wrapper + //! + //! @arg ResponseType : type of response returned by the server //---------------------------------------------------------------------------- - class SimpleFunctionWrapper: public ResponseHandler + template + class FunctionWrapper: public ResponseHandler { public: @@ -74,8 +188,8 @@ namespace XrdCl // //! @param func : function, functor or lambda //------------------------------------------------------------------------ - SimpleFunctionWrapper( - std::function handleFunction ) : + FunctionWrapper( + std::function handleFunction ) : fun( handleFunction ) { } @@ -85,7 +199,8 @@ namespace XrdCl //------------------------------------------------------------------------ void HandleResponse( XRootDStatus *status, AnyObject *response ) { - fun( *status ); + Response *res = GetResponse( status, response ); + fun( *status, *res ); delete status; delete response; delete this; @@ -95,16 +210,16 @@ namespace XrdCl //------------------------------------------------------------------------ //! user defined function, functor or lambda //------------------------------------------------------------------------ - std::function fun; + std::function fun; }; //---------------------------------------------------------------------------- //! Lambda wrapper //! - //! @arg ResponseType : type of response returned by the server + //! Template specialization for responses that return no value (void) //---------------------------------------------------------------------------- - template - class FunctionWrapper: public ResponseHandler + template<> + class FunctionWrapper : public ResponseHandler { public: @@ -114,7 +229,7 @@ namespace XrdCl //! @param func : function, functor or lambda //------------------------------------------------------------------------ FunctionWrapper( - std::function handleFunction ) : + std::function handleFunction ) : fun( handleFunction ) { } @@ -124,12 +239,7 @@ namespace XrdCl //------------------------------------------------------------------------ void HandleResponse( XRootDStatus *status, AnyObject *response ) { - ResponseType *res = nullptr; - if( status->IsOK() ) - response->Get( res ); - else - res = &nullref; - fun( *status, *res ); + fun( *status ); delete status; delete response; delete this; @@ -139,21 +249,9 @@ namespace XrdCl //------------------------------------------------------------------------ //! user defined function, functor or lambda //------------------------------------------------------------------------ - std::function fun; - - //------------------------------------------------------------------------ - //! Null reference to the response (not really but acts as one) - //------------------------------------------------------------------------ - static ResponseType nullref; + std::function fun; }; - //---------------------------------------------------------------------------- - // Initialize the 'null-reference' - //---------------------------------------------------------------------------- - template - ResponseType FunctionWrapper::nullref; - - //---------------------------------------------------------------------------- //! Packaged Task wrapper //! @@ -180,11 +278,7 @@ namespace XrdCl //------------------------------------------------------------------------ void HandleResponse( XRootDStatus *status, AnyObject *response ) { - Response *resp = nullptr; - if( status->IsOK() ) - response->Get( resp ); - else - resp = &nullref; + Response *resp = GetResponse( status, response ); task( *status, *resp ); delete status; delete response; @@ -197,19 +291,8 @@ namespace XrdCl //! 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. @@ -279,9 +362,9 @@ namespace XrdCl if( status->IsOK() ) XRootDStatus st = f.Stat( false, info ); else - info = &nullref; + info = &NullRef::value; fun( *status, *info ); - if( info != &nullref ) delete info; + if( info != &NullRef::value ) delete info; delete status; delete response; delete this; @@ -293,18 +376,8 @@ namespace XrdCl //! 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 //---------------------------------------------------------------------------- @@ -447,9 +520,11 @@ namespace XrdCl if( status->IsOK() ) { - Response *resp = 0; - response->Get( resp ); - this->prms.set_value( std::move( *resp ) ); + Response *resp = GetResponse( response ); + if( resp == &NullRef::value ) + this->SetException( XRootDStatus( stError, errInternal ) ); + else + this->prms.set_value( std::move( *resp ) ); } else this->SetException( *status ); @@ -599,7 +674,7 @@ namespace XrdCl //------------------------------------------------------------------------ inline static ResponseHandler* Create( std::function func ) { - return new SimpleFunctionWrapper( func ); + return new FunctionWrapper( func ); } //------------------------------------------------------------------------ diff --git a/src/XrdCl/XrdClOperations.hh b/src/XrdCl/XrdClOperations.hh index b6e046023fa..aa741a6de7d 100644 --- a/src/XrdCl/XrdClOperations.hh +++ b/src/XrdCl/XrdClOperations.hh @@ -269,9 +269,7 @@ namespace XrdCl void AddOperation( Operation *op ) { if( handler ) - { handler->AddOperation( op ); - } } //------------------------------------------------------------------------