1 /*************************************************************************** 2 rkrinterface.h - description 3 ------------------- 4 begin : Fri Nov 1 2002 5 copyright : (C) 2002 - 2018 by Thomas Friedrichsmeier 6 email : thomas.friedrichsmeier@kdemail.net 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 18 #ifndef RKRINTERFACE_H 19 #define RKRINTERFACE_H 20 21 #include <qobject.h> 22 #include <QFile> 23 24 #include "rcommand.h" 25 #include "rcommandreceiver.h" 26 27 class RCommand; 28 class RKWardMainWindow; 29 class RKRBackend; 30 class RBackendRequest; 31 32 /** This class provides the main interface to the R-processor. 33 34 Note that since communication with R is asynchronous, there is no way to get 35 R-output within the same function, the request is submitted. You have to 36 provide an RCommandReceiver object, if you're interested in the output. 37 38 For a detailed explanation see \ref UsingTheInterfaceToR . 39 40 @see RCommand 41 *@author Thomas Friedrichsmeier 42 */ 43 44 class RInterface : public QObject, public RCommandReceiver { 45 Q_OBJECT 46 public: 47 /** constructor */ 48 RInterface(); 49 /** destructor */ 50 ~RInterface(); 51 52 /** issues the given command in the given chain */ 53 void issueCommand (RCommand *command, RCommandChain *chain=0); 54 /** convenience function to create a new command and issue it. See documentation on RCommand::RCommand () and RInterface::issueCommand () */ 55 void issueCommand (const QString &command, int type = 0, const QString &rk_equiv = QString (), RCommandReceiver *receiver=0, int flags=0, RCommandChain *chain=0); 56 57 /** opens a new command chain. Returns a pointer to the new chain. If you specify a parent, the new chain will be a sub-chain of that chain. */ 58 RCommandChain *startChain (RCommandChain *parent=0); 59 /** closes the command chain. The chain (and even its parent, if it is already closed) may be deleted right afterwards! */ 60 void closeChain (RCommandChain *chain); 61 62 /** Ensures that the given command will not be executed, or, if it is already running, interrupts it. Note that commands marked RCommand::Sync can 63 not be interrupted. */ 64 void cancelCommand (RCommand *command); 65 /** Cancels the given command, unless it has already been submitted to the backend. Returns true, if command was cancelled, false otherwise. */ 66 bool softCancelCommand (RCommand *command); 67 /** Cancels all running or outstanding commands. @See cancelCommand() */ 68 void cancelAll (); 69 70 /** Pauses process. The current command will continue to run, but no new command will be */ 71 void pauseProcessing (bool pause); 72 73 /** returns the command currently running in the thread. Be careful when using the returned pointer! */ runningCommand()74 RCommand *runningCommand () const { return (all_current_commands.isEmpty () ? 0 : all_current_commands.last ()); }; 75 backendIsDead()76 bool backendIsDead () { return backend_dead; }; 77 bool backendIsIdle (); isNaReal(double value)78 static bool isNaReal (double value) { return na_real == value; }; isNaInt(int value)79 static bool isNaInt (int value) { return na_int == value; }; 80 private: 81 void timerEvent (QTimerEvent *) override; 82 int flush_timer_id; 83 /** Calls RThread::flushOutput(), and takes care of adding the output to all applicable commands */ 84 void flushOutput (bool forced); 85 /** pointer to the RThread */ 86 RKRBackend *r_thread; 87 /** Used by the testing framework. see R function rk.record.commands(). */ 88 QFile command_logfile; 89 enum { 90 NotRecordingCommands, 91 RecordingCommands, 92 RecordingCommandsUnfiltered 93 } command_logfile_mode; 94 95 void processHistoricalSubstackRequest (const QStringList &calllist, RCommand *parent_command); 96 QStringList processPlainGenericRequest (const QStringList &calllist); 97 void processRBackendRequest (RBackendRequest *request); 98 99 /** A list of all commands that have entered, and not yet left, the backend thread */ 100 QList<RCommand*> all_current_commands; 101 /** NOTE: processing R events while waiting for the next command may, conceivably, lead to new requests, which may also wait for sub-commands! Thus we keep a simple stack of requests. */ 102 QList<RBackendRequest*> command_requests; currentCommandRequest()103 RBackendRequest* currentCommandRequest () const { return (command_requests.isEmpty () ? 0 : command_requests.last ()); }; 104 void tryNextCommand (); 105 void doNextCommand (RCommand *command); 106 RCommand *popPreviousCommand (int id); 107 void handleCommandOut (RCommand *command); 108 bool previously_idle; 109 110 RCommandChain* openSubcommandChain (RCommand *parent_command); 111 QList<RCommand *> current_commands_with_subcommands; 112 void closeSubcommandChain (RCommand *parent_command); 113 114 /** @see locked */ 115 enum LockType { 116 User=1 /**< locked on user request */ 117 }; 118 119 /** Used for locking the backend, meaning not further commands will be given to the backend. It is called, if the RThread is paused on User request. 120 * @see RInterface::pauseProcessing 121 * May be an OR'ed combination of several LockType s, but currently, there is only one LockType */ 122 int locked; 123 124 QString startup_errors; 125 bool startup_phase2_error; 126 RCommand *dummy_command_on_stack; 127 friend class RKRBackendProtocolFrontend; 128 bool backend_dead; 129 static double na_real; 130 static int na_int; 131 friend class RKWardMainWindow; 132 friend class RCommand; 133 protected: 134 void handleRequest (RBackendRequest *request); 135 void rCommandDone (RCommand *command) override; 136 signals: 137 void backendWorkdirChanged(); 138 }; 139 140 /** 141 \page UsingTheInterfaceToR Using the Interface to R 142 \brief An Introduction to using the R-backend: Running commands in R and handling the results 143 144 This page tries to give you an introduction into using the RInterface and related classes. You'll learn how to submit a command for evaluation 145 by R and how you can get and handle the results. Note that this is fairly low-level. You do not need to read this documentation in order to develop 146 plugins. You'll only need to know this in order to do C++-hacking in rkward. 147 The page is divided into several sections on special problems, but if you're new to rkward, you will probably want to read it as a whole instead of 148 jumping right to those sections. 149 150 \section UsingTheInterfaceToRTheSimpleCase The simple case: Fire and forget 151 152 In the most simple case, all you want to do is to send a command to be evaluated executed in the R backend, and you are not interested in what 153 happens (whether the command runs successfully, or what the output is). For this, all you need is the following 154 code: 155 156 \code 157 #include "rkglobals.h" 158 #include "rbackend/rinterface.h" 159 160 RKGlobals::rInterface ()->issueCommand ("print (\"hello world!\")", RCommand::User); 161 \endcode 162 163 You will note, that actually there are two RInterface::issueCommand functions, this one is obviously the one taking a QString and several further 164 parameters as argument. It is actually quite similar to the other RInterface::issueCommand function which takes an RCommand as a parameter. This convenience class basically just creates an RCommand with the same parameters as the constructor of RCommand (RCommand::RCommand), and then submits this RCommand. We'll discuss what an RCommand really is further down below. For now a good enough explanations is, that it's simply a container for a command. 165 166 The first parameter here is fairly obvious, the command-string the R backend should evaluate. 167 168 The second parameter (RCommand::User) is an integer, which can be a bit-wise or-able combination of the values in the RCommand::CommandTypes enum. We'll deal with the more specific values in that enum later. Here, we're just using RCommand::User, which signifies, that the command came 169 directly from the user. This information is fairly important, as it affects the handling of the command at several places: Which color it will be given in 170 the R-command log (currently class RKwatch), whether the command can be cancelled (RCommand::User commands can be cancelled, but some other types of commands can not be cancelled), etc. See the documentation on RCommand::CommandTypes (not yet complete) for more information. 171 172 \section UsingTheInterfaceToRHandlingReturns A slightly more realistic example: Handling the result of an RCommand 173 174 Most of the time you don't just want to run a command, but you also want to know the result. Now, this is a tad bit more difficult than one might expect at first glance. The reason for this is that the R backend runs in a separate thread. Hence, whenever you submit a command, it generally does not get executed right away - or at least you just don't know, when exactly it gets executed, and when the result is available. This is necessary, so (expensive) commands running in the backend do not block operations in the GUI/frontend. 175 176 Ok, so how do you get informed, when your command was completed? Using RCommandReceiver. What you will want to do is inherit the class you 177 want to handle the results of RCommands from RCommandReceiver. When finished, the RCommand will be submitted to the (pure virtual) RCommandReceiver::rCommandDone function, which of course you'll have to implement in a meaningful way in your derived class. 178 179 The corresponding code would look something like this: 180 181 \code 182 #include "rkglobals.h" 183 #include "rbackend/rinterface.h" 184 #include "rbackend/rcommandreceiver.h" 185 186 class MyReceiver : public RCommandReceiver { 187 //... 188 protected: 189 /// receives finished RCommands and processes them 190 void rCommandDone (RCommand *command); 191 //... 192 private: 193 /// does something by submitting an RCommand 194 void someFunction (); 195 //... 196 }; 197 198 199 void MyReceiver::someFunction () { 200 RKGlobals::rInterface ()->issueCommand ("print (1+1)", RCommand::App, QString (), this); 201 } 202 203 void MyReceiver::rCommandDone (RCommand *command) { 204 if (command->successful ()) { 205 qDebug ("Result was %s", command->output ()->utf8 ()); 206 } 207 } 208 \endcode 209 210 First thing to note is, that this time we're passing two additional parameters to RInterface::issueCommand. The first (or rather third) is really not used as of the time of this writing. What it's meant to become is a short descriptive string attached to the RCommand, that allows the user to make some sense of what this command is all about. The other (fourth) is a pointer to an RCommandReceiver that should be informed of the result. In this case, we'll handle the result in the same object that we issued the command from, so we use "this". 211 212 So next the RCommand created with RInterface::issueCommand goes on its way to/through the backend (we'll discuss what happens there further down below). Then later, when it has completed its journey, rCommandDone will be called with a pointer to the command as parameter. Now we can use this pointer to retrieve the information we need to know. RCommand::successful and some further simple functions give information about whether the command had any errors and what kind of errors (see RCommand for details). RCommand::output contains the output of the command as a QString (provided the command was successful and had any output). In this case that should be "[1] 2". 213 214 \section UsingTheInterfaceToRMultipleCommands Dealing with several RCommands in the same object 215 216 In many cases you don't just want to deal with a single RCommand in an RCommandReceiver, but rather you might submit a bunch of different commands (for instance to find out about several different properties of an object in R-space), and then use some special handling for each of those commands. So the problem is, how to find out, which of your commands you're currently dealing with in rCommandDone. 217 218 There are several ways to deal with this: 219 220 - storing the RCommand::id () (each command is automatically assigned a unique id, TODO: do we need this functionality? Maybe remove it for redundancy) 221 - passing appropriate flags to know how to handle the command 222 - keeping the pointer (CAUTION: don't use that pointer except to compare it with the pointer of an incoming command. Commands get deleted when they are finished, and maybe (in the future) if they become obsolete etc. Hence the pointers you keep may be invalid!) 223 224 To illustrate the option of using "FLAGS", here is a reduced example of how RKVariable updates information about the dimensions and class of the corresponding object in R-space using two different RCommand s: 225 226 \code 227 #define UPDATE_DIM_COMMAND 1 228 #define UPDATE_CLASS_COMMAND 2 229 230 void RKVariable::updateFromR () { 231 //... 232 RCommand *command = new RCommand ("length (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetIntVector, QString (), this, UPDATE_DIM_COMMAND); 233 RKGlobals::rInterface ()->issueCommand (command, RKGlobals::rObjectList()->getUpdateCommandChain ()); 234 } 235 236 void RKVariable::rCommandDone (RCommand *command) { 237 //... 238 if (command->getFlags () == UPDATE_DIM_COMMAND) { 239 // ... 240 RCommand *ncommand = new RCommand ("class (" + getFullName () + ")", RCommand::App | RCommand::Sync | RCommand::GetStringVector, QString (), this, UPDATE_CLASS_COMMAND); 241 RKGlobals::rInterface ()->issueCommand (ncommand, RKGlobals::rObjectList()->getUpdateCommandChain ()); 242 } else if (command->getFlags () == UPDATE_CLASS_COMMAND) { 243 //... 244 } 245 } 246 \endcode 247 248 Note that you can freely assign whatever flags you like. Only your own class will need to know how to interpret the flags. 249 250 Now what about that RKGlobals::rObjectList()->getUpdateCommandChain ()? We'll talk about RCommandChain and what you need it for further down below. But first we'll have a look at how an RCommand is handled internally. 251 252 \section UsingTheInterfaceToRInternalHandling What happens with an RCommand internally? 253 254 So far we've discussed RInterface:issueCommand () and RCommandReceiver::rCommandDone (). But what happens in between? 255 256 First the RCommand is placed in a first-in-first-out stack. This stack is needed, since - as discussed - the commands get executed in a separate thread, so several command may get stacked up, before the first one gets run. 257 258 Then, in the backend thread (RThread) there is a loop running, which fetches those commands from the stack and executes them one by one. Whenver a command has been executed in this thread, it gets updated with information on any errors that occurred and of course also with the result of running the command. Next, a QCustomEvent is being posted. What this does is - rougly speaking -, transfer the pointer to the command back to the main thread in a safe way. 259 260 Whenever the main thread becomes active again, it will find that QCustomEvent and handle it in RInterface::customEvent. 261 262 The most important thing happening there, is a call to RCommand::finished (RCommand::finished basically just calls the responsible RCommandReceiver::rCommandDone), and right after that the RCommand gets deleted. 263 264 \section UsingTheInterfaceToRThreadingIssues Threading issues 265 266 The above description sounds simple enough, but there may be some threading issues to keep in mind. Consider what needs to happen when RKVariable is trying to update the information on the corresponding object in R-space (see code example above): 267 268 - RKVariable will first run a command to determine the dimensionality of the object. 269 270 Now this is more significant than you may think, as RKVariable is a special kind of RObject, which only handles one-dimensional data. Hence, if you create an object in R with 271 272 \code 273 myobject <- c (1, 2, 3) 274 \endcode 275 276 In RKWard an RKVariable will be responsible for "myobject". 277 278 However, if next, you assign something different to myobject: 279 280 \code 281 myobject <- data.frame (x=c (1, 2, 3), y=c (2, 3, 4)) 282 \endcode 283 284 the object "myobject" can no longer be handled by RKVariable, but instead by RContainerObject. 285 286 What this means practically is that if RKVariable finds out its corresponding object in R-space has more than a single dimension, the RKVariable will have to be deleted and an RContainerObject needs to be created instead. 287 288 So what's the problem? 289 290 Consider this hypothetical example: 291 292 - RKVariable for object "myobject" runs a command to determine the dimensionality of "myobject" 293 - Before that command has finished, the user assigns a data.frame to "myobject" (or deletes the object, or whatever) 294 - The command to determine the dimensionality gets run and returns "1 dimension". RKVariable will assume it knows how to handle the object, and tries to do something with "myobject" which is only applicable for one-dimensional objects (e.g. trying to get the data as a one-dimensional array) 295 - The user command assigning a data.frame gets run 296 - RKVariables command to get the data fails 297 298 Now, you may argue this does not sound all that likely, and probably it isn't, but the point to see is that there are cases in which the threaded nature of R access can pose some problems. More generally, that is the case, if you want a sequence of commands to run in exactly that order without being disturbed by intervening commands. 299 300 To cope with this, it is sometimes desirable to keep closer control over the order in which commands get run in the backend. 301 302 \section UsingTheInterfaceToRCommandChains How to ensure commands get executed in the correct order: RCommandChain 303 304 The way to do this is to use RCommandChain. Basically, when you want commands to be executed in a sequence being sure that no other commands intervene, you do this: 305 306 \code 307 RCommandChain *chain = RKGlobals::rInterface ()->startChain (); 308 309 // create first command 310 RKGlobals::rInterface ()->issueCommand (first_command, chain); 311 312 // wait for command to return, potentially allows further calls to RInterface::issueCommand () from other places in the code 313 314 // create second command 315 RKGlobals::rInterface ()->issueCommand (second_command, chain); 316 317 RKGlobals::rInterface ()->closeChain (chain); 318 \endcode 319 320 Now the point is that you place both of your commands in a dedicated "chain", telling RKWard that those two commands will have to be run in direct succession. If between the first and the second command, another section of the code issues a different command, this command will never be run until all commands in the chain have been run and the chain has been marked as closed. 321 322 To illustrate, consider this series of events: 323 324 \code 325 1) RCommandChain *chain = RKGlobals::rInterface ()->startChain (); 326 2) RKGlobals::rInterface ()->issueCommand (first_command, chain); 327 3) RKGlobals::rInterface ()->issueCommand (some_command); 328 4) RKGlobals::rInterface ()->issueCommand (second_command, chain); 329 5) RKGlobals::rInterface ()->issueCommand (some_command2); 330 6) RKGlobals::rInterface ()->closeChain (chain); 331 \endcode 332 333 Now let's assume for a second, the R backend has been busy doing other stuff and has not executed any of the commands so far, then the execution stack will now look like this: 334 335 - top level 336 - chain 337 - first_command 338 - second_command 339 - chain is marked as closed: after executing second_command, we may proceed with the top level 340 - some_command 341 - some_command2 342 343 So the order of execution will be guaranteed to be first_command, second_command, some_command, some_command2, although they were issued ina different order. You can also open sub chains, using 344 345 \code 346 RCommandChain *sub_chain = RKGlobals::rInterface ()->startChain (parent_chain); 347 \endcode 348 349 Remember to close chains when you placed all the commands you needed to. If you don't close the chain, RKWard will continue to wait for new commands in that chain, and never proceed with commands outside of the chain. 350 351 \section UsingTheInterfaceToROutputOptions Sending results to the output and retrieving low-level data from the backend 352 353 There are a few special type-modifiers you can specify when creating an RCommand (as part of the second parameter to RCommand::RCommand or RInterface::issueCommand), that determine what will be done with the result: 354 355 - RCommand::EmptyCommand 356 This one tells the backend, that the command does not really need to be executed, and does not contain anything. You'll rarely need this flag, but sometimes it is useful to submit an empty command simply to find out when it is finished. 357 358 - RCommand::DirectToOutput 359 This is typically used in plugins: When you specify this modifier, the plain text result of this command (i.e. whatever R prints out when evaluating the command) will be added to the HTML output file. Remember to call RKWardMainWindow::newOutput in order to refresh the output-window once the command has finished. 360 361 - RCommand::GetIntVector, RCommand::GetStringVector, RCommand::GetRealVector 362 These are special modifiers helpful when transferring data from R to RKWard (used primarily in the editor classes and in conjunction with RCommand::Sync): They tell the backend to try to fetch the result as an array of int, char*, or double, respectively. For instance, if you know object "myobject" is an integer vector, you may get the data using 363 364 \code 365 RKGlobals::rInterface ()->issueCommand ("myobject", RCommand::Sync | RCommand::GetIntVector, QString (), this); 366 \endcode 367 368 Assuming the data can in fact be converted to a vector of integers, you can then access the data using these members in RCommand: 369 370 - RCommand::intVectorLength (): size of int array 371 - RCommand::getIntVector (): a pointer to the int array. Warning: The array is owned by the RCommand and will be deleted together with the RCommand, so don't just store the pointer 372 - RCommand::detachIntVector (): If you do want to keep the array, use this call to transfer ownership to your class. You are now responsible for freeing up the data yourself. 373 374 Obviously, whenever trying to transfer data from the backend, this approach is highly superior to parsing the QString RCommand::output (). 375 376 \section UsingTheInterfaceToRFurtherReading Where to find more detailed information on these topics 377 378 The following classes contain (or should contain) further important documentation: 379 380 - \ref RInterface 381 - \ref RCommand 382 - \ref RCommandReceiver 383 - \ref RCommandStack 384 385 Even lower level API: 386 387 - \ref RRBackendProtcolFrontend 388 - \ref RBackend 389 - \ref RRBackendProtcolBackend 390 391 */ 392 393 #endif 394