iTasks.dcl 13.7 KB
Newer Older
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
1 2
definition module iTasks

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
3 4
// iTasks library for defining interactive multi-user workflow tasks (iTask) for the web.
// Defined on top of the iData library.
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
5

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
6
// (c) iTask & iData Concept and Implementation by Rinus Plasmeijer, 2006,2007,2008 - MJP
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
7 8
// This library is still under construction - MJP

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
9
iTaskVersion :== "0.99 - April 2008 - "
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
10

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
11
import iDataSettings, iDataButtons, StdBimap
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
12 13 14 15 16 17 18
derive gForm 	Void, Wid, TCl						
derive gUpd 	Void, Wid,  TCl
derive gPrint 	Void, Wid,  TCl
derive gParse 	Void, Wid,  TCl
derive gerda 	Void, Wid 
derive read 	Void, Wid, TCl
derive write 	Void, Wid, TCl
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
19

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
20 21
// iTask types

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
22
:: Task a			:== *TSt -> *(!a,!*TSt)			// an iTask is state stransition 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
23
:: LabeledTask a	:== !(!TaskLabel,!Task a)		// a Task with a label used for labeling buttons, pull down menu, and the like
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
24 25 26
:: TCl a 			= 	TCl !.(Task a)				// task closure, container for a task used for higher order tasks (task which deliver a task)			

:: *TSt												// TSt is abstract task state
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
27
:: TaskLabel		:== !String						// label name
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
28 29 30 31 32 33 34 35 36 37 38
:: UserId			:== !Int						// a user id of an iTask user must be a unique integer value

// iTask workflow processes types

:: Wid a											// reference to a workflow process
:: WorkflowStatus	= WflActive						// iTask workflow process is still being processed
					| WflSuspended					// it is (temporally) suspended
					| WflFinished					// it is finshed
					| WflDeleted					// it does not exist anymore because it is deleted

// general types
39

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
40
:: HtmlCode			:== ![BodyTag]					// most programmers will only write bodytags
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
41

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
42
:: Void 			= Void							// for tasks returning non interesting results, won't show up in editors either
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
43 44


Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
45
// *********************************************************************************************************************************
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
46
// Setting global options for any collection of iTask workflows:
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
47

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
48 49
class (<<@) infixl 3 b :: !(Task a) !b 	-> Task a 	 
class (@>>) infixl 7 b ::  !b !(Task a) -> Task a | iData a	
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
50

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
51 52 53 54
instance <<@		  Lifespan						// default: Session
					, StorageFormat					// default: PlainString
					, Mode							// default: Edit
					, GarbageCollect				// default: Collect
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
55

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
56 57 58
instance @>>		  SubPage						// default: the *whole* page will be updated when a form has been modified

// Lifespan, StorageFormat, Mode are already defined in iTask library
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
59

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
60 61
:: GarbageCollect 	= Collect 						// garbage collect iTask administration
					| NoCollect						// no garbage collection
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
62

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
63 64
:: SubPage			= UseAjax  						// use Ajax technology to update part of a page, only works if Ajax enabled 
					| OnClient 						// use SAPL to update part of a page on the client, only works if Client enabled and Sapl is running...
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
65

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
66 67
// *********************************************************************************************************************************
/* Initiate the iTask library with an iData server wrapper such as doHtmlServer in combination with one of the following functions:
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
68 69
					
singleUserTask 	:: iTask start function for defining tasks for one, single user
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
70
multiUserTask 	:: iTask start function for multi-users, with option in window to switch between [0..users - 1]  
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
71 72 73 74 75 76 77
workFlowTask	:: iTask start function for a real workflow
					- the first arument has to be an itask which is used for login purposes; it should yield
						Bool: 	True, is the user a new one: if so the second argument is spawned as a separate task for that user
						UserId:	the id of that user 
					- the second argument is workflow that will spawned as a task 
						(True if we have new user,user id of the user, has ) : 
					- the second one is the actual function for that user  
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
78
				   a predefined login task is defined in iTaskLogin.dcl				
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
79
*/
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
80 81
singleUserTask 	:: ![StartUpOptions] !(Task a) 				!*HSt -> (!Bool,Html,*HSt) 	| iData a
multiUserTask 	:: ![StartUpOptions] !(Task a)  			!*HSt -> (!Bool,Html,*HSt) 	| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
82 83
workFlowTask 	:: ![StartUpOptions] !(Task ((Bool,UserId),a)) 
							!(UserId a -> LabeledTask b) 	!*HSt -> (!Bool,Html,*HSt) | iData b 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
