r20538: Web Application Framework
authorDerrell Lipman <derrell@samba.org>
Fri, 5 Jan 2007 04:33:38 +0000 (04:33 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:36:49 +0000 (14:36 -0500)
- correct an error message in the JSON-RPC server

- provide a common RPC request function

- make it easier to have multiple pending RPC requests.  this allows an
  application-specified request to return "not logged in"; authentication
  information to be requested and sent; and the original request to be
  reissued.

- in statistics module, if a time is provided as zero, leave it blank rather
  than displaying 1 Jan 1970.  this showed up in the last_used_at field in the
  SMB status report.

- clean up makefile: remove no-longer-used hard-coded path and install target;
  remove "chmod" and "nice" commands which were part of the original skeleton,
  since that is not deemed appropriate for samba makefiles
(This used to be commit 339ee73ce2809905f608b1003cc645231f256420)

services/request.esp
webapps/swat/Makefile
webapps/swat/source/class/swat/module/AbstractModuleFsm.js
webapps/swat/source/class/swat/module/ldbbrowse/Fsm.js
webapps/swat/source/class/swat/module/statistics/Fsm.js
webapps/swat/source/class/swat/module/statistics/Gui.js

index 970ea6b4fb759ad57c924e6109f662d401273556..1b33b6196475b6a953abb4cfb271a5d1aaf4108f 100644 (file)
@@ -450,7 +450,7 @@ if (valid)
 if (! valid)
 {
     error.setError(jsonrpc.Constant.ErrorCode.MethodNotFound,
-                   "Method `" + method + "` not found.");
+                   "Method `" + jsonInput.method + "` not found.");
     error.Send();
     return;
 }
index bf8af850ff277abe2f5af4d3f521e59ece970a3d..c993dde82550c75570303339786a9e3863558a86 100644 (file)
@@ -10,7 +10,6 @@ OPTIMIZESTRINGS = false
 OPTIMIZEVARIABLES = false
 SOURCELOADER=
 NICE=10
-LOCALINSTALLDIR = /usr/local/samba/share/swat/apps/swat
 
 
 ###################################################################################
@@ -116,7 +115,7 @@ distclean: realclean
 ###################################################################################
 
 generate-script-source:
-       @chmod u+x $(GENERATOR) && nice -n $(NICE) $(GENERATOR) \
+       @$(GENERATOR) \
          --script-input $(FRAMEWORK)/source/class \
          --source-script-path ../$(FRAMEWORK)/source/class \
          --script-input $(API)/source/class \
@@ -136,7 +135,7 @@ generate-script-source:
 #      --resource-output defined for one set, it must be defined for each set
 #
 generate-script-build:
-       @chmod u+x $(GENERATOR) && nice -n $(NICE) $(GENERATOR) \
+       @$(GENERATOR) \
          --script-input $(FRAMEWORK)/source/class \
          --resource-input $(FRAMEWORK)/source/resource \
          --resource-output build/resource \
@@ -155,7 +154,7 @@ generate-script-build:
          --add-new-lines
 
 generate-api-build:
-       @chmod u+x $(GENERATOR) && nice -n $(NICE) $(GENERATOR) \
+       @$(GENERATOR) \
          --script-input $(FRAMEWORK)/source/class \
          --resource-input $(FRAMEWORK)/source/resource \
          --resource-output api/resource/qooxdoo \
@@ -172,7 +171,7 @@ generate-api-build:
          --cache-directory $(CACHE)
 
 generate-api-data:
-       @chmod u+x $(GENERATOR) && nice -n $(NICE) $(GENERATOR) \
+       @$(GENERATOR) \
          --script-input $(FRAMEWORK)/source/class \
          --script-input $(API)/source/class \
          --script-input source/class \
@@ -181,7 +180,7 @@ generate-api-data:
          --cache-directory $(CACHE)
 
 generate-pretty:
-       @chmod u+x $(GENERATOR) && nice -n $(NICE) $(GENERATOR) \
+       @$(GENERATOR) \
          --script-input source/class \
          --script-input $(FRAMEWORK)/source/class \
          --include-without-dependencies api.* \
@@ -189,7 +188,7 @@ generate-pretty:
          --cache-directory $(CACHE)
 
 generate-fix:
-       @chmod u+x $(GENERATOR) && nice -n $(NICE) $(GENERATOR) \
+       @$(GENERATOR) \
          --script-input source/class \
          --script-input $(FRAMEWORK)/source/class \
          --include-without-dependencies api.* \
