Search in sources :

Example 1 with StorageException

use of nikita.common.util.exceptions.StorageException in project nikita-noark5-core by HiOA-ABI.

the class DocumentObjectHateoasController method handleFileUpload.

// API - All POST Requests (CRUD - CREATE)
// upload a file and associate it with a documentObject
// POST [contextPath][api]/arkivstruktur/dokumentobjekt/{systemID}/referanseFil
@ApiOperation(value = "Uploads a file and associates it with the documentObject identified by a systemId", response = DocumentObjectHateoas.class)
@ApiResponses(value = { @ApiResponse(code = 200, message = "File uploaded successfully", response = DocumentObjectHateoas.class), @ApiResponse(code = 401, message = API_MESSAGE_UNAUTHENTICATED_USER), @ApiResponse(code = 403, message = API_MESSAGE_UNAUTHORISED_FOR_USER), @ApiResponse(code = 500, message = API_MESSAGE_INTERNAL_SERVER_ERROR) })
@Counted
@RequestMapping(value = SLASH + LEFT_PARENTHESIS + SYSTEM_ID + RIGHT_PARENTHESIS + SLASH + REFERENCE_FILE, method = RequestMethod.POST, headers = "Accept=*/*", produces = { NOARK5_V4_CONTENT_TYPE_JSON, NOARK5_V4_CONTENT_TYPE_JSON_XML })
public ResponseEntity<DocumentObjectHateoas> handleFileUpload(final UriComponentsBuilder uriBuilder, HttpServletRequest request, final HttpServletResponse response, @ApiParam(name = "systemID", value = "systemID of the documentObject you wish to associate a file with", required = true) @PathVariable("systemID") final String documentObjectSystemId) {
    try {
        DocumentObject documentObject = documentObjectService.findBySystemId(documentObjectSystemId);
        if (documentObject == null) {
            throw new NoarkEntityNotFoundException(documentObjectSystemId);
        }
        InputStream inputStream;
        // Following will be needed for uploading file in chunks
        // String headerContentRange = request.getHeader("content-range");//Content-Range:bytes 737280-819199/845769
        // Check that content-length is set, > 0 and in agreement with the value set in documentObject
        Long contentLength = 0L;
        if (request.getHeader("content-length") == null) {
            throw new StorageException("Attempt to upload a document without content-length set. The document " + "was attempted to be associated with " + documentObject);
        }
        contentLength = (long) request.getIntHeader("content-length");
        if (contentLength < 1) {
            throw new StorageException("Attempt to upload a document with 0 or negative content-length set. " + "Actual value was (" + contentLength + "). The document  was attempted to be associated with " + documentObject);
        }
        if (null == documentObject.getFileSize()) {
            throw new StorageException("Attempt to upload a document with a content-length set in the header (" + contentLength + "), but the value in documentObject has not been set (== null).  The " + "document was attempted to be associated with " + documentObject);
        }
        if (!contentLength.equals(documentObject.getFileSize())) {
            throw new StorageException("Attempt to upload a document with a content-length set in the header (" + contentLength + ") that is not the same as the value in documentObject (" + documentObject.getFileSize() + ").  The document was attempted to be associated with " + documentObject);
        }
        // Check that the content-type is set and in agreement with mimeType value in documentObject
        String headerContentType = request.getHeader("content-type");
        if (headerContentType == null) {
            throw new StorageException("Attempt to upload a document without content-type set. The document " + "was attempted to be associated with " + documentObject);
        }
        if (!headerContentType.equals(documentObject.getMimeType())) {
            throw new StorageException("Attempt to upload a document with a content-type set in the header (" + contentLength + ") that is not the same as the mimeType in documentObject (" + documentObject.getMimeType() + ").  The document was attempted to be associated with " + documentObject);
        }
        documentObjectService.storeAndCalculateChecksum(request.getInputStream(), documentObject);
        // We need to update the documentObject in the database as checksum and checksum algorithm are set after
        // the document has been uploaded
        documentObjectService.update(documentObject);
        DocumentObjectHateoas documentObjectHateoas = new DocumentObjectHateoas(documentObject);
        documentObjectHateoasHandler.addLinks(documentObjectHateoas, new Authorisation());
        return new ResponseEntity<>(documentObjectHateoas, HttpStatus.OK);
    } catch (IOException e) {
        throw new StorageException(e.toString());
    }
}
Also used : ResponseEntity(org.springframework.http.ResponseEntity) DocumentObjectHateoas(nikita.common.model.noark5.v4.hateoas.DocumentObjectHateoas) InputStream(java.io.InputStream) Authorisation(nikita.webapp.security.Authorisation) DocumentObject(nikita.common.model.noark5.v4.DocumentObject) NoarkEntityNotFoundException(nikita.common.util.exceptions.NoarkEntityNotFoundException) IOException(java.io.IOException) StorageException(nikita.common.util.exceptions.StorageException) Counted(com.codahale.metrics.annotation.Counted) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Example 2 with StorageException

use of nikita.common.util.exceptions.StorageException in project nikita-noark5-core by HiOA-ABI.

the class DocumentObjectService method storeAndCalculateChecksum.

@Override
public /**
 * Store an incoming file associated with a DocumentObject. When writing the Incoming filestream, calculate
 * the checksum at the same time and update the DocumentObject with referenceToFile, size (bytes), checksum
 * and checksum algorithm
 *
 * inputStream.read calculates the checksum while reading the input file as it is a DigestInputStream
 */