84

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
85 86 87
:: StartUpOptions	= TraceOn | TraceOff				// for single & multiUser: default = TraceOn
					| ThreadStorage Lifespan			// for Ajax: where to store threadinformation: default = TxtFile
					| ShowUsers Int						// for multiUserTask, toggle between given maximum number of users, default: ShowUser 5 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
88
					| VersionCheck | NoVersionCheck		// for single & multiUser: default = VersionNoCheck 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
89
					| TestModeOn | TestModeOff			// emties storages when starting from scratch: On for single and multi-user tasks
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
90
					| MyHeader HtmlCode					// wil replace standard iTask information line
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
91

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
92 93 94
// *********************************************************************************************************************************
/* iTask Workflow process management:

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
95
spawnWorkflow 		:: spawn an iTask workflow as a new separate process, Wid is a handle to that process, bool indicates whether it is active or suspended 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
96 97 98 99 100 101
waitForWorkflow		:: wait until the indicated process is finished and obtain the resulting value
deleteWorkflow 		:: delete iTask workflow
suspendWorkflow 	:: suspend iTask workflow, nobody can add results anymore
activateWorkflow 	:: activate the iTask workflow again
*/

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
102
spawnWorkflow 		:: !UserId !Bool !(LabeledTask a) 					-> Task (Wid a) 	| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
103
getWorkflowStatus 	:: !(Wid a) 										-> Task WorkflowStatus
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
104
waitForWorkflow 	:: !(Wid a) 										-> Task a 			| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
105
activateWorkflow 	:: !(Wid a) 										-> Task Bool 	
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
106 107
suspendWorkflow 	:: !(Wid a) 										-> Task Bool 		
deleteWorkflow 		:: !(Wid a) 										-> Task Bool 		
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
108

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
109
// *********************************************************************************************************************************
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
110
/* Here follow the iTasks combinators:
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
111

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
112
Basic editors:
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
113
editTask		:: create a task editor to edit a value of given type, and add a button with given name to finish the task
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
114
editTask		:: create a task editor (with submit button) to edit a value of given type, finish only if predicate holds 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
115

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
116
Standard monadic combinators on iTasks:
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
117 118 119
(=>>)			:: for sequencing: bind
return_V		:: lift a value to the iTask domain and return it

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
120
Prompting variants:
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
121 122
(?>>)			:: prompt as long as task is active but not finished
(!>>)			:: prompt when task is activated
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
123 124
(<<?)			:: as ?>>, except that prompt is displayed *after* task
(<<!)			:: as !>>, except that prompt is displayed *after* task
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

Assign tasks to user with indicated id:
assignTaskTo 	:: assign task to indicated user, True for verbose reporting

Repetition and loops:
foreverTask		:: infinitely repeating Task
(<!)			:: repeat task (as a loop)   as long as predicate does not hold; also works for tasks that don't require any user interactions (e.g. database access)

Sequencing Tasks:
seqTasks		:: do all iTasks one after another, task completed when all done

Choose the tasks you want to do one forehand:
chooseTask_btn	:: choose ONE task by pressing a button, True for horizontal buttons, else vertical
chooseTask_pdm	:: as chooseTask_btn, depending on pulldownmenu item selected, Int for initial value
chooseTask_radio:: as chooseTask_btn, depending on radio item selected, Int for initial value, htmlcode for option explanation 

chooseTask_cb	:: choice N tasks out of N, order of chosen task depending on first arg
				   (initial setting, effect for all when set, explanation) for each option

Do m Tasks parallel / interleaved and FINISH as soon as SOME Task completes:
orTask2			:: do both iTasks in any order, combined task completed as any subtask is done
andTask2		:: do both iTasks in any order (interleaved), task completed when both done
andTasksCond	:: do tasks in any order until pred holds for finished tasks, string used for naming group of task navigation buttons
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
148 149
*/

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
150 151 152 153 154 155
editTask 		:: !String 	!a 								-> Task a		| iData a 
editTaskPred 	:: 			!a !(a -> (Bool, HtmlCode))		-> Task a		| iData a 