@@ -234,14 +233,3 @@ info-source:
        @echo "****************************************************************************"
        @echo "  GENERATING SWAT WEB APPLICATION SOURCE"
        @echo "****************************************************************************"
-
-###################################################################################
-# INSTALL TARGETS (for developer use only)
-###################################################################################
-
-install:       
-       @echo "****************************************************************************"
-       @echo "  INSTALLING SWAT"
-       @echo "****************************************************************************"
-       @echo "  * Installing swat files..."
-       @rsync -av --exclude=crystalsvg --delete build/ $(LOCALINSTALLDIR)
index 57b8baaac94d304aca1462049bdf1cd0f957ba0f..cffeb8b00ad137aaf0d76e5d5719c8c7d4534752 100644 (file)
@@ -14,6 +14,9 @@
 qx.OO.defineClass("swat.module.AbstractModuleFsm", qx.core.Object, function()
 {
   qx.core.Object.call(this);
+
+  // Create an array for pushing request objects
+  this._requests = [ ];
 });
 
 
@@ -26,6 +29,7 @@ qx.Proto.buildFsm = function(module)
 qx.Proto.addAwaitRpcResultState = function(module)
 {
   var fsm = module.fsm;
+  var _this = this;
 
   /*
    * State: AwaitRpcResult
@@ -107,7 +111,7 @@ qx.Proto.addAwaitRpcResultState = function(module)
       "onentry" :
         function(fsm, state)
         {
-          // If we're coming from some other start...
+          // If we're coming from some other state...
           if (fsm.getPreviousState() != "State_AwaitRpcResult")
           {
             // ... then push the previous state onto the state stack
@@ -147,7 +151,7 @@ qx.Proto.addAwaitRpcResultState = function(module)
         function(fsm, event)
         {
           // Get the request object
-          var request = fsm.getObject("swat.module.fsmUtils.request");
+          var request = _this.getCurrentRpcRequest();
 
           // Issue an abort for the pending request
           request.abort();
@@ -170,7 +174,7 @@ qx.Proto.addAwaitRpcResultState = function(module)
         function(fsm, event)
         {
           // Get the request object
-          var request = fsm.getObject("swat.module.fsmUtils.request");
+          var request = _this.getCurrentRpcRequest();
           
           // Generate the result for a completed request
           request.setUserData("result",
@@ -197,7 +201,7 @@ qx.Proto.addAwaitRpcResultState = function(module)
         function(fsm, event)
         {
           // Get the request object
-          var request = fsm.getObject("swat.module.fsmUtils.request");
+          var request = _this.getCurrentRpcRequest();
           
           // Generate the result for a completed request
           request.setUserData("result",
@@ -209,3 +213,111 @@ qx.Proto.addAwaitRpcResultState = function(module)
     });
   state.addTransition(trans);
 };
+
+
+/**
+ * Issue a remote procedure call.
+ *
+ * @param fsm {qx.util.fsm.FiniteStateMachine}
+ *   The finite state machine issuing this remote procedure call.
+ *
+ * @param service {String}
+ *   The name of the remote service which provides the specified method.
+ *
+ * @param method {String}
+ *   The name of the method within the specified service.
+ *
+ * @param params {Array}
+ *   The parameters to be passed to the specified method.
+ *
+ * @return {qx.io.remote.Request}
+ *   The request object for the just-issued RPC request.
+ */
+qx.Proto.callRpc = function(fsm, service, method, params)
+{
+  // Create an object to hold a copy of the parameters.  (We need a
+  // qx.core.Object() to be able to store this in the finite state machine.)
+  var o = new qx.core.Object();
+
+  // copy the parameters; we'll prefix our copy with additional params
+  o.allParams = params.slice(0);
+
+  // prepend the method
+  o.allParams.unshift(method);
+
+  // prepend the flag indicating to coalesce failure events
+  o.allParams.unshift(true);
+
+  // prepend the service name
+  o.allParams.unshift(service);
+
+  // Save the complete parameter list in case authentication fails and we need
+  // to reissue the request.
+  fsm.addObject("swat.module.rpc_params", o);
+  
+  // Retrieve the RPC object */
+  var rpc = fsm.getObject("swat.module.rpc");
+
+  // Set the service name
+  rpc.setServiceName(o.allParams[0]);
+
+  // Issue the request, skipping the already-specified service name
+  var request =
+    qx.io.remote.Rpc.prototype.callAsyncListeners.apply(rpc,
+                                                        o.allParams.slice(1));
+
+  // Make the request object available to the AwaitRpcResult state
+  this.pushRpcRequest(request);
+
+  // Give 'em what they came for
+  return request;
+};
+
+
+/**
+ * Push an RPC request onto the request stack.
+ *
+ * @param request {qx.io.remote.Request}
+ *   The just-issued request
+ */
+qx.Proto.pushRpcRequest = function(request)
+{
+  this._requests.push(request);
+};
+
+
+/**
+ * Retrieve the most recent RPC request from the request stack and pop the
+ * stack.
+ *
+ * @return {qx.io.remote.Request}
+ *   The request from the top of the request stack
+ */
+qx.Proto.popRpcRequest = function()
+{
+  if (this._requests.length == 0)
+  {
+    throw new Error("Attempt to pop an RPC request when list is empty.");
+  }
+
+  var request = this._requests.pop();
+  return request;
+};
+
+
+/**
+ * Retrieve the most recent RPC request.
+ *
+ * @return {qx.io.remote.Request}
+ *   The request at the top of the request stack
+ */
+qx.Proto.getCurrentRpcRequest = function()
+{
+  if (this._requests.length == 0)
+  {
+    throw new Error("Attempt to retrieve an RPC request when list is empty.");
+  }
+
+  return this._requests[this._requests.length - 1];
+};
+
index 9362ef7687abecb8587930745b405faa97f5eb71..8052d9a57964721b4a81e07b992617f3fdd59de0 100644 (file)
@@ -20,6 +20,7 @@ function()
 qx.Proto.buildFsm = function(module)
 {
   var fsm = module.fsm;
+  var _this = this;
 
   /*
    * State: Idle
@@ -42,10 +43,7 @@ qx.Proto.buildFsm = function(module)
           if (fsm.getPreviousState() == "State_AwaitRpcResult")
           {
             // Yup.  Display the result.  We need to get the request object
-            var request = fsm.getObject("swat.module.fsmUtils.request");
-
-            // We don't need the request object to be saved any more
-            fsm.removeObject("swat.module.fsmUtils.request");
+            var request = _this.popRpcRequest();
 
             // Display the result
             var gui = swat.module.ldbbrowse.Gui.getInstance();
@@ -107,9 +105,6 @@ qx.Proto.buildFsm = function(module)
       "ontransition" :
         function(fsm, event)
         {
-          // Obtain the RPC object
-          var rpc = fsm.getObject("swat.module.rpc");
-
           // Get our module descriptor
           var module = fsm.getObject("swat.module.module");
 
@@ -128,21 +123,21 @@ qx.Proto.buildFsm = function(module)
           // We want all attributes
           var attributes = [ "*" ];
 
-          rpc.setServiceName("samba.ldb");
-          var request = rpc.callAsyncListeners(true, // coalesce failure events
-                                               "search",
-                                               dbHandle,
-                                               searchExpr,
-                                               baseDN,
-                                               scope,
-                                               attributes);
+          // Issue a Search call
+          var request = _this.callRpc(fsm,
+                                      "samba.ldb",
+                                      "search",
+                                      [
+                                       dbHandle,
+                                       searchExpr,
+                                       baseDN,
+                                       scope,
+                                       attributes
+                                      ]);
 
           // When we get the result, we'll need to know what type of request
           // we made.
           request.setUserData("requestType", "find");
-
-          // Save the request object
-          fsm.addObject("swat.module.fsmUtils.request", request);
         }
     });
   state.addTransition(trans);
@@ -207,23 +202,23 @@ qx.Proto.buildFsm = function(module)
           // Build the search expression
           var searchExpr = "(objectclass=*)";
 
-          // Obtain the RPC object
-          var rpc = fsm.getObject("swat.module.rpc");
-
           // Get our module descriptor
           var module = fsm.getObject("swat.module.module");
 
           // Retrieve the database handle
           var dbHandle = module.dbHandle;
 
-          rpc.setServiceName("samba.ldb");
-          var request = rpc.callAsyncListeners(true, // coalesce failure events
-                                               "search",
-                                               dbHandle,
-                                               searchExpr,
-                                               baseDN,
-                                               scope,
-                                               attributes);
+          // Issue a Get Statistics call
+          var request = _this.callRpc(fsm,
+                                      "samba.ldb",
+                                      "search",
+                                      [
+                                       dbHandle,
+                                       searchExpr,
+                                       baseDN,
+                                       scope,
+                                       attributes
+                                      ]);
 
           // When we get the result, we'll need to know what type of request
           // we made.
@@ -232,9 +227,6 @@ qx.Proto.buildFsm = function(module)
           // We'll also need some of our parameters
           request.setUserData("parent", parent);
           request.setUserData("attributes", attributes);
-
-          // Save the request object
-          fsm.addObject("swat.module.fsmUtils.request", request);
         }
     });
   state.addTransition(trans);
@@ -306,30 +298,27 @@ qx.Proto.buildFsm = function(module)
           // Build the search expression
           var searchExpr = "(objectclass=*)";
 
-          // Obtain the RPC object
-          var rpc = fsm.getObject("swat.module.rpc");
-
           // Get our module descriptor
           var module = fsm.getObject("swat.module.module");
 
           // Retrieve the database handle
           var dbHandle = module.dbHandle;
 
-          rpc.setServiceName("samba.ldb");
-          var request = rpc.callAsyncListeners(true, // coalesce failure events
-                                               "search",
-                                               dbHandle,
-                                               searchExpr,
-                                               baseDN,
-                                               scope,
-                                               attributes);
+          // Issue a Get Statistics call
+          var request = _this.callRpc(fsm,
+                                      "samba.ldb",
+                                      "search",
+                                      [
+                                       dbHandle,
+                                       searchExpr,
+                                       baseDN,
+                                       scope,
+                                       attributes
+                                      ]);
 
           // When we get the result, we'll need to know what type of request
           // we made.
           request.setUserData("requestType", "tree_selection_changed");
-
-          // Save the request object
-          fsm.addObject("swat.module.fsmUtils.request", request);
         }
     });
   state.addTransition(trans);
@@ -351,23 +340,18 @@ qx.Proto.buildFsm = function(module)
       "ontransition" :
         function(fsm, event)
         {
-          // Obtain the RPC object
-          var rpc = fsm.getObject("swat.module.rpc");
-
           // Obtain the name of the database to be connected to
           var dbName = fsm.getObject("dbName").getValue();
 
-          rpc.setServiceName("samba.ldb");
-          var request = rpc.callAsyncListeners(true, // coalesce failure events
-                                               "connect",
-                                               dbName);
+          // Issue a Get Statistics call
+          var request = _this.callRpc(fsm,
+                                      "samba.ldb",
+                                      "connect",
+                                      [ dbName ]);
 
           // When we get the result, we'll need to know what type of request
           // we made.
           request.setUserData("requestType", "database_name_changed");
-
-          // Save the request object
-          fsm.addObject("swat.module.fsmUtils.request", request);
         }
     });
   state.addTransition(trans);
index 771044172e092a326b22e6d72be45f4811f9cd60..1aeab8a4a335391eae1aadda6acf766ed828ffc2 100644 (file)
@@ -45,7 +45,7 @@ qx.Class._stopTimer = function(fsm)
 qx.Proto.buildFsm = function(module)
 {
   var fsm = module.fsm;
-  var thisClass = this;
+  var _this = this;
 
   /*
    * State: Idle
@@ -67,10 +67,7 @@ qx.Proto.buildFsm = function(module)
           if (fsm.getPreviousState() == "State_AwaitRpcResult")
           {
             // Yup.  Display the result.  We need to get the request object
-            var request = fsm.getObject("swat.module.fsmUtils.request");
-
-            // We don't need the request object to be saved any more
-            fsm.removeObject("swat.module.fsmUtils.request");
+            var request = _this.popRpcRequest();
 
             // Display the result
             var gui = swat.module.statistics.Gui.getInstance();
@@ -141,15 +138,11 @@ qx.Proto.buildFsm = function(module)
       "ontransition" :
         function(fsm, event)
         {
-          var rpc = fsm.getObject("swat.module.rpc");
-
-          rpc.setServiceName("samba.management");
-          var request = rpc.callAsyncListeners(true, // coalesce failure events
-                                               "get_statistics",
-                                               true,
-                                               true);
-          // Make the request object available to the AwaitRpcResult state
-          fsm.addObject("swat.module.fsmUtils.request", request);
+          // Issue a Get Statistics call
+          _this.callRpc(fsm,
+                        "samba.management",
+                        "get_statistics",
+                        [ true, true ]);
         }
     });
   state.addTransition(trans);
index 777caa73288c03686f0687eb157f0792263c2e66..28b21aa46d847fee5aa7638ecc222e6e09b28554 100644 (file)
@@ -366,6 +366,11 @@ qx.Proto.displayData = function(module, result)
   // Create a function for formatting dates
   var dateFormat = function(unixepoch)
   {
+    if (unixepoch == 0)
+    {
+      return "";
+    }
+
     var d = new Date(unixepoch * 1000);
     return (d.getFullYear() + "-" +
             ("0" + (d.getMonth() + 1)).substr(-2) + "-" +