14 from logging import getLogger |
14 from logging import getLogger |
15 from time import time, clock |
15 from time import time, clock |
16 from itertools import count |
16 from itertools import count |
17 |
17 |
18 from logilab.common.logging_ext import set_log_methods |
18 from logilab.common.logging_ext import set_log_methods |
|
19 from logilab.common.decorators import monkeypatch |
|
20 from logilab.common.deprecation import deprecated |
|
21 |
19 from cubicweb import ETYPE_NAME_MAP, ConnectionError, RequestSessionMixIn |
22 from cubicweb import ETYPE_NAME_MAP, ConnectionError, RequestSessionMixIn |
20 from cubicweb.cwvreg import CubicWebRegistry, MulCnxCubicWebRegistry |
23 from cubicweb import cwvreg, cwconfig |
21 from cubicweb.cwconfig import CubicWebNoAppConfiguration |
|
22 |
24 |
23 _MARKER = object() |
25 _MARKER = object() |
24 |
26 |
25 def _fake_property_value(self, name): |
27 def _fake_property_value(self, name): |
26 try: |
28 try: |
27 return super(dbapi.DBAPIRequest, self).property_value(name) |
29 return super(dbapi.DBAPIRequest, self).property_value(name) |
28 except KeyError: |
30 except KeyError: |
29 return '' |
31 return '' |
|
32 |
|
33 def _fix_cls_attrs(reg, appobject): |
|
34 appobject.vreg = reg.vreg |
|
35 appobject.schema = reg.schema |
|
36 appobject.config = reg.config |
|
37 |
|
38 def multiple_connections_fix(): |
|
39 """some monkey patching necessary when an application has to deal with |
|
40 several connections to different repositories. It tries to hide buggy class |
|
41 attributes since classes are not designed to be shared among multiple |
|
42 registries. |
|
43 """ |
|
44 defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None] |
|
45 orig_select_best = defaultcls.orig_select_best = defaultcls.select_best |
|
46 @monkeypatch(defaultcls) |
|
47 def select_best(self, appobjects, *args, **kwargs): |
|
48 """return an instance of the most specific object according |
|
49 to parameters |
|
50 |
|
51 raise NoSelectableObject if no object apply |
|
52 """ |
|
53 for appobjectcls in appobjects: |
|
54 _fix_cls_attrs(self, appobjectcls) |
|
55 selected = orig_select_best(self, appobjects, *args, **kwargs) |
|
56 # redo the same thing on the instance so it won't use equivalent class |
|
57 # attributes (which may change) |
|
58 _fix_cls_attrs(self, selected) |
|
59 return selected |
|
60 |
|
61 etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes'] |
|
62 orig_etype_class = etypescls.orig_etype_class = etypescls.etype_class |
|
63 @monkeypatch(defaultcls) |
|
64 def etype_class(self, etype): |
|
65 """return an entity class for the given entity type. |
|
66 Try to find out a specific class for this kind of entity or |
|
67 default to a dump of the class registered for 'Any' |
|
68 """ |
|
69 usercls = orig_etype_class(self, etype) |
|
70 if etype == 'Any': |
|
71 return usercls |
|
72 usercls.e_schema = self.schema.eschema(etype) |
|
73 return usercls |
|
74 |
|
75 def multiple_connections_unfix(): |
|
76 defaultcls = cwvreg.VRegistry.REGISTRY_FACTORY[None] |
|
77 defaultcls.select_best = defaultcls.orig_select_best |
|
78 etypescls = cwvreg.VRegistry.REGISTRY_FACTORY['etypes'] |
|
79 etypescls.etype_class = etypescls.orig_etype_class |
30 |
80 |
31 class ConnectionProperties(object): |
81 class ConnectionProperties(object): |
32 def __init__(self, cnxtype=None, lang=None, close=True, log=False): |
82 def __init__(self, cnxtype=None, lang=None, close=True, log=False): |
33 self.cnxtype = cnxtype or 'pyro' |
83 self.cnxtype = cnxtype or 'pyro' |
34 self.lang = lang |
84 self.lang = lang |
49 if method == 'inmemory': |
99 if method == 'inmemory': |
50 # get local access to the repository |
100 # get local access to the repository |
51 from cubicweb.server.repository import Repository |
101 from cubicweb.server.repository import Repository |
52 return Repository(config, vreg=vreg) |
102 return Repository(config, vreg=vreg) |
53 else: # method == 'pyro' |
103 else: # method == 'pyro' |
54 from Pyro import core, naming |
|
55 from Pyro.errors import NamingError, ProtocolError |
|
56 core.initClient(banner=0) |
|
57 nsid = ':%s.%s' % (config['pyro-ns-group'], database) |
|
58 locator = naming.NameServerLocator() |
|
59 # resolve the Pyro object |
104 # resolve the Pyro object |
|
105 from logilab.common.pyro_ext import ns_get_proxy |
60 try: |
106 try: |
61 nshost, nsport = config['pyro-ns-host'], config['pyro-ns-port'] |
107 return ns_get_proxy(database, |
62 uri = locator.getNS(nshost, nsport).resolve(nsid) |
108 defaultnsgroup=config['pyro-ns-group'], |
63 except ProtocolError: |
109 nshost=config['pyro-ns-host']) |
64 raise ConnectionError('Could not connect to the Pyro name server ' |
110 except Exception, ex: |
65 '(host: %s:%i)' % (nshost, nsport)) |
111 raise ConnectionError(str(ex)) |
66 except NamingError: |
|
67 raise ConnectionError('Could not get repository for %s ' |
|
68 '(not registered in Pyro), ' |
|
69 'you may have to restart your server-side ' |
|
70 'instance' % nsid) |
|
71 return core.getProxyForURI(uri) |
|
72 |
112 |
73 def repo_connect(repo, login, password, cnxprops=None): |
113 def repo_connect(repo, login, password, cnxprops=None): |
74 """Constructor to create a new connection to the CubicWeb repository. |
114 """Constructor to create a new connection to the CubicWeb repository. |
75 |
115 |
76 Returns a Connection instance. |
116 Returns a Connection instance. |
80 cnx = Connection(repo, cnxid, cnxprops) |
120 cnx = Connection(repo, cnxid, cnxprops) |
81 if cnxprops.cnxtype == 'inmemory': |
121 if cnxprops.cnxtype == 'inmemory': |
82 cnx.vreg = repo.vreg |
122 cnx.vreg = repo.vreg |
83 return cnx |
123 return cnx |
84 |
124 |
85 def connect(database=None, login=None, password=None, host=None, |
125 def connect(database=None, login=None, password=None, host=None, group=None, |
86 group=None, cnxprops=None, port=None, setvreg=True, mulcnx=True, |
126 cnxprops=None, setvreg=True, mulcnx=True, initlog=True): |
87 initlog=True): |
|
88 """Constructor for creating a connection to the CubicWeb repository. |
127 """Constructor for creating a connection to the CubicWeb repository. |
89 Returns a Connection object. |
128 Returns a Connection object. |
90 |
129 |
91 When method is 'pyro' and setvreg is True, use a special registry class |
130 When method is 'pyro', setvreg is True, try to deal with connections to |
92 (MulCnxCubicWebRegistry) made to deal with connections to differents instances |
131 differents instances in the same process unless specified otherwise by |
93 in the same process unless specified otherwise by setting the mulcnx to |
132 setting the mulcnx to False. |
94 False. |
|
95 """ |
133 """ |
96 config = CubicWebNoAppConfiguration() |
134 config = cwconfig.CubicWebNoAppConfiguration() |
97 if host: |
135 if host: |
98 config.global_set_option('pyro-ns-host', host) |
136 config.global_set_option('pyro-ns-host', host) |
99 if port: |
|
100 config.global_set_option('pyro-ns-port', port) |
|
101 if group: |
137 if group: |
102 config.global_set_option('pyro-ns-group', group) |
138 config.global_set_option('pyro-ns-group', group) |
103 cnxprops = cnxprops or ConnectionProperties() |
139 cnxprops = cnxprops or ConnectionProperties() |
104 method = cnxprops.cnxtype |
140 method = cnxprops.cnxtype |
105 repo = get_repository(method, database, config=config) |
141 repo = get_repository(method, database, config=config) |
106 if method == 'inmemory': |
142 if method == 'inmemory': |
107 vreg = repo.vreg |
143 vreg = repo.vreg |
108 elif setvreg: |
144 elif setvreg: |
109 if mulcnx: |
145 if mulcnx: |
110 vreg = MulCnxCubicWebRegistry(config, initlog=initlog) |
146 multiple_connections_fix() |
111 else: |
147 vreg = cwvreg.CubicWebVRegistry(config, initlog=initlog) |
112 vreg = CubicWebRegistry(config, initlog=initlog) |
|
113 schema = repo.get_schema() |
148 schema = repo.get_schema() |
114 for oldetype, newetype in ETYPE_NAME_MAP.items(): |
149 for oldetype, newetype in ETYPE_NAME_MAP.items(): |
115 if oldetype in schema: |
150 if oldetype in schema: |
116 print 'aliasing', newetype, 'to', oldetype |
151 print 'aliasing', newetype, 'to', oldetype |
117 schema._entities[newetype] = schema._entities[oldetype] |
152 schema._entities[newetype] = schema._entities[oldetype] |
432 hm.register_system_hooks(config) |
467 hm.register_system_hooks(config) |
433 # instance specific hooks |
468 # instance specific hooks |
434 if self._repo.config.instance_hooks: |
469 if self._repo.config.instance_hooks: |
435 hm.register_hooks(config.load_hooks(self.vreg)) |
470 hm.register_hooks(config.load_hooks(self.vreg)) |
436 |
471 |
|
472 load_vobjects = deprecated()(load_appobjects) |
|
473 |
437 def use_web_compatible_requests(self, baseurl, sitetitle=None): |
474 def use_web_compatible_requests(self, baseurl, sitetitle=None): |
438 """monkey patch DBAPIRequest to fake a cw.web.request, so you should |
475 """monkey patch DBAPIRequest to fake a cw.web.request, so you should |
439 able to call html views using rset from a simple dbapi connection. |
476 able to call html views using rset from a simple dbapi connection. |
440 |
477 |
441 You should call `load_vobjects` at some point to register those views. |
478 You should call `load_appobjects` at some point to register those views. |
442 """ |
479 """ |
443 from cubicweb.web.request import CubicWebRequestBase as cwrb |
480 from cubicweb.web.request import CubicWebRequestBase as cwrb |
444 DBAPIRequest.build_ajax_replace_url = cwrb.build_ajax_replace_url.im_func |
481 DBAPIRequest.build_ajax_replace_url = cwrb.build_ajax_replace_url.im_func |
445 DBAPIRequest.list_form_param = cwrb.list_form_param.im_func |
482 DBAPIRequest.list_form_param = cwrb.list_form_param.im_func |
446 DBAPIRequest.property_value = _fake_property_value |
483 DBAPIRequest.property_value = _fake_property_value |
474 eid, login, groups, properties = self._repo.user_info(self.sessionid, |
511 eid, login, groups, properties = self._repo.user_info(self.sessionid, |
475 props) |
512 props) |
476 if req is None: |
513 if req is None: |
477 req = self.request() |
514 req = self.request() |
478 rset = req.eid_rset(eid, 'CWUser') |
515 rset = req.eid_rset(eid, 'CWUser') |
479 user = self.vreg.etype_class('CWUser')(req, rset, row=0, groups=groups, |
516 user = self.vreg['etypes'].etype_class('CWUser')(req, rset, row=0, |
480 properties=properties) |
517 groups=groups, |
|
518 properties=properties) |
481 user['login'] = login # cache login |
519 user['login'] = login # cache login |
482 return user |
520 return user |
483 |
521 |
484 def __del__(self): |
522 def __del__(self): |
485 """close the remote connection if necessary""" |
523 """close the remote connection if necessary""" |