(=>>) infixl 1 	:: !(Task a) !(a -> Task b) 				-> Task b		| iCreateAndPrint b
return_V 		:: !a 										-> Task a 		| iCreateAndPrint a

156 157 158 159
(?>>) infixr 5 	:: !HtmlCode !(Task a) 						-> Task a		| iCreate a
(!>>) infixr 5 	:: !HtmlCode !(Task a) 						-> Task a		| iCreate a
(<<?) infixl 5 	:: !(Task a) !HtmlCode 						-> Task a		| iCreate a
(<<!) infixl 5 	:: !(Task a) !HtmlCode 						-> Task a		| iCreate a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
160

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
161
assignTaskTo 	:: !Bool !UserId !(LabeledTask a) 			-> Task a		| iData a	
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
162

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
163
foreverTask		:: !(Task a) 								-> Task a 		| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
164
(<!)  infixl 6 	:: !(Task a)  !(a -> .Bool) 				-> Task a 		| iCreateAndPrint a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
165

166 167
seqTasks		:: ![LabeledTask a] 						-> Task [a]		| iCreateAndPrint a

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
168
chooseTask_btn 	:: !HtmlCode !Bool![LabeledTask a] 			-> Task a	 	| iCreateAndPrint a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
169 170 171
chooseTask_pdm 	:: !HtmlCode !Int ![LabeledTask a] 			-> Task a	 	| iCreateAndPrint a
chooseTask_radio:: !HtmlCode !Int ![(HtmlCode,LabeledTask a)]
															-> Task a		| iCreateAndPrint a
172

Peter Achten's avatar
Peter Achten committed
173
:: ChoiceUpdate	:== !Bool [Bool] -> [Bool]									// changed checkbox + current settings -> new settings
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
174

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
175
chooseTask_cbox	:: !([LabeledTask a] -> Task [a])
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
176 177 178
				   !HtmlCode ![((!Bool,!ChoiceUpdate,!HtmlCode),LabeledTask a)] 
															-> Task [a] 	| iData a

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
179 180
orTask2			:: !(Task a,Task b) 						-> Task (EITHER a b) 	
																			| iCreateAndPrint a & iCreateAndPrint b
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
181 182
andTask2		:: !(Task a,Task b) 						-> Task (a,b) 	| iCreateAndPrint a & iCreateAndPrint b
andTasksCond	:: !String !([a] -> Bool) ![LabeledTask a] -> (Task [a]) 	| iData a 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
183

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
184 185 186 187 188 189 190
/* Time and Date management:
waitForTimeTask	:: Task is done when time has come
waitForDateTask	:: Task is done when date has come
*/
waitForTimeTask	:: !HtmlTime								-> Task HtmlTime
waitForDateTask	:: !HtmlDate								-> Task HtmlDate

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
191
/* Experimental department:
192

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
193 194
   May not work when the tasks are garbage collected !!

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
195 196 197 198 199 200 201 202 203 204 205 206
-!>				:: a task, either finished or interrupted (by completion of the first task) is returned in the closure
				   if interrupted, the work done so far is returned (!) which can be continued somewhere else
channel			:: splits a task in respectively a sender task closure and receiver taskclosure; 
				   when the sender is evaluated, the original task is evaluated as usual;
				   when the receiver task is evaluated, it will wait upon completeion of the sender and then get's its result;
				   Important: Notice that a receiver will never finish if you don't activate the corresponding receiver somewhere.
closureTask		:: The task is executed as usual, but a receiver closure is returned immediately.
				   When the closure is evaluated somewhere, one has to wait until the task is finished.
				   Handy for passing a result to several interested parties.
closureLZTask	:: Same, but now the original task will not be done unless someone is asking for the result somewhere.
*/

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
207 208 209 210
(-!>) infix 4 	:: (Task stop) (Task a) 					-> Task (Maybe stop,TCl a) 	| iCreateAndPrint stop & iCreateAndPrint a
channel  		:: String (Task a) 							-> Task (TCl a,TCl a) 		| iCreateAndPrint a
closureTask  	:: String (Task a) 							-> Task (TCl a) 			| iCreateAndPrint a
closureLzTask  	:: String (Task a) 							-> Task (TCl a) 			| iCreateAndPrint a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
211

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
212
/* Exception Handling:
213

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
214
<^>				:: Evaluate the task; An exception of type e raised by this task, will be catched by the closest handler.
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
215
				   One can use the function create a proper task value or signal the fact that an exception has occured.  
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
216
Raise 			:: Raises an exception of type e which will be catched by the closest parent handler for this type
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
217
*/
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
218 219
(<^>) infix  1  :: !(e -> a) !(Task a) 						-> Task a 					| iData a   & TC e			// assigns an exception Handler
Raise 			:: e 										-> Task a 					| iCreate a & TC e			// rases an exception
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
220

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
221 222 223 224 225

