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

org.ehrbase.rest.openehr.OpenehrDirectoryController Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2024 vitasystems GmbH.
 *
 * This file is part of project EHRbase
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.ehrbase.rest.openehr;

import static org.apache.commons.lang3.StringUtils.unwrap;
import static org.ehrbase.api.rest.HttpRestContext.EHR_ID;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.web.util.UriComponentsBuilder.fromPath;

import com.nedap.archie.rm.directory.Folder;
import com.nedap.archie.rm.support.identification.ObjectVersionId;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.time.OffsetDateTime;
import java.util.Optional;
import java.util.UUID;
import org.apache.commons.lang3.StringUtils;
import org.ehrbase.api.exception.InvalidApiParameterException;
import org.ehrbase.api.exception.ObjectNotFoundException;
import org.ehrbase.api.rest.HttpRestContext;
import org.ehrbase.api.service.DirectoryService;
import org.ehrbase.openehr.sdk.response.dto.DirectoryResponseData;
import org.ehrbase.rest.BaseController;
import org.ehrbase.rest.openehr.specification.DirectoryApiSpecification;
import org.joda.time.DateTime;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * Controller for openEHR /directory endpoints
 */
@ConditionalOnMissingBean(name = "primaryopenehrdirectorycontroller")
@RestController
@RequestMapping(path = BaseController.API_CONTEXT_PATH_WITH_VERSION + "/ehr")
public class OpenehrDirectoryController extends BaseController implements DirectoryApiSpecification {

    private final DirectoryService directoryService;

