iTasks.dcl 13.8 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
:: UserId			:== !Int						// a user id of an iTask user must be a unique integer value

// iTask workflow processes types

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
32
:: Wid a											// reference to a workflow process
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
33 34 35 36 37
:: 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

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
38 39
instance ==			WorkflowStatus

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
40
// general types
41

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

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


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

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
50 51
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
52

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

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
58 59 60
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
61

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

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
65 66
:: 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
67

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
68 69
// *********************************************************************************************************************************
/* 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
70 71
					
singleUserTask 	:: iTask start function for defining tasks for one, single user
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
72
multiUserTask 	:: iTask start function for multi-users, with option in window to switch between [0..users - 1]  
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
73 74 75 76 77 78 79
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
80
				   a predefined login task is defined in iTaskLogin.dcl				
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
81
*/
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
82 83
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
84 85
workFlowTask 	:: ![StartUpOptions] !(Task ((Bool,UserId),a)) 
							!(UserId a -> LabeledTask b) 	!*HSt -> (!Bool,Html,*HSt) | iData b 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
86

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
87 88 89
:: 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
90
					| VersionCheck | NoVersionCheck		// for single & multiUser: default = VersionNoCheck 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
91
					| TestModeOn | TestModeOff			// emties storages when starting from scratch: On for single and multi-user tasks
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
92
					| MyHeader HtmlCode					// wil replace standard iTask information line
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
93

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
94 95 96
// *********************************************************************************************************************************
/* iTask Workflow process management:

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
97
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
98
waitForWorkflow		:: wait until the indicated process is finished and obtain the resulting value; returns Nothing when process is deleted
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
99 100
getWorkflowStatus 	:: get status of workflow
deleteWorkflow 		:: delete iTask workflow; returns False if workflow does not exist anymore
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
101
suspendWorkflow 	:: suspend iTask workflow, all corresponding tasks will vanish temporally; returns False if workflow does not exist anymore
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
102 103 104 105 106
activateWorkflow 	:: activate the iTask workflow again; returns False if workflow does not exist anymore

suspendMe 			:: suspend current workflow process; no effect on start task
deleteMe 			:: delete current workflow process;  no effect on start task

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
107
changeWorkflowUser :: transfer the workflow task to the indicated user; returns False if workflow does not exist anymore
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
108 109
*/

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
110
spawnWorkflow 		:: !UserId !Bool !(LabeledTask a) 					-> Task (Wid a) 	| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
111
waitForWorkflow 	:: !(Wid a) 										-> Task (Maybe a )	| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
112
getWorkflowStatus 	:: !(Wid a) 										-> Task WorkflowStatus
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
113
activateWorkflow 	:: !(Wid a) 										-> Task Bool 	
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
114 115
suspendWorkflow 	:: !(Wid a) 										-> Task Bool 		
deleteWorkflow 		:: !(Wid a) 										-> Task Bool 		
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
116
changeWorkflowUser	:: !UserId !(Wid a) 								-> Task Bool 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
117

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
118 119 120
suspendMe 			:: (Task Void)
deleteMe 			:: (Task Void)

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
121

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
122
// *********************************************************************************************************************************
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
123
/* Here follow the iTasks combinators:
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
124

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
125
Basic editors:
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
126
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
127
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
128

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
129
Standard monadic combinators on iTasks:
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
130 131 132
(=>>)			:: for sequencing: bind
return_V		:: lift a value to the iTask domain and return it

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
133
Prompting variants:
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
134 135
(?>>)			:: prompt as long as task is active but not finished
(!>>)			:: prompt when task is activated
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
136 137
(<<?)			:: as ?>>, except that prompt is displayed *after* task
(<<!)			:: as !>>, except that prompt is displayed *after* task
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

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
161 162
*/

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
163 164 165 166 167 168
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

169 170 171 172
(?>>) 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
173

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

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
176
foreverTask		:: !(Task a) 								-> Task a 		| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
177
(<!)  infixl 6 	:: !(Task a)  !(a -> .Bool) 				-> Task a 		| iCreateAndPrint a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
178

179 180
seqTasks		:: ![LabeledTask a] 						-> Task [a]		| iCreateAndPrint a

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
181
chooseTask_btn 	:: !HtmlCode !Bool![LabeledTask a] 			-> Task a	 	| iCreateAndPrint a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
182 183 184
chooseTask_pdm 	:: !HtmlCode !Int ![LabeledTask a] 			-> Task a	 	| iCreateAndPrint a
chooseTask_radio:: !HtmlCode !Int ![(HtmlCode,LabeledTask a)]
															-> Task a		| iCreateAndPrint a
185

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

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
188
chooseTask_cbox	:: !([LabeledTask a] -> Task [a])
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
189 190 191
				   !HtmlCode ![((!Bool,!ChoiceUpdate,!HtmlCode),LabeledTask a)] 
															-> Task [a] 	| iData a

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
192 193
orTask2			:: !(Task a,Task b) 						-> Task (EITHER a b) 	
																			| iCreateAndPrint a & iCreateAndPrint b
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
194 195
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
196

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
197 198 199 200 201 202 203
/* 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
204
/* Experimental department:
205

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

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
208 209 210 211 212 213 214 215
-!>				:: 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.
*/

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
216 217
(-!>) 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
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
218

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
219
/* Exception Handling:
220

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
221
<^>				:: 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
222
				   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
223
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
224
*/
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
225 226
(<^>) 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
227

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
228 229 230 231 232

// *********************************************************************************************************************************
/* 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
233
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
234 235 236
*/
mkTask 			:: !String !(Task a) 						-> Task a 		| iCreateAndPrint a
newTask 		:: !String !(Task a) 						-> Task a		| iData a 
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
237
Once 			:: !String !(Task a) 						-> Task a 		| iData a
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
238 239 240

// *********************************************************************************************************************************
/* Lifting of other domains to the iTask domain
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
241 242 243
(*>>)			:: 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
244
appIData2		:: lift iData editors to iTask domain, and pass iDataTasknumber for naming convenience
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
245 246
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
247
*/
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
248 249 250 251 252 253
(*=>) 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
254 255
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
256

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
257
// *********************************************************************************************************************************
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
258
/* Operations on Task state
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
259 260
taskId			:: give id of user assigned to task
userId			:: give id of application user
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
261 262 263 264
addHtml			:: add html code
*/
taskId			:: TSt 				-> (Int,TSt)
userId 			:: TSt 				-> (Int,TSt)
265
addHtml 		:: HtmlCode TSt 	-> TSt
Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
266

Rinus Plasmeijer's avatar
Rinus Plasmeijer committed
267 268 269 270 271 272 273
// *********************************************************************************************************************************