package eu.openaire.urls_worker.controllers; import eu.openaire.urls_worker.services.FileStorageService; import eu.openaire.urls_worker.util.FilesZipper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; import java.io.File; import java.util.HashMap; import java.util.List; @RestController @RequestMapping("full-texts/") public class FullTextsController { private static final Logger logger = LoggerFactory.getLogger(GeneralController.class); private final FileStorageService fileStorageService; public static HashMap assignmentsNumsHandledAndLocallyDeleted = new HashMap<>(); public static String assignmentsBaseDir = null; public FullTextsController(FileStorageService fileStorageService) { this.fileStorageService = fileStorageService; assignmentsBaseDir = FileStorageService.assignmentsLocation.toString() + File.separator; } @GetMapping("getFullTexts/{assignmentsCounter:[\\d]+}/{totalZipBatches:[\\d]+}/{zipBatchCounter:[\\d]+}/{fileNamesWithExtensions}") public ResponseEntity getMultipleFullTexts(@PathVariable long assignmentsCounter, @PathVariable int totalZipBatches, @PathVariable int zipBatchCounter, @PathVariable List fileNamesWithExtensions, HttpServletRequest request) { int fileNamesListNum = fileNamesWithExtensions.size(); if ( (fileNamesListNum == 1) && (fileNamesWithExtensions.get(0).length() == 0) ) { // In case the last "/" in the url was given, then this list will not be empty, but have one empty item instead. // In case the url does not end in "/", then Spring will automatically return an "HTTP-BadRequest". String errorMsg = "An empty \"fileNamesWithExtensions\" list was given from assignments_" + assignmentsCounter + ", for batch_" + zipBatchCounter; logger.warn(errorMsg); return ResponseEntity.badRequest().body(errorMsg); } logger.info("Received a \"getMultipleFullTexts\" request for returning a zip-file containing " + fileNamesListNum + " full-texts, from assignments_" + assignmentsCounter + ", for batch_" + zipBatchCounter); String currentAssignmentsBaseFullTextsPath = assignmentsBaseDir + "assignments_" + assignmentsCounter + "_fullTexts" + File.separator; if ( ! (new File(currentAssignmentsBaseFullTextsPath).isDirectory()) ) { String errorMsg = "The base directory for assignments_" + assignmentsCounter + " was not found: " + currentAssignmentsBaseFullTextsPath; logger.error(errorMsg); return ResponseEntity.badRequest().body(errorMsg); } if ( zipBatchCounter > totalZipBatches ) { String errorMsg = "The given \"zipBatchCounter\" (" + zipBatchCounter + ") is greater than the \"totalZipBatches\" (" + totalZipBatches + ")!"; logger.error(errorMsg); return ResponseEntity.badRequest().body(errorMsg); } File zipFile = FilesZipper.zipMultipleFilesAndGetZip(assignmentsCounter, zipBatchCounter, fileNamesWithExtensions, currentAssignmentsBaseFullTextsPath); if ( zipFile == null ) { String errorMsg = "Failed to create the zip file for \"zipBatchCounter\"-" + zipBatchCounter; logger.error(errorMsg); return ResponseEntity.internalServerError().body(errorMsg); } String zipName = zipFile.getName(); String zipFileFullPath = currentAssignmentsBaseFullTextsPath + zipName; ByteArrayOutputStream byteArrayOutputStream = this.fileStorageService.loadFileAsAStream(zipFileFullPath); if ( byteArrayOutputStream == null ) return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Could not load file: " + zipFileFullPath); // If this is the last batch for this assignments-count, then make sure it is deleted in the next scheduled delete-operation. if ( zipBatchCounter == totalZipBatches ) { assignmentsNumsHandledAndLocallyDeleted.put(assignmentsCounter, false); logger.debug("Will return the last batch of Assignments_" + assignmentsCounter + " to the Controller and these assignments will be deleted later."); } String contentType = request.getServletContext().getMimeType(zipFileFullPath); if ( contentType == null ) contentType = "application/octet-stream"; logger.info("Sending the zip file \"" + zipFileFullPath + "\"."); return ResponseEntity.ok() .contentType(MediaType.parseMediaType(contentType)) .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + zipName + "\"") .body(byteArrayOutputStream.toByteArray()); } @GetMapping("getFullText/{assignmentsCounter:[\\d]+]}/{fileNameWithExtension:[\\w]+.[\\w]{2,10}}") public ResponseEntity getFullText(@PathVariable long assignmentsCounter, @PathVariable String fileNameWithExtension, HttpServletRequest request) { logger.info("Received a \"getFullText\" request."); String fullTextFile = assignmentsBaseDir + "assignments_" + assignmentsCounter + "_fullTexts" + File.separator + fileNameWithExtension; File file = new File(fullTextFile); if ( !file.isFile() ) { logger.error("The file \"" + fullTextFile + "\" does not exist!"); return ResponseEntity.notFound().build(); } Resource resource = this.fileStorageService.loadFileAsResource(fullTextFile); if ( resource == null ) return ResponseEntity.internalServerError().body("Could not load file: " + fullTextFile); String contentType = null; contentType = request.getServletContext().getMimeType(file.getAbsolutePath()); if ( contentType == null ) { contentType = "application/octet-stream"; } return ResponseEntity.ok() .contentType(MediaType.parseMediaType(contentType)) .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + resource.getFilename() + "\"") .body(resource); } }