// *********************************************************************************************************************************
/* Support for user defined combinators
mkTask			:: for making a user defined combinator, name will appear intrace 
newTask			:: same, but optimized: after completion only result will remembered
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
226
Once			:: task will be done only once, the value of the task will be remembered, important for side effecting functions lifted to iData domain
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
227 228 229
*/
mkTask 			:: !String !(Task a) 						-> Task a 		| iCreateAndPrint a
newTask 		:: !String !(Task a) 						-> Task a		| iData a 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
230
Once 			:: !String !(Task a) 						-> Task a 		| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
231 232 233

// *********************************************************************************************************************************
/* Lifting of other domains to the iTask domain
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
234 235 236
(*>>)			:: lift functions of type (TSt -> (a,TSt)) to iTask domain 
(@>>)			:: lift functions of (TSt -> TSt) to iTask domain 
appIData		:: lift iData editors to iTask domain
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
237
appIData2		:: lift iData editors to iTask domain, and pass iDataTasknumber for naming convenience
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
238 239
appHStOnce		:: lift HSt domain to TSt domain, will be executed only once; string used for tracing
appHSt			:: lift HSt domain to TSt domain, will be executed on each invocation; string used for tracing
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
240
*/
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
241 242 243 244 245 246
(*=>) infix 4 	:: (TSt -> (a,TSt)) (a -> Task b) 			-> Task b
(*#>) infix 4 	:: (TSt -> TSt)     (Task a) 				-> Task a
appIData 		:: (IDataFun a) 							-> Task a 		| iData a
appIData2 		:: (String *HSt -> *(Form a,*HSt)) 			-> Task a		| iData a 
appHStOnce 		:: !String (HSt -> (a,HSt)) 				-> Task a		| iData a
appHSt			:: !String (HSt -> (a,HSt)) 				-> Task a		| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
247 248
appWorldOnce 	:: !String (*World -> *(a,*World)) 			-> Task a		| iData a
appWorld 		:: !String (*World -> *(a,*World)) 			-> Task a		| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
249

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
250
// *********************************************************************************************************************************
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
251
/* Operations on Task state
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
252 253
taskId			:: give id of user assigned to task
userId			:: give id of application user
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
254 255 256 257
addHtml			:: add html code
*/
taskId			:: TSt 				-> (Int,TSt)
userId 			:: TSt 				-> (Int,TSt)
258
addHtml 		:: HtmlCode TSt 	-> TSt
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
259

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
260 261 262 263 264 265 266
// *********************************************************************************************************************************