1 /*=========================================================================
3 Module: $RCSfile: bbtkBlackBox.h,v $
5 Date: $Date: 2009/05/28 08:12:05 $
6 Version: $Revision: 1.26 $
7 =========================================================================*/
9 /* ---------------------------------------------------------------------
11 * Copyright (c) CREATIS-LRMN (Centre de Recherche en Imagerie Medicale)
12 * Authors : Eduardo Davila, Laurent Guigues, Jean-Pierre Roux
14 * This software is governed by the CeCILL-B license under French law and
15 * abiding by the rules of distribution of free software. You can use,
16 * modify and/ or redistribute the software under the terms of the CeCILL-B
17 * license as circulated by CEA, CNRS and INRIA at the following URL
18 * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
19 * or in the file LICENSE.txt.
21 * As a counterpart to the access to the source code and rights to copy,
22 * modify and redistribute granted by the license, users are provided only
23 * with a limited warranty and the software's author, the holder of the
24 * economic rights, and the successive licensors have only limited
27 * The fact that you are presently reading this means that you have had
28 * knowledge of the CeCILL-B license and that you accept its terms.
29 * ------------------------------------------------------------------------ */
35 * \brief Class bbtk::BlackBox : abstract black-box interface.
39 * \class bbtk::BlackBox
40 * \brief Abstract black-box interface
43 #ifndef __bbtkBlackBox_h__
44 #define __bbtkBlackBox_h__
46 #include "bbtkSystem.h"
47 #include "bbtkMessageManager.h"
48 #include "bbtkBlackBoxDescriptor.h"
49 #include "bbtkBlackBoxInputConnector.h"
50 //#include "bbtkBlackBoxOutputConnector.h"
53 // Signal/slot mechanism for output change events
54 #include <boost/signal.hpp>
55 #include <boost/bind.hpp>
58 #define bbtkBlackBoxMessage(key,level,mess) \
59 bbtkMessage(key,level,"["<<bbGetName()<<"] "<<mess)
60 #define bbtkBlackBoxDebugMessage(key,level,mess) \
61 bbtkDebugMessage(key,level,"["<<bbGetName()<<"] "<<mess)
67 struct Void { Void(int = 0) {} };
71 class BlackBoxOutputConnector;
75 class BBTK_EXPORT BlackBox : public Object
77 BBTK_ABSTRACT_OBJECT_INTERFACE(BlackBox);
79 //==================================================================
81 //==================================================================
82 typedef boost::signals::trackable OutputChangeObserverType;
83 typedef boost::signal<void (bbtk::BlackBox::Pointer,
85 IOStatus)> OutputChangeSignalType;
86 typedef OutputChangeSignalType::slot_function_type
87 OutputChangeCallbackType;
89 /// The type of map of output connector pointers
90 typedef std::map<std::string, BlackBoxOutputConnector*>
91 OutputConnectorMapType;
92 /// The type of map of input connector pointers
93 typedef std::map<std::string, BlackBoxInputConnector*>
94 InputConnectorMapType;
96 /// Returns the pointer on the descriptor of the box
97 virtual BlackBoxDescriptor::Pointer bbGetDescriptor() const = 0;
99 /// Returns a pointer on a clone of the box with name <name>
100 virtual BlackBox::Pointer bbClone(const std::string& name) = 0;
102 /// User overloadable destruction method of a black box
103 virtual void bbUserDelete();
105 /// Returns the Name of the Type of the BlackBox
106 const std::string& bbGetTypeName() const
107 { return bbGetDescriptor()->GetTypeName(); }
110 /// Returns the name of the BlackBox (instance)
111 const std::string& bbGetName() const { return bbmName; }
113 /// Returns the full name of the BlackBox (instance+type)
114 virtual std::string bbGetFullName() const;
116 /// Returns the name with the name of the parent prepended if any
117 virtual std::string bbGetNameWithParent() const;
119 /// Returns the parent of the BlackBox, i.e the BlackBox that contains it (0 if none)
120 BlackBox::Pointer bbGetParent() const { return bbmParent.lock(); }
123 /// Main processing method of the box.
124 virtual void bbExecute(bool force = false);
131 /// Returns true iff the BlackBox has an input of name label
132 virtual bool bbHasInput(const std::string& label) const;
133 /// Returns true iff the BlackBox has an output of name label
134 virtual bool bbHasOutput(const std::string& label) const;
136 /// Gets the input type of a given label
137 virtual TypeInfo bbGetInputType( const std::string &label ) const;
138 /// Gets the output type of a given label
139 virtual TypeInfo bbGetOutputType( const std::string &label ) const;
141 /// Gets the data of the input called <name>
142 virtual Data bbGetInput( const std::string &name ) = 0;
143 /// Gets the data of the output called <name>
144 virtual Data bbGetOutput( const std::string &name ) = 0;
146 /// Sets the data of the input called <name>.
147 /// If update_time is false then does not update ChangeTime of input
148 virtual void bbSetInput( const std::string &name, Data data,
149 bool update_time = true ) = 0;
150 virtual void bbBruteForceSetInputPointer( const std::string &name,
152 bool update_time = true) =0;
153 /// Sets the data of the output called <name>
154 virtual void bbSetOutput( const std::string &name, Data data) = 0;
157 /// Gets the status of the input called <name>
158 IOStatus bbGetInputStatus( const std::string &name ) const
159 { return mInputConnectorMap.find(name)->second->GetStatus(); }
161 /// Returns the input connectors map
162 InputConnectorMapType& bbGetInputConnectorMap()
163 { return mInputConnectorMap; }
164 /// Returns the output connectors map
165 OutputConnectorMapType& bbGetOutputConnectorMap()
166 { return mOutputConnectorMap; }
167 /// Returns the input connectors map (const)
168 const InputConnectorMapType& bbGetInputConnectorMap() const
169 { return mInputConnectorMap; }
170 /// Returns the output connectors map (const)
171 const OutputConnectorMapType& bbGetOutputConnectorMap() const
172 { return mOutputConnectorMap; }
174 /// Returns the input connector
175 BlackBoxInputConnector& bbGetInputConnector(const std::string& n)
176 { return *(mInputConnectorMap.find(n)->second); }
177 /// Returns the output connector
178 BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n)
179 { return *(mOutputConnectorMap.find(n)->second); }
180 /// Returns the input connector (const)
181 const BlackBoxInputConnector& bbGetInputConnector(const std::string& n) const
182 { return *(mInputConnectorMap.find(n)->second); }
183 /// Returns the output connector (const)
184 const BlackBoxOutputConnector& bbGetOutputConnector(const std::string& n) const
185 { return *(mOutputConnectorMap.find(n)->second); }
190 /// Prints the Help on the BlackBox type
191 virtual void bbGetHelp(bool full=true) const;
193 //==================================================================
194 /// Adds the function f to the list of functions to call when
195 /// the output changes.
196 /// f is of type ChangeCallbackType which is basically:
197 /// void (*ChangeCallbackType)(bbtk::BlackBox::Pointer,
198 /// const std::string&,
200 /// To pass a member function 'f' of an instance 'c' of a class 'C'
201 /// as callback you have to 'bind' it, i.e. call:
202 /// bbAddOutputObserver ( "Out", boost::bind( &C::f , c, _1, _2, _3 ) );
203 /// The convenience macro BBTK_BIND_OUTPUT_OBSERVER ( c, C::f ) does it for you
204 void bbAddOutputObserver(const std::string& output_name,
205 OutputChangeCallbackType f);
207 /// Removes the function f from the list of functions to call when
208 /// the output changes (TO WRITE)
209 void bbRemoveOutputObserver(const std::string& output_name,
210 OutputChangeCallbackType f);
211 //==================================================================
214 //==================================================================
215 /// Signals that the BlackBox outputs have been modified
216 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
217 /// This method should be used by widgets in response
218 /// to user interaction when **ALL** outputs have been modified
219 /// (after the outputs has been updated !).
220 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
221 /// ** USER INTENDED **
222 virtual void bbSignalOutputModification(bool reaction = true);
223 /// Signals that the BlackBox output "output_name" has been modified
224 /// (without marking the box as MODIFIED because its output state is ok : don't care if you understand : use it !).
225 /// This method should be used by widgets in response to user interaction
226 /// only when **ONE** output has been modified
227 /// (after the output has been updated !)
228 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
229 /// ** USER INTENDED **
230 virtual void bbSignalOutputModification( const std::string& output_name,
231 bool reaction = true);
232 /// Signals that the BlackBox vector of outputs "output_name"
233 /// have been modified.
234 /// Should be used when more than ONE output is modified but not ALL
235 /// (optimization issue).
236 /// (without marking the box as MODIFIED because its output state is ok).
237 /// This method should be used by widgets in response to user interaction
238 /// When more than one output has been changed but not all
239 /// (after the outputs have been updated of course!)
240 /// DO NOT PASS reaction = false OR WILL NOT WORK PROPERLY
241 /// ** USER INTENDED **
242 virtual void bbSignalOutputModification( const std::vector<std::string>&
244 bool reaction = true);
245 //==================================================================
249 //==================================================================
250 /// User can redefine this method to set
251 /// the default values of the box inputs and outputs
252 /// (it is called in the box constructor)
253 virtual void bbUserSetDefaultValues() {}
255 /// User can redefine this method to initialize what must be
256 /// initialized for the box to work, for example allocate dynamic data.
257 /// It is called once and only once before any call to bbUserCreateWidget
258 /// or bbUserProcess.
259 /// What has been allocated here must be desalocated in
260 /// bbFinalizeProcessing
261 virtual void bbUserInitializeProcessing() {}
263 /// User must redefine this method to uninitialize what has been
264 /// initialized in bbUserInitializeProcessing,
265 /// typically desallocate memory that has been allocated dynamically.
266 /// It is called in the box destructor if and only if (iff)
267 /// bbUserInitializeProcessing has been called previously.
268 virtual void bbUserFinalizeProcessing() {}
271 /// Initializes processing IF NEEDED.
272 /// Calls bbRecursiveInitializeProcessing if the box is in
273 /// "uninitialized" state and put it in "initialized" state.
274 /// On construction, boxes are "uninitialized".
275 /// See also bbFinalizeProcessing
276 void bbInitializeProcessing();
278 /// Finalizes processing IF NEEDED.
279 /// Calls bbRecursiveFinalizeProcessing if the box is in
280 /// "initialized" state and put it in "uninitialized" state.
281 /// On construction, boxes are "uninitialized".
282 /// See also bbInitializeProcessing
283 void bbFinalizeProcessing();
285 /// Abstract prototype of the method which
286 /// Recursively calls itself for the parent black box and then
287 /// calls bbUserInitializeProcessing for its own class.
288 /// It is redefined in each black box descendant.
289 /// Allows to call bbUserInitializeProcessing for all inherited classes
290 /// (like a constructor does)
291 virtual void bbRecursiveInitializeProcessing() {}
294 /// Abstract prototype of the method which
295 /// calls bbUserFinalizeProcessing for its own class and then
296 /// recursively calls itself for the parent black box.
297 /// It is redefined in each black box descendant.
298 /// Allows to call bbUserFinalizeProcessing for all inherited classes
299 /// (like a destructor does)
300 virtual void bbRecursiveFinalizeProcessing() {}
302 //==================================================================
305 //==================================================================
306 // Common inputs / outputs to all boxes
307 /// Returns the value of the input "BoxProcessMode"
308 std::string bbGetInputBoxProcessMode() { return bbmBoxProcessMode; }
309 /// Sets the value of the input "BoxProcessMode"
310 void bbSetInputBoxProcessMode(std::string a) { bbmBoxProcessMode = a; }
318 /// Returns the "decoded" value of the input "BoxProcessMode"
319 BoxProcessModeValue bbGetBoxProcessModeValue() const;
321 virtual bool bbBoxProcessModeIsReactive() const;
323 virtual bool bbBoxProcessModeIsAlways() const;
325 /// Returns the value of the input "Execute"
326 Void bbGetInputBoxExecute() { return Void(); }
327 /// Sets the value of the input "Execute"
328 void bbSetInputBoxExecute(Void = 0) {}
330 /// Returns the value of the output "Change"
331 Void bbGetOutputBoxChange() { return Void(); }
332 /// Sets the value of the output "Change" : signal a modification
333 void bbSetOutputBoxChange(Void = 0) { } //bbSetModifiedStatus(); }
335 //==================================================================
338 //==================================================================
340 /// Does nothing here : overloaded in ComplexBlackBox
341 void bbInsertHTMLGraph( std::ofstream& s,
345 const std::string& output_dir,
349 /// Write Graphviz-dot description in file.
350 /// Here dumps a single box description (i/o) but overloaded
351 /// in ComplexBlackBox to dump the internal pipeline representation
352 /// recursing into internal boxes descriptions if level>0.
353 /// detail = 1 : draw inputs and outputs (do not draw otherwise)
354 /// instanceOrtype = true : draw inputs and outputs VALUES
355 /// (uses bbGetInputAsString / bbGetOutputAsString which use adaptors)
356 /// If relative_link is true then creates relative hrefs
357 virtual void bbWriteDotFileBlackBox(FILE *ff,
358 BlackBox::Pointer parentblackbox,
359 int detail, int level,
361 bool relative_link );
362 /// Auxiliary method for bbWriteDotFileBlackBox
363 virtual void bbWriteDotInputOutputName(FILE *ff,
365 int detail, int level);
368 virtual void bbShowRelations(BlackBox::Pointer parentblackbox,
369 int detail, int level
372 std::string bbGetOutputAsString( const std::string &output ); //,Factory *factory);
373 std::string bbGetInputAsString( const std::string &input); //,Factory *factory);
374 virtual BlackBox::Pointer bbFindBlackBox(const std::string &blackboxname)
375 { return BlackBox::Pointer();}
377 virtual void Check(bool recursive = true);
379 virtual void bbSetShown(bool) {}
380 virtual bool bbIsShown() { return false; }
381 virtual void bbUserOnShow() {}
384 //==================================================================
385 // PROTECTED PART : ACCESSIBLE TO THE BlackBox DEVELOPER
386 // (IN INHERITED CLASSES)
387 /// Constructor that take the BlackBox's name
388 BlackBox(const std::string &name);
389 /// Constructor from an existing box (copy) with a new name
390 BlackBox(BlackBox& from, const std::string &name);
391 //==================================================================
394 //==================================================================
395 /// Signals that the input whose connector is c has changed
396 /// and propagates the info downward
397 /// ** NOT USER INTENDED **
398 virtual void bbSetStatusAndPropagate(BlackBoxInputConnector* c,
400 //==================================================================
403 //==================================================================
404 friend class Connection;
405 friend class ComplexBlackBox;
407 /// Sets the parent of the BlackBox
408 void bbSetParent(BlackBox::Pointer p) { bbmParent = p; }
411 /// Connects the input <name> to the connection c
412 virtual void bbConnectInput( const std::string& name,
414 /// Connects the output <name> to the connection c
415 virtual void bbConnectOutput( const std::string& name,
417 /// Disconnects the input <name> from the connection c
418 virtual void bbDisconnectInput( const std::string& name,
420 /// Disconnects the output <name> from the connection c
421 virtual void bbDisconnectOutput( const std::string& name,
424 //==================================================================
426 /// @name Pipeline processing methods
427 /// Methods which participate to pipeline processing.
431 //==================================================================
432 /// Recursive execution method
434 /// \param caller : The connection which invoked the method; null if called by bbExecute
435 virtual void bbRecursiveExecute(Connection::Pointer caller);
436 //==================================================================
438 //==================================================================
439 /// Updates the BlackBox inputs
440 /// Calls RecursiveExecute on all BlackBoxInputConnector
441 /// \returns The maximum of final IOStatus after each input update
442 IOStatus bbUpdateInputs();
443 //==================================================================
446 //==================================================================
447 /// Actual CreateWindow method (vitual)
448 /// Overloaded in AtomicBlacBox and descendants
449 virtual void bbCreateWindow()
451 // bbtkError("BlackBox::bbCreateWidget called : how can this happen ?");
453 //==================================================================
455 //==================================================================
456 /// Actual ShowWindow method (vitual)
457 /// Overloaded in AtomicBlacBox and descendants
458 virtual void bbShowWindow()
460 // bbtkError("BlackBox::bbShowWidget called : how can this happen ?");
462 //==================================================================
465 //==================================================================
466 /// Actual processing method (vitual)
467 /// Overloaded in AtomicBlacBox and descendants
468 virtual void bbProcess()
470 bbtkError("BlackBox::bbProcess called : how can this happen ?");
471 // this->bbUserProcess();
473 //==================================================================
475 //==================================================================
476 /// Computes the final IOStatus of inputs and outputs after processing
477 void bbComputePostProcessStatus();
478 //==================================================================
483 static bool bbGlobalGetSomeBoxExecuting();
484 static void bbGlobalSetSomeBoxExecuting(bool b);
486 static void bbGlobalSetFreezeExecution(bool b);
487 static bool bbGlobalGetFreezeExecution();
489 /// Returns true if the box can "react",
490 /// which means execute in response to an input change
491 virtual bool bbCanReact() const;
493 /// Returns true iff the box is executing
494 bool bbGetExecuting() const { return bbmExecuting; }
497 static void bbGlobalAddToExecutionList( BlackBox::Pointer b );
498 static void bbGlobalProcessExecutionList();
499 /// Sets the bbmExecuting bool returned by bbGetExecuting
500 void bbSetExecuting(bool b) { bbmExecuting = b; }
502 //==================================================================
504 //==================================================================
505 /// Allocates the i/o connectors of the black box
506 virtual void bbAllocateConnectors();
507 /// Desallocates the i/o connectors of the black box
508 virtual void bbDesallocateConnectors();
509 /// Copies the values of the inputs/output from the BlackBox from
510 virtual void bbCopyIOValues(BlackBox& from);
511 //==================================================================
513 //==================================================================
514 // Black box objects have a special deleter
515 // which must take care of releasing the descriptor
516 // **AFTER** the box is deleted
517 // (Releasing it in the destructor may cause dl close and crash)
518 /// Black box deleter
519 /// 1) Calls the user overloadable bbDelete method
520 /// 2) Releases the box descriptor
521 struct BBTK_EXPORT Deleter : public Object::Deleter
524 int Delete(Object* p);
526 //==================================================================
528 //==================================================================
530 static boost::shared_ptr<U> MakeBlackBoxPointer(U* s, bool lock = false)
532 return MakePointer(s,BlackBox::Deleter(),lock);
534 //==================================================================
536 //==================================================================
537 virtual int bbDelete() { delete this; return 0; }
538 //==================================================================
541 //==================================================================
543 //==================================================================
545 //==================================================================
547 /// Is the box initialized ?
549 /// Is the box executing ?
551 /// The name of the black-box
553 /// The name of the package to which it belongs
554 std::string bbmPackageName;
555 /// The box processing mode
556 /// 0 : "Pipeline" mode
557 /// 1 : "Always" mode
558 /// 2 : "Reactive" mode
559 std::string bbmBoxProcessMode;
560 /// The parent of the black box in the ComplexBlackBox hierarchy
561 BlackBox::WeakPointer bbmParent;
562 //==================================================================
565 //==================================================================
567 /// Map that contains the output connectors of the black box
568 OutputConnectorMapType mOutputConnectorMap;
569 /// Map that contains the input connectors of the black box
570 InputConnectorMapType mInputConnectorMap;
571 //==================================================================
579 /// Convenient macro to create output observer callbacks (freehand functions) from object and method pointer (see samples/SampleOutputObserver)
580 #define BBTK_MAKE_OUTPUT_OBSERVER(OBJECT,METHOD) \
581 boost::bind( METHOD, OBJECT, _1, _2, _3)