cb62c1f976ad941440ac697f33ab433f0d880f81
[samba.git] / webapps / swat / source / class / swat / module / ldbbrowse / Fsm.js
1 /*
2  * Copyright:
3  *   (C) 2006 by Derrell Lipman
4  *       All rights reserved
5  *
6  * License:
7  *   LGPL 2.1: http://creativecommons.org/licenses/LGPL/2.1/
8  */
9
10 /**
11  * Swat LDB Browser class finite state machine
12  */
13 qx.OO.defineClass("swat.module.ldbbrowse.Fsm", swat.main.AbstractModuleFsm,
14 function()
15 {
16   swat.main.AbstractModuleFsm.call(this);
17 });
18
19
20 qx.Proto.buildFsm = function(module)
21 {
22   var fsm = module.fsm;
23   var _this = this;
24
25   /*
26    * State: Idle
27    *
28    * Actions upon entry
29    *   - if returning from RPC, display the result
30    *
31    * Transition on:
32    *   "execute" on search button
33    *   "treeopenwhileempty" on tree
34    *   "changeselection" on tree
35    */
36   var state = new qx.util.fsm.State(
37     "State_Idle",
38     {
39       "onentry" :
40         function(fsm, event)
41         {
42           // Did we just return from an RPC request?
43           if (fsm.getPreviousState() == "State_AwaitRpcResult")
44           {
45             // Yup.  Display the result.  We need to get the request object
46             var rpcRequest = _this.popRpcRequest();
47
48             // Display the result
49             var gui = swat.module.ldbbrowse.Gui.getInstance();
50
51             // Did we get a Resource Not Found error?  We'll get this after a
52             // session timeout, because the request is retried but can't
53             // succeed because the database has been closed by the session
54             // timing out.
55             var result = rpcRequest.getUserData("result");
56             var origins = swat.main.AbstractModuleFsm.JsonRpc_Origin;
57             var serverErrors = swat.main.AbstractModuleFsm.JsonRpc_ServerError;
58             if (result.type == "failed" &&
59                 result.data.origin == origins.Server &&
60                 result.data.code == serverErrors.ResourceError)
61             {
62               // Yup.  Re-open the database
63               var dbName = fsm.getObject("dbName");
64               dbName.dispatchEvent(new qx.event.type.Event("changeSelection"),
65                                    true);
66             }
67             else
68             {
69               // Otherwise, display the result
70               gui.displayData(module, rpcRequest);
71             }
72
73             // Dispose of the request
74             rpcRequest.request.dispose();
75             rpcRequest.request = null;
76           }
77         },
78
79       "events" :
80         {
81           // If the search button is activated, issue a search request
82           "execute" :
83           {
84             "search" :
85               "Transition_Idle_to_AwaitRpcResult_via_search",
86
87             "commit" :
88               "Transition_Idle_to_AwaitRpcResult_via_commit"
89           },
90
91           // If a previously unexpanded tree node is expanded, issue a request
92           // to retrieve its contents.
93           "treeOpenWhileEmpty":
94           {
95             "tree" :
96               "Transition_Idle_to_AwaitRpcResult_via_tree_open"
97           },
98
99           // If the selection changes, issue a request to retrieve contents to
100           // populate the attribute/value table.
101           "changeSelection":
102           {
103             "tree:manager" :
104               "Transition_Idle_to_AwaitRpcResult_via_tree_selection_changed",
105
106             "dbName":
107               "Transition_Idle_to_AwaitRpcResult_via_db_changed"
108           }
109         }
110     });
111
112   // Replace the initial Idle state with this one
113   fsm.replaceState(state, true);
114   
115   /*
116    * Transition: Idle to AwaitRpcResult
117    *
118    * Cause: "execute" on search button
119    *
120    * Action:
121    *  Issue a search request
122    */
123   var trans = new qx.util.fsm.Transition(
124     "Transition_Idle_to_AwaitRpcResult_via_search",
125     {
126       "nextState" :
127         "State_AwaitRpcResult",
128
129       "ontransition" :
130         function(fsm, event)
131         {
132           // Get our module descriptor
133           var module = fsm.getObject("swat.main.module");
134
135           // Retrieve the database handle
136           var dbHandle = module.dbHandle;
137
138           // Retrieve the search expression
139           var searchExpr = fsm.getObject("searchExpr").getValue();
140
141           // Retrieve the base DN
142           var baseDN = fsm.getObject("baseDN").getValue();
143
144           // Retrieve the selected scope
145           var scope = fsm.getObject("scope").getValue();
146
147           // We want all attributes
148           var attributes = [ "*" ];
149
150           // Issue a Search call
151           var request = _this.callRpc(fsm,
152                                       "samba.ldb",
153                                       "search",
154                                       [
155                                        dbHandle,
156                                        searchExpr,
157                                        baseDN,
158                                        scope,
159                                        attributes
160                                       ]);
161
162           // When we get the result, we'll need to know what type of request
163           // we made.
164           request.setUserData("requestType", "search");
165         }
166     });
167   state.addTransition(trans);
168
169   /*
170    * Transition: Idle to AwaitRpcResult
171    *
172    * Cause: "execute" on OK button
173    *
174    * Action:
175    *  Commit modification or add new record to ldb
176    */
177   var trans = new qx.util.fsm.Transition(
178     "Transition_Idle_to_AwaitRpcResult_via_commit",
179     {
180       "nextState" :
181         "State_AwaitRpcResult",
182
183       "ontransition" :
184         function(fsm, event)
185         {
186           // Get our module descriptor
187           var module = fsm.getObject("swat.main.module");
188
189           // Retrieve the database handle
190           var dbHandle = module.dbHandle;
191
192           // Retrieve the ldbmod object
193           var ldbmod = fsm.getObject("ldbmod");
194
195           var ldif = ldbmod.getLdif();
196
197           // Issue a Search call
198           var request = _this.callRpc(fsm,
199                                       "samba.ldb",
200                                       ldbmod.getOpType(),
201                                       [ ldif ]);
202
203           // When we get the result, we'll need to know what type of request
204           // we made.
205           request.setUserData("requestType", ldbmod.getOpType());
206         }
207     });
208   state.addTransition(trans);
209
210   /*
211    * Transition: Idle to AwaitRpcResult
212    *
213    * Cause: "treeOpenWhileEmpty" on tree
214    *
215    * Action:
216    *  Issue a search request
217    */
218   var trans = new qx.util.fsm.Transition(
219     "Transition_Idle_to_AwaitRpcResult_via_tree_open",
220     {
221       "nextState" :
222         "State_AwaitRpcResult",
223
224       "ontransition" :
225         function(fsm, event)
226         {
227           var parent = event.getData();
228           var hierarchy = parent.getHierarchy(new Array());
229
230           parent.debug("Requesting children...");
231
232           // Strip off the root node
233           hierarchy.shift();
234
235           // Get the tree object
236           var tree = fsm.getObject("tree");
237
238           // Determine the children.  Differs depending on root or otherwise
239           var attributes;
240           var scope;
241           var baseDN;
242             
243           // If parent is the root...
244           if (parent == tree)
245           {
246             // ... then we want the defaultNamingContext, ...
247             attributes = [ "defaultNamingContext", "namingContexts" ];
248
249             // ... and we want only base scope
250             scope = "base";
251
252             // ... and an empty base DN
253             baseDN = "";
254           }
255           else
256           {
257             // otherwise, retrieve the DN,
258             attributes = [ "dn" ];
259
260             // ... and we want one level of scope
261             scope = "one";
262
263             // ... and base DN is the parent
264             baseDN = hierarchy.reverse().join(",");
265           }
266
267           // Build the search expression
268           var searchExpr = "(objectclass=*)";
269
270           // Get our module descriptor
271           var module = fsm.getObject("swat.main.module");
272
273           // Retrieve the database handle
274           var dbHandle = module.dbHandle;
275
276           // Issue a Get Statistics call
277           var request = _this.callRpc(fsm,
278                                       "samba.ldb",
279                                       "search",
280                                       [
281                                        dbHandle,
282                                        searchExpr,
283                                        baseDN,
284                                        scope,
285                                        attributes
286                                       ]);
287
288           // When we get the result, we'll need to know what type of request
289           // we made.
290           request.setUserData("requestType", "tree_open");
291
292           // We'll also need some of our parameters
293           request.setUserData("parent", parent);
294           request.setUserData("attributes", attributes);
295         }
296     });
297   state.addTransition(trans);
298
299   /*
300    * Transition: Idle to AwaitRpcResult
301    *
302    * Cause: "changeSelection" on tree
303    *
304    * Action:
305    *  Issue a search request
306    */
307   var trans = new qx.util.fsm.Transition(
308     "Transition_Idle_to_AwaitRpcResult_via_tree_selection_changed",
309     {
310       "nextState" :
311         "State_AwaitRpcResult",
312
313       "predicate" :
314         function(fsm, event)
315         {
316           var element = event.getData()[0];
317           var hierarchy = element.getHierarchy(new Array());
318
319           // Strip off the root node
320           hierarchy.shift();
321
322           // Get the tree object
323           var tree = fsm.getObject("tree");
324
325           // If element is the root...
326           if (element == tree)
327           {
328             // ... then just clear out the attribute/value table.
329             var tableModel = fsm.getObject("tableModel:browse");
330             tableModel.setData([]);
331             return null;        // don't search additional transitionis
332           }
333
334           return true;
335         },
336
337       "ontransition" :
338         function(fsm, event)
339         {
340           var element = event.getData()[0];
341           var hierarchy = element.getHierarchy(new Array());
342
343           // Strip off the root node
344           hierarchy.shift();
345
346           // Get the tree object
347           var tree = fsm.getObject("tree");
348
349           // Determine the children.  Differs depending on root or otherwise
350           var attributes;
351           var scope;
352           var baseDN;
353             
354           // We want all attributes
355           attributes = [ "*" ];
356
357           // We want the attributes only for the current element
358           scope = "base";
359
360           // Base DN is the current element
361           baseDN = hierarchy.reverse().join(",");
362
363           // Build the search expression
364           var searchExpr = "(objectclass=*)";
365
366           // Get our module descriptor
367           var module = fsm.getObject("swat.main.module");
368
369           // Retrieve the database handle
370           var dbHandle = module.dbHandle;
371
372           // Issue a Get Statistics call
373           var request = _this.callRpc(fsm,
374                                       "samba.ldb",
375                                       "search",
376                                       [
377                                        dbHandle,
378                                        searchExpr,
379                                        baseDN,
380                                        scope,
381                                        attributes
382                                       ]);
383
384           // When we get the result, we'll need to know what type of request
385           // we made.
386           request.setUserData("requestType", "tree_selection_changed");
387         }
388     });
389   state.addTransition(trans);
390
391   /*
392    * Transition: Idle to AwaitRpcResult
393    *
394    * Cause: "changeSelection" on dbName
395    *
396    * Action:
397    *  Issue a connect request
398    */
399   var trans = new qx.util.fsm.Transition(
400     "Transition_Idle_to_AwaitRpcResult_via_db_changed",
401     {
402       "nextState" :
403         "State_AwaitRpcResult",
404
405       "ontransition" :
406         function(fsm, event)
407         {
408           // Obtain the name of the database to be connected to
409           var dbName = fsm.getObject("dbName").getValue();
410
411           // Issue a Get Statistics call
412           var request = _this.callRpc(fsm,
413                                       "samba.ldb",
414                                       "connect",
415                                       [ dbName ]);
416
417           // When we get the result, we'll need to know what type of request
418           // we made.
419           request.setUserData("requestType", "database_name_changed");
420         }
421     });
422   state.addTransition(trans);
423
424   // Create the list of events that should be blocked while we're awaiting the
425   // results of another RPC request
426   blockedEvents =
427   {
428     // If a previously unexpanded tree node is expanded, issue a request
429     // to retrieve its contents.
430     "treeOpenWhileEmpty":
431     {
432       "tree" :
433         qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED
434     },
435
436     // If the selection changes, issue a request to retrieve contents to
437     // populate the attribute/value table.
438     "changeSelection":
439     {
440       "tree:manager" : 
441         qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED,
442
443       "dbName":
444         qx.util.fsm.FiniteStateMachine.EventHandling.BLOCKED
445     }
446   }
447
448   // Add the AwaitRpcResult state and all of its transitions
449   this.addAwaitRpcResultState(module, blockedEvents);
450 };
451
452
453 /**
454  * Singleton Instance Getter
455  */
456 qx.Class.getInstance = qx.lang.Function.returnInstance;