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

no.ks.fiks.dokumentlager.klient.DokumentlagerApiImpl Maven / Gradle / Ivy

Go to download

Klient for opplasting, sletting og nedlasting av dokumenter fra Fiks Dokumentlager

The newest version!
package no.ks.fiks.dokumentlager.klient;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import no.ks.fiks.dokumentlager.klient.authentication.AuthenticationStrategy;
import no.ks.fiks.dokumentlager.klient.model.*;
import no.ks.fiks.dokumentlager.klient.path.DefaultPathHandler;
import no.ks.fiks.dokumentlager.klient.path.PathHandler;
import org.apache.commons.io.IOUtils;
import org.apache.hc.core5.http.ContentType;
import org.eclipse.jetty.client.*;
import org.eclipse.jetty.client.transport.HttpClientTransportDynamic;
import org.eclipse.jetty.http.*;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

@Slf4j
public class DokumentlagerApiImpl implements DokumentlagerApi {

    private static final String KRYPTERT_PARAM = "kryptert";
    private static final String METADATA_PART = "metadata";
    private static final String DOKUMENT_PART = "dokument";

    private final JsonMapper mapper = new JsonMapper();

    private final HttpClient client;
    private final Duration uploadTimeout;
    private final Duration downloadTimeout;

    private final String uploadbaseUrl;
    private final String downloadBaseUrl;
    private final AuthenticationStrategy authenticationStrategy;
    private final PathHandler pathHandler;

    private final Function requestInterceptor;

