1 /* 2 * Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>. 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5 #ifndef PROCESS_COORDINATOR_H 6 #define PROCESS_COORDINATOR_H 7 8 #include "ProcessCoordinator.h" 9 10 #include <ObjectList.h> 11 12 #include "AbstractProcess.h" 13 #include "AbstractProcessNode.h" 14 15 16 class ProcessCoordinator; 17 18 19 /*! This class carries the state of the current process coordinator so that 20 it can be dealt with atomically without having call back to the coordinator. 21 */ 22 23 class ProcessCoordinatorState { 24 public: 25 ProcessCoordinatorState( 26 const ProcessCoordinator* 27 processCoordinator, 28 float progress, const BString& message, 29 bool isRunning, status_t errorStatus); 30 virtual ~ProcessCoordinatorState(); 31 32 const ProcessCoordinator* Coordinator() const; 33 float Progress() const; 34 BString Message() const; 35 bool IsRunning() const; 36 status_t ErrorStatus() const; 37 38 private: 39 const ProcessCoordinator* fProcessCoordinator; 40 float fProgress; 41 BString fMessage; 42 bool fIsRunning; 43 status_t fErrorStatus; 44 }; 45 46 47 /*! Clients are able to subclass from this 'interface' in order to accept 48 call-backs when a coordinator has exited; either through failure, 49 stopping or completion. 50 */ 51 52 class ProcessCoordinatorListener { 53 public: 54 55 /*! Signals to the listener that the coordinator has changed in some way - 56 for example, a process has started or stopped or even that the whole 57 coordinator has finished. 58 */ 59 60 virtual void CoordinatorChanged( 61 ProcessCoordinatorState& 62 processCoordinatorState) = 0; 63 64 }; 65 66 67 /*! Classes implementing this 'interface' are able to consume process 68 coordinators. This may be in order to run them. 69 */ 70 71 class ProcessCoordinatorConsumer { 72 public: 73 virtual void Consume(ProcessCoordinator *item) = 0; 74 }; 75 76 77 /*! It is possible to create a number of ProcessNodes (themselves associated 78 with AbstractProcess-s) that may have dependencies (predecessors and 79 successors) and then an instance of this class is able to coordinate the 80 list of ProcessNode-s so that they are all completed in the correct order. 81 */ 82 83 class ProcessCoordinator : public AbstractProcessListener { 84 public: 85 ProcessCoordinator( 86 const char* name, 87 BMessage* message = NULL); 88 virtual ~ProcessCoordinator(); 89 90 void SetListener( 91 ProcessCoordinatorListener *listener); 92 93 void AddNode(AbstractProcessNode* nodes); 94 95 void ProcessChanged(); 96 // AbstractProcessListener 97 98 bool IsRunning(); 99 100 void Start(); 101 void RequestStop(); 102 103 status_t ErrorStatus(); 104 105 float Progress(); 106 107 const BString& Name() const; 108 BMessage* Message() const; 109 110 private: 111 bool _IsRunning(AbstractProcessNode* node); 112 void _CoordinateAndCallListener(); 113 ProcessCoordinatorState 114 _Coordinate(); 115 ProcessCoordinatorState 116 _CreateStatus(); 117 BString _CreateStatusMessage(); 118 int32 _CountNodesCompleted(); 119 void _StopSuccessorNodesToErroredOrStoppedNodes(); 120 void _StopSuccessorNodes(AbstractProcessNode* node); 121 122 private: 123 BString fName; 124 BLocker fLock; 125 BObjectList<AbstractProcessNode> 126 fNodes; 127 ProcessCoordinatorListener* 128 fListener; 129 BMessage* fMessage; 130 bool fWasStopped; 131 }; 132 133 134 #endif // PROCESS_COORDINATOR_H 135