mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-03-17 21:36:54 +01:00
formatting
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
package stirling.software.SPDF.controller.api.pipeline;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
@@ -17,44 +19,39 @@ import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
|
||||
import stirling.software.SPDF.SPdfApplication;
|
||||
import stirling.software.SPDF.model.ApiEndpoint;
|
||||
import stirling.software.SPDF.model.Role;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@Service
|
||||
public class ApiDocService {
|
||||
|
||||
private final Map<String, ApiEndpoint> apiDocumentation = new HashMap<>();
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ApiDocService.class);
|
||||
|
||||
@Autowired
|
||||
private ServletContext servletContext;
|
||||
|
||||
@Autowired private ServletContext servletContext;
|
||||
|
||||
private String getApiDocsUrl() {
|
||||
String contextPath = servletContext.getContextPath();
|
||||
String port = SPdfApplication.getPort();
|
||||
|
||||
return "http://localhost:"+ port + contextPath + "/v1/api-docs";
|
||||
return "http://localhost:" + port + contextPath + "/v1/api-docs";
|
||||
}
|
||||
|
||||
|
||||
@Autowired(required=false)
|
||||
private UserServiceInterface userService;
|
||||
@Autowired(required = false)
|
||||
private UserServiceInterface userService;
|
||||
|
||||
private String getApiKeyForUser() {
|
||||
if(userService == null)
|
||||
return "";
|
||||
return userService.getApiKeyForUser(Role.INTERNAL_API_USER.getRoleId());
|
||||
}
|
||||
|
||||
JsonNode apiDocsJsonRootNode;
|
||||
|
||||
|
||||
//@EventListener(ApplicationReadyEvent.class)
|
||||
private synchronized void loadApiDocumentation() {
|
||||
String apiDocsJson = "";
|
||||
private String getApiKeyForUser() {
|
||||
if (userService == null) return "";
|
||||
return userService.getApiKeyForUser(Role.INTERNAL_API_USER.getRoleId());
|
||||
}
|
||||
|
||||
JsonNode apiDocsJsonRootNode;
|
||||
|
||||
// @EventListener(ApplicationReadyEvent.class)
|
||||
private synchronized void loadApiDocumentation() {
|
||||
String apiDocsJson = "";
|
||||
try {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
String apiKey = getApiKeyForUser();
|
||||
@@ -64,49 +61,52 @@ public class ApiDocService {
|
||||
HttpEntity<String> entity = new HttpEntity<>(headers);
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
ResponseEntity<String> response = restTemplate.exchange(getApiDocsUrl(), HttpMethod.GET, entity, String.class);
|
||||
ResponseEntity<String> response =
|
||||
restTemplate.exchange(getApiDocsUrl(), HttpMethod.GET, entity, String.class);
|
||||
apiDocsJson = response.getBody();
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
apiDocsJsonRootNode = mapper.readTree(apiDocsJson);
|
||||
|
||||
JsonNode paths = apiDocsJsonRootNode.path("paths");
|
||||
paths.fields().forEachRemaining(entry -> {
|
||||
String path = entry.getKey();
|
||||
JsonNode pathNode = entry.getValue();
|
||||
if (pathNode.has("post")) {
|
||||
JsonNode postNode = pathNode.get("post");
|
||||
ApiEndpoint endpoint = new ApiEndpoint(path, postNode);
|
||||
apiDocumentation.put(path, endpoint);
|
||||
}
|
||||
});
|
||||
paths.fields()
|
||||
.forEachRemaining(
|
||||
entry -> {
|
||||
String path = entry.getKey();
|
||||
JsonNode pathNode = entry.getValue();
|
||||
if (pathNode.has("post")) {
|
||||
JsonNode postNode = pathNode.get("post");
|
||||
ApiEndpoint endpoint = new ApiEndpoint(path, postNode);
|
||||
apiDocumentation.put(path, endpoint);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
// Handle exceptions
|
||||
logger.error("Error grabbing swagger doc, body result {}", apiDocsJson);
|
||||
logger.error("Error grabbing swagger doc, body result {}", apiDocsJson);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isValidOperation(String operationName, Map<String, Object> parameters) {
|
||||
if(apiDocumentation.size() == 0) {
|
||||
loadApiDocumentation();
|
||||
}
|
||||
if (apiDocumentation.size() == 0) {
|
||||
loadApiDocumentation();
|
||||
}
|
||||
if (!apiDocumentation.containsKey(operationName)) {
|
||||
return false;
|
||||
}
|
||||
ApiEndpoint endpoint = apiDocumentation.get(operationName);
|
||||
return endpoint.areParametersValid(parameters);
|
||||
}
|
||||
|
||||
|
||||
public boolean isMultiInput(String operationName) {
|
||||
if(apiDocsJsonRootNode == null || apiDocumentation.size() == 0) {
|
||||
loadApiDocumentation();
|
||||
}
|
||||
if (!apiDocumentation.containsKey(operationName)) {
|
||||
if (apiDocsJsonRootNode == null || apiDocumentation.size() == 0) {
|
||||
loadApiDocumentation();
|
||||
}
|
||||
if (!apiDocumentation.containsKey(operationName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ApiEndpoint endpoint = apiDocumentation.get(operationName);
|
||||
String description = endpoint.getDescription();
|
||||
String description = endpoint.getDescription();
|
||||
|
||||
Pattern pattern = Pattern.compile("Type:(\\w+)");
|
||||
Matcher matcher = pattern.matcher(description);
|
||||
@@ -115,9 +115,8 @@ public class ApiDocService {
|
||||
return type.startsWith("MI");
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Model class for API Endpoint
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
||||
import stirling.software.SPDF.model.ApplicationProperties;
|
||||
import stirling.software.SPDF.model.PipelineConfig;
|
||||
import stirling.software.SPDF.model.api.HandleDataRequest;
|
||||
@@ -34,84 +35,80 @@ import stirling.software.SPDF.utils.WebResponseUtils;
|
||||
@Tag(name = "Pipeline", description = "Pipeline APIs")
|
||||
public class PipelineController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PipelineController.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(PipelineController.class);
|
||||
|
||||
final String watchedFoldersDir = "./pipeline/watchedFolders/";
|
||||
final String finishedFoldersDir = "./pipeline/finishedFolders/";
|
||||
@Autowired
|
||||
PipelineProcessor processor;
|
||||
|
||||
final String watchedFoldersDir = "./pipeline/watchedFolders/";
|
||||
final String finishedFoldersDir = "./pipeline/finishedFolders/";
|
||||
@Autowired PipelineProcessor processor;
|
||||
|
||||
@Autowired
|
||||
ApplicationProperties applicationProperties;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired ApplicationProperties applicationProperties;
|
||||
|
||||
@PostMapping("/handleData")
|
||||
public ResponseEntity<byte[]> handleData(@ModelAttribute HandleDataRequest request) throws JsonMappingException, JsonProcessingException {
|
||||
if (!Boolean.TRUE.equals(applicationProperties.getSystem().getEnableAlphaFunctionality())) {
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
@Autowired private ObjectMapper objectMapper;
|
||||
|
||||
MultipartFile[] files = request.getFileInput();
|
||||
String jsonString = request.getJson();
|
||||
if (files == null) {
|
||||
return null;
|
||||
}
|
||||
PipelineConfig config = objectMapper.readValue(jsonString, PipelineConfig.class);
|
||||
logger.info("Received POST request to /handleData with {} files", files.length);
|
||||
try {
|
||||
List<Resource> inputFiles = processor.generateInputFiles(files);
|
||||
if(inputFiles == null || inputFiles.size() == 0) {
|
||||
return null;
|
||||
@PostMapping("/handleData")
|
||||
public ResponseEntity<byte[]> handleData(@ModelAttribute HandleDataRequest request)
|
||||
throws JsonMappingException, JsonProcessingException {
|
||||
if (!Boolean.TRUE.equals(applicationProperties.getSystem().getEnableAlphaFunctionality())) {
|
||||
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
MultipartFile[] files = request.getFileInput();
|
||||
String jsonString = request.getJson();
|
||||
if (files == null) {
|
||||
return null;
|
||||
}
|
||||
PipelineConfig config = objectMapper.readValue(jsonString, PipelineConfig.class);
|
||||
logger.info("Received POST request to /handleData with {} files", files.length);
|
||||
try {
|
||||
List<Resource> inputFiles = processor.generateInputFiles(files);
|
||||
if (inputFiles == null || inputFiles.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
List<Resource> outputFiles = processor.runPipelineAgainstFiles(inputFiles, config);
|
||||
if (outputFiles != null && outputFiles.size() == 1) {
|
||||
// If there is only one file, return it directly
|
||||
Resource singleFile = outputFiles.get(0);
|
||||
InputStream is = singleFile.getInputStream();
|
||||
byte[] bytes = new byte[(int) singleFile.contentLength()];
|
||||
is.read(bytes);
|
||||
is.close();
|
||||
List<Resource> outputFiles = processor.runPipelineAgainstFiles(inputFiles, config);
|
||||
if (outputFiles != null && outputFiles.size() == 1) {
|
||||
// If there is only one file, return it directly
|
||||
Resource singleFile = outputFiles.get(0);
|
||||
InputStream is = singleFile.getInputStream();
|
||||
byte[] bytes = new byte[(int) singleFile.contentLength()];
|
||||
is.read(bytes);
|
||||
is.close();
|
||||
|
||||
logger.info("Returning single file response...");
|
||||
return WebResponseUtils.bytesToWebResponse(bytes, singleFile.getFilename(),
|
||||
MediaType.APPLICATION_OCTET_STREAM);
|
||||
} else if (outputFiles == null) {
|
||||
return null;
|
||||
}
|
||||
logger.info("Returning single file response...");
|
||||
return WebResponseUtils.bytesToWebResponse(
|
||||
bytes, singleFile.getFilename(), MediaType.APPLICATION_OCTET_STREAM);
|
||||
} else if (outputFiles == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create a ByteArrayOutputStream to hold the zip
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOut = new ZipOutputStream(baos);
|
||||
// Create a ByteArrayOutputStream to hold the zip
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ZipOutputStream zipOut = new ZipOutputStream(baos);
|
||||
|
||||
// Loop through each file and add it to the zip
|
||||
for (Resource file : outputFiles) {
|
||||
ZipEntry zipEntry = new ZipEntry(file.getFilename());
|
||||
zipOut.putNextEntry(zipEntry);
|
||||
// Loop through each file and add it to the zip
|
||||
for (Resource file : outputFiles) {
|
||||
ZipEntry zipEntry = new ZipEntry(file.getFilename());
|
||||
zipOut.putNextEntry(zipEntry);
|
||||
|
||||
// Read the file into a byte array
|
||||
InputStream is = file.getInputStream();
|
||||
byte[] bytes = new byte[(int) file.contentLength()];
|
||||
is.read(bytes);
|
||||
// Read the file into a byte array
|
||||
InputStream is = file.getInputStream();
|
||||
byte[] bytes = new byte[(int) file.contentLength()];
|
||||
is.read(bytes);
|
||||
|
||||
// Write the bytes of the file to the zip
|
||||
zipOut.write(bytes, 0, bytes.length);
|
||||
zipOut.closeEntry();
|
||||
// Write the bytes of the file to the zip
|
||||
zipOut.write(bytes, 0, bytes.length);
|
||||
zipOut.closeEntry();
|
||||
|
||||
is.close();
|
||||
}
|
||||
is.close();
|
||||
}
|
||||
|
||||
zipOut.close();
|
||||
|
||||
logger.info("Returning zipped file response...");
|
||||
return WebResponseUtils.boasToWebResponse(baos, "output.zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error handling data: ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
zipOut.close();
|
||||
|
||||
logger.info("Returning zipped file response...");
|
||||
return WebResponseUtils.boasToWebResponse(
|
||||
baos, "output.zip", MediaType.APPLICATION_OCTET_STREAM);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error handling data: ", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,50 +33,48 @@ import stirling.software.SPDF.model.PipelineOperation;
|
||||
@Service
|
||||
public class PipelineDirectoryProcessor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PipelineDirectoryProcessor.class);
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
@Autowired
|
||||
private ApiDocService apiDocService;
|
||||
@Autowired
|
||||
private ApplicationProperties applicationProperties;
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PipelineDirectoryProcessor.class);
|
||||
@Autowired private ObjectMapper objectMapper;
|
||||
@Autowired private ApiDocService apiDocService;
|
||||
@Autowired private ApplicationProperties applicationProperties;
|
||||
|
||||
final String watchedFoldersDir = "./pipeline/watchedFolders/";
|
||||
final String finishedFoldersDir = "./pipeline/finishedFolders/";
|
||||
|
||||
@Autowired
|
||||
PipelineProcessor processor;
|
||||
final String finishedFoldersDir = "./pipeline/finishedFolders/";
|
||||
|
||||
@Autowired PipelineProcessor processor;
|
||||
|
||||
@Scheduled(fixedRate = 60000)
|
||||
public void scanFolders() {
|
||||
if (!Boolean.TRUE.equals(applicationProperties.getSystem().getEnableAlphaFunctionality())) {
|
||||
return;
|
||||
}
|
||||
Path watchedFolderPath = Paths.get(watchedFoldersDir);
|
||||
if (!Files.exists(watchedFolderPath)) {
|
||||
try {
|
||||
Files.createDirectories(watchedFolderPath);
|
||||
logger.info("Created directory: {}", watchedFolderPath);
|
||||
} catch (IOException e) {
|
||||
logger.error("Error creating directory: {}", watchedFolderPath, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try (Stream<Path> paths = Files.walk(watchedFolderPath)) {
|
||||
paths.filter(Files::isDirectory).forEach(t -> {
|
||||
try {
|
||||
if (!t.equals(watchedFolderPath) && !t.endsWith("processing")) {
|
||||
handleDirectory(t);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error handling directory: {}", t, e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.error("Error walking through directory: {}", watchedFolderPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void scanFolders() {
|
||||
if (!Boolean.TRUE.equals(applicationProperties.getSystem().getEnableAlphaFunctionality())) {
|
||||
return;
|
||||
}
|
||||
Path watchedFolderPath = Paths.get(watchedFoldersDir);
|
||||
if (!Files.exists(watchedFolderPath)) {
|
||||
try {
|
||||
Files.createDirectories(watchedFolderPath);
|
||||
logger.info("Created directory: {}", watchedFolderPath);
|
||||
} catch (IOException e) {
|
||||
logger.error("Error creating directory: {}", watchedFolderPath, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
try (Stream<Path> paths = Files.walk(watchedFolderPath)) {
|
||||
paths.filter(Files::isDirectory)
|
||||
.forEach(
|
||||
t -> {
|
||||
try {
|
||||
if (!t.equals(watchedFolderPath) && !t.endsWith("processing")) {
|
||||
handleDirectory(t);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("Error handling directory: {}", t, e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.error("Error walking through directory: {}", watchedFolderPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleDirectory(Path dir) throws IOException {
|
||||
logger.info("Handling directory: {}", dir);
|
||||
Path processingDir = createProcessingDirectory(dir);
|
||||
@@ -113,13 +111,14 @@ public class PipelineDirectoryProcessor {
|
||||
return objectMapper.readValue(jsonString, PipelineConfig.class);
|
||||
}
|
||||
|
||||
private void processPipelineOperations(Path dir, Path processingDir, Path jsonFile, PipelineConfig config) throws IOException {
|
||||
private void processPipelineOperations(
|
||||
Path dir, Path processingDir, Path jsonFile, PipelineConfig config) throws IOException {
|
||||
for (PipelineOperation operation : config.getOperations()) {
|
||||
validateOperation(operation);
|
||||
File[] files = collectFilesForProcessing(dir, jsonFile, operation);
|
||||
if(files == null || files.length == 0) {
|
||||
logger.debug("No files detected for {} ", dir);
|
||||
return;
|
||||
if (files == null || files.length == 0) {
|
||||
logger.debug("No files detected for {} ", dir);
|
||||
return;
|
||||
}
|
||||
List<File> filesToProcess = prepareFilesForProcessing(files, processingDir);
|
||||
runPipelineAgainstFiles(filesToProcess, config, dir, processingDir);
|
||||
@@ -132,20 +131,22 @@ public class PipelineDirectoryProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private File[] collectFilesForProcessing(Path dir, Path jsonFile, PipelineOperation operation) throws IOException {
|
||||
private File[] collectFilesForProcessing(Path dir, Path jsonFile, PipelineOperation operation)
|
||||
throws IOException {
|
||||
try (Stream<Path> paths = Files.list(dir)) {
|
||||
if ("automated".equals(operation.getParameters().get("fileInput"))) {
|
||||
return paths.filter(path -> !Files.isDirectory(path) && !path.equals(jsonFile))
|
||||
.map(Path::toFile)
|
||||
.toArray(File[]::new);
|
||||
.map(Path::toFile)
|
||||
.toArray(File[]::new);
|
||||
} else {
|
||||
String fileInput = (String) operation.getParameters().get("fileInput");
|
||||
return new File[]{new File(fileInput)};
|
||||
return new File[] {new File(fileInput)};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<File> prepareFilesForProcessing(File[] files, Path processingDir) throws IOException {
|
||||
private List<File> prepareFilesForProcessing(File[] files, Path processingDir)
|
||||
throws IOException {
|
||||
List<File> filesToProcess = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
Path targetPath = resolveUniqueFilePath(processingDir, file.getName());
|
||||
@@ -173,27 +174,33 @@ public class PipelineDirectoryProcessor {
|
||||
if (dotIndex == -1) {
|
||||
return originalFileName + suffix;
|
||||
} else {
|
||||
return originalFileName.substring(0, dotIndex) + suffix + originalFileName.substring(dotIndex);
|
||||
return originalFileName.substring(0, dotIndex)
|
||||
+ suffix
|
||||
+ originalFileName.substring(dotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void runPipelineAgainstFiles(List<File> filesToProcess, PipelineConfig config, Path dir, Path processingDir) throws IOException {
|
||||
private void runPipelineAgainstFiles(
|
||||
List<File> filesToProcess, PipelineConfig config, Path dir, Path processingDir)
|
||||
throws IOException {
|
||||
try {
|
||||
List<Resource> inputFiles = processor.generateInputFiles(filesToProcess.toArray(new File[0]));
|
||||
if(inputFiles == null || inputFiles.size() == 0) {
|
||||
return;
|
||||
List<Resource> inputFiles =
|
||||
processor.generateInputFiles(filesToProcess.toArray(new File[0]));
|
||||
if (inputFiles == null || inputFiles.size() == 0) {
|
||||
return;
|
||||
}
|
||||
List<Resource> outputFiles = processor.runPipelineAgainstFiles(inputFiles, config);
|
||||
List<Resource> outputFiles = processor.runPipelineAgainstFiles(inputFiles, config);
|
||||
if (outputFiles == null) return;
|
||||
moveAndRenameFiles(outputFiles, config, dir);
|
||||
deleteOriginalFiles(filesToProcess, processingDir);
|
||||
} catch (Exception e) {
|
||||
logger.error("error during processing", e);
|
||||
logger.error("error during processing", e);
|
||||
moveFilesBack(filesToProcess, processingDir);
|
||||
}
|
||||
}
|
||||
|
||||
private void moveAndRenameFiles(List<Resource> resources, PipelineConfig config, Path dir) throws IOException {
|
||||
private void moveAndRenameFiles(List<Resource> resources, PipelineConfig config, Path dir)
|
||||
throws IOException {
|
||||
for (Resource resource : resources) {
|
||||
String outputFileName = createOutputFileName(resource, config);
|
||||
Path outputPath = determineOutputPath(config, dir);
|
||||
@@ -217,26 +224,36 @@ public class PipelineDirectoryProcessor {
|
||||
String baseName = resourceName.substring(0, resourceName.lastIndexOf('.'));
|
||||
String extension = resourceName.substring(resourceName.lastIndexOf('.') + 1);
|
||||
|
||||
String outputFileName = config.getOutputPattern()
|
||||
.replace("{filename}", baseName)
|
||||
.replace("{pipelineName}", config.getName())
|
||||
.replace("{date}", LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")))
|
||||
.replace("{time}", LocalTime.now().format(DateTimeFormatter.ofPattern("HHmmss")))
|
||||
+ "." + extension;
|
||||
String outputFileName =
|
||||
config.getOutputPattern()
|
||||
.replace("{filename}", baseName)
|
||||
.replace("{pipelineName}", config.getName())
|
||||
.replace(
|
||||
"{date}",
|
||||
LocalDate.now()
|
||||
.format(DateTimeFormatter.ofPattern("yyyyMMdd")))
|
||||
.replace(
|
||||
"{time}",
|
||||
LocalTime.now()
|
||||
.format(DateTimeFormatter.ofPattern("HHmmss")))
|
||||
+ "."
|
||||
+ extension;
|
||||
|
||||
return outputFileName;
|
||||
}
|
||||
|
||||
private Path determineOutputPath(PipelineConfig config, Path dir) {
|
||||
String outputDir = config.getOutputDir()
|
||||
.replace("{outputFolder}", finishedFoldersDir)
|
||||
.replace("{folderName}", dir.toString())
|
||||
.replaceAll("\\\\?watchedFolders", "");
|
||||
String outputDir =
|
||||
config.getOutputDir()
|
||||
.replace("{outputFolder}", finishedFoldersDir)
|
||||
.replace("{folderName}", dir.toString())
|
||||
.replaceAll("\\\\?watchedFolders", "");
|
||||
|
||||
return Paths.get(outputDir).isAbsolute() ? Paths.get(outputDir) : Paths.get(".", outputDir);
|
||||
}
|
||||
|
||||
private void deleteOriginalFiles(List<File> filesToProcess, Path processingDir) throws IOException {
|
||||
private void deleteOriginalFiles(List<File> filesToProcess, Path processingDir)
|
||||
throws IOException {
|
||||
for (File file : filesToProcess) {
|
||||
Files.deleteIfExists(processingDir.resolve(file.getName()));
|
||||
logger.info("Deleted original file: {}", file.getName());
|
||||
@@ -247,12 +264,13 @@ public class PipelineDirectoryProcessor {
|
||||
for (File file : filesToProcess) {
|
||||
try {
|
||||
Files.move(processingDir.resolve(file.getName()), file.toPath());
|
||||
logger.info("Moved file back to original location: {} , {}",file.toPath(), file.getName());
|
||||
logger.info(
|
||||
"Moved file back to original location: {} , {}",
|
||||
file.toPath(),
|
||||
file.getName());
|
||||
} catch (IOException e) {
|
||||
logger.error("Error moving file back to original location: {}", file.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import jakarta.servlet.ServletContext;
|
||||
|
||||
import stirling.software.SPDF.SPdfApplication;
|
||||
import stirling.software.SPDF.model.PipelineConfig;
|
||||
import stirling.software.SPDF.model.PipelineOperation;
|
||||
@@ -43,152 +42,160 @@ import stirling.software.SPDF.model.Role;
|
||||
@Service
|
||||
public class PipelineProcessor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PipelineProcessor.class);
|
||||
private static final Logger logger = LoggerFactory.getLogger(PipelineProcessor.class);
|
||||
|
||||
@Autowired private ApiDocService apiDocService;
|
||||
|
||||
@Autowired
|
||||
private ApiDocService apiDocService;
|
||||
|
||||
@Autowired(required=false)
|
||||
@Autowired(required = false)
|
||||
private UserServiceInterface userService;
|
||||
|
||||
@Autowired
|
||||
private ServletContext servletContext;
|
||||
|
||||
|
||||
@Autowired private ServletContext servletContext;
|
||||
|
||||
private String getApiKeyForUser() {
|
||||
if (userService == null) return "";
|
||||
return userService.getApiKeyForUser(Role.INTERNAL_API_USER.getRoleId());
|
||||
}
|
||||
|
||||
private String getApiKeyForUser() {
|
||||
if (userService == null)
|
||||
return "";
|
||||
return userService.getApiKeyForUser(Role.INTERNAL_API_USER.getRoleId());
|
||||
}
|
||||
private String getBaseUrl() {
|
||||
String contextPath = servletContext.getContextPath();
|
||||
String port = SPdfApplication.getPort();
|
||||
|
||||
return "http://localhost:" + port + contextPath + "/";
|
||||
}
|
||||
|
||||
private String getBaseUrl() {
|
||||
String contextPath = servletContext.getContextPath();
|
||||
String port = SPdfApplication.getPort();
|
||||
List<Resource> runPipelineAgainstFiles(List<Resource> outputFiles, PipelineConfig config)
|
||||
throws Exception {
|
||||
|
||||
return "http://localhost:" + port + contextPath + "/";
|
||||
}
|
||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
||||
PrintStream logPrintStream = new PrintStream(logStream);
|
||||
|
||||
|
||||
|
||||
List<Resource> runPipelineAgainstFiles(List<Resource> outputFiles, PipelineConfig config) throws Exception {
|
||||
boolean hasErrors = false;
|
||||
|
||||
ByteArrayOutputStream logStream = new ByteArrayOutputStream();
|
||||
PrintStream logPrintStream = new PrintStream(logStream);
|
||||
for (PipelineOperation pipelineOperation : config.getOperations()) {
|
||||
String operation = pipelineOperation.getOperation();
|
||||
boolean isMultiInputOperation = apiDocService.isMultiInput(operation);
|
||||
|
||||
boolean hasErrors = false;
|
||||
logger.info(
|
||||
"Running operation: {} isMultiInputOperation {}",
|
||||
operation,
|
||||
isMultiInputOperation);
|
||||
Map<String, Object> parameters = pipelineOperation.getParameters();
|
||||
String inputFileExtension = "";
|
||||
|
||||
for (PipelineOperation pipelineOperation : config.getOperations()) {
|
||||
String operation = pipelineOperation.getOperation();
|
||||
boolean isMultiInputOperation = apiDocService.isMultiInput(operation);
|
||||
// TODO
|
||||
// if (operationNode.has("inputFileType")) {
|
||||
// inputFileExtension = operationNode.get("inputFileType").asText();
|
||||
// } else {
|
||||
inputFileExtension = ".pdf";
|
||||
// }
|
||||
final String finalInputFileExtension = inputFileExtension;
|
||||
|
||||
logger.info("Running operation: {} isMultiInputOperation {}", operation, isMultiInputOperation);
|
||||
Map<String, Object> parameters = pipelineOperation.getParameters();
|
||||
String inputFileExtension = "";
|
||||
|
||||
//TODO
|
||||
//if (operationNode.has("inputFileType")) {
|
||||
// inputFileExtension = operationNode.get("inputFileType").asText();
|
||||
//} else {
|
||||
inputFileExtension = ".pdf";
|
||||
//}
|
||||
final String finalInputFileExtension = inputFileExtension;
|
||||
|
||||
String url = getBaseUrl() + operation;
|
||||
|
||||
List<Resource> newOutputFiles = new ArrayList<>();
|
||||
if (!isMultiInputOperation) {
|
||||
for (Resource file : outputFiles) {
|
||||
boolean hasInputFileType = false;
|
||||
if (file.getFilename().endsWith(inputFileExtension)) {
|
||||
hasInputFileType = true;
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("fileInput", file);
|
||||
String url = getBaseUrl() + operation;
|
||||
|
||||
|
||||
for(Entry<String, Object> entry : parameters.entrySet()) {
|
||||
body.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
List<Resource> newOutputFiles = new ArrayList<>();
|
||||
if (!isMultiInputOperation) {
|
||||
for (Resource file : outputFiles) {
|
||||
boolean hasInputFileType = false;
|
||||
if (file.getFilename().endsWith(inputFileExtension)) {
|
||||
hasInputFileType = true;
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("fileInput", file);
|
||||
|
||||
ResponseEntity<byte[]> response = sendWebRequest(url, body);
|
||||
for (Entry<String, Object> entry : parameters.entrySet()) {
|
||||
body.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
// If the operation is filter and the response body is null or empty, skip this
|
||||
// file
|
||||
if (operation.startsWith("filter-")
|
||||
&& (response.getBody() == null || response.getBody().length == 0)) {
|
||||
logger.info("Skipping file due to failing {}", operation);
|
||||
continue;
|
||||
}
|
||||
ResponseEntity<byte[]> response = sendWebRequest(url, body);
|
||||
|
||||
if (!response.getStatusCode().equals(HttpStatus.OK)) {
|
||||
logPrintStream.println("Error: " + response.getBody());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
processOutputFiles(operation, file.getFilename(), response, newOutputFiles);
|
||||
|
||||
}
|
||||
// If the operation is filter and the response body is null or empty, skip
|
||||
// this
|
||||
// file
|
||||
if (operation.startsWith("filter-")
|
||||
&& (response.getBody() == null || response.getBody().length == 0)) {
|
||||
logger.info("Skipping file due to failing {}", operation);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hasInputFileType) {
|
||||
logPrintStream.println(
|
||||
"No files with extension " + inputFileExtension + " found for operation " + operation);
|
||||
hasErrors = true;
|
||||
}
|
||||
if (!response.getStatusCode().equals(HttpStatus.OK)) {
|
||||
logPrintStream.println("Error: " + response.getBody());
|
||||
hasErrors = true;
|
||||
continue;
|
||||
}
|
||||
processOutputFiles(operation, file.getFilename(), response, newOutputFiles);
|
||||
}
|
||||
|
||||
outputFiles = newOutputFiles;
|
||||
}
|
||||
if (!hasInputFileType) {
|
||||
logPrintStream.println(
|
||||
"No files with extension "
|
||||
+ inputFileExtension
|
||||
+ " found for operation "
|
||||
+ operation);
|
||||
hasErrors = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Filter and collect all files that match the inputFileExtension
|
||||
List<Resource> matchingFiles = outputFiles.stream()
|
||||
.filter(file -> file.getFilename().endsWith(finalInputFileExtension))
|
||||
.collect(Collectors.toList());
|
||||
outputFiles = newOutputFiles;
|
||||
}
|
||||
|
||||
// Check if there are matching files
|
||||
if (!matchingFiles.isEmpty()) {
|
||||
// Create a new MultiValueMap for the request body
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
} else {
|
||||
// Filter and collect all files that match the inputFileExtension
|
||||
List<Resource> matchingFiles =
|
||||
outputFiles.stream()
|
||||
.filter(
|
||||
file ->
|
||||
file.getFilename()
|
||||
.endsWith(finalInputFileExtension))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Add all matching files to the body
|
||||
for (Resource file : matchingFiles) {
|
||||
body.add("fileInput", file);
|
||||
}
|
||||
// Check if there are matching files
|
||||
if (!matchingFiles.isEmpty()) {
|
||||
// Create a new MultiValueMap for the request body
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
|
||||
for(Entry<String, Object> entry : parameters.entrySet()) {
|
||||
body.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
ResponseEntity<byte[]> response = sendWebRequest(url, body);
|
||||
// Add all matching files to the body
|
||||
for (Resource file : matchingFiles) {
|
||||
body.add("fileInput", file);
|
||||
}
|
||||
|
||||
// Handle the response
|
||||
if (response.getStatusCode().equals(HttpStatus.OK)) {
|
||||
processOutputFiles(operation, matchingFiles.get(0).getFilename(), response, newOutputFiles);
|
||||
} else {
|
||||
// Log error if the response status is not OK
|
||||
logPrintStream.println("Error in multi-input operation: " + response.getBody());
|
||||
hasErrors = true;
|
||||
}
|
||||
} else {
|
||||
logPrintStream.println("No files with extension " + inputFileExtension + " found for multi-input operation " + operation);
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
logPrintStream.close();
|
||||
for (Entry<String, Object> entry : parameters.entrySet()) {
|
||||
body.add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
if (hasErrors) {
|
||||
logger.error("Errors occurred during processing. Log: {}", logStream.toString());
|
||||
}
|
||||
return outputFiles;
|
||||
}
|
||||
ResponseEntity<byte[]> response = sendWebRequest(url, body);
|
||||
|
||||
private ResponseEntity<byte[]> sendWebRequest(String url, MultiValueMap<String, Object> body ){
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
// Set up headers, including API key
|
||||
// Handle the response
|
||||
if (response.getStatusCode().equals(HttpStatus.OK)) {
|
||||
processOutputFiles(
|
||||
operation,
|
||||
matchingFiles.get(0).getFilename(),
|
||||
response,
|
||||
newOutputFiles);
|
||||
} else {
|
||||
// Log error if the response status is not OK
|
||||
logPrintStream.println(
|
||||
"Error in multi-input operation: " + response.getBody());
|
||||
hasErrors = true;
|
||||
}
|
||||
} else {
|
||||
logPrintStream.println(
|
||||
"No files with extension "
|
||||
+ inputFileExtension
|
||||
+ " found for multi-input operation "
|
||||
+ operation);
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
logPrintStream.close();
|
||||
}
|
||||
if (hasErrors) {
|
||||
logger.error("Errors occurred during processing. Log: {}", logStream.toString());
|
||||
}
|
||||
return outputFiles;
|
||||
}
|
||||
|
||||
private ResponseEntity<byte[]> sendWebRequest(String url, MultiValueMap<String, Object> body) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
// Set up headers, including API key
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
String apiKey = getApiKeyForUser();
|
||||
headers.add("X-API-Key", apiKey);
|
||||
@@ -199,134 +206,141 @@ public class PipelineProcessor {
|
||||
|
||||
// Make the request to the REST endpoint
|
||||
return restTemplate.exchange(url, HttpMethod.POST, entity, byte[].class);
|
||||
}
|
||||
|
||||
private List<Resource> processOutputFiles(String operation, String fileName, ResponseEntity<byte[]> response, List<Resource> newOutputFiles) throws IOException{
|
||||
// Define filename
|
||||
String newFilename;
|
||||
if ("auto-rename".equals(operation)) {
|
||||
// If the operation is "auto-rename", generate a new filename.
|
||||
// This is a simple example of generating a filename using current timestamp.
|
||||
// Modify as per your needs.
|
||||
newFilename = "file_" + System.currentTimeMillis();
|
||||
} else {
|
||||
// Otherwise, keep the original filename.
|
||||
newFilename = fileName;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the response body is a zip file
|
||||
if (isZip(response.getBody())) {
|
||||
// Unzip the file and add all the files to the new output files
|
||||
newOutputFiles.addAll(unzip(response.getBody()));
|
||||
} else {
|
||||
Resource outputResource = new ByteArrayResource(response.getBody()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return newFilename;
|
||||
}
|
||||
};
|
||||
newOutputFiles.add(outputResource);
|
||||
}
|
||||
|
||||
return newOutputFiles;
|
||||
|
||||
}
|
||||
List<Resource> generateInputFiles(File[] files) throws Exception {
|
||||
if (files == null || files.length == 0) {
|
||||
logger.info("No files");
|
||||
return null;
|
||||
}
|
||||
private List<Resource> processOutputFiles(
|
||||
String operation,
|
||||
String fileName,
|
||||
ResponseEntity<byte[]> response,
|
||||
List<Resource> newOutputFiles)
|
||||
throws IOException {
|
||||
// Define filename
|
||||
String newFilename;
|
||||
if ("auto-rename".equals(operation)) {
|
||||
// If the operation is "auto-rename", generate a new filename.
|
||||
// This is a simple example of generating a filename using current timestamp.
|
||||
// Modify as per your needs.
|
||||
newFilename = "file_" + System.currentTimeMillis();
|
||||
} else {
|
||||
// Otherwise, keep the original filename.
|
||||
newFilename = fileName;
|
||||
}
|
||||
|
||||
|
||||
List<Resource> outputFiles = new ArrayList<>();
|
||||
// Check if the response body is a zip file
|
||||
if (isZip(response.getBody())) {
|
||||
// Unzip the file and add all the files to the new output files
|
||||
newOutputFiles.addAll(unzip(response.getBody()));
|
||||
} else {
|
||||
Resource outputResource =
|
||||
new ByteArrayResource(response.getBody()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return newFilename;
|
||||
}
|
||||
};
|
||||
newOutputFiles.add(outputResource);
|
||||
}
|
||||
|
||||
for (File file : files) {
|
||||
Path path = Paths.get(file.getAbsolutePath());
|
||||
logger.info("Reading file: " + path); // debug statement
|
||||
return newOutputFiles;
|
||||
}
|
||||
|
||||
if (Files.exists(path)) {
|
||||
Resource fileResource = new ByteArrayResource(Files.readAllBytes(path)) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return file.getName();
|
||||
}
|
||||
};
|
||||
outputFiles.add(fileResource);
|
||||
} else {
|
||||
logger.info("File not found: " + path);
|
||||
}
|
||||
}
|
||||
logger.info("Files successfully loaded. Starting processing...");
|
||||
return outputFiles;
|
||||
}
|
||||
List<Resource> generateInputFiles(File[] files) throws Exception {
|
||||
if (files == null || files.length == 0) {
|
||||
logger.info("No files");
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Resource> generateInputFiles(MultipartFile[] files) throws Exception {
|
||||
if (files == null || files.length == 0) {
|
||||
logger.info("No files");
|
||||
return null;
|
||||
}
|
||||
List<Resource> outputFiles = new ArrayList<>();
|
||||
|
||||
List<Resource> outputFiles = new ArrayList<>();
|
||||
for (File file : files) {
|
||||
Path path = Paths.get(file.getAbsolutePath());
|
||||
logger.info("Reading file: " + path); // debug statement
|
||||
|
||||
for (MultipartFile file : files) {
|
||||
Resource fileResource = new ByteArrayResource(file.getBytes()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return file.getOriginalFilename();
|
||||
}
|
||||
};
|
||||
outputFiles.add(fileResource);
|
||||
}
|
||||
logger.info("Files successfully loaded. Starting processing...");
|
||||
return outputFiles;
|
||||
}
|
||||
if (Files.exists(path)) {
|
||||
Resource fileResource =
|
||||
new ByteArrayResource(Files.readAllBytes(path)) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return file.getName();
|
||||
}
|
||||
};
|
||||
outputFiles.add(fileResource);
|
||||
} else {
|
||||
logger.info("File not found: " + path);
|
||||
}
|
||||
}
|
||||
logger.info("Files successfully loaded. Starting processing...");
|
||||
return outputFiles;
|
||||
}
|
||||
|
||||
private boolean isZip(byte[] data) {
|
||||
if (data == null || data.length < 4) {
|
||||
return false;
|
||||
}
|
||||
List<Resource> generateInputFiles(MultipartFile[] files) throws Exception {
|
||||
if (files == null || files.length == 0) {
|
||||
logger.info("No files");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check the first four bytes of the data against the standard zip magic number
|
||||
return data[0] == 0x50 && data[1] == 0x4B && data[2] == 0x03 && data[3] == 0x04;
|
||||
}
|
||||
List<Resource> outputFiles = new ArrayList<>();
|
||||
|
||||
private List<Resource> unzip(byte[] data) throws IOException {
|
||||
logger.info("Unzipping data of length: {}", data.length);
|
||||
List<Resource> unzippedFiles = new ArrayList<>();
|
||||
for (MultipartFile file : files) {
|
||||
Resource fileResource =
|
||||
new ByteArrayResource(file.getBytes()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return file.getOriginalFilename();
|
||||
}
|
||||
};
|
||||
outputFiles.add(fileResource);
|
||||
}
|
||||
logger.info("Files successfully loaded. Starting processing...");
|
||||
return outputFiles;
|
||||
}
|
||||
|
||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
||||
ZipInputStream zis = new ZipInputStream(bais)) {
|
||||
private boolean isZip(byte[] data) {
|
||||
if (data == null || data.length < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int count;
|
||||
// Check the first four bytes of the data against the standard zip magic number
|
||||
return data[0] == 0x50 && data[1] == 0x4B && data[2] == 0x03 && data[3] == 0x04;
|
||||
}
|
||||
|
||||
while ((count = zis.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, count);
|
||||
}
|
||||
private List<Resource> unzip(byte[] data) throws IOException {
|
||||
logger.info("Unzipping data of length: {}", data.length);
|
||||
List<Resource> unzippedFiles = new ArrayList<>();
|
||||
|
||||
final String filename = entry.getName();
|
||||
Resource fileResource = new ByteArrayResource(baos.toByteArray()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
};
|
||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
|
||||
ZipInputStream zis = new ZipInputStream(bais)) {
|
||||
|
||||
// If the unzipped file is a zip file, unzip it
|
||||
if (isZip(baos.toByteArray())) {
|
||||
logger.info("File {} is a zip file. Unzipping...", filename);
|
||||
unzippedFiles.addAll(unzip(baos.toByteArray()));
|
||||
} else {
|
||||
unzippedFiles.add(fileResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[1024];
|
||||
int count;
|
||||
|
||||
logger.info("Unzipping completed. {} files were unzipped.", unzippedFiles.size());
|
||||
return unzippedFiles;
|
||||
}
|
||||
while ((count = zis.read(buffer)) != -1) {
|
||||
baos.write(buffer, 0, count);
|
||||
}
|
||||
|
||||
final String filename = entry.getName();
|
||||
Resource fileResource =
|
||||
new ByteArrayResource(baos.toByteArray()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
};
|
||||
|
||||
// If the unzipped file is a zip file, unzip it
|
||||
if (isZip(baos.toByteArray())) {
|
||||
logger.info("File {} is a zip file. Unzipping...", filename);
|
||||
unzippedFiles.addAll(unzip(baos.toByteArray()));
|
||||
} else {
|
||||
unzippedFiles.add(fileResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Unzipping completed. {} files were unzipped.", unzippedFiles.size());
|
||||
return unzippedFiles;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
package stirling.software.SPDF.controller.api.pipeline;
|
||||
|
||||
public interface UserServiceInterface {
|
||||
String getApiKeyForUser(String username);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user