You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2013/02/22 09:11:16 UTC

svn commit: r1448926 - in /incubator/ambari/trunk: CHANGES.txt ambari-web/app/controllers/global/background_operations_controller.js ambari-web/app/controllers/main/service/item.js ambari-web/app/initialize.js ambari-web/app/utils/ajax.js

Author: yusaku
Date: Fri Feb 22 08:11:16 2013
New Revision: 1448926

URL: http://svn.apache.org/r1448926
Log:
AMBARI-1471. Refactor ajax calls. (yusaku)

Added:
    incubator/ambari/trunk/ambari-web/app/utils/ajax.js
Modified:
    incubator/ambari/trunk/CHANGES.txt
    incubator/ambari/trunk/ambari-web/app/controllers/global/background_operations_controller.js
    incubator/ambari/trunk/ambari-web/app/controllers/main/service/item.js
    incubator/ambari/trunk/ambari-web/app/initialize.js

Modified: incubator/ambari/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/CHANGES.txt?rev=1448926&r1=1448925&r2=1448926&view=diff
==============================================================================
--- incubator/ambari/trunk/CHANGES.txt (original)
+++ incubator/ambari/trunk/CHANGES.txt Fri Feb 22 08:11:16 2013
@@ -51,6 +51,8 @@ Trunk (unreleased changes):
 
  IMPROVEMENTS
 
+ AMBARI-1471. Refactor ajax calls. (yusaku)
+
  AMBARI-1461. Optimize query for getting service and host component status back
  from the server. (yusaku)
 

Modified: incubator/ambari/trunk/ambari-web/app/controllers/global/background_operations_controller.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/controllers/global/background_operations_controller.js?rev=1448926&r1=1448925&r2=1448926&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/controllers/global/background_operations_controller.js (original)
+++ incubator/ambari/trunk/ambari-web/app/controllers/global/background_operations_controller.js Fri Feb 22 08:11:16 2013
@@ -41,15 +41,6 @@ App.BackgroundOperationsController = Em.
   updateInterval: App.bgOperationsUpdateInterval,
   url : '',
 
