From b303bfe5a4bacc5f75cc5710ee9435a6110cf1bb Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Thu, 31 Jan 2013 14:10:51 +0100 Subject: [PATCH] [REF] service: A new openerp.service.rpc decorator is provided to replace the ExportService class. bzr revid: vmt@openerp.com-20130131131051-5189susswxlshp29 --- doc/index.rst | 1 + doc/routing.rst | 18 ++++++++++++++++++ openerp/netsvc.py | 20 ++++++++++---------- openerp/service/__init__.py | 18 ++++++++++++++++++ openerp/service/wsgi_server.py | 8 ++++++++ openerp/tests/common.py | 1 + openerp/tests/test_xmlrpc.py | 8 ++++++++ 7 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 doc/routing.rst diff --git a/doc/index.rst b/doc/index.rst index 33474e2da57..daa212d07e0 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -35,6 +35,7 @@ OpenERP Server API :maxdepth: 1 api_models.rst + routing.rst Concepts '''''''' diff --git a/doc/routing.rst b/doc/routing.rst new file mode 100644 index 00000000000..1e4f76d25b8 --- /dev/null +++ b/doc/routing.rst @@ -0,0 +1,18 @@ +.. _routing: + +Routing +======= + +The OpenERP framework, as an HTTP server, serves a few hard-coded URLs +(``models``, ``db``, ...) to expose RPC endpoints. When running the web addons +(which is almost always the case), it also serves URLs without them being RPC +endpoints. + +In older version of OpenERP, adding RPC endpoints was done by subclassing the +``openerp.netsvc.ExportService`` class. Adding WSGI handlers was done by +registering them with the ``openerp.wsgi.register_wsgi_handler()`` function. + +Starting with OpenERP 7.1, exposing a new arbitrary WSGI handler is done with +the ``openerp.service.handler`` decorator while adding an RPC endpoint is done +with the ``openerp.service.rpc`` decorator. + diff --git a/openerp/netsvc.py b/openerp/netsvc.py index 14ee0d67215..6b70dc972a8 100644 --- a/openerp/netsvc.py +++ b/openerp/netsvc.py @@ -29,7 +29,6 @@ import logging.handlers import os import platform import release -import socket import sys import threading import time @@ -242,16 +241,17 @@ def dispatch_rpc(service_name, method, params): threading.current_thread().uid = None threading.current_thread().dbname = None - service = None - if service_name == 'object': - service = openerp.service.model - if service_name == 'db': - service = openerp.service.db if service_name == 'common': - service = openerp.service.common - if service_name == 'report': - service = openerp.service.report - result = service.dispatch(method, params) + dispatch = openerp.service.common.dispatch + elif service_name == 'db': + dispatch = openerp.service.db.dispatch + elif service_name == 'object': + dispatch = openerp.service.model.dispatch + elif service_name == 'report': + dispatch = openerp.service.report.dispatch + else: + dispatch = openerp.service.wsgi_server.rpc_handlers.get(service_name) + result = dispatch(method, params) if rpc_request_flag or rpc_response_flag: end_time = time.time() diff --git a/openerp/service/__init__.py b/openerp/service/__init__.py index 9db73223029..db5d4542bf4 100644 --- a/openerp/service/__init__.py +++ b/openerp/service/__init__.py @@ -150,4 +150,22 @@ def restart_server(): openerp.phoenix = True os.kill(os.getpid(), signal.SIGINT) +def handler(): + """TODO""" + def decorator(f): + wsgi_server.register_wsgi_handler(f) + return decorator + +def route(url): + """TODO""" + def decorator(f): + pass # TODO Same as handler() but register the handler under a specific url. + return decorator + +def rpc(endpoint): + """TODO""" + def decorator(f): + wsgi_server.register_rpc_endpoint(endpoint, f) + return decorator + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/service/wsgi_server.py b/openerp/service/wsgi_server.py index f55f9de6669..8d9d7b4a83c 100644 --- a/openerp/service/wsgi_server.py +++ b/openerp/service/wsgi_server.py @@ -34,6 +34,7 @@ import errno import logging import os import signal +import socket import sys import threading import traceback @@ -373,6 +374,8 @@ def parse_http_response(s): # WSGI handlers registered through the register_wsgi_handler() function below. module_handlers = [] +# RPC endpoints registered through the register_rpc_endpoint() function below. +rpc_handlers = {} def register_wsgi_handler(handler): """ Register a WSGI handler. @@ -382,6 +385,11 @@ def register_wsgi_handler(handler): """ module_handlers.append(handler) +def register_rpc_endpoint(endpoint, handler): + """ Register a handler for a given RPC enpoint. + """ + rpc_handlers[endpoint] = handler + def application_unproxied(environ, start_response): """ WSGI entry point.""" openerp.service.start_internal() diff --git a/openerp/tests/common.py b/openerp/tests/common.py index 3f0143ef9df..f8472e81fcf 100644 --- a/openerp/tests/common.py +++ b/openerp/tests/common.py @@ -133,6 +133,7 @@ class RpcCase(unittest2.TestCase): self.proxy.common_60 = xmlrpclib.ServerProxy(url_60 + 'common') self.proxy.db_60 = xmlrpclib.ServerProxy(url_60 + 'db') self.proxy.object_60 = xmlrpclib.ServerProxy(url_60 + 'object') + #self.proxy.edi_60 = xmlrpclib.ServerProxy(url_60 + 'edi') # Use the new (6.1) API. self.proxy.url_61 = url_61 = 'http://%s:%d/openerp/xmlrpc/1/' % (HOST, PORT) diff --git a/openerp/tests/test_xmlrpc.py b/openerp/tests/test_xmlrpc.py index 1198c0fa2f2..8c9d6911e7b 100644 --- a/openerp/tests/test_xmlrpc.py +++ b/openerp/tests/test_xmlrpc.py @@ -64,6 +64,14 @@ class test_xmlrpc(common.RpcCase): ids = proxy.execute(ADMIN_USER_ID, ADMIN_PASSWORD, 'search', [], {}) assert ids + # This test was written to test the creation of a new RPC endpoint, not + # really for the EDI itself. + #def test_xmlrpc_import_edi_document(self): + # """ Try to call an EDI method. """ + # msg_re = 'EDI Document is empty!' + # with self.assertRaisesRegexp(Exception, msg_re): + # self.proxy.edi_60.import_edi_document(DB, ADMIN_USER_ID, ADMIN_PASSWORD, {}) + def test_zz_xmlrpc_drop_database(self): """ Simulate a OpenERP client requesting the deletion of a database.