[FIX] views inheritance: deleting a non-existing attribute must be a no-op
[odoo/odoo.git] / openerp / service / __init__.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
6 #    Copyright (C) 2010-2013 OpenERP SA (<http://www.openerp.com>)
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU Affero General Public License as
10 #    published by the Free Software Foundation, either version 3 of the
11 #    License, or (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU Affero General Public License for more details.
17 #
18 #    You should have received a copy of the GNU Affero General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 import logging
24 import os
25 import signal
26 import subprocess
27 import sys
28 import threading
29 import time
30
31 import cron
32 import wsgi_server
33
34 import openerp
35 import openerp.modules
36 import openerp.netsvc
37 import openerp.osv
38 from openerp.release import nt_service_name
39 import openerp.tools
40 from openerp.tools.misc import stripped_sys_argv
41
42 import common
43 import db
44 import model
45 import report
46
47 #.apidoc title: RPC Services
48
49 """ Classes of this module implement the network protocols that the
50     OpenERP server uses to communicate with remote clients.
51
52     Some classes are mostly utilities, whose API need not be visible to
53     the average user/developer. Study them only if you are about to
54     implement an extension to the network protocols, or need to debug some
55     low-level behavior of the wire.
56 """
57
58 _logger = logging.getLogger(__name__)
59
60 def load_server_wide_modules():
61     for m in openerp.conf.server_wide_modules:
62         try:
63             openerp.modules.module.load_openerp_module(m)
64         except Exception:
65             msg = ''
66             if m == 'web':
67                 msg = """
68 The `web` module is provided by the addons found in the `openerp-web` project.
69 Maybe you forgot to add those addons in your addons_path configuration."""
70             _logger.exception('Failed to load server-wide module `%s`.%s', m, msg)
71
72 start_internal_done = False
73 main_thread_id = threading.currentThread().ident
74
75 def start_internal():
76     global start_internal_done
77     if start_internal_done:
78         return
79     openerp.netsvc.init_logger()
80
81     load_server_wide_modules()
82     start_internal_done = True
83
84 def start_services():
85     """ Start all services including http, and cron """
86     start_internal()
87     # Start the WSGI server.
88     wsgi_server.start_service()
89     # Start the main cron thread.
90     if not openerp.evented:
91         cron.start_service()
92
93 def stop_services():
94     """ Stop all services. """
95     # stop services
96     if not openerp.evented:
97         cron.stop_service()
98     wsgi_server.stop_service()
99
100     _logger.info("Initiating shutdown")
101     _logger.info("Hit CTRL-C again or send a second signal to force the shutdown.")
102
103     # Manually join() all threads before calling sys.exit() to allow a second signal
104     # to trigger _force_quit() in case some non-daemon threads won't exit cleanly.
105     # threading.Thread.join() should not mask signals (at least in python 2.5).
106     me = threading.currentThread()
107     _logger.debug('current thread: %r', me)
108     for thread in threading.enumerate():
109         _logger.debug('process %r (%r)', thread, thread.isDaemon())
110         if thread != me and not thread.isDaemon() and thread.ident != main_thread_id:
111             while thread.isAlive():
112                 _logger.debug('join and sleep')
113                 # Need a busyloop here as thread.join() masks signals
114                 # and would prevent the forced shutdown.
115                 thread.join(0.05)
116                 time.sleep(0.05)
117
118     _logger.debug('--')
119     openerp.modules.registry.RegistryManager.delete_all()
120     logging.shutdown()
121
122 def start_services_workers():
123     import openerp.service.workers
124     openerp.multi_process = True
125     openerp.service.workers.Multicorn(openerp.service.wsgi_server.application).run()
126
127 def _reexec():
128     """reexecute openerp-server process with (nearly) the same arguments"""
129     if openerp.tools.osutil.is_running_as_nt_service():
130         subprocess.call('net stop {0} && net start {0}'.format(nt_service_name), shell=True)
131     exe = os.path.basename(sys.executable)
132     args = stripped_sys_argv()
133     if not args or args[0] != exe:
134         args.insert(0, exe)
135     os.execv(sys.executable, args)
136
137 def restart_server():
138     if openerp.multi_process:
139         raise NotImplementedError("Multicorn is not supported (but gunicorn was)")
140         pid = openerp.wsgi.core.arbiter_pid
141         os.kill(pid, signal.SIGHUP)
142     else:
143         if os.name == 'nt':
144             def reborn():
145                 stop_services()
146                 _reexec()
147
148             # run in a thread to let the current thread return response to the caller.
149             threading.Thread(target=reborn).start()
150         else:
151             openerp.phoenix = True
152             os.kill(os.getpid(), signal.SIGINT)
153
154 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: