All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nl.vpro.beeldengeluid.gtaa.OpenskosRepository Maven / Gradle / Ivy

There is a newer version: 8.3.3
Show newest version
/*
 * Copyright (C) 2015 All rights reserved
 * VPRO The Netherlands
 */
package nl.vpro.beeldengeluid.gtaa;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Supplier;
import java.util.regex.Pattern;

import javax.annotation.PostConstruct;
import javax.ws.rs.core.Context;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXB;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.*;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.XmlMappingException;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.web.client.*;

import nl.vpro.domain.gtaa.*;
import nl.vpro.logging.LoggerOutputStream;
import nl.vpro.openarchives.oai.*;
import nl.vpro.openarchives.oai.Record; // java 14's java.lang.Record

import nl.vpro.util.BatchedReceiver;
import nl.vpro.util.CountedIterator;
import nl.vpro.w3.rdf.Description;
import nl.vpro.w3.rdf.RDF;

import static java.time.format.DateTimeFormatter.ISO_INSTANT;
import static org.springframework.http.HttpStatus.CREATED;

/**
 * See http://editor.openskos.org/apidoc/index.html ?
 *
 * @author Roelof Jan Koekoek
 * @since 3.7
 */
@Slf4j
public class OpenskosRepository implements GTAARepository {

    public static final String CONFIG_FILE = "openskosrepository.properties";

    public static final ZoneId ZONE_ID = ZoneId.of("Europe/Amsterdam");


    private final RestTemplate template;

    private final String gtaaUrl;
    private final String gtaaKey;

    @Value("${gtaa.personsSpec}")
    @Getter
    @Setter
    @Nullable
    private String personsSpec;

    @Value("${gtaa.geolocationsSpec}")
    @Getter
    @Setter
    @Nullable
    private String geoLocationsSpec;

    @Value("${gtaa.tenant}")
    @Getter
    @Setter
    @Nullable
    private String tenant;

    @Value("${gtaa.retries}")
    @Getter
    @Setter
    private int retries;

    public OpenskosRepository(
        @Value("${gtaa.baseUrl}")
        @NonNull String baseUrl,
        @Value("${gtaa.key}")
        @NonNull String key) {
        this(baseUrl, key, null, null, null, true, null, 1);
    }

    @lombok.Builder(builderClassName = "Builder")
    private OpenskosRepository(
        @NonNull String baseUrl,
        @NonNull String key,
        @Nullable RestTemplate template,
        @Nullable String personsSpec,
        @Nullable String geoLocationsSpec,
        boolean useXLLabels,
        @Nullable String tenant,
        int retries
        ) {
        this.gtaaUrl = baseUrl;
        this.gtaaKey = key;
        this.template = createTemplateIfNull(template);
        this.tenant = tenant;
        this.personsSpec = personsSpec;
        this.geoLocationsSpec = geoLocationsSpec;
        this.retries = retries;

    }

    private void addErrorHandler() {
        template.setErrorHandler(new ResponseErrorHandler() {
            @Override
            public boolean hasError(@NonNull ClientHttpResponse response) throws IOException {
                boolean hasError = ! response.getStatusCode().is2xxSuccessful();
                if (hasError) {
                    log.warn("{}", response);
                } else {
                    Post_RDF.remove();
                }
                return hasError;
            }

            @Override
            public void handleError(@NonNull ClientHttpResponse response) throws IOException {
                StringWriter body = new StringWriter();
                IOUtils.copy(response.getBody(), body, StandardCharsets.UTF_8);
                RDFPost postRdf = Post_RDF.get();
                try {
                    switch (response.getStatusCode()) {
                        case CONFLICT:
                            throw new GTAAConflict("Conflicting or duplicate label: " + postRdf.prefLabel + ": " + body);
                        case BAD_REQUEST:
                            if (body.toString().startsWith("The pref label already exists in that concept scheme")) {
                                throw new GTAAConflict(body.toString());
                            }
                        default:
                            StringWriter writer = new StringWriter();
                            if (postRdf != null) {
                                writer.append("Request:\n");
                                JAXB.marshal(postRdf.rdf, writer);
                            }
                            writer.append("Response:\n");
                            writer.append(body.toString());
                            throw new RuntimeException("For " + gtaaUrl + " " +
                                response.getStatusCode() + " " + response.getStatusText() + " " + writer.toString());
                    }
                } finally {
                    Post_RDF.remove();
                }
            }
        });
    }

    private static RestTemplate createTemplateIfNull(@Nullable RestTemplate template) {
        if (template == null) {

            Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
            jaxb2Marshaller.setPackagesToScan(
                "nl.vpro.beeldengeluid.gtaa",
                "nl.vpro.w3.rdf",
                "nl.vpro.openarchives.oai"
            );

            try {
                jaxb2Marshaller.afterPropertiesSet();
            } catch (Exception ex) {
                log.warn(ex.getMessage());

            }
            DOMSourceUnmarshaller domSourceUnmarshaller = new DOMSourceUnmarshaller();

            MarshallingHttpMessageConverter rdfHttpMessageConverter = new MarshallingHttpMessageConverter();
            rdfHttpMessageConverter.setMarshaller(jaxb2Marshaller);
            rdfHttpMessageConverter.setUnmarshaller(jaxb2Marshaller);

            MarshallingHttpMessageConverter rdfToDomHttpMessageConverter = new MarshallingHttpMessageConverter();
            rdfToDomHttpMessageConverter.setMarshaller(jaxb2Marshaller);
            rdfToDomHttpMessageConverter.setUnmarshaller(domSourceUnmarshaller);

            template = new RestTemplate();
            template.setMessageConverters(
                Arrays.asList(rdfHttpMessageConverter, rdfToDomHttpMessageConverter)
            );
        }
        return template;
    }

    @PostConstruct
    public void init() {
        log.info("Communicating with {} (personSpec: {}, geolocationsSpec: {})",
            gtaaUrl,
            personsSpec,
            geoLocationsSpec
        );
        addErrorHandler();
    }


    @SuppressWarnings("unchecked")
    @Override
    public  T submit(@NonNull S thesaurusObject, @NonNull String creator) {
        final Description description = submit(
            thesaurusObject.getName(),
            thesaurusObject.getScopeNotesAsLabel(),
            creator,
            thesaurusObject.getObjectType()
        );
        return (T) GTAAConcepts.toConcept(description).orElseThrow(() -> new IllegalStateException("Could not convert " + description));

    }


    @SuppressWarnings("StringConcatenationInLoop")
    private Description submit(@NonNull String prefLabel, @NonNull  List




© 2015 - 2025 Weber Informatics LLC | Privacy Policy