Restructure code in preparation for sharing with new TKO.

-Change structure of RPC handler.  New rpc_handler.py is independent of AFE and will eventually be moved to a common dir, along with the JSON and JSON-RPC stuff.  rpc_handler.py now has a class structure that allows multiple apps to instantiate their own RPC handlers with different interfaces.

-Pull out generic model extensions from models.py into model_logic.py.  This too will be moved to a common dir.


git-svn-id: http://test.kernel.org/svn/autotest/trunk@1566 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/frontend/afe/rpc_handler.py b/frontend/afe/rpc_handler.py
index ecf730a..f9ba2e2 100644
--- a/frontend/afe/rpc_handler.py
+++ b/frontend/afe/rpc_handler.py
@@ -9,54 +9,64 @@
 import traceback, pydoc
 
 from frontend.afe.json_rpc import serviceHandler
-from frontend.afe import rpc_interface, rpc_utils, site_rpc_interface
+from frontend.afe import rpc_utils
 
-# since site_rpc_interface is later in the list, its methods will override those
-# of rpc_interface
-RPC_INTERFACE_MODULES = (rpc_interface, site_rpc_interface)
 
 class RpcMethodHolder(object):
-        'Dummy class to hold RPC interface methods as attributes.'
-
-rpc_methods = RpcMethodHolder()
-
-dispatcher = serviceHandler.ServiceHandler(rpc_methods)
-
-# get documentation for rpc_interface we can send back to the user
-html_doc = pydoc.html.document(rpc_interface)
-
-def rpc_handler(request):
-        rpc_utils.set_user(request.afe_user)
-	response = django.http.HttpResponse()
-	if len(request.POST):
-		response.write(dispatcher.handleRequest(request.raw_post_data))
-	else:
-		response.write(html_doc)
-
-	response['Content-length'] = str(len(response.content))
-	return response
+		'Dummy class to hold RPC interface methods as attributes.'
 
 
-def allow_keyword_args(f):
-	"""\
-	Decorator to allow a function to take keyword args even though the RPC
-	layer doesn't support that.  The decorated function assumes its last
-	argument is a dictionary of keyword args and passes them to the original
-	function as keyword args.
-	"""
-	def new_fn(*args):
-		assert args
-		keyword_args = args[-1]
-		args = args[:-1]
-		return f(*args, **keyword_args)
-	new_fn.func_name = f.func_name
-	return new_fn
+class RpcHandler(object):
+	def __init__(self, rpc_interface_modules, document_module=None):
+		self._rpc_methods = RpcMethodHolder()
+		self._dispatcher = serviceHandler.ServiceHandler(
+		    self._rpc_methods)
 
-# decorate all functions in rpc_interface to take keyword args
-function_type = type(rpc_handler) # could be any function
-for module in RPC_INTERFACE_MODULES:
-	for name in dir(module):
-		thing = getattr(module, name)
-		if type(thing) is function_type:
-			decorated_function = allow_keyword_args(thing)
-			setattr(rpc_methods, name, decorated_function)
+		# store all methods from interface modules
+		for module in rpc_interface_modules:
+			self._grab_methods_from(module)
+
+		# get documentation for rpc_interface we can send back to the
+		# user
+		if document_module is None:
+			document_module = rpc_interface_modules[0]
+		self.html_doc = pydoc.html.document(document_module)
+
+
+	def handle_rpc_request(self, request):
+		response = django.http.HttpResponse()
+		if len(request.POST):
+			response.write(self._dispatcher.handleRequest(
+			    request.raw_post_data))
+		else:
+			response.write(self.html_doc)
+
+		response['Content-length'] = str(len(response.content))
+		return response
+
+
+	@staticmethod
+	def _allow_keyword_args(f):
+		"""\
+		Decorator to allow a function to take keyword args even though
+		the RPC layer doesn't support that.  The decorated function
+		assumes its last argument is a dictionary of keyword args and
+		passes them to the original function as keyword args.
+		"""
+		def new_fn(*args):
+			assert args
+			keyword_args = args[-1]
+			args = args[:-1]
+			return f(*args, **keyword_args)
+		new_fn.func_name = f.func_name
+		return new_fn
+
+
+	def _grab_methods_from(self, module):
+		for name in dir(module):
+			attribute = getattr(module, name)
+			if not callable(attribute):
+				continue
+			decorated_function = (
+			    RpcHandler._allow_keyword_args(attribute))
+			setattr(self._rpc_methods, name, decorated_function)