package org.alien4cloud.tosca.editor.processors;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.TreeSet;
import javax.inject.Inject;
import org.alien4cloud.tosca.editor.EditionContextManager;
import org.alien4cloud.tosca.editor.exception.InvalidPathException;
import org.alien4cloud.tosca.editor.operations.AbstractUpdateFileOperation;
import org.alien4cloud.tosca.editor.services.EditorTopologyUploadService;
import alien4cloud.component.repository.IFileRepository;
import alien4cloud.exception.NotFoundException;
import alien4cloud.utils.TreeNode;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
/**
* Process an operation that uploaded or updated a file.
*/
@Slf4j
public abstract class AbstractUpdateFileProcessor<T extends AbstractUpdateFileOperation>
implements IEditorCommitableProcessor<T>, IEditorOperationProcessor<T> {
@Inject
private IFileRepository artifactRepository;
@Inject
private EditorTopologyUploadService editorTopologyUploadService;
@Override
public void process(T operation) {
// archive content tree is actually a node that contains only the folder of the topology
TreeNode root = EditionContextManager.get().getArchiveContentTree().getChildren().first();
// walk the file path to insert an element
TreeNode target = root;
if (operation.getPath().endsWith("/")) {
throw new InvalidPathException("Path <" + operation.getPath() + "> is invalid (must be a file and not a directory).");
}
// File upload management
String[] pathElements = operation.getPath().split("/");
for (int i = 0; i < pathElements.length; i++) {
String pathElement = pathElements[i];
TreeNode child = target.getChild(pathElement);
if (child == null) {
if (target.isLeaf()) {
throw new InvalidPathException("Path <" + operation.getPath() + "> is invalid (one of the folder of the path is actualy a file).");
}
// add an element
child = new TreeNode();
child.setName(pathElement);
child.setFullPath(target.getFullPath() + "/" + pathElement);
child.setParent(target);
target.getChildren().add(child);
if (i == pathElements.length - 1) {
child.setLeaf(true);
} else {
child.setChildren(new TreeSet<>());
}
}
target = child;
}
if (target.isLeaf()) {
// store the file in the local temporary file repository
// If already applied the input stream is closed and I should just get the artifact id
String artifactFileId = operation.getTempFileId();
if (artifactFileId == null) {
artifactFileId = artifactRepository.storeFile(operation.getArtifactStream());
operation.setTempFileId(artifactFileId);
operation.setArtifactStream(null); // Note the input stream should be closed by the caller (controller in our situation).
}
try {
if (EditionContextManager.getCsar().getYamlFilePath().equals(operation.getPath())) {
// the operation updates the topology file, we have to parse it and override the topology data out of it.
editorTopologyUploadService.processTopology(artifactRepository.resolveFile(artifactFileId),
EditionContextManager.getTopology().getWorkspace());
}
} catch (RuntimeException e) {
// remove the file from the temp repository if the topology cannot be parsed
artifactRepository.deleteFile(artifactFileId);
throw e;
}
target.setArtifactId(artifactFileId); // let's just impact the url to point to the temp file.
} else {
// Fail as we cannot override a directory
throw new InvalidPathException("Path <" + operation.getPath() + "> is invalid (must be a file and not a directory).");
}
}
@Override
@SneakyThrows
public void beforeCommit(T operation) {
try {
TreeNode fileTreeNode = FileProcessorHelper.getFileTreeNode(operation.getPath());
Path targetPath = EditionContextManager.get().getLocalGitPath().resolve(operation.getPath());
Files.createDirectories(targetPath.getParent());
try (InputStream inputStream = artifactRepository.getFile(operation.getTempFileId())) {
Files.copy(inputStream, targetPath, StandardCopyOption.REPLACE_EXISTING);
}
artifactRepository.deleteFile(operation.getTempFileId());
fileTreeNode.setArtifactId(null);
} catch (NotFoundException e) {
log.debug("The file is not referenced in the tree, must have been deleted in later operation.", e);
}
}
}