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 KuhaEntryPointException(Exception): """Base for entry point exceptions."""
[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())