Skip to content

Commit

Permalink
Update BagIt library to support BagIt version 1.0 (fix #2)
Browse files Browse the repository at this point in the history
Extend max file size to 10MB and improve exception handling. (fix #3)
The maximum file size for uploading can be adjusted in the configuration file 'application.properties'.
  • Loading branch information
Volker Hartmann committed Nov 2, 2018
1 parent 76a494d commit db6e1f2
Show file tree
Hide file tree
Showing 7 changed files with 290 additions and 64 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ dependencies {
compile("org.slf4j:slf4j-api:1.7.25")
compile("ch.qos.logback:logback-classic:1.2.3")
// bag it
compile("gov.loc:bagit:4.0")
compile("gov.loc:bagit:5.2.0")

// local dependencies
compile("org.fzk.ipe:Tools:1.6")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import edu.kit.datamanager.metastore.storageservice.StorageService;
import edu.kit.datamanager.metastore.util.BagItUtil;
import edu.kit.datamanager.metastore.util.ZipUtils;
import gov.loc.repository.bagit.Bag;
import java.io.File;
import java.io.IOException;
import java.net.URI;
Expand Down Expand Up @@ -52,8 +51,16 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import edu.kit.datamanager.metastore.controller.IBagItUploadController;
import edu.kit.datamanager.metastore.exception.BagItException;
import edu.kit.datamanager.metastore.exception.ResourceAlreadyExistsException;
import gov.loc.repository.bagit.domain.Bag;
import java.nio.file.FileAlreadyExistsException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.tomcat.util.http.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

/**
* REST service handling upload of zipped Bagit containers.
Expand All @@ -66,6 +73,14 @@ public class BagItUploadController implements IBagItUploadController {
* Logger for this class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(MetastoreApplication.class);
/**
* Key inside Bagit container defining location of the METS file.
*/
public static final String X_OCRD_METS = "X-Ocrd-Mets";

This comment has been minimized.

Copy link
@kba

kba Nov 2, 2018

Member

We should probably drop the X-prefix in assets and here, it's been dropped from OCR-D/spec#70. It's an HTTP convention not needed here, we can just use Ocrd-.

/**
* Default location of the METS file.
*/
public static final String METS_LOCATION_DEFAULT = "data/mets.xml";

This comment has been minimized.

Copy link
@kba

kba Nov 2, 2018

Member

Does the bagit lib you're using handle bagit profiles? E.g. this information is in the profile json we have in spec.

This comment has been minimized.

Copy link
@VolkerHartmann

VolkerHartmann Nov 5, 2018

Contributor

LibraryOfCongress/bagit-java#78
Unfortunately at the moment there is no bag that contains the corresponding information!
It's some kind of hen egg problem.

This comment has been minimized.


/**
* Services for handling METS documents.
Expand Down Expand Up @@ -140,7 +155,7 @@ public ResponseEntity<Resource> serveFile(@PathVariable String filename) {
*/
@Override
public ResponseEntity<?> handleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) throws IOException {
RedirectAttributes redirectAttributes) throws IOException, BagItException {
LOGGER.info("handleFileUpload");
storageService.store(file);
redirectAttributes.addFlashAttribute("message",
Expand All @@ -152,10 +167,16 @@ public ResponseEntity<?> handleFileUpload(@RequestParam("file") MultipartFile fi
if (file.getOriginalFilename().endsWith(".zip")) {
String baseName = FilenameUtils.getBaseName(file.getOriginalFilename());
Path pathToArchive = Paths.get(archiveService.getBasePath(), baseName);
Path createDirectory = Files.createDirectory(pathToArchive);
Path createDirectory;
try {
createDirectory = Files.createDirectory(pathToArchive);
} catch (FileAlreadyExistsException faee) {
LOGGER.error("File '{}' already exists!", baseName, faee);
throw new ResourceAlreadyExistsException("File '" + baseName + "' already exists!");
}
ZipUtils.unzip(storageService.getPath(file.getOriginalFilename()).toFile(), createDirectory.toFile());
Bag bag = BagItUtil.createBag(pathToArchive.toFile());
String xOcrdMets = bag.getBagInfoTxt().getOrDefault("X-Ocrd-Mets", "data/mets.xml");
Bag bag = BagItUtil.readBag(pathToArchive);
String xOcrdMets = getPathToMets(bag);
File metsFile = Paths.get(pathToArchive.toString(), xOcrdMets).toFile();
if (metsFile.exists()) {
String metsFileAsString = FileUtils.readFileToString(metsFile, "UTF-8");
Expand All @@ -170,16 +191,22 @@ public ResponseEntity<?> handleFileUpload(@RequestParam("file") MultipartFile fi
LOGGER.info(location.toString());
return ResponseEntity.created(location).build();
}

/**
* Handler for Exceptions.
*
* @param exc Exception reading/writing file.
*
* @return Error status.
/**
* Determines the path to the METS file.
*
* @param bag BagIt container.
*
* @return Relative path to METS file.
*/
@ExceptionHandler(StorageFileNotFoundException.class)
public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {
return ResponseEntity.notFound().build();
private String getPathToMets(Bag bag) {
List<String> listOfEntries = bag.getMetadata().get(X_OCRD_METS);
String pathToMets = METS_LOCATION_DEFAULT;
if (listOfEntries != null) {
if (listOfEntries.size() > 1) {
LOGGER.warn("There are multiple location for METS defined!");
}
pathToMets = listOfEntries.get(0);
}
return pathToMets;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2018 Karlsruhe Institute of Technology.
*
* 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
*
* http://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 edu.kit.datamanager.metastore.controller.impl;

import edu.kit.datamanager.metastore.storageservice.StorageFileNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import edu.kit.datamanager.metastore.exception.BagItException;
import edu.kit.datamanager.metastore.exception.ResourceAlreadyExistsException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

/**
* Handling Exceptions
*/
@ControllerAdvice
public class SpringBootExceptionHandler{

/**
* Logger for this class.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(SpringBootExceptionHandler.class);

/**
* Handler for FileNotFoundExceptions.
*
* @param exc Exception writing file.
*
* @return Error status.
*/
@ExceptionHandler(ResourceAlreadyExistsException.class)
public ResponseEntity<?> handleStorageFileNotFound(ResourceAlreadyExistsException exc) {
return ResponseEntity.badRequest().body(exc.getMessage());
}

/**
* Handler for FileNotFoundExceptions.
*
* @param exc Exception reading/writing file.
*
* @return Error status.
*/
@ExceptionHandler(StorageFileNotFoundException.class)
public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {
return ResponseEntity.notFound().build();
}

/**
* Handler for BagItExceptions.
*
* @param exc Exception reading/writing BagIt container.
*
* @return Error status.
*/
@ExceptionHandler(BagItException.class)
public ResponseEntity<?> handleInvalidBagItContainer(BagItException exc) {
return ResponseEntity.badRequest().body(exc.getMessage());
}
/**
* Handler for exceeding maximum size for uploading files.
*
* @param exc Exception thrown by SpringBoot.
* @param request Instance holding request.
* @param response Instance holding response.
*
* @return Message for client.
*/
@ExceptionHandler(MaxUploadSizeExceededException.class)
public ResponseEntity<?> handleMaxSizeException(MaxUploadSizeExceededException exc, RedirectAttributes redirectAttributes) {
String message = exc.getRootCause().getMessage();
return ResponseEntity.badRequest().body(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2018 Karlsruhe Institute of Technology.
*
* 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
*
* http://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 edu.kit.datamanager.metastore.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;

/**
* Invalid format of data.
*/
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public class BagItException extends RuntimeException {

/**
* Default constructor.
*/
public BagItException() {
super();
}

/**
* Constructor with given message and cause.
*
* @param message Message.
* @param cause Cause.
*/
public BagItException(String message, Throwable cause) {
super(message, cause);
}

/**
* Constructor with given message.
*
* @param message Message.
*/
public BagItException(String message) {
super(message);
}

/**
* Constructor with given message and cause.
*
* @param cause Cause.
*/
public BagItException(Throwable cause) {
super(cause);
}
}
Loading

0 comments on commit db6e1f2

Please sign in to comment.