Skip to content

[NAE 1843] Import/Export services #296

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: release/7.0.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions src/main/java/com/netgrif/application/engine/archive/ZipService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package com.netgrif.application.engine.archive;

import com.netgrif.application.engine.archive.interfaces.IArchiveService;
import com.netgrif.application.engine.files.IStorageResolverService;
import com.netgrif.application.engine.files.interfaces.IStorageService;
import com.netgrif.application.engine.petrinet.domain.dataset.StorageField;
import com.netgrif.application.engine.workflow.domain.CaseExportFiles;
import com.netgrif.application.engine.workflow.domain.StorageFieldWithFileNames;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.UUID;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

@Slf4j
@Service
@RequiredArgsConstructor
public class ZipService implements IArchiveService {

private final IStorageResolverService storageResolverService;

@Override
public void pack(String archivePath, CaseExportFiles caseExportFiles, String... additionalFiles) throws IOException {
FileOutputStream fos = new FileOutputStream(archivePath);
this.pack(fos, caseExportFiles, additionalFiles);
fos.close();
}

@Override
public void pack(OutputStream archiveStream, CaseExportFiles caseExportFiles, String... additionalFiles) throws IOException {
ZipOutputStream zipStream = new ZipOutputStream(archiveStream);
for (String caseId : caseExportFiles.getCaseIds()) {
for (StorageFieldWithFileNames fieldWithFileNames : caseExportFiles.getFieldsOfCase(caseId)) {
StorageField<?> field = fieldWithFileNames.getField();
IStorageService storageService = storageResolverService.resolve(field.getStorageType());
for (String fileName : fieldWithFileNames.getFileNames()) {
String filePath = storageService.getPath(caseId, field.getStringId(), fileName);
InputStream fis = storageService.get(field, filePath);
String newFileName = Paths.get(caseId, field.getStringId(), fileName).getFileName().toString();
createAndWriteZipEntry(newFileName, zipStream, fis);
fis.close();
}
}
}
for (String filePath : additionalFiles) {
InputStream fis = new FileInputStream(filePath);
createAndWriteZipEntry(Paths.get(filePath).getFileName().toString(), zipStream, fis);
fis.close();
}
zipStream.close();
}

@Override
public OutputStream createArchive(CaseExportFiles caseExportFiles) throws IOException {
return createArchive(Files.createTempFile(UUID.randomUUID().toString(), ".zip").toString(), caseExportFiles);
}

@Override
public OutputStream createArchive(String archivePath, CaseExportFiles caseExportFiles) throws IOException {
File zipFile = new File(archivePath);
return zipFiles(zipFile, caseExportFiles);
}

private OutputStream zipFiles(File zipFile, CaseExportFiles caseExportFiles) throws IOException {
FileOutputStream fos = new FileOutputStream(zipFile);
this.pack(fos, caseExportFiles);
return fos;
}

@Override
public void append(OutputStream archiveStream, String... filePaths) throws IOException {
// todo implement
}

private void createAndWriteZipEntry(String fileName, ZipOutputStream zipStream, InputStream fis) throws IOException {
// source https://www.baeldung.com/java-compress-and-uncompress
ZipEntry zipEntry = new ZipEntry(fileName);
zipStream.putNextEntry(zipEntry);
byte[] bytes = new byte[1024];
int length;
while ((length = fis.read(bytes)) >= 0) {
zipStream.write(bytes, 0, length);
}
}

@Override
public String unpack(String archivePath, String outputPath) throws IOException {
return this.unpack(new FileInputStream(archivePath), outputPath);
}

@Override
public String unpack(InputStream archiveStream, String outputPath) throws IOException {
// source: https://www.baeldung.com/java-compress-and-uncompress
File destDir = new File(outputPath);

byte[] buffer = new byte[1024];
ZipInputStream zis = new ZipInputStream(archiveStream);
ZipEntry zipEntry = zis.getNextEntry();
while (zipEntry != null) {
File newFile = newFile(destDir, zipEntry);
if (zipEntry.isDirectory()) {
if (!newFile.isDirectory() && !newFile.mkdirs()) {
throw new IOException("Failed to create directory " + newFile);
}
} else {
// fix for Windows-created archives
File parent = newFile.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("Failed to create directory " + parent);
}

// write file content
FileOutputStream fos = new FileOutputStream(newFile);
int len;
while ((len = zis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
fos.close();
}
zipEntry = zis.getNextEntry();
}

zis.closeEntry();
zis.close();
return destDir.getPath();
}

private File newFile(File destinationDir, ZipEntry zipEntry) throws IOException {
File destFile = new File(destinationDir, zipEntry.getName());

String destDirPath = destinationDir.getCanonicalPath();
String destFilePath = destFile.getCanonicalPath();

if (!destFilePath.startsWith(destDirPath + File.separator)) {
throw new IOException("Entry is outside of the target dir: " + zipEntry.getName());
}

return destFile;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.netgrif.application.engine.archive.interfaces;

import com.netgrif.application.engine.workflow.domain.CaseExportFiles;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public interface IArchiveService {

void pack(String archivePath, CaseExportFiles caseExportFiles, String... additionalFiles) throws IOException;

void pack(OutputStream archiveStream, CaseExportFiles caseExportFiles, String... additionalFiles) throws IOException;

OutputStream createArchive(CaseExportFiles caseExportFiles) throws IOException;

OutputStream createArchive(String archivePath, CaseExportFiles caseExportFiles) throws IOException;

void append(OutputStream archiveStream, String... filePaths) throws IOException;

String unpack(String archivePath, String outputPath) throws IOException;

String unpack(InputStream archiveStream, String outputPath) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
import com.netgrif.application.engine.pdf.generator.service.interfaces.IPdfGenerator;
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate;
import com.netgrif.application.engine.workflow.domain.FileStorageConfiguration;
import com.netgrif.application.engine.workflow.service.CaseExporter;
import com.netgrif.application.engine.workflow.service.CaseImporter;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;

@Configuration
Expand Down Expand Up @@ -60,4 +61,15 @@ public IPdfDrawer pdfDrawer() {
public UserResourceAssembler userResourceAssembler() {
return new UserResourceAssembler();
}

@Bean("caseExporter")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public CaseExporter caseExporter() {
return new CaseExporter();
}
@Bean("caseImporter")
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public CaseImporter caseImporter() {
return new CaseImporter();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.netgrif.application.engine.configuration.properties;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Slf4j
@Data
@Component
@ConfigurationProperties(prefix = "nae.case.export")
public class CaseExportProperties {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a separate class? This class is used only in the properties bean.


private String fileName;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.netgrif.application.engine.configuration.properties;


import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Slf4j
@Data
@Component
@ConfigurationProperties(prefix = "nae.schema")
public class SchemaProperties {

private String location;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.runner.Expression;
import com.netgrif.application.engine.petrinet.domain.dataset.logic.validation.DynamicValidation;
import com.netgrif.application.engine.petrinet.domain.views.View;
import com.netgrif.application.engine.utils.ImporterUtils;
import com.netgrif.application.engine.workflow.domain.Case;
import com.netgrif.application.engine.workflow.domain.DataField;
import com.netgrif.application.engine.workflow.service.interfaces.IDataValidationExpressionEvaluator;
Expand Down Expand Up @@ -276,13 +277,13 @@ Field getField(Data data, Importer importer) throws IllegalArgumentException, Mi
if (data.getValid() != null) {
List<Valid> list = data.getValid();
for (Valid item : list) {
field.addValidation(makeValidation(item.getValue(), null, item.isDynamic()));
field.addValidation(ImporterUtils.makeValidation(item.getValue(), null, item.isDynamic()));
}
}
if (data.getValidations() != null) {
List<com.netgrif.application.engine.importer.model.Validation> list = data.getValidations().getValidation();
for (com.netgrif.application.engine.importer.model.Validation item : list) {
field.addValidation(makeValidation(item.getExpression().getValue(), importer.toI18NString(item.getMessage()), item.getExpression().isDynamic()));
field.addValidation(ImporterUtils.makeValidation(item.getExpression().getValue(), importer.toI18NString(item.getMessage()), item.getExpression().isDynamic()));
}
}

Expand Down Expand Up @@ -318,10 +319,6 @@ private StringCollectionField buildStringCollectionField(Data data, Importer imp
return field;
}

private com.netgrif.application.engine.petrinet.domain.dataset.logic.validation.Validation makeValidation(String rule, I18nString message, boolean dynamic) {
return dynamic ? new DynamicValidation(rule, message) : new com.netgrif.application.engine.petrinet.domain.dataset.logic.validation.Validation(rule, message);
}

private TaskField buildTaskField(Data data, List<Transition> transitions) {
TaskField field = new TaskField();
setDefaultValues(field, data, defaultValues -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import com.netgrif.application.engine.petrinet.service.ArcFactory;
import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService;
import com.netgrif.application.engine.petrinet.service.interfaces.IProcessRoleService;
import com.netgrif.application.engine.utils.ImporterUtils;
import com.netgrif.application.engine.workflow.domain.FileStorageConfiguration;
import com.netgrif.application.engine.workflow.domain.ProcessResourceId;
import com.netgrif.application.engine.workflow.domain.triggers.Trigger;
Expand Down Expand Up @@ -220,7 +221,7 @@ protected Optional<PetriNet> createPetriNet() throws MissingPetriNetMetaDataExce
net.setDefaultCaseName(toI18NString(document.getCaseName()));
}
if (document.getTags() != null) {
net.setTags(this.buildTagsMap(document.getTags().getTag()));
net.setTags(ImporterUtils.buildTagsMap(document.getTags().getTag()));
}

return Optional.of(net);
Expand Down Expand Up @@ -496,7 +497,7 @@ protected void createTransition(com.netgrif.application.engine.importer.model.Tr
transition.setTitle(importTransition.getLabel() != null ? toI18NString(importTransition.getLabel()) : new I18nString(""));
transition.setPosition(importTransition.getX(), importTransition.getY());
if (importTransition.getTags() != null) {
transition.setTags(this.buildTagsMap(importTransition.getTags().getTag()));
transition.setTags(ImporterUtils.buildTagsMap(importTransition.getTags().getTag()));
}

if (importTransition.getLayout() != null) {
Expand Down Expand Up @@ -1322,14 +1323,4 @@ protected void setMetaData() throws MissingPetriNetMetaDataException {
if (!missingMetaData.isEmpty())
throw new MissingPetriNetMetaDataException(missingMetaData);
}

protected Map<String, String> buildTagsMap(List<Tag> tagsList) {
Map<String, String> tags = new HashMap<>();
if (tagsList != null) {
tagsList.forEach(tag -> {
tags.put(tag.getKey(), tag.getValue());
});
}
return tags;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.netgrif.application.engine.utils;

import com.netgrif.application.engine.importer.model.Tag;
import com.netgrif.application.engine.petrinet.domain.I18nString;
import com.netgrif.application.engine.petrinet.domain.dataset.logic.validation.DynamicValidation;
import com.netgrif.application.engine.petrinet.domain.dataset.logic.validation.Validation;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ImporterUtils {

public static Map<String, String> buildTagsMap(List<Tag> tagsList) {
Map<String, String> tags = new HashMap<>();
if (tagsList != null) {
tagsList.forEach(tag -> {
tags.put(tag.getKey(), tag.getValue());
});
}
return tags;
}

public static Validation makeValidation(String rule, I18nString message, boolean dynamic) {
return dynamic ? new DynamicValidation(rule, message) : new Validation(rule, message);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,12 @@ protected Case() {
}

public Case(PetriNet petriNet) {
this(petriNet,new ProcessResourceId(petriNet.getObjectId()));
}

public Case(PetriNet petriNet, ProcessResourceId _id) {
this();
this._id = new ProcessResourceId(petriNet.getObjectId());
this._id = _id;
petriNetObjectId = petriNet.getObjectId();
processIdentifier = petriNet.getIdentifier();
this.petriNet = petriNet;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.netgrif.application.engine.workflow.domain;

import java.util.*;

public class CaseExportFiles {

private final Map<String, List<StorageFieldWithFileNames>> caseFileMapping = new HashMap<>();

public void addFieldFilenames(String caseId, StorageFieldWithFileNames storageField) {
List<StorageFieldWithFileNames> emptyFieldMapping = new ArrayList<>();
List<StorageFieldWithFileNames> fieldMapping = caseFileMapping.putIfAbsent(caseId, emptyFieldMapping);
if (fieldMapping == null) {
fieldMapping = emptyFieldMapping;
}
fieldMapping.add(storageField);
}

public Set<String> getCaseIds() {
return caseFileMapping.keySet();
}

public List<StorageFieldWithFileNames> getFieldsOfCase(String caseId) {
return caseFileMapping.get(caseId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.netgrif.application.engine.workflow.domain;

import com.netgrif.application.engine.petrinet.domain.dataset.StorageField;
import lombok.Data;

import java.util.Set;

@Data
public class StorageFieldWithFileNames {

private StorageField<?> field;
private Set<String> fileNames;

public StorageFieldWithFileNames(StorageField<?> field, Set<String> fileNames) {
this.field = field;
this.fileNames = fileNames;
}
}
Loading
Loading