Reorganization of the host selection UI in the AFE create job view.
* refactor HostSelector into view/presenter (except for tables, which will need to be separately refactored)
* reorganize view into a tabbed format with a unified hostname input tab, a metahost tab and a browse hosts tab, with the selected hosts table alongside as before

Minor changes:
* extracted SimplifiedList interface from MultiListSelectPresenter to a top-level entity
* made ExtendedListBox implement the SimplifiedList interface and got rid of the SimplifiedListWrapper decorator class
* rewrote ArrayDataSource to use a TreeSet so it's actually efficient.  this should speed up working with large host selections.
* edited JSONObjectComparator to be consistent with equals() for safety when using with TreeSet
* small change to how widths get set on TabPanels in AFE. rather than setting 100% width on all tab panels' contents using CSS, set it explicitly in CustomTabPanel.  there's a quirk with browser layout where a 100% width div inside a table cell will have it's width set larger than the cell containing it.  it happens on IE6, FF3 and Chrome so it's probably not something that's going to change.  It does go away with the "border box" model, which can be enabled with nonstandard CSS attributes, but it's easy enough to work around here that that's not worth it.

Signed-off-by: Steve Howard <showard@google.com>


git-svn-id: http://test.kernel.org/svn/autotest/trunk@3673 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/frontend/afe/json_rpc/serviceHandler.py b/frontend/afe/json_rpc/serviceHandler.py
index 3936b3a..4265c56 100644
--- a/frontend/afe/json_rpc/serviceHandler.py
+++ b/frontend/afe/json_rpc/serviceHandler.py
@@ -72,15 +72,33 @@
         self.service=service
 
     def dispatchRequest(self, request):
+        """
+        Invoke a json RPC call from a decoded json request.
+        @param request: a decoded json_request
+        @returns a dictionary with keys id, result, err and err_traceback
+        """
+        results = {}
+        results['id'] = None
+        results['result'] = None
+        results['err'] = None
+        results['err_traceback'] = None
+
         try:
+            results['id'] = self._getRequestId(request)
             methName = request['method']
             args = request['params']
         except KeyError:
             raise BadServiceRequest(request)
 
-        meth = self.findServiceEndpoint(methName)
-        result = self.invokeServiceEndpoint(meth, args)
-        return result
+        try:
+            meth = self.findServiceEndpoint(methName)
+            results['result'] = self.invokeServiceEndpoint(meth, args)
+        except Exception, err:
+            results['err_traceback'] = traceback.format_exc()
+            results['err'] = err
+
+        return results
+
 
     def _getRequestId(self, request):
         try:
@@ -88,21 +106,12 @@
         except KeyError:
             raise BadServiceRequest(request)
 
+
     def handleRequest(self, jsonRequest):
-        id_ = None
-        result = None
-        err = None
-        err_traceback = None
-
         request = self.translateRequest(jsonRequest)
+        results = self.dispatchRequest(request)
+        return self.translateResult(results)
 
-        try:
-            id_ = self._getRequestId(request)
-            result = self.dispatchRequest(request)
-        except Exception, err:
-            err_traceback = traceback.format_exc()
-
-        return self.translateResult(result, err, err_traceback, id_)
 
     @staticmethod
     def translateRequest(data):
@@ -124,20 +133,31 @@
         return meth(*args)
 
     @staticmethod
-    def translateResult(rslt, err, err_traceback, id_):
-        if err is not None:
-            err = {"name": err.__class__.__name__, "message":str(err),
-                   "traceback": err_traceback}
-            rslt = None
+    def translateResult(result_dict):
+        """
+        @param result_dict: a dictionary containing the result, error, traceback
+                            and id.
+        @returns translated json result
+        """
+        if result_dict['err'] is not None:
+            error_name = result_dict['err'].__class__.__name__
+            result_dict['err'] = {'name': error_name,
+                                  'message': str(result_dict['err']),
+                                  'traceback': result_dict['err_traceback']}
+            result_dict['result'] = None
 
         try:
-            data = json_encoder.encode({"result":rslt,"id":id_,"error":err})
+            json_dict = {'result': result_dict['result'],
+                         'id': result_dict['id'],
+                         'error': result_dict['err'] }
+            data = json_encoder.encode(json_dict)
         except TypeError, e:
             err_traceback = traceback.format_exc()
             print err_traceback
             err = {"name" : "JSONEncodeException",
                    "message" : "Result Object Not Serializable",
                    "traceback" : err_traceback}
-            data = json_encoder.encode({"result":None, "id":id_,"error":err})
+            data = json_encoder.encode({"result":None, "id":result_dict['id'],
+                                        "error":err})
 
         return data