00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifndef PkgModuleCallbacksYCP_h
00023 #define PkgModuleCallbacksYCP_h
00024
00025 #include <stack>
00026
00027 #include <y2util/Y2SLog.h>
00028 #include <y2util/stringutil.h>
00029 #include <y2util/Date.h>
00030 #include <y2util/FSize.h>
00031 #include <y2util/Url.h>
00032 #include <y2util/Pathname.h>
00033
00034 #include <y2/Y2ComponentBroker.h>
00035 #include <y2/Y2Component.h>
00036 #include <y2/Y2Namespace.h>
00037 #include <y2/Y2Function.h>
00038
00039 #include <ycpTools.h>
00040 #include <PkgModuleCallbacks.h>
00041
00042 #include <ycp/y2log.h>
00043
00044 using namespace std;
00045
00047
00048
00063 class PkgModuleFunctions::CallbackHandler::YCPCallbacks
00064 {
00065 public:
00066
00071 enum CBid {
00072 CB_StartRebuildDb, CB_ProgressRebuildDb, CB_NotifyRebuildDb, CB_StopRebuildDb,
00073 CB_StartConvertDb, CB_ProgressConvertDb, CB_NotifyConvertDb, CB_StopConvertDb,
00074 CB_StartProvide, CB_ProgressProvide, CB_DoneProvide,
00075 CB_StartPackage, CB_ProgressPackage, CB_DonePackage,
00076 CB_StartDownload, CB_ProgressDownload, CB_DoneDownload,
00077 CB_MediaChange,
00078 CB_SourceChange,
00079 CB_YouProgress,
00080 CB_YouPatchProgress,
00081 CB_YouError,
00082 CB_YouMessage,
00083 CB_YouLog,
00084 CB_YouExecuteYcpScript,
00085 CB_YouScriptProgress
00086 };
00087
00093 static string cbName( CBid id_r ) {
00094 switch ( id_r ) {
00095 #define ENUM_OUT(N) case CB_##N: return #N
00096 ENUM_OUT( StartRebuildDb );
00097 ENUM_OUT( ProgressRebuildDb );
00098 ENUM_OUT( NotifyRebuildDb );
00099 ENUM_OUT( StopRebuildDb );
00100 ENUM_OUT( StartConvertDb );
00101 ENUM_OUT( ProgressConvertDb );
00102 ENUM_OUT( NotifyConvertDb );
00103 ENUM_OUT( StopConvertDb );
00104 ENUM_OUT( StartProvide );
00105 ENUM_OUT( ProgressProvide );
00106 ENUM_OUT( DoneProvide );
00107 ENUM_OUT( StartPackage );
00108 ENUM_OUT( ProgressPackage );
00109 ENUM_OUT( DonePackage );
00110 ENUM_OUT( StartDownload );
00111 ENUM_OUT( ProgressDownload );
00112 ENUM_OUT( DoneDownload );
00113 ENUM_OUT( MediaChange );
00114 ENUM_OUT( SourceChange );
00115 ENUM_OUT( YouProgress );
00116 ENUM_OUT( YouPatchProgress );
00117 ENUM_OUT( YouError );
00118 ENUM_OUT( YouMessage );
00119 ENUM_OUT( YouLog );
00120 ENUM_OUT( YouExecuteYcpScript );
00121 ENUM_OUT( YouScriptProgress );
00122 #undef ENUM_OUT
00123
00124 }
00125 return stringutil::form( "CBid(%d)", id_r );
00126 }
00127
00128 private:
00129
00130 struct CBdata
00131 {
00132 CBdata (string module, string symbol, Y2Namespace* component)
00133 : module (module), symbol (symbol), component (component)
00134 { }
00135
00136 const string module, symbol;
00137 Y2Namespace* component;
00138 };
00139
00140 typedef map <CBid, stack <CBdata> > _cbdata_t;
00141 _cbdata_t _cbdata;
00142
00143 public:
00144
00148 YCPCallbacks( )
00149 {}
00150
00151
00152 void popCallback( CBid id_r ) {
00153 _cbdata_t::iterator tmp1 = _cbdata.find(id_r);
00154 if (tmp1 != _cbdata.end() && !tmp1->second.empty())
00155 tmp1->second.pop();
00156 }
00157
00161 void setCallback( CBid id_r, const string & name_r ) {
00162 y2debug ("Registering callback %s", name_r.c_str ());
00163 string::size_type colonpos = name_r.find("::");
00164 if ( colonpos != string::npos ) {
00165
00166 string module = name_r.substr ( 0, colonpos );
00167 string symbol = name_r.substr ( colonpos + 2 );
00168
00169 Y2Component *c = Y2ComponentBroker::getNamespaceComponent (module.c_str());
00170 if (c == NULL)
00171 {
00172 ycp2error ("No component can provide namespace %s for a callback of %s (callback id %d)",
00173 module.c_str (), symbol.c_str (), id_r);
00174 return;
00175 }
00176
00177 Y2Namespace *ns = c->import (module.c_str ());
00178 if (ns == NULL)
00179 {
00180 y2error ("Component %p could not provide namespace %s for a callback of %s",
00181 c, module.c_str (), symbol.c_str ());
00182 return;
00183 }
00184
00185
00186 ns->initialize ();
00187
00188 _cbdata[id_r].push (CBdata (module, symbol, ns));
00189 } else {
00190 ycp2error ("Callback must be a part of a namespace");
00191 }
00192 }
00196 bool setCallback( CBid id_r, const YCPString & args ) {
00197 string name = args->value();
00198 setCallback( id_r, name );
00199 return true;
00200 }
00205 YCPValue setYCPCallback( CBid id_r, const YCPString & args_r ) {
00206 if (!args_r->value().empty ())
00207 {
00208 if ( ! setCallback( id_r, args_r ) ) {
00209 return YCPError( string("Bad args to Pkg::Callback") + cbName( id_r ) );
00210 }
00211 }
00212 else
00213 {
00214 popCallback( id_r );
00215 }
00216 return YCPVoid();
00217 }
00218
00223 bool isSet( CBid id_r ) const {
00224 const _cbdata_t::const_iterator tmp1 = _cbdata.find(id_r);
00225 return tmp1 != _cbdata.end() && !tmp1->second.empty();
00226 }
00227
00228 public:
00229
00233 Y2Function* createCallback( CBid id_r ) const {
00234 const _cbdata_t::const_iterator tmp1 = _cbdata.find(id_r);
00235 if (tmp1 == _cbdata.end() || tmp1->second.empty())
00236 return NULL;
00237 const CBdata& tmp2 = tmp1->second.top();
00238
00239 string module = tmp2.module;
00240 string name = tmp2.symbol;
00241 Y2Namespace *ns = tmp2.component;
00242 if (ns == NULL)
00243 {
00244 y2error ("No namespace %s for a callback of %s", module.c_str (), name.c_str ());
00245 return NULL;
00246 }
00247
00248 Y2Function* func = ns->createFunctionCall (name);
00249 if (func == NULL)
00250 {
00251 ycp2error ("Cannot find function %s in module %s as a callback", name.c_str (), module.c_str());
00252 return NULL;
00253 }
00254
00255 return func;
00256 }
00257
00258 public:
00259
00260 #warning Free interface for YCPCallback sending is ok, but a functional one is desired too.
00261
00272 class Send {
00273 public:
00277 struct CB {
00278 const Send & _send;
00279 CBid _id;
00280 bool _set;
00281 Y2Function* _func;
00282 YCPValue _result;
00283 CB( const Send & send_r, CBid func )
00284 : _send( send_r )
00285 , _id( func )
00286 , _set( _send.ycpcb().isSet( func ) )
00287 , _func( _send.ycpcb().createCallback( func ) )
00288 , _result( YCPVoid() )
00289 {}
00290
00291 ~CB ()
00292 {
00293 if (_func) delete _func;
00294 }
00295
00296 CB & addStr( const string & arg ) { if (_func != NULL) _func->appendParameter( YCPString( arg ) ); return *this; }
00297 CB & addStr( const Pathname & arg ) { return addStr( arg.asString() ); }
00298 CB & addStr( const Url & arg ) { return addStr( arg.asString() ); }
00299
00300 CB & addInt( long long arg ) { if (_func != NULL) _func->appendParameter( YCPInteger( arg ) ); return *this; }
00301
00302 CB & addBool( bool arg ) { if (_func != NULL) _func->appendParameter( YCPBoolean( arg ) ); return *this; }
00303
00304 bool isStr() const { return _result->isString(); }
00305 bool isInt() const { return _result->isInteger(); }
00306 bool isBool() const { return _result->isBoolean(); }
00307
00308 bool expecting( YCPValueType exp_r ) const {
00309 if ( _result->valuetype() == exp_r )
00310 return true;
00311 INT << "Wrong return type " << _result->valuetype() << ": Expected " << exp_r << endl;
00312 return false;
00313 }
00314
00315 bool evaluate() {
00316 if ( _set && _func ) {
00317 y2debug ("Evaluating callback");
00318 _result = _func->evaluateCall ();
00319
00320 delete _func;
00321 _func = _send.ycpcb().createCallback( _id );
00322 return true;
00323 }
00324 return false;
00325 }
00326
00327 bool evaluate( YCPValueType exp_r ) {
00328 return evaluate() && expecting( exp_r );
00329 }
00330
00331 string evaluateStr( const string & def_r = "" ) {
00332 return evaluate( YT_STRING ) ? _result->asString()->value() : def_r;
00333 }
00334
00335 long long evaluateInt( const long long & def_r = 0 ) {
00336 return evaluate( YT_INTEGER ) ? _result->asInteger()->value() : def_r;
00337 }
00338
00339 bool evaluateBool( const bool & def_r = false ) {
00340 return evaluate( YT_BOOLEAN ) ? _result->asBoolean()->value() : def_r;
00341 }
00342 };
00343 private:
00344 const YCPCallbacks & _ycpcb;
00345 public:
00346 Send( const YCPCallbacks & ycpcb_r ) : _ycpcb( ycpcb_r ) {}
00347 virtual ~Send() {}
00348 const YCPCallbacks & ycpcb() const { return _ycpcb; }
00349 CB ycpcb( CBid func ) const { return CB( *this, func ); }
00350 };
00351 };
00352
00354
00355 #endif // PkgModuleCallbacksYCP_h