    public OpenehrDirectoryController(DirectoryService directoryService) {
        this.directoryService = directoryService;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @PostMapping(path = "/{ehr_id}/directory")
    public ResponseEntity createDirectory(
            @PathVariable(name = "ehr_id") UUID ehrId,
            @RequestHeader(name = OPENEHR_VERSION, required = false) String openEhrVersion,
            @RequestHeader(name = OPENEHR_AUDIT_DETAILS, required = false) String openEhrAuditDetails,
            @RequestHeader(name = HttpHeaders.CONTENT_TYPE) String contentType,
            @RequestHeader(name = HttpHeaders.ACCEPT, defaultValue = MediaType.APPLICATION_JSON_VALUE) String accept,
            @RequestHeader(name = PREFER, defaultValue = RETURN_MINIMAL) String prefer,
            @RequestBody Folder folder) {

        var createdFolder = directoryService.create(ehrId, folder);

        return createDirectoryResponse(POST, prefer, accept, createdFolder, ehrId);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @PutMapping(path = "/{ehr_id}/directory")
    public ResponseEntity updateDirectory(
            @PathVariable(name = "ehr_id") UUID ehrId,
            @RequestHeader(name = HttpHeaders.IF_MATCH) ObjectVersionId folderId,
            @RequestHeader(name = HttpHeaders.CONTENT_TYPE) String contentType,
            @RequestHeader(name = HttpHeaders.ACCEPT, defaultValue = MediaType.APPLICATION_JSON_VALUE) String accept,
            @RequestHeader(name = PREFER, defaultValue = RETURN_MINIMAL) String prefer,
            @RequestHeader(name = OPENEHR_VERSION, required = false) String openEhrVersion,
            @RequestHeader(name = OPENEHR_AUDIT_DETAILS, required = false) String openEhrAuditDetails,
            @RequestBody Folder folder) {

        folderId.setValue(unwrap(folderId.getValue(), '"'));

        // Update folder and get new version
        Folder updatedFolder = directoryService.update(ehrId, folder, folderId);

        return createDirectoryResponse(HttpMethod.PUT, prefer, accept, updatedFolder, ehrId);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @DeleteMapping(path = "/{ehr_id}/directory")
    public ResponseEntity deleteDirectory(
            @PathVariable(name = "ehr_id") UUID ehrId,
            @RequestHeader(name = OPENEHR_VERSION, required = false) String openEhrVersion,
            @RequestHeader(name = OPENEHR_AUDIT_DETAILS, required = false) String openEhrAuditDetails,
            @RequestHeader(name = HttpHeaders.ACCEPT, defaultValue = MediaType.APPLICATION_JSON_VALUE) String accept,
            @RequestHeader(name = HttpHeaders.IF_MATCH) ObjectVersionId folderId) {

        folderId.setValue(unwrap(folderId.getValue(), '"'));

        directoryService.delete(ehrId, folderId);

        createRestContext(ehrId, folderId.toString());

        return createDirectoryResponse(HttpMethod.DELETE, null, accept, null, ehrId);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @GetMapping(path = "/{ehr_id}/directory/{version_uid}")
    public ResponseEntity getFolderInDirectory(
            @PathVariable(name = "ehr_id") UUID ehrId,
            @PathVariable(name = "version_uid") ObjectVersionId versionUid,
            @RequestParam(name = "path", required = false) String path,
            @RequestHeader(name = HttpHeaders.ACCEPT, defaultValue = MediaType.APPLICATION_JSON_VALUE) String accept) {

        validateVersionUid(versionUid);

        assertValidPath(path);

        // Get the folder entry from database
        Optional foundFolder = directoryService.get(ehrId, versionUid, path);
        if (foundFolder.isEmpty()) {
            throw new ObjectNotFoundException(
                    "DIRECTORY",
                    String.format(
                            "Folder with id %s and path %s does not exist.", versionUid, path != null ? path : "/"));
        }

        return createDirectoryResponse(HttpMethod.GET, RETURN_REPRESENTATION, accept, foundFolder.get(), ehrId);
    }

    private void validateVersionUid(ObjectVersionId versionUid) {
        String versionUidStr = versionUid.getValue();
        if (StringUtils.isEmpty(versionUidStr)) {
            throw new InvalidApiParameterException("a valid  must be provided");
        }

        try {
            versionUid.getCreatingSystemId();
            if (versionUid.isBranch()) {
                throw new InvalidApiParameterException("Version branching is not supported");
            }
        } catch (UnsupportedOperationException e) {
            throw new InvalidApiParameterException(e.getMessage(), e);
        }
    }

    @Override
    @GetMapping(path = "/{ehr_id}/directory")
    public ResponseEntity getFolderInDirectoryVersionAtTime(
            @PathVariable(name = "ehr_id") UUID ehrId,
            @RequestParam(name = "version_at_time", required = false) String versionAtTime,
            @RequestParam(name = "path", required = false) String path,
            @RequestHeader(name = ACCEPT, required = false, defaultValue = MediaType.APPLICATION_JSON_VALUE)
                    String accept) {

        // Check ehr exists

        assertValidPath(path);

        final Optional foundFolder;
        // Get the folder entry from database
        Optional temporal = decodeVersionAtTime(versionAtTime);

        if (temporal.isPresent()) {
            foundFolder = directoryService.getByTime(ehrId, temporal.get(), path);
        } else {
            foundFolder = directoryService.get(ehrId, null, path);
        }

        if (foundFolder.isEmpty()) {
            throw new ObjectNotFoundException(
                    "folder",
                    "The FOLDER for ehrId %s and path %s does not exist."
                            .formatted(ehrId.toString(), path != null ? path : "/"));
        }

        return createDirectoryResponse(HttpMethod.GET, RETURN_REPRESENTATION, accept, foundFolder.get(), ehrId);
    }

    private DirectoryResponseData buildResponse(Folder folderDto) {
        DirectoryResponseData resBody = new DirectoryResponseData();
        resBody.setDetails(folderDto.getDetails());
        resBody.setFolders(folderDto.getFolders());
        resBody.setItems(folderDto.getItems());
        resBody.setName(folderDto.getName());
        resBody.setUid(folderDto.getUid());
        return resBody;
    }

    private ResponseEntity createDirectoryResponse(
            HttpMethod method, String prefer, String accept, Folder folderDto, UUID ehrId) {
        HttpHeaders headers = new HttpHeaders();
        HttpStatus successStatus;
        DirectoryResponseData body;

        if (prefer != null && prefer.equals(RETURN_REPRESENTATION)) {
            headers.setContentType(resolveContentType(accept));
            body = buildResponse(folderDto);
            successStatus = getSuccessStatus(method);
        } else {
            body = null;
            successStatus = HttpStatus.NO_CONTENT;
        }

        if (folderDto != null) {

            String versionUid = folderDto.getUid().toString();
            headers.setETag("\"" + versionUid + "\"");
            headers.setLocation(createLocationUri(EHR, ehrId.toString(), DIRECTORY, versionUid));

            // TODO: Extract last modified from SysPeriod timestamp of fetched folder record
            headers.setLastModified(DateTime.now().getMillis());
            createRestContext(ehrId, versionUid);
        }

        return new ResponseEntity<>(body, headers, successStatus);
    }

    private HttpStatus getSuccessStatus(HttpMethod method) {
        if (method.equals(HttpMethod.POST)) {
            return HttpStatus.CREATED;
        } else if (method.equals(HttpMethod.DELETE)) {
            return HttpStatus.NO_CONTENT;
        }
        return HttpStatus.OK;
    }

    /**
     * Assert that the given path is valid.
     *
     * @param path the path to check
     * @throws InvalidApiParameterException if the path is invalid
     */
    private void assertValidPath(String path) {
        if (path == null) {
            return;
        }

        try {
            Paths.get(path);
        } catch (InvalidPathException e) {
            throw new InvalidApiParameterException("The value of path parameter is invalid", e);
        }
    }

    private void createRestContext(UUID ehrId, String versionedObjectUid) {
        HttpRestContext.register(
                EHR_ID,
                ehrId,
                HttpRestContext.LOCATION,
                fromPath("")
                        .pathSegment(EHR, ehrId.toString(), DIRECTORY, versionedObjectUid)
                        .build()
                        .toString());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy