1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 """
31 This module contains the implementation of the registry as well as associated
32 interface declarations. The registry is the core component of EOxServer that
33 links different parts of the system together. The registry allows for
34 components to bind to implementations of registered interfaces. It supports
35 modularity, extensibility and flexibility of EOxServer.
36 """
37
38 import imp
39 import os.path
40 from inspect import isclass
41
42 from django.conf import settings
43
44 from eoxserver.core.models import Component
45 from eoxserver.core.exceptions import (InternalError, ConfigError,
46 ImplementationNotFound, ImplementationAmbiguous,
47 ImplementationDisabled, BindingMethodError
48 )
49 from eoxserver.core.interfaces import *
50 from eoxserver.core.util.filetools import findFiles, pathToModuleName
53 """
54 The :class:`Registry` class implements the functionalities for detecting,
55 registering, finding and binding to implementations of registered
56 interfaces. It is instantiated by :class:`eoxserver.core.system.System`
57 during the startup process.
58
59 The constructor expects a :class:`~.Config` instance as input. The values
60 will be validate and read using a :class:`RegistryConfigReader` instance.
61 """
62
64 self.config = config
65
66 self.__intf_index = {}
67 self.__impl_index = {}
68 self.__kvp_index = {}
69 self.__fact_index = {}
70
71 - def bind(self, impl_id):
72 """
73 Bind to the implementation with ID ``impl_id``. This method returns
74 a new instance of the requested implementation if it is enabled.
75
76 If the implementation is disabled :exc:`~.ImplementationDisabled` will
77 be raised. If the ID ``impl_id`` is not known to the registry
78 :exc:`ImplementationNotFound` will be raised.
79 """
80
81 if impl_id in self.__impl_index:
82 if self.__impl_index[impl_id]["enabled"]:
83 return self.__impl_index[impl_id]["cls"]()
84 else:
85 raise ImplementationDisabled(
86 "Implementation '%s' is disabled." % impl_id
87 )
88 else:
89 raise ImplementationNotFound(impl_id)
90
92 """
93 Get an implementation instance from the factory with ID ``factory_id``
94 using the parameter dictionary ``params``. This is a shortcut which
95 binds to the factory and calls its :meth:`~FactoryInterface.get` method
96 then.
97
98 :exc:`~.InternalError` will be raised if required arguments are missing
99 in the ``params`` dictionary. :exc:`~.ImplementationDisabled` will be
100 raised if either the factory or the appropriate implementation are
101 disabled. :exc:`~.ImplementationNotFound` will be raised if either
102 the factory or the appropriate implementation are unknown to the
103 registry.
104 """
105
106 factory = self.bind(factory_id)
107
108 return factory.get(**params)
109
111 """
112 This method finds implementations based of a registered interface
113 with ID ``intf_id`` using the parameter dictionary ``params`` and
114 returns an instance of the matching implementation. This
115 works only for the ``kvp`` and ``testing`` binding methods, in other
116 cases :exc:`~.BindingMethodError` will be raised.
117
118 If the binding method of the interface is ``kvp`` the ``params``
119 dictionary must map the registry keys defined in the interface
120 declaration to values. The KVP combination will be compared with the
121 values given in the respective implementations. If a matching
122 implementation is found an instance will be returned, otherwise
123 :exc:`~.ImplementationNotFound` is raised. If the class found is
124 disabled :exc:`~.ImplementationDisabled` is raised.
125
126 If the binding method of the interface is ``testing`` the ``params``
127 dictionary will be passed to the :meth:`~TestingInterface.test` method
128 of the respective implementations. If no implementation matches
129 :exc:`~.ImplementationNotFound` will be raised. If more than one are
130 found :exc:`~.ImplementationAmbiguous` will be raised.
131 """
132
133 if intf_id in self.__intf_index:
134 InterfaceCls = self.__intf_index[intf_id]["intf"]
135 if InterfaceCls.getBindingMethod() == "direct":
136 raise BindingMethodError("You have to bind directly to implementations of '%s'" % intf_id)
137 elif InterfaceCls.getBindingMethod() == "kvp":
138 ImplementationCls = self.__find_by_values(
139 InterfaceCls, params
140 )
141 elif InterfaceCls.getBindingMethod() == "testing":
142 ImplementationCls = self.__find_by_test(
143 self.__intf_index[intf_id]["impls"],
144 params
145 )
146 elif InterfaceCls.getBindingMethod() == "factory":
147 raise BindingMethodError("The registry cannot generate '%s' implementations. Use getFromFactory() instead." % intf_id)
148
149 return ImplementationCls()
150 else:
151 raise InternalError("Unknown interface ID '%s'" % intf_id)
152
154 """
155 This method returns a list of implementations of a given interface.
156 It requires the interface ID as a parameter.
157
158 Furthermore, a parameter dictionary can be passed to the method. The
159 results will then be filtered according to these parameters. The
160 dictionary does not have to contain all the parameters defined by the
161 interface; in case some parameters are omitted, the result list may
162 contain several different implementations.
163
164 Third is an optional ``include_disabled`` parameter with defaults to
165 ``False``. If ``True``, disabled implementations will be reported as
166 well.
167
168 An :exc:`~.InternalError` is raised if parameters are passed to the
169 method that are not defined in the interface declaration or not
170 recognized by the interface :meth:`test` method.
171 """
172
173 if intf_id in self.__intf_index:
174 InterfaceCls = self.__intf_index[intf_id]["intf"]
175 if params is not None:
176 _params = params
177 else:
178 _params = {}
179
180 if InterfaceCls.getBindingMethod() == "direct" or \
181 InterfaceCls.getBindingMethod() == "factory":
182 impls = self.__find_all_impls(
183 self.__intf_index[intf_id]["impls"],
184 include_disabled
185 )
186 elif InterfaceCls.getBindingMethod() == "kvp":
187 impls = self.__find_all_by_values(
188 self.__intf_index[intf_id]["impls"],
189 _params,
190 include_disabled
191 )
192 elif InterfaceCls.getBindingMethod() == "testing":
193 impls = self.__find_all_by_test(
194 self.__intf_index[intf_id]["impls"],
195 _params,
196 include_disabled
197 )
198
199 return impls
200 else:
201 raise InternalError("Unknown interface ID '%s'" % intf_id)
202
204 """
205 This method returns a list of implementation IDs for a given interface.
206 It requires the interface ID as a parameter.
207
208 Furthermore, a parameter dictionary can be passed to the method. The
209 results will then be filtered according to these parameters. The
210 dictionary does not have to contain all the parameters defined by the
211 interface; in case some parameters are omitted, the result list may
212 contain several different implementations.
213
214 Third is an optional ``include_disabled`` parameter with defaults to
215 ``False``. If ``True``, disabled implementations will be reported as
216 well.
217
218 An :exc:`~.InternalError` is raised if parameters are passed to the
219 method that are not defined in the interface declaration or not
220 recognized by the interface :meth:`test` method.
221 """
222 impls = self.findImplementations(intf_id, params, include_disabled)
223
224 return [impl.__get_impl_id__() for impl in impls]
225
226 - def getRegistryValues(self, intf_id, registry_key, filter=None, include_disabled=False):
227 """
228 This method returns a list of registry values of implementations
229 of an interface with ``interface_id`` and a registry key
230 ``registry_key`` defined in the interface declaration.
231
232 With the ``filter`` argument you can impose certain restrictions on the
233 implementations (registry values) to be returned. It is expected to
234 contain a dictionary of registry keys and values that the implementation
235 must expose to be included.
236
237 Using the ``include_disabled`` argument you can determine whether.
238
239 This method raises :exc:`~.InternalError` if the interface ID is
240 unknown.
241 """
242 if intf_id in self.__intf_index:
243 InterfaceCls = self.__intf_index[intf_id]["intf"]
244
245 if InterfaceCls.getBindingMethod() == "kvp":
246 if registry_key not in InterfaceCls.getRegistryKeys():
247 raise InternalError("Interface '%s' has no registry key '%s'" % (
248 intf_id, registry_key
249 ))
250
251 else:
252 if filter:
253 _filter = filter
254 else:
255 _filter = {}
256
257 impls = self.__find_all_by_values(
258 self.__intf_index[intf_id]["impls"],
259 _filter
260 )
261
262 return [impl.__get_kvps__()[registry_key] for impl in impls]
263 else:
264 raise InternalError("Binding method of interface '%s' is '%s', not 'kvp'." % (
265 intf_id,
266 InterfaceCls.getBindingMethod()
267 ))
268 else:
269 raise InternalError("Unknown interface ID '%s'" % intf_id)
270
272 """
273 Returns a list of implementations for a given factory.
274
275 Raises :exc:`~.InternalError` if the factory is not found in the
276 registry.
277 """
278 factory_id = factory.__get_impl_id__()
279
280 if factory_id in self.__fact_index:
281 return [entry["cls"] for entry in self.__fact_index[factory_id]]
282 else:
283 raise InternalError("Unknown Factory ID '%s'." % factory_id)
284
286 """
287 This method loads the registry, i.e. it scans the modules specified
288 in the configuration for interfaces and implementations. It is
289 invoked by the ``~.System`` class upon initialization.
290
291 You should *never* invoke this method directly. Always use
292 :meth:`~.System.init` to initialize and :meth:`~.System.getRegistry` to
293 access the registry.
294
295 There are three configuration settings taken into account.
296
297 First, the ``system_modules`` setting in ``default.conf``. These
298 modules are always loaded and cannot be left aside in individual
299 instances.
300
301 Second, the ``module_dirs`` setting in the local configuration of the
302 instance (``eoxserver.conf``) is taken into account. This expected to
303 be a comma-separated list of directories. These directories and all
304 the directory trees underneath them are searched for Python modules.
305
306 Third, the ``modules`` setting in ``eoxserver.conf``. This is
307 expecte to be a comma-separated list of module names which shall be
308 loaded.
309
310 All modules specified or detected by scanning directories will be
311 loaded and searched for interfaces descending from
312 :class:`RegisteredInterface` as well as their implementations. These
313 will be automatically included in the registry and accessible using
314 the different binding methods provided.
315
316 As a last step, the registry is synchronized with the database. This
317 means that the implementation looks up the entries for the different
318 implementations in the database and determines whether they are
319 enabled or not. If it finds an implementation which has not yet been
320 registered it will be saved to the database but disabled by default.
321 """
322
323 reader = RegistryConfigReader(self.config)
324 reader.validate()
325
326 system_modules = reader.getSystemModules()
327 module_dirs = reader.getModuleDirectories()
328 modules = reader.getModules()
329
330
331 for module_dir in module_dirs:
332
333
334 modules.extend(self.__find_modules(module_dir))
335
336
337 for module_name in system_modules:
338 self.__load_module(module_name, strict=True)
339
340 for module_name in modules:
341 self.__load_module(module_name)
342
343 self.__synchronize()
344
345 self.validate()
346
348 """
349 This method is intended to validate the component configuration.
350
351 It looks up all implementations of :class:`ComponentManagerInterface`
352 and calls their respective :meth:`~ComponentManagerInterface.validate`
353 methods.
354
355 At the moment, no component managers are implemented, so this
356 method does not have any effects.
357 """
358 msgs = []
359
360 Managers = self.findImplementations("core.registry.ComponentManager")
361
362 for Manager in Managers:
363 manager = Manager()
364 try:
365 manager.validate(self)
366 except ConfigError, e:
367 msgs.append(str(e))
368
369 if len(msgs) > 0:
370 raise ConfigError("\n".join(msgs))
371
373 """
374 This saves the registry configuration to the database. This means
375 the status of the enabled / disabled flag for each implementation
376 will be saved overriding any previous settings stored.
377 """
378 self.validate()
379
380 self.__save_to_db()
381
383 """
384 Returns the implementation status (``True`` for enabled, ``False`` for
385 disabled) for the given implementation ID ``impl_id``.
386
387 Raises :exc:`~.InternalError` if the implementation ID is
388 unknown.
389 """
390 if impl_id in self.__impl_index:
391 return self.__impl_index[impl_id]["enabled"]
392 else:
393 raise InternalError("Unknown implementation ID '%s'" % impl_id)
394
396 """
397 Changes the implementation status to enabled for implementation ID
398 ``impl_id``. Note that this change is not automatically stored to
399 the database (you have to call :meth:`save` to do that).
400
401 Raises :exc:`~.InternalError` if the implementation ID is unknown.
402 """
403 if impl_id in self.__impl_index:
404 self.__impl_index[impl_id]["enabled"] = True
405 else:
406 raise InternalError("Unknown implementation ID '%s'" % impl_id)
407
409 """
410 Changed the implementation status to disable for implementation ID
411 ``impl_id``. Note that this change is not automatically stored to
412 the database (you have to call :meth:`save` to do that).
413
414 Raises :exc:`~.InternalError` if the implementation ID is unknown.
415 """
416 if impl_id in self.__impl_index:
417 self.__impl_index[impl_id]["enabled"] = False
418 else:
419 raise InternalError("Unknown implementation ID '%s'" % impl_id)
420
434
445
473
487
501
503 if include_disabled:
504 return [entry["cls"] for entry in entries]
505 else:
506 return [entry["cls"] for entry in filter(
507 lambda entry: entry["enabled"], entries
508 )]
509
529
531 impls = []
532
533 for entry in entries:
534 if entry["enabled"] or include_disabled:
535 impl_dict = entry["cls"].__get_kvps__()
536 matches = True
537
538 for key, value in kvp_dict.items():
539 if key in impl_dict:
540 if value != impl_dict[key]:
541 matches = False
542 break
543 else:
544 raise InternalError("Key '%s' not found in registry values of implementation '%s'" % (
545 key, entry["impl_id"]
546 ))
547
548 if matches:
549 impls.append(entry["cls"])
550
551 return impls
552
553 - def __find_by_test(self, entries, test_params, include_disabled=False):
562
564 impls = []
565
566 for entry in entries:
567 if entry["enabled"] or include_disabled:
568 if entry["cls"]().test(test_params):
569 impls.append(entry["cls"])
570
571 return impls
572
585
587 logging.debug("Registry.__register_interface(): intf_id: %s" % InterfaceCls.getInterfaceId())
588
589 intf_id = InterfaceCls.getInterfaceId()
590
591 if intf_id in self.__intf_index:
592 if InterfaceCls is not self.__intf_index[intf_id]["intf"]:
593 raise InternalError("Duplicate interface ID '%s' for '%s' in module '%s' and '%s' in module '%s'" % (
594 intf_id,
595 InterfaceCls.__name__,
596 InterfaceCls.__module__,
597 self.__intf_index[intf_id]["intf"].__name__,
598 self.__intf_index[intf_id]["intf"].__module__
599 ))
600 else:
601 self.__intf_index[intf_id] = {
602 "intf": InterfaceCls,
603 "impls": []
604 }
605
607 intf_id = ImplementationCls.__get_intf_id__()
608 impl_id = ImplementationCls.__get_impl_id__()
609
610 if intf_id in self.__intf_index:
611 if self.__intf_index[intf_id]["intf"] is ImplementationCls.__ifclass__:
612 self.__intf_index[intf_id]["impls"].append(
613 self.__get_index_entry(ImplementationCls)
614 )
615 else:
616 raise InternalError("Duplicate Interface ID '%s' for '%s' in '%s' and '%s' in '%s'." % (
617 intf_id,
618 ImplementationCls.__ifclass__.__name__,
619 ImplementationCls.__ifclass__.__module__,
620 self.__intf_index[intf_id]["intf"].__name__,
621 self.__intf_index[intf_id]["intf"].__module__
622 ))
623 else:
624 self.__intf_index[intf_id] = {
625 "intf": ImplementationCls.__ifclass__,
626 "impls": [self.__get_index_entry(ImplementationCls)]
627 }
628
642
666
668 if ImplementationCls.__ifclass__.getBindingMethod() == "factory":
669
670
671 for factory_id in ImplementationCls.__get_factory_ids__():
672 logging.debug("Registry.__add_to_fact_index(): adding '%s' to '%s'" % (
673 ImplementationCls.__get_impl_id__(),
674 factory_id
675 ))
676
677 if factory_id in self.__fact_index:
678 self.__fact_index[factory_id].append(
679 self.__get_index_entry(ImplementationCls)
680 )
681 else:
682 self.__fact_index[factory_id] = [
683 self.__get_index_entry(ImplementationCls)
684 ]
685
686 - def __get_index_entry(self, ImplementationCls, enabled=False):
687 return {
688 "cls": ImplementationCls,
689 "impl_id": ImplementationCls.__get_impl_id__(),
690 "enabled": enabled
691 }
692
694 key_list = [intf_id]
695
696 if registry_keys is None:
697 raise InternalError("Interface '%s' has no registry keys." % intf_id)
698
699 for registry_key in registry_keys:
700 if registry_key in kvp_dict:
701 key_list.append((kvp_dict[registry_key], registry_key))
702 else:
703 raise InternalError("Missing registry key '%s'." % registry_key)
704
705 return tuple(key_list)
706
708
709
710 abs_path = os.path.abspath(dir)
711
712 if abs_path.startswith(settings.PROJECT_DIR) or \
713 abs_path.startswith(self.config.getEOxSPath()):
714 module_files = findFiles(abs_path, "*.py")
715
716 try:
717 return [pathToModuleName(module_file) for module_file in module_files]
718 except InternalError, e:
719 raise ConfigError(str(e))
720 else:
721 raise ConfigError("Can search for extending modules and plugins in subdirecories of EOxServer distribution and instance dir only.")
722
724 try:
725
726 module = __import__(module_name, globals(), locals(), [])
727
728 for sub_module_name in module_name.split(".")[1:]:
729 module = getattr(module, sub_module_name)
730
731
732
733 except Exception, e:
734 if strict:
735 raise InternalError("Could not load required module '%s'. Error was: %s" % (
736 module_name, str(e)
737 ))
738 else:
739
740
741
742 logging.warning("Could not load module '%s'. Error was: %s" % (
743 module_name, str(e)
744 ))
745 return
746
747 for attr in module.__dict__.values():
748 if isclass(attr) and issubclass(attr, RegisteredInterface):
749 self.__register_interface(attr)
750 elif hasattr(attr, "__ifclass__") and\
751 hasattr(attr, "__rconf__") and\
752 hasattr(attr, "__get_intf_id__") and\
753 hasattr(attr, "__get_impl_id__") and\
754 hasattr(attr, "__get_kvps__"):
755 self.__register_implementation(attr)
756
773
774 @classmethod
781
782
783 @classmethod
786
788 """
789 This class is the base class for all interfaces to be registered in the
790 registry. All interfaces whose implementations shall be registered must
791 be derived from :class:`RegisteredInterface`.
792
793 All interfaces derived from :class:`RegisteredInterface` must contain a
794 ``REGISTRY_CONF`` dictionary. See the introduction for details.
795 """
796
797 __metaclass__ = RegisteredInterfaceMetaClass
798
799 REGISTRY_CONF = {
800 "name": "Abstract Registered Interface base class",
801 "intf_id": "core.registy.Registered",
802 "binding_method": "kvp"
803 }
804
805 @classmethod
807 class_dict = super(RegisteredInterface, InterfaceCls)._getClassDict(ImplementationCls, bases)
808
809 if hasattr(ImplementationCls, "REGISTRY_CONF"):
810 conf = ImplementationCls.REGISTRY_CONF
811 else:
812 raise InternalError("Missing 'REGISTRY_CONF' configuration dictionary in implementing class '%s'." % ImplementationCls.__name__)
813
814 InterfaceCls._validateImplementationConf(conf)
815
816 intf_id = InterfaceCls.getInterfaceId()
817 impl_id = conf["impl_id"]
818 kvps = conf.get("registry_values")
819 factory_ids = conf.get("factory_ids", ())
820
821 class_dict.update({
822 "__rconf__": conf,
823 "__get_intf_id__": classmethod(lambda cls: intf_id),
824 "__get_impl_id__": classmethod(lambda cls: impl_id),
825 "__get_kvps__": classmethod(lambda cls: kvps),
826 "__get_factory_ids__": classmethod(lambda cls: factory_ids)
827 })
828
829 return class_dict
830
831 @classmethod
833 if "name" not in conf:
834 raise InternalError("Missing 'name' parameter in implementation configuration dictionary.")
835
836 if "impl_id" not in conf:
837 raise InternalError("Missing 'impl_id' parameter in implementation configuration dictionary.")
838
839 if InterfaceCls.getBindingMethod() == "kvp":
840 if "registry_values" not in conf:
841 raise InternalError("Missing 'registry_values' parameter in implementation configuration dictionary.")
842
843 if not InterfaceCls._keysMatch(conf["registry_values"].keys(), InterfaceCls.getRegistryKeys()):
844 raise InternalError("Registry keys in implementation configuration dictionary for '%s' do not match interface definition" % conf["impl_id"])
845
846 @classmethod
847 - def _keysMatch(InterfaceCls, impl_keys, intf_keys):
848 return (len(impl_keys) == 0 and len(intf_keys) == 0) or\
849 (all(map(lambda key: key in intf_keys, impl_keys)) and \
850 all(map(lambda key: key in impl_keys, intf_keys)))
851
852 @classmethod
855
856 @classmethod
859
860 @classmethod
862 if "registry_keys" in cls.__rconf__:
863 return cls.__rconf__["registry_keys"]
864 else:
865 return []
866
868 """
869 This class is a descendant of :class:`RegisteredInterface` that adds
870 a single method. It is used for binding by test, which enables binding
871 decisions that cannot easily be implemented by key-value-pair comparisons.
872
873 .. method:: test(params)
874
875 This method is invoked by the registry when determining which
876 implementation to bind to. Based on the parameter dictionary ``params``
877 the method shall decide whether the implementation is applicable and
878 return ``True``. If it is not applicable the method shall return
879 ``False``.
880 """
881 REGISTRY_CONF = {
882 "name": "Registered Testing Interface",
883 "intf_id": "core.registry.Testing",
884 "binding_method": "testing"
885 }
886
887 test = Method(
888 DictArg("params"),
889 returns=BoolArg("@return")
890 )
891
893 """
894 This is the basic interface for factories. It is a descendant of
895 :class:`RegisteredInterface`.
896
897 .. method:: get(**kwargs)
898
899 This method shall return an instance of an implementation that matches
900 the parameters given as keyword arguments. The set of arguments
901 understood depends on the individual factory and can be found in the
902 respective documentation.
903
904 The method shall raise an exception if no matching implementation or
905 instance thereof can be found, or if the choice is ambiguous.
906
907 .. method:: find(**kwargs)
908
909 This method shall return a list of implementation instances that
910 matches the parameters given as keyword arguments. The set of arguments
911 understood depends on the individual factory and can be found in the
912 respective documentation.
913 """
914
915 REGISTRY_CONF = {
916 "name": "Registered Factory Interface",
917 "intf_id": "core.registry.Factory",
918 "binding_method": "direct"
919 }
920
921 get = Method(
922 KwArgs("kwargs"),
923 returns=Arg("@return")
924 )
925
926 find = Method(
927 KwArgs("kwargs"),
928 returns=ListArg("@return")
929 )
930
932 """
933 This interface is not in use at the moment. It was intended to provide
934 an API for controlling the status of a larger set of implementations and
935 their dependencies, though the concept has never been elaborated.
936 """
937 REGISTRY_CONF = {
938 "name": "Component Manager Interface",
939 "intf_id": "core.registry.ComponentManager",
940 "binding_method": "direct"
941 }
942
943 getName = Method(
944 returns=StringArg("@returns")
945 )
946
947 getId = Method(
948 returns=StringArg("@returns")
949 )
950
951 enable = Method(
952 ObjectArg("registry", arg_class=Registry),
953 BoolArg("cascade", default=False)
954 )
955
956 disable = Method(
957 ObjectArg("registry", arg_class=Registry),
958 BoolArg("cascade", default=False)
959 )
960
961 createRelations = Method()
962
963 enableRelation = Method(
964 StringArg("obj_id")
965 )
966
967 disableRelation = Method(
968 StringArg("obj_id")
969 )
970
971 notify = Method(
972 ObjectArg("resource"),
973 StringArg("event")
974 )
975
977 """
978 This class provides some functions for reading configuration settings used
979 by the :class:`Registry`.
980 """
983
985 """
986 Validates the configuration; a no-op at the moment.
987 """
988 pass
989
991 """
992 This method returns a list of dotted names of system modules. The
993 values are read from ``system_modules`` setting in the
994 ``[core.registry]`` section of the ``default.conf`` configuration file.
995
996 The format of the setting is expected to be a comma-separated list of
997 the module names.
998 """
999 sys_mod_str = self.config.getDefaultConfigValue("core.registry", "system_modules")
1000
1001 if sys_mod_str:
1002 return [name.strip() for name in sys_mod_str.split(",")]
1003 else:
1004 return []
1005
1007 """
1008 This method returns a list of directory paths where to look for
1009 modules to load (see also :meth:`Registry.load`). The values are read
1010 from the ``module_dirs`` setting in the ``[core.registry]`` section of
1011 the instance specific ``eoxserver.conf`` configuration file.
1012
1013 The format of the setting is expected to be a comma-separated list of
1014 paths.
1015 """
1016 mod_dir_str = self.config.getConfigValue("core.registry", "module_dirs")
1017
1018 if mod_dir_str:
1019 return [dir.strip() for dir in mod_dir_str.split(",")]
1020 else:
1021 return []
1022
1024 """
1025 This method returs a list of dotted names of modules to be loaded (see
1026 also :meth:`Registry.load`). The values are read from the ``modules``
1027 setting in the ``[core.registry]`` section of the instance specific
1028 ``eoxserver.conf`` configuration file.
1029
1030 The format of the setting is expected to be a comma-separated list of
1031 dotted module names.
1032 """
1033 mod_str = self.config.getConfigValue("core.registry", "modules")
1034
1035 if mod_str:
1036 return [name.strip() for name in mod_str.split(",")]
1037 else:
1038 return []
1039