/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.vfs;
import com.google.common.io.ByteStreams;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.vfs.util.NotClosableInputStream;
import org.eclipse.che.api.vfs.util.ZipContent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class ZipArchiver extends Archiver {
public ZipArchiver(VirtualFile folder) {
super(folder);
}
@Override
public void compress(OutputStream zipOutput) throws IOException, ServerException {
compress(zipOutput, VirtualFileFilter.ACCEPT_ALL);
}
@Override
public void compress(OutputStream zipOutput, VirtualFileFilter filter) throws IOException, ServerException {
try (ZipOutputStream zipOutputStream = new ZipOutputStream(zipOutput)) {
folder.accept(new VirtualFileVisitor() {
@Override
public void visit(VirtualFile visitedVirtualFile) throws ServerException {
if (filter.accept(visitedVirtualFile)) {
if (!visitedVirtualFile.equals(folder)) {
addZipEntry(visitedVirtualFile, zipOutputStream);
}
if (visitedVirtualFile.isFolder()) {
for (VirtualFile child : visitedVirtualFile.getChildren()) {
child.accept(this);
}
}
}
}
});
}
}
private String getZipEntryName(VirtualFile virtualFile) {
Path zipPath = virtualFile.getPath().subPath(folder.getPath());
if (virtualFile.isFolder()) {
return zipPath.toString() + '/';
}
return zipPath.toString();
}
private void addZipEntry(VirtualFile virtualFile, ZipOutputStream zipOutputStream) throws ServerException {
try {
ZipEntry zipEntry = new ZipEntry(getZipEntryName(virtualFile));
zipOutputStream.putNextEntry(zipEntry);
if (virtualFile.isFolder()) {
zipEntry.setTime(0);
} else {
try (InputStream content = virtualFile.getContent()) {
ByteStreams.copy(content, zipOutputStream);
}
zipEntry.setTime(virtualFile.getLastModificationDate());
}
zipOutputStream.closeEntry();
} catch (ForbiddenException e) {
throw new ServerException(e.getServiceError());
} catch (IOException e) {
throw new ServerException(e.getMessage(), e);
}
}
@Override
public void extract(InputStream zipInput, boolean overwrite, int stripNumber)
throws IOException, ForbiddenException, ConflictException, ServerException {
try (ZipInputStream zip = new ZipInputStream(ZipContent.of(zipInput).getContent())) {
InputStream notClosableInputStream = new NotClosableInputStream(zip);
ZipEntry zipEntry;
while ((zipEntry = zip.getNextEntry()) != null) {
VirtualFile extractFolder = folder;
Path relativePath = Path.of(zipEntry.getName());
if (stripNumber > 0) {
if (relativePath.length() <= stripNumber) {
continue;
}
relativePath = relativePath.subPath(stripNumber);
}
if (zipEntry.isDirectory()) {
if (!extractFolder.hasChild(relativePath)) {
extractFolder.createFolder(relativePath.toString());
}
continue;
}
if (relativePath.length() > 1) {
Path neededParentPath = relativePath.getParent();
VirtualFile neededParent = extractFolder.getChild(neededParentPath);
if (neededParent == null) {
neededParent = extractFolder.createFolder(neededParentPath.toString());
}
extractFolder = neededParent;
}
String fileName = relativePath.getName();
VirtualFile file = extractFolder.getChild(Path.of(fileName));
if (file == null) {
extractFolder.createFile(fileName, notClosableInputStream);
} else {
if (overwrite) {
file.updateContent(notClosableInputStream);
} else {
throw new ConflictException(String.format("File '%s' already exists", file.getPath()));
}
}
zip.closeEntry();
}
}
}
}