Source code for kuha_oai_pmh_repo_handler.serve
#!/usr/bin/env python3
# Author(s): Toni Sissala
# Copyright 2021 Finnish Social Science Data Archive FSD / University of Tampere
# Licensed under the EUPL. See LICENSE.txt for full license.
"""Main entry point for starting OAI-PMH Repo Handler.
"""
import sys
import logging
import pkg_resources
from kuha_common import (
conf,
cli_setup
)
from kuha_common.server import serve
from kuha_oai_pmh_repo_handler import (
http_api,
controller,
constants
)
_logger = logging.getLogger(__name__)
MDFORMATS_EPGROUP = 'kuha.oai.metadataformats'
[docs]class InvalidMetadataFormatException(KuhaEntryPointException):
"""A loaded metadataformat is constructed wrong.
Raised for instance, when a metadataformat implements different sets
that other metadataformats in same repository.
"""
[docs]class ConflictingMetadataPrefixException(KuhaEntryPointException):
"""Raise when non-overridable metadataformats implement the same metadataprefix"""
[docs]class NoMetadataFormatsException(KuhaEntryPointException):
"""Unable to load any metadataformats for OAI-PMH Repo Handler"""
[docs]def load_metadataformats(entry_point_group):
"""Load metadataformat using plugin discovery via setuptools entry-points.
The following constraints apply to loaded metadataformats:
* Every loaded metadataformat must have a unique
mdprefix. Consults overridable (bool) attribute to check if
a certain mdprefix can be overridden by another
metadataformat. Raises ConflictingMetadataPrefixException,
if metadataformats have same mdprefix and are
non-overridable.
* Every loaded metadataformat must implement the same sets;
sets-attribute and list_sets method must be the same for
every loaded metadataformat. Note that overridden
metadataformats can have different sets that the ones that
are finally loaded, as long as the loaded ones implement the
same sets. Raises InvalidMetadataFormatException if loaded
metadataformats implement different sets.
Also, it is mandatory to load at least one metadataformat. Raises
NoMetadataFormatsException if no metadataformats are loaded.
:param str entry_point_group: Entry point group for metadataformats.
:returns: Loaded metadataformat classes.
:rtype: list
"""
mdformats = {}
for entry_point in pkg_resources.iter_entry_points(entry_point_group):
candidate = entry_point.load()
loaded = mdformats.get(candidate.mdprefix)
if loaded and loaded.overridable is False:
if candidate.overridable is False:
raise ConflictingMetadataPrefixException(
"Conflicting non-overridable metadata prefix '%s'"
% (candidate.mdprefix,))
continue
mdformats.update({candidate.mdprefix: candidate})
if mdformats == {}:
raise NoMetadataFormatsException(
"Could not load any metadataformats from entry point group '%s'"
% (entry_point_group,))
mdformats = list(mdformats.values())
sets_list_sets = (mdformats[0].sets, mdformats[0].list_sets)
if any((mdf.sets, mdf.list_sets) != sets_list_sets for mdf in mdformats[1:]):
raise InvalidMetadataFormatException("Metadataformats must implement same OAI sets.")
return mdformats
[docs]def configure(mdformats):
"""Configure OAI-PMH Server.
:param list mdformats: Metadataformats to serve
:returns: Server settings
:rtype: :obj:`argparse.Namespace`
"""
conf.load('Kuha OAI-PMH Repo Handler',
package='kuha_oai_pmh_repo_handler',
env_var_prefix='KUHA_')
conf.add('--api-version',
help='OAI-PMH api version',
default=constants.API_VERSION,
env_var='OPRH_API_VERSION',
type=str)
conf.add('--port',
help='Server port',
default=constants.SERVER_PORT,
env_var='OPRH_PORT',
type=int)
conf.add_config_arg()
conf.add_print_arg()
controller.add_cli_args()
for mdformat in mdformats:
mdformat.add_cli_args(conf)
settings = cli_setup.setup_common_modules(
cli_setup.MOD_SERVER, cli_setup.MOD_LOGGING)
for mdformat in mdformats:
mdformat.configure(settings)
return settings
[docs]def main():
"""Application main function.
Parse commandline for settings. Setup and serve webapp.
Exit on exceptions propagated at this level.
:returns: None
"""
mdformats = load_metadataformats(MDFORMATS_EPGROUP)
settings = configure(mdformats)
if settings.print_configuration:
print("Print active configuration and exit\n")
conf.print_conf()
return
ctrl = controller.from_settings(settings, mdformats)
web_app = http_api.get_app(settings.api_version, controller=ctrl)
try:
serve(web_app, settings.port)
except KeyboardInterrupt as exc:
_logger.warning("Shutdown by CTRL + C")
_logger.warning(str(exc))
except:
_logger.exception("Exception in main()")
raise
finally:
# Cleanup
_logger.info("Shutdown")
if __name__ == '__main__':
sys.exit(main())