/*
* #%L
* gitools-core
* %%
* Copyright (C) 2013 Universitat Pompeu Fabra - Biomedical Genomics group
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
package org.gitools.persistence.locators.filters.zip;
import org.gitools.api.ApplicationContext;
import org.gitools.api.PersistenceException;
import org.gitools.api.analysis.IProgressMonitor;
import org.gitools.api.resource.IResourceFilter;
import org.gitools.api.resource.IResourceLocator;
import org.gitools.persistence.locators.filters.FilterResourceLocator;
import org.gitools.utils.progressmonitor.NullProgressMonitor;
import org.zeroturnaround.zip.ZipUtil;
import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class ZipResourceLocatorAdaptor extends FilterResourceLocator {
private File tmpFolder;
private String entryName;
public ZipResourceLocatorAdaptor(String entryName, IResourceFilter filter, IResourceLocator resourceLocator) {
super(filter, resourceLocator);
this.entryName = entryName;
}
private ZipResourceLocatorAdaptor(String entryName, String name, String extension, IResourceLocator resourceLocator) {
super(name, extension, resourceLocator);
this.entryName = entryName;
}
@Override
public boolean isContainer() {
return true;
}
@Override
public IResourceLocator getReferenceLocator(String referenceName) throws PersistenceException {
String extension = ApplicationContext.getPersistenceManager().getFormatExtension(referenceName);
int extensionIndex = referenceName.indexOf(extension);
String extensionWithFilters = referenceName.substring(extensionIndex);
return new ZipResourceLocatorAdaptor(referenceName, referenceName, extensionWithFilters, getParentLocator()) {
@Override
public File getWriteFile() {
try {
return new File(getTemporalFolder(), getEntryName());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected File getTemporalFolder() throws IOException {
return ZipResourceLocatorAdaptor.this.getTemporalFolder();
}
@Override
public void close(IProgressMonitor monitor) {
}
@Override
public OutputStream openOutputStream(IProgressMonitor monitor) throws IOException {
return new FileOutputStream(getWriteFile());
}
};
}
@Override
public InputStream openInputStream(IProgressMonitor progressMonitor) throws IOException {
ZipInputStream in = new ZipInputStream(getParentLocator().openInputStream(progressMonitor));
ZipEntry entry;
while ((entry = in.getNextEntry()) != null) {
if (entryName.equals(entry.getName())) {
return in;
}
}
// Exact match not found. Return the first with the same extension.
String extension = getExtension();
in.close();
in = new ZipInputStream(getParentLocator().openInputStream(progressMonitor));
while ((entry = in.getNextEntry()) != null) {
if (entry.getName().endsWith(extension)) {
entryName = entry.getName();
setName(entryName);
setBaseName(entryName, extension);
return in;
}
}
throw new PersistenceException("Entry '" + entryName + "' not found in '" + getParentLocator().getURL() + "'");
}
@Override
public OutputStream openOutputStream(IProgressMonitor monitor) throws IOException {
// Create a temporal folder
tmpFolder = createTemporalFolder(getURL());
// Extract all the files
monitor.title("Extracting to temporal folder...");
try {
ZipUtil.unpack(getParentLocator().openInputStream(new NullProgressMonitor()), tmpFolder);
// Check if we are doing a 'Save as...'
if (!getWriteFile().equals(getReadFile())) {
// Rename all entries
String inName = getReadFile().getName().replace("." + getExtension() + ".zip", "");
String toName = getBaseName();
renameAll(getTemporalFolder(), inName, toName);
}
} catch (FileNotFoundException e) {
// It's a all in memory resource
}
monitor.title("Copying files...");
return new FileOutputStream(new File(tmpFolder, entryName));
}
@Override
public void close(IProgressMonitor monitor) {
try {
// Compress folder
monitor.title("Compressing files...");
ZipUtil.pack(getTemporalFolder(), getWriteFile(), Deflater.NO_COMPRESSION);
// Close temporal file
getParentLocator().close(monitor);
// Remove temporal folder
deleteFolder(getTemporalFolder());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected File getTemporalFolder() throws IOException {
return tmpFolder;
}
protected String getEntryName() {
return entryName;
}
/**
*
* Creates a temporal folder. If the 'url' is a file then the temporal folder is
* created next to the file, otherwise is created at the system temporal folder.
*
* @param url
* @return
* @throws IOException
*/
private File createTemporalFolder(URL url) throws IOException {
File tmpFolder;
if ("file".equals(url.getProtocol())) {
try {
File parentFolder = (new File(url.toURI())).getParentFile();
tmpFolder = File.createTempFile(getName(), "", parentFolder);
} catch (URISyntaxException e) {
tmpFolder = File.createTempFile("gitools" + getBaseName(), "");
}
} else {
tmpFolder = File.createTempFile("gitools" + getBaseName(), "");
}
tmpFolder.delete();
tmpFolder.mkdir();
return tmpFolder;
}
private static void renameAll(File folder, String inName, String toName) {
File[] files = folder.listFiles();
if(files!=null) { //some JVMs return null for empty dirs
for(File f : files) {
String name = f.getName();
if (!f.isDirectory() && name.contains(inName)) {
name = name.replace(inName, toName);
File toFile = new File(f.getParentFile(), name);
f.renameTo(toFile);
}
}
}
}
private static void deleteFolder(File folder) {
File[] files = folder.listFiles();
if(files!=null) { //some JVMs return null for empty dirs
for(File f: files) {
if(f.isDirectory()) {
deleteFolder(f);
} else {
f.delete();
}
}
}
folder.delete();
}
}