-  generateUrl: function(){
-    var url = App.testMode ?
-      '/data/background_operations/list_on_start.json' :
-      App.apiPrefix + '/clusters/' + App.router.getClusterName() + '/requests/?fields=tasks/*';
-
-    this.set('url', url);
-    return url;
-  },
-
   timeoutId : null,
 
   /**
@@ -100,39 +91,30 @@ App.BackgroundOperationsController = Em.
     if(!this.get('isWorking')){
       return;
     }
-    var self = this;
 
     if(!App.router.getClusterName()){
       this.loadOperationsDelayed(this.get('updateInterval')/2, 'error:clusterName');
       return;
     }
 
-    var url = this.get('url');
-    if(!url){
-      url = this.generateUrl();
-    }
-
-    $.ajax({
-      type: "GET",
-      url: url,
-      dataType: 'json',
-      timeout: App.timeout,
-      success: function (data) {
-        //refresh model
-        self.updateBackgroundOperations(data);
-
-        self.loadOperationsDelayed();
-      },
-
-      error: function (request, ajaxOptions, error) {
-        self.loadOperationsDelayed(null, 'error:response error');
-      },
+    App.ajax.send({
+      'name': 'background_operations',
+      'sender': this,
+      'success': 'ajaxSuccess', //todo provide interfaces for strings and functions
+      'error': 'ajaxError'
+    })
 
-      statusCode: require('data/statusCodes')
-    });
 
   }.observes('isWorking'),
 
+  ajaxSuccess: function(data) {
+    this.updateBackgroundOperations(data);
+    this.loadOperationsDelayed();
+  },
+  ajaxError: function(request, ajaxOptions, error) {
+    this.loadOperationsDelayed(null, 'error:response error');
+  },
+
   /**
    * Update info about background operations
    * Put all tasks with command 'EXECUTE' into <code>executeTasks</code>, other tasks with it they are still running put into <code>runningTasks</code>

Modified: incubator/ambari/trunk/ambari-web/app/controllers/main/service/item.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/controllers/main/service/item.js?rev=1448926&r1=1448925&r2=1448926&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/controllers/main/service/item.js (original)
+++ incubator/ambari/trunk/ambari-web/app/controllers/main/service/item.js Fri Feb 22 08:11:16 2013
@@ -22,89 +22,106 @@ App.MainServiceItemController = Em.Contr
   name: 'mainServiceItemController',
 
   /**
-   * Send specific command to server
-   * @param url
-   * @param data Object to send
-   */
-  sendCommandToServer : function(url, method, postData, callback){
-    var url =  (App.testMode) ?
-      '/data/wizard/deploy/poll_1.json' : //content is the same as ours
-      App.apiPrefix + '/clusters/' + App.router.getClusterName() + url;
-
-    method = App.testMode ? 'GET' : method;
-
-    $.ajax({
-      type: method,
-      url: url,
-      data: (postData != null) ? JSON.stringify(postData) : null,
-      dataType: 'json',
-      timeout: App.timeout,
-      success: function(data){
-        if(data && data.Requests){
-          callback(data.Requests.id);
-        } else{
-          callback(null);
-          console.log('cannot get request id from ', data);
+   * Callback functions for start and stop service have few differences
+   *
+   * Used with currentCallBack property
+   */
+  callBackConfig: {
+    'STARTED': {
+      'c': 'STARTING',
+      'f': 'starting',
+      'c2': 'live',
+      'hs': 'started',
+      's': 'start'
+    },
+    'INSTALLED': {
+      'c': 'STOPPING',
+      'f': 'stopping',
+      'c2': 'dead',
+      'hs': 'stopped',
+      's': 'stop'
+    }
+  },
+  /**
+   * Success ajax response processing
+   * @param data
+   * @param ajaxOptions
+   */
+  ajaxSuccess: function(data, ajaxOptions) {
+    if(data && data.Requests) {
+      this.ajaxCallBack(data.Requests.id, (JSON.parse(ajaxOptions.data)).ServiceInfo.state);
+    }
+    else {
+      console.log('cannot get request id from ', data);
+    }
+  },
+  /**
+   * Common method for ajax (start/stop service) responses
+   * @param requestId
+   * @param serviceHealth
+   */
+  ajaxCallBack: function(requestId, serviceHealth) {
+    var config = this.get('callBackConfig')[serviceHealth];
+    var self = this;
+    console.log('Send request for ' + config.c + ' successfully');
+    if (App.testMode) {
+      self.set('content.workStatus', App.Service.Health[config.f]);
+      self.get('content.hostComponents').setEach('workStatus', App.HostComponentStatus[config.f]);
+      setTimeout(function () {
+        self.set('content.workStatus', App.Service.Health[config.c2]);
+        self.get('content.hostComponents').setEach('workStatus', App.HostComponentStatus[config.hs]);
+      }, App.testModeDelayForActions);
+    }
+    else {
+      App.router.get('clusterController').loadUpdatedStatusDelayed(500);// @todo check working without param 500
+      App.router.get('backgroundOperationsController.eventsArray').push({
+        "when": function (controller) {
+          var result = (controller.getOperationsForRequestId(requestId).length == 0);
+          console.log(config.s + 'Service.when = ', result)
+          return result;
+        },
+        "do": function () {
+          App.router.get('clusterController').loadUpdatedStatus();
         }
-      },
-
-      error: function (request, ajaxOptions, error) {
-        //do something
-        callback(null);
-        console.log('error on change component host status')
-      },
-
-      statusCode: require('data/statusCodes')
-    });
+      });
+    }
+    App.router.get('backgroundOperationsController').showPopup();
   },
-
   /**
-   * On click callback for <code>start service</code> button
+   * Confirmation popup for start/stop services
    * @param event
+   * @param serviceHealth - 'STARTED' or 'INSTALLED'
    */
-  startService: function (event) {
+  startStopPopup: function(event, serviceHealth) {
     if ($(event.target).hasClass('disabled') || $(event.target.parentElement).hasClass('disabled')) {
       return;
     }
-
     var self = this;
-    App.showConfirmationPopup(function(){
-      self.sendCommandToServer('/services/' + self.get('content.serviceName').toUpperCase(), "PUT", {
-        ServiceInfo: {
-          state: 'STARTED'
-        }
-      }, function (requestId) {
-
-        if (!requestId) {
-          return;
-        }
-        console.log('Send request for STARTING successfully');
+    App.showConfirmationPopup(function() {
+      self.startStopPopupPrimary(serviceHealth);
+    });
+  },
 
-        if (App.testMode) {
-          self.set('content.workStatus', App.Service.Health.starting);
-          self.get('content.hostComponents').setEach('workStatus', App.HostComponentStatus.starting);
-          setTimeout(function () {
-            self.set('content.workStatus', App.Service.Health.live);
-            self.get('content.hostComponents').setEach('workStatus', App.HostComponentStatus.started);
-          }, App.testModeDelayForActions);
-        } else {
-          App.router.get('clusterController').loadUpdatedStatusDelayed(500);
-          App.router.get('backgroundOperationsController.eventsArray').push({
-            "when": function (controller) {
-              var result = (controller.getOperationsForRequestId(requestId).length == 0);
-              console.log('startService.when = ', result)
-              return result;
-            },
-            "do": function () {
-              App.router.get('clusterController').loadUpdatedStatus();
-            }
-          });
-        }
-        App.router.get('backgroundOperationsController').showPopup();
-      });
-      self.set('content.isStopDisabled',true);
-      self.set('content.isStartDisabled',true);
+  startStopPopupPrimary: function(serviceHealth) {
+    App.ajax.send({
+      'name': 'service.item.start_stop',
+      'sender': this,
+      'success': 'ajaxSuccess',
+      'data': {
+        'serviceName': this.get('content.serviceName').toUpperCase(),
+        'state': serviceHealth
+      }
     });
+    this.set('content.isStopDisabled',true);
+    this.set('content.isStartDisabled',true);
+  },
+
+  /**
+   * On click callback for <code>start service</code> button
+   * @param event
+   */
+  startService: function (event) {
+    this.startStopPopup(event, App.HostComponentStatus.started);
   },
 
   /**
@@ -112,46 +129,7 @@ App.MainServiceItemController = Em.Contr
    * @param event
    */
   stopService: function (event) {
-    if ($(event.target).hasClass('disabled') || $(event.target.parentElement).hasClass('disabled')) {
-      return;
-    }
-
-    var self = this;
-    App.showConfirmationPopup(function(){
-      self.sendCommandToServer('/services/' + self.get('content.serviceName').toUpperCase(), "PUT",{
-        ServiceInfo:{
-          state: 'INSTALLED'
-        }
-      }, function (requestId) {
-        if (!requestId) {
-          return
-        }
-        console.log('Send request for STOPPING successfully');
-        if (App.testMode) {
-          self.set('content.workStatus', App.Service.Health.stopping);
-          self.get('content.hostComponents').setEach('workStatus', App.HostComponentStatus.stopping);
-          setTimeout(function () {
-            self.set('content.workStatus', App.Service.Health.dead);
-            self.get('content.hostComponents').setEach('workStatus', App.HostComponentStatus.stopped);
-          }, App.testModeDelayForActions);
-        } else {
-          App.router.get('clusterController').loadUpdatedStatusDelayed(500);
-          App.router.get('backgroundOperationsController.eventsArray').push({
-            "when": function (controller) {
-              var result = (controller.getOperationsForRequestId(requestId).length == 0);
-              console.log('stopService.when = ', result)
-              return result;
-            },
-            "do": function () {
-              App.router.get('clusterController').loadUpdatedStatus();
-            }
-          });
-        }
-        App.router.get('backgroundOperationsController').showPopup();
-      });
-      self.set('content.isStopDisabled',true);
-      self.set('content.isStartDisabled',true);
-    });
+    this.startStopPopup(event, App.HostComponentStatus.stopped);
   },
 
   /**
@@ -161,8 +139,8 @@ App.MainServiceItemController = Em.Contr
   runRebalancer: function (event) {
     var self = this;
     App.showConfirmationPopup(function() {
-        self.content.set('runRebalancer', true);
-        App.router.get('backgroundOperationsController').showPopup();
+      self.content.set('runRebalancer', true);
+      App.router.get('backgroundOperationsController').showPopup();
     });
   },
 
@@ -173,8 +151,8 @@ App.MainServiceItemController = Em.Contr
   runCompaction: function (event) {
     var self = this;
     App.showConfirmationPopup(function() {
-        self.content.set('runCompaction', true);
-        App.router.get('backgroundOperationsController').showPopup();
+      self.content.set('runCompaction', true);
+      App.router.get('backgroundOperationsController').showPopup();
     });
   },
 
@@ -184,23 +162,31 @@ App.MainServiceItemController = Em.Contr
    */
   runSmokeTest: function (event) {
     var self = this;
-    App.showConfirmationPopup(function(){
-      var serviceName = self.get('content.serviceName').toUpperCase();
-      var smokeName = serviceName + "_SERVICE_CHECK";
-      self.sendCommandToServer('/services/' + serviceName + '/actions/' + smokeName, "POST",
-        null,
-        function (requestId) {
-
-          if (!requestId) {
-            return;
-          }
-          self.content.set('runSmokeTest', true);
-          App.router.get('backgroundOperationsController').showPopup();
-        }
-      );
+    App.showConfirmationPopup(function() {
+      self.runSmokeTestPrimary();
     });
   },
 
+  runSmokeTestPrimary: function() {
+    App.ajax.send({
+      'name': 'service.item.smoke',
+      'sender': this,
+      'success':'runSmokeTestSuccessCallBack',
+      'data': {
+        'serviceName': this.get('content.serviceName').toUpperCase()
+      }
+    });
+  },
+
+  runSmokeTestSuccessCallBack: function(data) {
+    if (data.Requests.id) {
+      App.router.get('backgroundOperationsController').showPopup();
+    }
+    else {
+      console.warn('error during runSmokeTestSuccessCallBack');
+    }
+  },
+
   /**
    * On click callback for <code>Reassign <master component></code> button
    * @param hostComponent

Modified: incubator/ambari/trunk/ambari-web/app/initialize.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/initialize.js?rev=1448926&r1=1448925&r2=1448926&view=diff
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/initialize.js (original)
+++ incubator/ambari/trunk/ambari-web/app/initialize.js Fri Feb 22 08:11:16 2013
@@ -31,6 +31,8 @@ require('templates');
 require('views');
 require('router');
 
+require('utils/ajax');
+
 require('mappers/server_data_mapper');
 require('mappers/status_mapper');
 require('mappers/hosts_mapper');
@@ -46,6 +48,11 @@ require('utils/http_client');
 
 App.initialize();
 
+/**
+ * Test Mode values
+ */
+App.test_hostname = 'hostname';
+
 console.log('after initialize');
 console.log('TRACE: app.js-> localStorage:Ambari.authenticated=' + localStorage.getItem('Ambari' + 'authenticated'));
 console.log('TRACE: app.js-> localStorage:currentStep=' + localStorage.getItem(App.get('router').getLoginName() + 'Installer' + 'currentStep'));

Added: incubator/ambari/trunk/ambari-web/app/utils/ajax.js
URL: http://svn.apache.org/viewvc/incubator/ambari/trunk/ambari-web/app/utils/ajax.js?rev=1448926&view=auto
==============================================================================
--- incubator/ambari/trunk/ambari-web/app/utils/ajax.js (added)
+++ incubator/ambari/trunk/ambari-web/app/utils/ajax.js Fri Feb 22 08:11:16 2013
@@ -0,0 +1,156 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+var App = require('app');
+
+/**
+ * Config for each ajax-request
+ *
+ * Fields example:
+ *  mock - testMode url
+ *  real - real url (without API prefix)
+ *  type - request type (also may be defined in the format method)
+ *  format - function for processing ajax params after default formatRequest. Return ajax-params object
+ *  testInProduction - can this request be executed on production tests (used only in tests)
+ *
+ * @type {Object}
+ */
+var urls = {
+  'background_operations': {
+    'mock': '/data/background_operations/list_on_start.json',
+    'real': '/clusters/{clusterName}/requests/?fields=tasks/*',
+    'testInProduction': true
+  },
+  'service.item.start_stop': {
+    'mock': '/data/wizard/deploy/poll_1.json',
+    'real': '/clusters/{clusterName}/services/{serviceName}',
+    'format': function (data, opt) {
+      return {
+        type: 'PUT',
+        data: JSON.stringify({
+          ServiceInfo: {
+            state: data.state
+          }
+        })
+      };
+    }
+  },
+  'service.item.smoke': {
+    'mock': '/data/wizard/deploy/poll_1.json',
+    'real': '/clusters/{clusterName}/services/{serviceName}/actions/{serviceName}_SERVICE_CHECK',
+    'type': 'POST'
+  }
+};
+/**
+ * Replace data-placeholders to its values
+ *
+ * @param {String} url
+ * @param {Object} data
+ * @return {String}
+ */
+var formatUrl = function(url, data) {
+  var keys = url.match(/\{\w+\}/g);
+  keys.forEach(function(key){
+    var raw_key = key.substr(1, key.length - 2);
+    var replace;
+    if (!data[raw_key]) {
+      replace = '';
+    }
+    else {
+      replace = data[raw_key];
+    }
+    url = url.replace(new RegExp(key, 'g'), replace);
+  });
+  return url;
+};
+
+/**
+ * this = object from config
+ * @return {Object}
+ */
+var formatRequest = function(data) {
+  var opt = {
+    type : this.type || 'GET',
+    timeout : App.timeout,
+    dataType: 'json',
+    statusCode: require('data/statusCodes')
+  };
+  if(App.testMode) {
+    opt.url = this.mock;
+  }
+  else {
+    opt.url = App.apiPrefix + formatUrl(this.real, data);
+  }
+
+  if(this.format) {
+    jQuery.extend(opt, this.format(data, opt));
+  }
+  return opt;
+};
+
+/**
+ * Wrapper for all ajax requests
+ *
+ * @type {Object}
+ */
+App.ajax = {
+  /**
+   * Send ajax request
+   *
+   * @param {Object} config
+   * @return {Boolean}
+   *
+   * config fields:
+   *  name - url-key in the urls-object *required*
+   *  sender - object that send request (need for proper callback initialization) *required*
+   *  data - object with data for url-format
+   *  success - method-name for ajax success response callback
+   *  error - method-name for ajax error response callback
+   */
+  send: function(config) {
+    if (!config.sender) {
+      console.warn('Ajax sender should be defined!');
+      return false;
+    }
+
+    // default parameters
+    var params = {
+      clusterName: App.router.get('clusterController.clusterName')
+    };
+
+    // extend default parameters with provided
+    if (config.data) {
+      jQuery.extend(params, config.data);
+    }
+
+    var opt = {};
+    opt = formatRequest.call(urls[config.name], params);
+
+    // object sender should be provided for processing success and error responses
+    opt.success = function(data) {
+      if(config.success) {
+        config.sender[config.success](data, opt);
+      }
+    };
+    opt.error = function(request, ajaxOptions, error) {
+      if (config.error) {
+        config.sender[config.error](request, ajaxOptions, error, opt);
+      }
+    };
+    $.ajax(opt);
+  }
+}