package com.compomics.software.autoupdater;
import com.compomics.util.waiting.WaitingHandler;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import net.jimmc.jshortcut.JShellLink;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.io.IOUtils;
/**
* FileDAO file access.
*
* @author Davy Maddelein
* @author Harald Barsnes
*/
public abstract class FileDAO {
/**
* Creates a new Desktop Shortcut to the Maven jar file, atm windows only.
*
* @param file the Maven jarfile to make a shortcut to
* @param iconName the name of the icon file in the resources folder
* @param toolName the name of the tool, e.g., PeptideShaker
* @param deleteOldShortcut if previous shortcuts containing the Maven jar
* file artifact id should be removed
* @return true id the shortcut was created (?)
* @throws IOException if an IOException occurs
*/
public abstract boolean createDesktopShortcut(MavenJarFile file, String iconName, String toolName, boolean deleteOldShortcut) throws IOException;
/**
* Add desktop shortcut.
*
* @param mavenJarFile the Maven jar file
* @return true id the shortcut was created (?)
*/
public boolean addShortcutAtDeskTop(MavenJarFile mavenJarFile) {
return addShortcutAtDeskTop(mavenJarFile, null);
}
/**
* Adds a shortcut to the desktop. At the moment for Windows only.
*
* @param mavenJarFile the {@code MavenJarFile} to create the shortcut for
* @param iconName the name of the icon in the resource folder of the
* {@code MavenJarFile} to link to
* @return true if the shortcut was created otherwise false
* @throws NullPointerException if a NullPointerException occurs
* @throws RuntimeException if a RuntimeException occurs
*/
public boolean addShortcutAtDeskTop(MavenJarFile mavenJarFile, String iconName) throws NullPointerException, RuntimeException {
JShellLink link = new JShellLink();
link.setFolder(JShellLink.getDirectory("desktop"));
link.setName(new StringBuilder().append(mavenJarFile.getArtifactId()).append("-").append(mavenJarFile.getVersionNumber()).toString());
if (iconName != null) {
link.setIconLocation(new StringBuilder().append(new File(mavenJarFile.getAbsoluteFilePath()).getParentFile().getAbsolutePath()).append("/resources/").append(iconName).toString());
}
link.setPath(mavenJarFile.getAbsoluteFilePath());
link.save();
return true;
}
/**
* Try to find an at least somewhat sane location to download files to.
*
* @param targetDownloadFolder first place to check if it is a possible
* download location
* @return the folder to download in (in best case scenario this is the
* passed parameter targetDownloadFolder)
* @throws IOException if an IOException occurs
*/
public abstract File getLocationToDownloadOnDisk(String targetDownloadFolder) throws IOException;
// @TODO: rewrite both downloadAndUnzipFiles to use apache commons compress library?
/**
* Unzips a zip archive.
*
* @param zip the zipfile to unzip
* @param fileLocationOnDiskToDownloadTo the folder to unzip in
* @return true if successful
* @throws IOException if an IOException occurs
*/
public boolean unzipFile(ZipFile zip, File fileLocationOnDiskToDownloadTo) throws IOException {
FileOutputStream dest = null;
InputStream inStream = null;
Enumeration<? extends ZipEntry> zipFileEnum = zip.entries();
while (zipFileEnum.hasMoreElements()) {
ZipEntry entry = zipFileEnum.nextElement();
File destFile = new File(String.format("%s/%s", fileLocationOnDiskToDownloadTo, entry.getName()));
if (!destFile.getParentFile().exists()) {
if (!destFile.getParentFile().mkdirs()) {
throw new IOException("Could not create the folder \'" + destFile.getParentFile().getAbsolutePath() + "\' to unzip to.");
}
}
if (!entry.isDirectory()) {
try {
dest = new FileOutputStream(destFile);
inStream = zip.getInputStream(entry);
IOUtils.copyLarge(inStream, dest);
} finally {
if (dest != null) {
dest.close();
}
if (inStream != null) {
inStream.close();
}
}
} else {
if (!destFile.exists()) {
if (!destFile.mkdirs()) {
throw new IOException("Could not create folder \'" + destFile.getAbsolutePath() + "\' to unzip to.");
}
}
}
}
zip.close();
return true;
}
/**
* Untars and ungzips a .tar.gz file.
*
* @param in a {@code GZIPInputStream} of the file that needs to be
* ungzipped and untarred
* @param fileLocationOnDiskToDownloadTo the file to ungzip and untar to
* @param waitingHandler the waiting handler
* @return true if successful
* @throws IOException if an IOException occurs
*/
public boolean unGzipAndUntarFile(GZIPInputStream in, File fileLocationOnDiskToDownloadTo, WaitingHandler waitingHandler) throws IOException {
try {
FileOutputStream fos = new FileOutputStream(fileLocationOnDiskToDownloadTo);
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
//close resources
fos.close();
in.close();
if (waitingHandler != null) {
waitingHandler.setSecondaryProgressCounterIndeterminate(true);
}
untar(fileLocationOnDiskToDownloadTo);
} catch (IOException e) {
if (waitingHandler != null) {
waitingHandler.setRunCanceled();
}
e.printStackTrace();
}
return true;
}
/**
* Untars a .tar.
*
* @param fileToUntar
* @return true if successful
* @throws FileNotFoundException if an FileNotFoundException occurs
* @throws IOException if an IOException occurs
*/
private boolean untar(File fileToUntar) throws FileNotFoundException, IOException {
boolean fileUntarred = false;
String untarLocation = fileToUntar.getParentFile().getAbsolutePath();
TarArchiveInputStream tarStream = null;
try {
tarStream = new TarArchiveInputStream(new FileInputStream(fileToUntar));
BufferedReader bufferedTarReader = null;
try {
bufferedTarReader = new BufferedReader(new InputStreamReader(tarStream));
ArchiveEntry entry;
while ((entry = tarStream.getNextEntry()) != null) {
byte[] buffer = new byte[8 * 1024];
File tempFile = new File(String.format("%s/%s", untarLocation, entry.getName()));
if (entry.isDirectory()) {
if (!tempFile.exists()) {
tempFile.mkdir();
}
} else {
OutputStream output = new FileOutputStream(tempFile);
try {
int bytesRead;
while ((bytesRead = tarStream.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
} finally {
output.close();
}
tempFile.setExecutable(true); // make sure the binary files can be executed
}
}
} finally {
if (bufferedTarReader != null) {
bufferedTarReader.close();
}
}
} finally {
if (tarStream != null) {
tarStream.close();
}
}
return fileUntarred;
}
/**
* Fetches a Maven built jar file from a folder for the given artifact id
* (e.g peptideshaker or ms-lims).
*
* @param folder the folder to look in
* @param artifactId the artifactid in the properties of the (@code
* MavenJarFile) in the folder
* @return the last found {@code MavenJarFile} with the given artifactid,
* can be null
* @throws IOException if an IOException occurs
*/
public MavenJarFile getMavenJarFileFromFolderWithArtifactId(File folder, String artifactId) throws IOException {
MavenJarFile mainJarFile = null;
for (File aFile : folder.listFiles()) {
if (aFile.isDirectory()) {
mainJarFile = getMavenJarFileFromFolderWithArtifactId(aFile, artifactId);
if (mainJarFile != null) {
break;
}
} else {
if (aFile.getName().contains(artifactId) && aFile.getName().contains("jar")) {
mainJarFile = new MavenJarFile(aFile);
break;
}
}
}
/**
* if (mainJarFile == null) { throw new IOException("Could not find jar
* file in folder and child folders"); }
*/
return mainJarFile;
}
/**
* Writes a stream to disk.
*
* @param in the stream to write to disk
* @param name the name the file that will be created
* @param outputLocationFolder the location to write to
* @return the written file
* @throws FileNotFoundException if a FileNotFoundException occurs
* @throws IOException if an IOException occurs
*/
public File writeStreamToDisk(InputStream in, String name, File outputLocationFolder) throws FileNotFoundException, IOException {
if (!outputLocationFolder.exists()) {
if (!outputLocationFolder.mkdirs()) {
throw new IOException("Could not create the folder \'" + outputLocationFolder.getAbsolutePath() + "\' to write stream to disk.");
}
}
File outputFile = new File(outputLocationFolder, name);
FileOutputStream out = null;
try {
out = new FileOutputStream(outputFile);
IOUtils.copyLarge(in, out);
} finally {
if (out != null) {
out.close();
}
}
in.close();
return outputFile;
}
}