171 self.sources.insert(0, self.system_source) |
170 self.sources.insert(0, self.system_source) |
172 # cache eid -> type / source |
171 # cache eid -> type / source |
173 self._type_source_cache = {} |
172 self._type_source_cache = {} |
174 # cache (extid, source uri) -> eid |
173 # cache (extid, source uri) -> eid |
175 self._extid_cache = {} |
174 self._extid_cache = {} |
176 # create the hooks manager |
|
177 self.hm = HooksManager(self.schema) |
|
178 # open some connections pools |
175 # open some connections pools |
179 self._available_pools = Queue.Queue() |
176 self._available_pools = Queue.Queue() |
180 self._available_pools.put_nowait(ConnectionsPool(self.sources)) |
177 self._available_pools.put_nowait(ConnectionsPool(self.sources)) |
181 if config.read_instance_schema: |
178 if config.read_instance_schema: |
182 # normal start: load the instance schema from the database |
179 # normal start: load the instance schema from the database |
183 self.fill_schema() |
180 self.fill_schema() |
184 elif config.bootstrap_schema: |
181 elif config.bootstrap_schema: |
185 # usually during repository creation |
182 # usually during repository creation |
186 self.warning("set fs instance'schema as bootstrap schema") |
183 self.warning("set fs instance'schema as bootstrap schema") |
187 config.bootstrap_cubes() |
184 config.bootstrap_cubes() |
188 self.set_bootstrap_schema(self.config.load_schema()) |
185 self.set_schema(self.config.load_schema(), resetvreg=False) |
189 # need to load the Any and CWUser entity types |
186 # need to load the Any and CWUser entity types |
190 self.vreg.schema = self.schema |
187 self.vreg.schema = self.schema |
191 etdirectory = join(CW_SOFTWARE_ROOT, 'entities') |
188 etdirectory = join(CW_SOFTWARE_ROOT, 'entities') |
192 self.vreg.init_registration([etdirectory]) |
189 self.vreg.init_registration([etdirectory]) |
193 self.vreg.load_file(join(etdirectory, '__init__.py'), |
190 self.vreg.load_file(join(etdirectory, '__init__.py'), |
220 self.pools = [] |
217 self.pools = [] |
221 for i in xrange(config['connections-pool-size']): |
218 for i in xrange(config['connections-pool-size']): |
222 self.pools.append(ConnectionsPool(self.sources)) |
219 self.pools.append(ConnectionsPool(self.sources)) |
223 self._available_pools.put_nowait(self.pools[-1]) |
220 self._available_pools.put_nowait(self.pools[-1]) |
224 self._shutting_down = False |
221 self._shutting_down = False |
|
222 self.hm = vreg['hooks'] |
225 if not (config.creating or config.repairing): |
223 if not (config.creating or config.repairing): |
226 # call instance level initialisation hooks |
224 # call instance level initialisation hooks |
227 self.hm.call_hooks('server_startup', repo=self) |
225 self.hm.call_hooks('server_startup', repo=self) |
228 # register a task to cleanup expired session |
226 # register a task to cleanup expired session |
229 self.looping_task(self.config['session-time']/3., |
227 self.looping_task(self.config['session-time']/3., |
230 self.clean_sessions) |
228 self.clean_sessions) |
231 CW_EVENT_MANAGER.bind('after-registry-load', self.reset_hooks) |
|
232 |
229 |
233 # internals ############################################################### |
230 # internals ############################################################### |
234 |
231 |
235 def get_source(self, uri, source_config): |
232 def get_source(self, uri, source_config): |
236 source_config['uri'] = uri |
233 source_config['uri'] = uri |
246 self.schema = schema |
243 self.schema = schema |
247 if resetvreg: |
244 if resetvreg: |
248 # full reload of all appobjects |
245 # full reload of all appobjects |
249 self.vreg.reset() |
246 self.vreg.reset() |
250 self.vreg.set_schema(schema) |
247 self.vreg.set_schema(schema) |
251 self.reset_hooks() |
|
252 |
|
253 def reset_hooks(self): |
|
254 self.hm.set_schema(self.schema) |
|
255 self.hm.register_system_hooks(self.config) |
|
256 # instance specific hooks |
|
257 if self.config.instance_hooks: |
|
258 self.info('loading instance hooks') |
|
259 self.hm.register_hooks(self.config.load_hooks(self.vreg)) |
|
260 |
248 |
261 def fill_schema(self): |
249 def fill_schema(self): |
262 """lod schema from the repository""" |
250 """lod schema from the repository""" |
263 from cubicweb.server.schemaserial import deserialize_schema |
251 from cubicweb.server.schemaserial import deserialize_schema |
264 self.info('loading schema from the repository') |
252 self.info('loading schema from the repository') |
265 appschema = CubicWebSchema(self.config.appid) |
253 appschema = CubicWebSchema(self.config.appid) |
266 self.set_bootstrap_schema(self.config.load_bootstrap_schema()) |
254 self.set_schema(self.config.load_bootstrap_schema(), resetvreg=False) |
267 self.debug('deserializing db schema into %s %#x', appschema.name, id(appschema)) |
255 self.debug('deserializing db schema into %s %#x', appschema.name, id(appschema)) |
268 session = self.internal_session() |
256 session = self.internal_session() |
269 try: |
257 try: |
270 try: |
258 try: |
271 deserialize_schema(appschema, session) |
259 deserialize_schema(appschema, session) |
275 import traceback |
263 import traceback |
276 traceback.print_exc() |
264 traceback.print_exc() |
277 raise Exception('Is the database initialised ? (cause: %s)' % |
265 raise Exception('Is the database initialised ? (cause: %s)' % |
278 (ex.args and ex.args[0].strip() or 'unknown')), \ |
266 (ex.args and ex.args[0].strip() or 'unknown')), \ |
279 None, sys.exc_info()[-1] |
267 None, sys.exc_info()[-1] |
280 self.info('set the actual schema') |
|
281 # XXX have to do this since CWProperty isn't in the bootstrap schema |
|
282 # it'll be redone in set_schema |
|
283 self.set_bootstrap_schema(appschema) |
|
284 # 2.49 migration |
|
285 if exists(join(self.config.apphome, 'vc.conf')): |
|
286 session.set_pool() |
|
287 if not 'template' in file(join(self.config.apphome, 'vc.conf')).read(): |
|
288 # remaning from cubicweb < 2.38... |
|
289 session.execute('DELETE CWProperty X WHERE X pkey "system.version.template"') |
|
290 session.commit() |
|
291 finally: |
268 finally: |
292 session.close() |
269 session.close() |
|
270 self.set_schema(appschema) |
293 self.config.init_cubes(self.get_cubes()) |
271 self.config.init_cubes(self.get_cubes()) |
294 self.set_schema(appschema) |
|
295 |
|
296 def set_bootstrap_schema(self, schema): |
|
297 """disable hooks when setting a bootstrap schema, but restore |
|
298 the configuration for the next time |
|
299 """ |
|
300 config = self.config |
|
301 # XXX refactor |
|
302 config.core_hooks = False |
|
303 config.usergroup_hooks = False |
|
304 config.schema_hooks = False |
|
305 config.notification_hooks = False |
|
306 config.instance_hooks = False |
|
307 self.set_schema(schema, resetvreg=False) |
|
308 config.core_hooks = True |
|
309 config.usergroup_hooks = True |
|
310 config.schema_hooks = True |
|
311 config.notification_hooks = True |
|
312 config.instance_hooks = True |
|
313 |
272 |
314 def start_looping_tasks(self): |
273 def start_looping_tasks(self): |
315 assert isinstance(self._looping_tasks, list), 'already started' |
274 assert isinstance(self._looping_tasks, list), 'already started' |
316 for i, (interval, func, args) in enumerate(self._looping_tasks): |
275 for i, (interval, func, args) in enumerate(self._looping_tasks): |
317 self._looping_tasks[i] = task = LoopTask(interval, func, args) |
276 self._looping_tasks[i] = task = LoopTask(interval, func, args) |
873 eid = self.system_source.create_eid(session) |
832 eid = self.system_source.create_eid(session) |
874 self._extid_cache[cachekey] = eid |
833 self._extid_cache[cachekey] = eid |
875 self._type_source_cache[eid] = (etype, source.uri, extid) |
834 self._type_source_cache[eid] = (etype, source.uri, extid) |
876 entity = source.before_entity_insertion(session, extid, etype, eid) |
835 entity = source.before_entity_insertion(session, extid, etype, eid) |
877 if source.should_call_hooks: |
836 if source.should_call_hooks: |
878 self.hm.call_hooks('before_add_entity', etype, session, entity) |
837 self.hm.call_hooks('before_add_entity', session, entity=entity) |
879 # XXX call add_info with complete=False ? |
838 # XXX call add_info with complete=False ? |
880 self.add_info(session, entity, source, extid) |
839 self.add_info(session, entity, source, extid) |
881 source.after_entity_insertion(session, extid, entity) |
840 source.after_entity_insertion(session, extid, entity) |
882 if source.should_call_hooks: |
841 if source.should_call_hooks: |
883 self.hm.call_hooks('after_add_entity', etype, session, entity) |
842 self.hm.call_hooks('after_add_entity', session, entity=entity) |
884 else: |
843 else: |
885 # minimal meta-data |
844 # minimal meta-data |
886 session.execute('SET X is E WHERE X eid %(x)s, E name %(name)s', |
845 session.execute('SET X is E WHERE X eid %(x)s, E name %(name)s', |
887 {'x': entity.eid, 'name': entity.id}, 'x') |
846 {'x': entity.eid, 'name': entity.id}, 'x') |
888 session.commit(reset_pool) |
847 session.commit(reset_pool) |
996 print 'ADD entity', etype, entity.eid, dict(entity) |
955 print 'ADD entity', etype, entity.eid, dict(entity) |
997 entity._is_saved = False # entity has an eid but is not yet saved |
956 entity._is_saved = False # entity has an eid but is not yet saved |
998 relations = [] |
957 relations = [] |
999 # if inlined relations are specified, fill entity's related cache to |
958 # if inlined relations are specified, fill entity's related cache to |
1000 # avoid unnecessary queries |
959 # avoid unnecessary queries |
1001 for attr in entity.keys(): |
960 entity.edited_attributes = set(entity) |
|
961 for attr in entity.edited_attributes: |
1002 rschema = eschema.subject_relation(attr) |
962 rschema = eschema.subject_relation(attr) |
1003 if not rschema.is_final(): # inlined relation |
963 if not rschema.is_final(): # inlined relation |
1004 relations.append((attr, entity[attr])) |
964 relations.append((attr, entity[attr])) |
1005 if source.should_call_hooks: |
965 if source.should_call_hooks: |
1006 self.hm.call_hooks('before_add_entity', etype, session, entity) |
966 self.hm.call_hooks('before_add_entity', session, entity=entity) |
1007 entity.edited_attributes = entity.keys() |
|
1008 entity.set_defaults() |
967 entity.set_defaults() |
1009 entity.check(creation=True) |
968 entity.check(creation=True) |
1010 source.add_entity(session, entity) |
969 source.add_entity(session, entity) |
1011 if source.uri != 'system': |
970 if source.uri != 'system': |
1012 extid = source.get_extid(entity) |
971 extid = source.get_extid(entity) |
1033 # set inline relation cache before call to after_add_entity |
992 # set inline relation cache before call to after_add_entity |
1034 for attr, value in relations: |
993 for attr, value in relations: |
1035 session.update_rel_cache_add(entity.eid, attr, value) |
994 session.update_rel_cache_add(entity.eid, attr, value) |
1036 # trigger after_add_entity after after_add_relation |
995 # trigger after_add_entity after after_add_relation |
1037 if source.should_call_hooks: |
996 if source.should_call_hooks: |
1038 self.hm.call_hooks('after_add_entity', etype, session, entity) |
997 self.hm.call_hooks('after_add_entity', session, entity=entity) |
1039 # call hooks for inlined relations |
998 # call hooks for inlined relations |
1040 for attr, value in relations: |
999 for attr, value in relations: |
1041 self.hm.call_hooks('before_add_relation', attr, session, |
1000 self.hm.call_hooks('before_add_relation', session, |
1042 entity.eid, attr, value) |
1001 eidfrom=entity.eid, rtype=attr, eidto=value) |
1043 self.hm.call_hooks('after_add_relation', attr, session, |
1002 self.hm.call_hooks('after_add_relation', session, |
1044 entity.eid, attr, value) |
1003 eidfrom=entity.eid, rtype=attr, eidto=value) |
1045 return entity.eid |
1004 return entity.eid |
1046 |
1005 |
1047 def glob_update_entity(self, session, entity, edited_attributes): |
1006 def glob_update_entity(self, session, entity, edited_attributes): |
1048 """replace an entity in the repository |
1007 """replace an entity in the repository |
1049 the type and the eid of an entity must not be changed |
1008 the type and the eid of an entity must not be changed |
1072 if previous_value: |
1031 if previous_value: |
1073 previous_value = previous_value[0][0] # got a result set |
1032 previous_value = previous_value[0][0] # got a result set |
1074 if previous_value == entity[attr]: |
1033 if previous_value == entity[attr]: |
1075 previous_value = None |
1034 previous_value = None |
1076 else: |
1035 else: |
1077 self.hm.call_hooks('before_delete_relation', attr, |
1036 self.hm.call_hooks('before_delete_relation', session, |
1078 session, entity.eid, attr, |
1037 eidfrom=entity.eid, rtype=attr, |
1079 previous_value) |
1038 eidto=previous_value) |
1080 relations.append((attr, entity[attr], previous_value)) |
1039 relations.append((attr, entity[attr], previous_value)) |
1081 source = self.source_from_eid(entity.eid, session) |
1040 source = self.source_from_eid(entity.eid, session) |
1082 if source.should_call_hooks: |
1041 if source.should_call_hooks: |
1083 # call hooks for inlined relations |
1042 # call hooks for inlined relations |
1084 for attr, value, _ in relations: |
1043 for attr, value, _ in relations: |
1085 self.hm.call_hooks('before_add_relation', attr, session, |
1044 self.hm.call_hooks('before_add_relation', session, |
1086 entity.eid, attr, value) |
1045 eidfrom=entity.eid, rtype=attr, eidto=value) |
1087 if not only_inline_rels: |
1046 if not only_inline_rels: |
1088 self.hm.call_hooks('before_update_entity', etype, session, |
1047 self.hm.call_hooks('before_update_entity', session, entity=entity) |
1089 entity) |
|
1090 source.update_entity(session, entity) |
1048 source.update_entity(session, entity) |
1091 if not only_inline_rels: |
1049 if not only_inline_rels: |
1092 if need_fti_update and self.do_fti: |
1050 if need_fti_update and self.do_fti: |
1093 # reindex the entity only if this query is updating at least |
1051 # reindex the entity only if this query is updating at least |
1094 # one indexable attribute |
1052 # one indexable attribute |
1095 FTIndexEntityOp(session, entity=entity) |
1053 FTIndexEntityOp(session, entity=entity) |
1096 if source.should_call_hooks: |
1054 if source.should_call_hooks: |
1097 self.hm.call_hooks('after_update_entity', etype, session, |
1055 self.hm.call_hooks('after_update_entity', session, entity=entity) |
1098 entity) |
|
1099 if source.should_call_hooks: |
1056 if source.should_call_hooks: |
1100 for attr, value, prevvalue in relations: |
1057 for attr, value, prevvalue in relations: |
1101 # if the relation is already cached, update existant cache |
1058 # if the relation is already cached, update existant cache |
1102 relcache = entity.relation_cached(attr, 'subject') |
1059 relcache = entity.relation_cached(attr, 'subject') |
1103 if prevvalue: |
1060 if prevvalue: |
1104 self.hm.call_hooks('after_delete_relation', attr, session, |
1061 self.hm.call_hooks('after_delete_relation', session, |
1105 entity.eid, attr, prevvalue) |
1062 eidfrom=entity.eid, rtype=attr, eidto=prevvalue) |
1106 if relcache is not None: |
1063 if relcache is not None: |
1107 session.update_rel_cache_del(entity.eid, attr, prevvalue) |
1064 session.update_rel_cache_del(entity.eid, attr, prevvalue) |
1108 del_existing_rel_if_needed(session, entity.eid, attr, value) |
1065 del_existing_rel_if_needed(session, entity.eid, attr, value) |
1109 if relcache is not None: |
1066 if relcache is not None: |
1110 session.update_rel_cache_add(entity.eid, attr, value) |
1067 session.update_rel_cache_add(entity.eid, attr, value) |
1111 else: |
1068 else: |
1112 entity.set_related_cache(attr, 'subject', |
1069 entity.set_related_cache(attr, 'subject', |
1113 session.eid_rset(value)) |
1070 session.eid_rset(value)) |
1114 self.hm.call_hooks('after_add_relation', attr, session, |
1071 self.hm.call_hooks('after_add_relation', session, |
1115 entity.eid, attr, value) |
1072 eidfrom=entity.eid, rtype=attr, eidto=value) |
1116 |
1073 |
1117 def glob_delete_entity(self, session, eid): |
1074 def glob_delete_entity(self, session, eid): |
1118 """delete an entity and all related entities from the repository""" |
1075 """delete an entity and all related entities from the repository""" |
1119 # call delete_info before hooks |
1076 # call delete_info before hooks |
1120 self._prepare_delete_info(session, eid) |
1077 self._prepare_delete_info(session, eid) |
1123 print 'DELETE entity', etype, eid |
1080 print 'DELETE entity', etype, eid |
1124 if eid == 937: |
1081 if eid == 937: |
1125 server.DEBUG |= (server.DBG_SQL | server.DBG_RQL | server.DBG_MORE) |
1082 server.DEBUG |= (server.DBG_SQL | server.DBG_RQL | server.DBG_MORE) |
1126 source = self.sources_by_uri[uri] |
1083 source = self.sources_by_uri[uri] |
1127 if source.should_call_hooks: |
1084 if source.should_call_hooks: |
1128 self.hm.call_hooks('before_delete_entity', etype, session, eid) |
1085 entity = session.entity_from_eid(eid) |
|
1086 self.hm.call_hooks('before_delete_entity', session, entity=entity) |
1129 self._delete_info(session, eid) |
1087 self._delete_info(session, eid) |
1130 source.delete_entity(session, etype, eid) |
1088 source.delete_entity(session, etype, eid) |
1131 if source.should_call_hooks: |
1089 if source.should_call_hooks: |
1132 self.hm.call_hooks('after_delete_entity', etype, session, eid) |
1090 self.hm.call_hooks('after_delete_entity', session, entity=entity) |
1133 # don't clear cache here this is done in a hook on commit |
1091 # don't clear cache here this is done in a hook on commit |
1134 |
1092 |
1135 def glob_add_relation(self, session, subject, rtype, object): |
1093 def glob_add_relation(self, session, subject, rtype, object): |
1136 """add a relation to the repository""" |
1094 """add a relation to the repository""" |
1137 if server.DEBUG & server.DBG_REPO: |
1095 if server.DEBUG & server.DBG_REPO: |
1138 print 'ADD relation', subject, rtype, object |
1096 print 'ADD relation', subject, rtype, object |
1139 source = self.locate_relation_source(session, subject, rtype, object) |
1097 source = self.locate_relation_source(session, subject, rtype, object) |
1140 if source.should_call_hooks: |
1098 if source.should_call_hooks: |
1141 del_existing_rel_if_needed(session, subject, rtype, object) |
1099 del_existing_rel_if_needed(session, subject, rtype, object) |
1142 self.hm.call_hooks('before_add_relation', rtype, session, |
1100 self.hm.call_hooks('before_add_relation', session, |
1143 subject, rtype, object) |
1101 eidfrom=subject, rtype=rtype, eidto=object) |
1144 source.add_relation(session, subject, rtype, object) |
1102 source.add_relation(session, subject, rtype, object) |
1145 rschema = self.schema.rschema(rtype) |
1103 rschema = self.schema.rschema(rtype) |
1146 session.update_rel_cache_add(subject, rtype, object, rschema.symetric) |
1104 session.update_rel_cache_add(subject, rtype, object, rschema.symetric) |
1147 if source.should_call_hooks: |
1105 if source.should_call_hooks: |
1148 self.hm.call_hooks('after_add_relation', rtype, session, |
1106 self.hm.call_hooks('after_add_relation', session, |
1149 subject, rtype, object) |
1107 eidfrom=subject, rtype=rtype, eidto=object) |
1150 |
1108 |
1151 def glob_delete_relation(self, session, subject, rtype, object): |
1109 def glob_delete_relation(self, session, subject, rtype, object): |
1152 """delete a relation from the repository""" |
1110 """delete a relation from the repository""" |
1153 if server.DEBUG & server.DBG_REPO: |
1111 if server.DEBUG & server.DBG_REPO: |
1154 print 'DELETE relation', subject, rtype, object |
1112 print 'DELETE relation', subject, rtype, object |
1155 source = self.locate_relation_source(session, subject, rtype, object) |
1113 source = self.locate_relation_source(session, subject, rtype, object) |
1156 if source.should_call_hooks: |
1114 if source.should_call_hooks: |
1157 self.hm.call_hooks('before_delete_relation', rtype, session, |
1115 self.hm.call_hooks('before_delete_relation', session, |
1158 subject, rtype, object) |
1116 eidfrom=subject, rtype=rtype, eidto=object) |
1159 source.delete_relation(session, subject, rtype, object) |
1117 source.delete_relation(session, subject, rtype, object) |
1160 rschema = self.schema.rschema(rtype) |
1118 rschema = self.schema.rschema(rtype) |
1161 session.update_rel_cache_del(subject, rtype, object, rschema.symetric) |
1119 session.update_rel_cache_del(subject, rtype, object, rschema.symetric) |
1162 if rschema.symetric: |
1120 if rschema.symetric: |
1163 # on symetric relation, we can't now in which sense it's |
1121 # on symetric relation, we can't now in which sense it's |
1164 # stored so try to delete both |
1122 # stored so try to delete both |
1165 source.delete_relation(session, object, rtype, subject) |
1123 source.delete_relation(session, object, rtype, subject) |
1166 if source.should_call_hooks: |
1124 if source.should_call_hooks: |
1167 self.hm.call_hooks('after_delete_relation', rtype, session, |
1125 self.hm.call_hooks('after_delete_relation', session, |
1168 subject, rtype, object) |
1126 eidfrom=subject, rtype=rtype, eidto=object) |
1169 |
1127 |
1170 |
1128 |
1171 # pyro handling ########################################################### |
1129 # pyro handling ########################################################### |
1172 |
1130 |
1173 def pyro_register(self, host=''): |
1131 def pyro_register(self, host=''): |