void storeAndCalculateChecksum(InputStream inputStream, DocumentObject documentObject) {
    String checksumAlgorithm = documentObject.getChecksumAlgorithm();
    if (null == checksumAlgorithm) {
        checksumAlgorithm = defaultChecksumAlgorithm;
        documentObject.setChecksumAlgorithm(checksumAlgorithm);
    }
    if (null != documentObject.getReferenceDocumentFile()) {
        throw new StorageException("There is already a file associated with " + documentObject);
    }
    try {
        MessageDigest md = MessageDigest.getInstance(checksumAlgorithm);
        String filename = UUID.randomUUID().toString();
        Path directory = Paths.get(rootLocation + File.separator);
        Path file = Paths.get(rootLocation + File.separator + filename);
        // TODO perhaps better to raise an error if somehow init failed to create it?
        if (!Files.exists(directory)) {
            Files.createDirectory(directory);
        }
        // Check if we actually can create the file
        Path path = Files.createFile(file);
        // Check if we can write something to the file
        if (!Files.isWritable(file)) {
            throw new StorageException("The file (" + file.getFileName() + ") is not writable server-side. This" + " file is being associated with " + documentObject);
        }
        // Create a DigestInputStream to be read with the
        // checksumAlgorithm identified in the properties file
        DigestInputStream digestInputStream = new DigestInputStream(inputStream, md);
        FileOutputStream outputStream = new FileOutputStream(path.toFile());
        long bytesTotal = -1;
        try {
            // Try close without exceptions if copy() threw an exception.
            bytesTotal = IOUtils.copyLarge(digestInputStream, outputStream);
            // Tidy up and close outputStream
            outputStream.flush();
            outputStream.close();
            // Finished with inputStream now as well
            digestInputStream.close();
        } finally {
            try {
                // Try close without exceptions if copy() threw an exception.
                digestInputStream.close();
            } catch (IOException e) {
            // swallow any error to expose exceptions from IOUtil.copy()
            }
            try {
                // same for outputStream
                outputStream.close();
            } catch (IOException e) {
            // empty
            }
        }
        if (bytesTotal == 0L) {
            Files.delete(file);
            logger.warn("The file (" + file.getFileName() + ") has 0 length content and should have been deleted");
            throw new StorageException("The file (" + file.getFileName() + ") has 0 length content. Rejecting " + "upload! This file is being associated with " + documentObject);
        }
        if (!documentObject.getFileSize().equals(bytesTotal)) {
            Files.delete(file);
            String logmsg = "The uploaded file (" + file.getFileName() + ") length " + bytesTotal + " did not match the dokumentobjekt filstoerrelse " + documentObject.getFileSize() + " and was deleted.";
            logger.warn(logmsg);
            String msg = logmsg + " Rejecting upload! This file is being associated with " + documentObject;
            throw new StorageException(msg);
        }
        // Get the digest
        byte[] digest = digestInputStream.getMessageDigest().digest();
        // Convert digest to HEX
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
        }
        // TODO figure what the spec will say about existing
        // values in documentObject.  For now, only set the values
        // if they are blank, and reject the file if the checksum
        // did not match.
        String olddigest = documentObject.getChecksum();
        String newdigest = sb.toString();
        if (null == olddigest) {
            documentObject.setChecksum(newdigest);
        } else if (!olddigest.equals(newdigest)) {
            Files.delete(file);
            String msg = "The file (" + file.getFileName() + ") checksum " + newdigest + " do not match the already stored checksum.  Rejecting " + "upload! This file is being associated with " + documentObject;
            throw new StorageException(msg);
        }
        documentObject.setReferenceDocumentFile(file.toString());
    } catch (IOException e) {
        logger.error("When associating an uploaded file with " + documentObject + " an exception occurred." + "Exception is " + e);
        throw new StorageException("Failed to store file to be associated with " + documentObject + " " + e.toString());
    } catch (NoSuchAlgorithmException e) {
        logger.error("When associating an uploaded file with " + documentObject + " an exception occurred." + "Exception is " + e);
        throw new StorageException("Internal error, could not load checksum algorithm (" + checksumAlgorithm + ") when attempting to store a file associated with " + documentObject);
    }
}
Also used : Path(java.nio.file.Path) DigestInputStream(java.security.DigestInputStream) FileOutputStream(java.io.FileOutputStream) IOException(java.io.IOException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) MessageDigest(java.security.MessageDigest) StorageException(nikita.common.util.exceptions.StorageException)

Aggregations

IOException (java.io.IOException)2 StorageException (nikita.common.util.exceptions.StorageException)2 Counted (com.codahale.metrics.annotation.Counted)1 ApiOperation (io.swagger.annotations.ApiOperation)1 ApiResponses (io.swagger.annotations.ApiResponses)1 FileOutputStream (java.io.FileOutputStream)1 InputStream (java.io.InputStream)1 Path (java.nio.file.Path)1 DigestInputStream (java.security.DigestInputStream)1 MessageDigest (java.security.MessageDigest)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 DocumentObject (nikita.common.model.noark5.v4.DocumentObject)1 DocumentObjectHateoas (nikita.common.model.noark5.v4.hateoas.DocumentObjectHateoas)1 NoarkEntityNotFoundException (nikita.common.util.exceptions.NoarkEntityNotFoundException)1 Authorisation (nikita.webapp.security.Authorisation)1 ResponseEntity (org.springframework.http.ResponseEntity)1