Next, we'll talk more about Opticks Resource and Service objects. A Resource is an auto pointer which handles creation and cleaup of a variety of objects. Resource implements the "resource acquisition is initialization" (RAII) design pattern. They help manage the lifecycle of message log entries, model elements, and other objects. There are many kinds of resources available and you can create your own. Look at the reference documentation for more information. A Service is a type of Resource which obtains a singleton pointer. We've already seen a Service used in Tutorial 1. Look at the Service reference documentation for a list of available services. In this tutorial we'll explore a couple of the more often used resource types, message log resources and plug-in resources.
If you would like to run this tutorial as you follow along with the code, see Running Tutorials With Opticks. If you would like to build and experiment with this tutorial as you follow along with the code, see Building and Running Tutorial plug-ins. If you are running this tutorial in Opticks, you will need to select "Tutorial 2" from the Tutorial toolbar to execute it.
Steps are similar to messages as they also have a short description and zero or more properties. Steps also have a result (success, failure, or aborted) and a failure reason. Steps may contain sub-steps. Managing a complex hierarchy of message log steps can be difficult, especially when your plug-in calls other plug-ins. StepResource and MessageResource simplify the process. When you create a StepResource or MessageResource, it will be added as a sub-step or sub-message to the currently active step. The active step is the deepest step in the hierarchy which has not been finalized. This allows you to create complex step hierarchies without keeping track of where you are in the hierarchy. Lets look at some of the code for the Tutorial2 plug-in.
#ifdef WIN_API #include <windows.h> #else #include <unistd.h> #endif
allowMultipleInstances(true);
pInArgList->addArg<int>("Count", 5, "How many times should the plug-in recurse?"); pInArgList->addArg<int>("Depth", 1, "This is the recursive depth. Not usually set by the initial caller.");
StepResource pStep("Tutorial 2", "app", "A8FEFCB3-5D08-4670-B47E-CC533A932737");
int count; int depth; pInArgList->getPlugInArgValue("Count", count); pInArgList->getPlugInArgValue("Depth", depth); if (count < 1 || count >= 10 || depth < 1 || depth >= 10) { std::string msg = "Count and depth must be between 1 and 9 inclusive."; pStep->finalize(Message::Failure, msg); if (pProgress != NULL) { pProgress->updateProgress(msg, 0, ERRORS); } return false; } if (depth > count) { std::string msg = "Depth must be <= count"; pStep->finalize(Message::Failure, msg); if (pProgress != NULL) { pProgress->updateProgress(msg, 0, ERRORS); } return false; } pStep->addProperty("Depth", depth);
if (pProgress != NULL) { pProgress->updateProgress("Tutorial 2: Count " + StringUtilities::toDisplayString(count) + " Depth " + StringUtilities::toDisplayString(depth), depth * 100 / count, NORMAL); }
// sleep to simulate some work #ifdef WIN_API _sleep(1000); #else sleep(1); #endif
if (depth < count) { ExecutableResource pSubCall("Tutorial 2", std::string(), pProgress, false); VERIFY(pSubCall->getPlugIn() != NULL); pSubCall->getInArgList().setPlugInArgValue("Count", &count); pSubCall->getInArgList().setPlugInArgValue("Depth", &++depth);
NULL. Since we are creating another instance of the same plug-in and have the multiple instance option enabled, this should never be NULL. If you are calling another plug-in this will usually not be a VERIFY() but should present a better error message to the user indicating that the requested plug-in is not available. We access the input argument list and set the values of the Count and Depth arguments. We don't need to set the progress argument this way since we specified a Progress object in the ExecutableResource constructor. If we don't supply a Progress object and the plug-in is called in interactive mode, the ExecutableResource will create a new Progress dialog and pass that to the plug-in. if (!pSubCall->execute()) { // sub-call has already posted an error message return false; }
pStep->finalize(); return true;