    private DokumentlagerApiImpl(@NonNull String uploadBaseUrl,
                                 @NonNull String downloadBaseUrl,
                                 @NonNull AuthenticationStrategy authenticationStrategy,
                                 Function requestInterceptor,
                                 @NonNull PathHandler pathHandler,
                                 @NonNull HttpConfiguration httpConfiguration) {
        this.uploadbaseUrl = uploadBaseUrl;
        this.downloadBaseUrl = downloadBaseUrl;
        this.authenticationStrategy = authenticationStrategy;
        this.requestInterceptor = requestInterceptor;
        this.pathHandler = pathHandler;

        ClientConnector clientConnector = new ClientConnector();
        clientConnector.setSslContextFactory(new SslContextFactory.Client());
        this.client = new HttpClient(new HttpClientTransportDynamic(clientConnector));
        this.client.setIdleTimeout(httpConfiguration.getIdleTimeout().toMillis());
        this.uploadTimeout = httpConfiguration.getUploadTimeout();
        this.downloadTimeout = httpConfiguration.getDownloadTimeout();

        try {
            this.client.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static DokumentlagerApiImplBuilder builder() {
        return new DokumentlagerApiImplBuilder();
    }

    @Override
    public DokumentlagerResponse uploadDokument(@NonNull InputStream dokumentStream,
                                                                              @NonNull DokumentMetadataUpload metadata,
                                                                              @NonNull UUID fiksOrganisasjonId,
                                                                              @NonNull UUID kontoId,
                                                                              boolean kryptert) {
        log.debug("Uploading {}dokument for organisasjon {} and konto {}: {}", kryptert ? "encrypted " : "", fiksOrganisasjonId, kontoId, metadata);
        try {
            ContentResponse response = newUploadRequest()
                    .method(HttpMethod.POST)
                    .path(pathHandler.getUploadPath(fiksOrganisasjonId, kontoId))
                    .param(KRYPTERT_PARAM, String.valueOf(kryptert))
                    .body(buildMultipartContent(metadata, dokumentStream))
                    .timeout(uploadTimeout.toMillis(), TimeUnit.MILLISECONDS)
                    .send();

            if (isError(response.getStatus())) {
                log.info("Upload request failed with status {}", response.getStatus());
                int status = response.getStatus();
                String content = response.getContentAsString();
                throw new DokumentlagerHttpException(String.format("HTTP-error during upload (%d): %s", status, content), status, content);
            }

            return buildResponse(response, mapper.fromJson(response.getContent(), DokumentMetadataUploadResult.class));
        } catch (InterruptedException | TimeoutException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    private MultiPartRequestContent buildMultipartContent(DokumentMetadataUpload metadata, InputStream dokumentStream) {
        MultiPartRequestContent multipart = new MultiPartRequestContent();
        addMetadataPart(multipart, metadata);
        addDokumentPart(multipart, metadata.getDokumentnavn(), dokumentStream);
        multipart.close();
        return multipart;
    }

    private void addMetadataPart(MultiPartRequestContent multipart, DokumentMetadataUpload metadata) {
        addPart(
                multipart,
                new MultiPart.ContentSourcePart(
                        METADATA_PART,
                        null,
                        HttpFields.from(
                                new HttpField(HttpHeader.CONTENT_TYPE, ContentType.APPLICATION_JSON.getMimeType())
                        ),
                        new StringRequestContent(mapper.toJson(metadata))
                )
        );
    }

    private void addDokumentPart(MultiPartRequestContent multipart, String fileName, InputStream dokumentStream) {
        addPart(
                multipart,
                new MultiPart.ContentSourcePart(
                        DOKUMENT_PART,
                        fileName,
                        HttpFields.from(
                                new HttpField(HttpHeader.CONTENT_TYPE, ContentType.APPLICATION_OCTET_STREAM.getMimeType())
                        ),
                        new InputStreamRequestContent(dokumentStream)
                )
        );
    }

    private void addPart(MultiPartRequestContent multipart, MultiPart.Part part) {
        boolean added = multipart.addPart(part);
        if (!added) {
            throw new RuntimeException("Failed to add multipart");
        }
    }

    @Override
    public DokumentlagerResponse updateDokumentMetadata(UUID fiksOrganisasjonId, UUID kontoId, UUID dokumentId, DokumentMetadataUpdate update) {
        log.debug("Updating metadata for dokument with id {} for organisasjon {} and konto {}", dokumentId, fiksOrganisasjonId, kontoId);
        try {
            ContentResponse response = newUploadRequest()
                    .method(HttpMethod.PATCH)
                    .path(pathHandler.getUpdateMetadataPath(fiksOrganisasjonId, kontoId, dokumentId))
                    .body(createJsonBody(update))
                    .send();

            if (isError(response.getStatus())) {
                int status = response.getStatus();
                String content = response.getContentAsString();
                throw new DokumentlagerHttpException(
                        String.format("HTTP-error during metadata update (%d): %s", status, content), status, content);
            }

            return buildResponse(response, mapper.fromJson(response.getContent(), DokumentMetadataUpdateResult.class));
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public DokumentlagerResponse deleteDokument(@NonNull UUID fiksOrganisasjonId,
                                                      @NonNull UUID kontoId,
                                                      @NonNull UUID dokumentId) {
        log.debug("Deleting dokument with id {} for organisasjon {} and konto {}", dokumentId, fiksOrganisasjonId, kontoId);
        try {
            ContentResponse response = newUploadRequest()
                    .method(HttpMethod.DELETE)
                    .path(pathHandler.getDeletePath(fiksOrganisasjonId, kontoId, dokumentId))
                    .send();

            if (isError(response.getStatus())) {
                int status = response.getStatus();
                String content = response.getContentAsString();
                throw new DokumentlagerHttpException(
                        String.format("HTTP-error during delete (%d): %s", status, content), status, content);
            }

            return buildResponse(response, null);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public DokumentlagerResponse deleteDokumenterByKorrelasjonsid(UUID fiksOrganisasjonId, UUID kontoId, UUID korrelasjonsid) {
        log.debug("Deleting dokumenter with korrelasjonsid {} for organisasjon {} and konto {}", korrelasjonsid, fiksOrganisasjonId, kontoId);
        try {
            ContentResponse response = newUploadRequest()
                    .method(HttpMethod.DELETE)
                    .path(pathHandler.getDeleteByKorrelasjonsidPath(fiksOrganisasjonId, kontoId, korrelasjonsid))
                    .send();

            if (isError(response.getStatus())) {
                int status = response.getStatus();
                String content = response.getContentAsString();
                throw new DokumentlagerHttpException(
                        String.format("HTTP-error during delete by korrelasjonsid (%d): %s", status, content), status, content);
            }

            return buildResponse(response, null);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public DokumentlagerResponse downloadDokument(@NonNull UUID dokumentId) {
        return createDownloadRequestSupplier(dokumentId).get();
    }

    @Override
    public DokumentlagerResponse downloadDokumentLazy(@NonNull UUID dokumentId) {
        log.debug("Initialized lazy download for dokument {} ", dokumentId);
        Supplier> downloadRequestSupplier = createDownloadRequestSupplier(dokumentId);
        return new LazyDokumentlagerResponse(downloadRequestSupplier::get);
    }

    private Supplier> createDownloadRequestSupplier(@NonNull UUID dokumentId) {
        Request request = newDownloadRequest()
                .method(HttpMethod.GET)
                .path(pathHandler.getDownloadPath(dokumentId));

        return () -> {
            try {
                log.debug("Downloading dokument {}", dokumentId);

                InputStreamResponseListener listener = new InputStreamResponseListener();
                request.send(listener);

                Response response = listener.get(downloadTimeout.toMillis(), TimeUnit.MILLISECONDS);
                if (isError(response.getStatus())) {
                    int status = response.getStatus();
                    String content = IOUtils.toString(listener.getInputStream(), StandardCharsets.UTF_8);
                    throw new DokumentlagerHttpException(
                            String.format("HTTP-error during download (%d): %s", status, content), status, content);
                }

                return buildResponse(response, listener.getInputStream());
            } catch (InterruptedException | ExecutionException | TimeoutException | IOException e) {
                throw new RuntimeException(e);
            }
        };
    }

    @Override
    public DokumentlagerResponse downloadDokumentMetadata(@NonNull UUID dokumentId) {
        log.debug("Downloading metadata for dokument with id {}", dokumentId);
        try {
            ContentResponse response = newDownloadRequest()
                    .method(HttpMethod.GET)
                    .path(pathHandler.getDownloadMetadataPath(dokumentId))
                    .send();

            if (isError(response.getStatus())) {
                int status = response.getStatus();
                String content = response.getContentAsString();
                throw new DokumentlagerHttpException(
                        String.format("HTTP-error during download (%d): %s", status, content), status, content);
            }

            return buildResponse(response, mapper.fromJson(response.getContent(), DokumentMetadataDownloadResult.class));
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public DokumentlagerResponse sokDokumenterMedKorrelasjonsid(UUID fiksOrganisasjonId, UUID kontoId, UUID korrelasjonsid, Integer fra, Integer til) {
        log.debug("Search documents with correlationid {}", korrelasjonsid);
        try {
            ContentResponse response = newUploadRequest()
                    .method(HttpMethod.POST)
                    .path(pathHandler.getQueryDocumentPath(fiksOrganisasjonId, kontoId))
                    .param("fra", String.valueOf(fra))
                    .param("til", String.valueOf(til))
                    .body(createJsonBody(new Korrelasjonsid(korrelasjonsid)))
                    .send();

            if (isError(response.getStatus())) {
                int status = response.getStatus();
                String content = response.getContentAsString();
                throw new DokumentlagerHttpException(
                        String.format("HTTP-error during document query (%d): %s", status, content), status, content);
            }

            return buildResponse(response, mapper.fromJson(response.getContent(), Sokeresultat.class));
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }

    private record Korrelasjonsid(UUID korrelasjonsid) {}

    @Override
    public DokumentlagerResponse getPublicKey() {
        log.debug("Getting public key");
        try {
            ContentResponse response = newUploadRequest()
                    .method(HttpMethod.GET)
                    .path(pathHandler.getPublicKeyPath())
                    .send();

            if (isError(response.getStatus())) {
                int status = response.getStatus();
                String content = response.getContentAsString();
                throw new DokumentlagerHttpException(
                        String.format("HTTP-error getting public-key (%d): %s", status, content), status, content);
            }

            return buildResponse(response, response.getContentAsString());
        } catch (InterruptedException | TimeoutException | ExecutionException e) {
            throw new RuntimeException(e);
        }
    }

    private boolean isError(int httpStatus) {
        return HttpStatus.isClientError(httpStatus) || HttpStatus.isServerError(httpStatus);
    }

    private  DokumentlagerResponse buildResponse(Response response, T result) {
        return DokumentlagerResponse.builder()
                .result(result)
                .httpStatus(response.getStatus())
                .httpHeaders(response.getHeaders().stream().collect(Collectors.toMap(HttpField::getName, HttpField::getValue, (prev, next) -> next, HashMap::new)))
                .build();
    }

    private Request newUploadRequest() {
        return newRequest(uploadbaseUrl);
    }

    private Request newDownloadRequest() {
        return newRequest(downloadBaseUrl);
    }

    private Request newRequest(String baseUrl) {
        Request request = client.newRequest(baseUrl);

        authenticationStrategy.setAuthenticationHeaders(request);

        if (requestInterceptor != null) {
            return requestInterceptor.apply(request);
        }
        return request;
    }

    private StringRequestContent createJsonBody(Object body) {
        return new StringRequestContent("application/json", mapper.toJson(body), StandardCharsets.UTF_8);
    }

    @Override
    public void close() {
        try {
            client.stop();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static class DokumentlagerApiImplBuilder {

        private String uploadBaseUrl;
        private String downloadBaseUrl;
        private AuthenticationStrategy authenticationStrategy;
        private PathHandler pathHandler;
        private Function requestInterceptor;
        private HttpConfiguration httpConfiguration;

        public DokumentlagerApiImplBuilder uploadBaseUrl(String uploadBaseUrl) {
            this.uploadBaseUrl = uploadBaseUrl;
            return this;
        }

        public DokumentlagerApiImplBuilder downloadBaseUrl(String downloadBaseUrl) {
            this.downloadBaseUrl = downloadBaseUrl;
            return this;
        }

        public DokumentlagerApiImplBuilder authenticationStrategy(AuthenticationStrategy authenticationStrategy) {
            this.authenticationStrategy = authenticationStrategy;
            return this;
        }

        public DokumentlagerApiImplBuilder pathHandler(PathHandler pathHandler) {
            this.pathHandler = pathHandler;
            return this;
        }

        public DokumentlagerApiImplBuilder requestInterceptor(Function requestInterceptor) {
            this.requestInterceptor = requestInterceptor;
            return this;
        }

        public DokumentlagerApiImplBuilder httpConfiguration(HttpConfiguration httpConfiguration) {
            this.httpConfiguration = httpConfiguration;
            return this;
        }

        public DokumentlagerApiImpl build() {
            if (pathHandler == null) {
                pathHandler = new DefaultPathHandler();
            }
            if (httpConfiguration == null) {
                httpConfiguration = HttpConfiguration.builder().build();
            }
            return new DokumentlagerApiImpl(uploadBaseUrl, downloadBaseUrl, authenticationStrategy, requestInterceptor, pathHandler, httpConfiguration);
        }

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy