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