Skip to content

Commit

Permalink
Merge branch 'release/1.5.5'
Browse files Browse the repository at this point in the history
  • Loading branch information
bill-baumgartner committed Jan 1, 2017
2 parents 3e88d6b + 9f1ccbc commit 98fe5f6
Show file tree
Hide file tree
Showing 5 changed files with 243 additions and 26 deletions.
3 changes: 1 addition & 2 deletions README.md
Expand Up @@ -12,10 +12,9 @@ Code in the [master branch](https://github.com/UCDenver-ccp/common/tree/master)
<dependency>
<groupId>edu.ucdenver.ccp</groupId>
<artifactId>common</artifactId>
<version>1.5.4</version>
<version>1.5.5</version>
</dependency>


<repository>
<id>bionlp-sourceforge</id>
<url>http://svn.code.sf.net/p/bionlp/code/repo/</url>
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -9,7 +9,7 @@
<groupId>edu.ucdenver.ccp</groupId>
<artifactId>common</artifactId>
<packaging>jar</packaging>
<version>1.5.4</version>
<version>1.5.5</version>

<name>common</name>
<description>The ccp-common project contains utility code for a variety of "common" tasks
Expand Down
113 changes: 113 additions & 0 deletions src/main/java/edu/ucdenver/ccp/common/download/DownloadMetadata.java
@@ -0,0 +1,113 @@
package edu.ucdenver.ccp.common.download;

/*
* #%L
* Colorado Computational Pharmacology's common module
* %%
* Copyright (C) 2012 - 2017 Regents of the University of Colorado
* %%
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the Regents of the University of Colorado nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* #L%
*/


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Properties;

import lombok.Data;
import edu.ucdenver.ccp.common.file.CharacterEncoding;
import edu.ucdenver.ccp.common.file.FileReaderUtil;
import edu.ucdenver.ccp.common.file.FileWriterUtil;

/**
* A class to store relevant metadata about the download of a data source.
*/
@Data
public class DownloadMetadata {
private final Calendar downloadDate;
private final File downloadedFile;
private final long fileSizeInBytes;
private final Calendar fileLastModifiedDate;
private final URL downloadUrl;

enum DownloadMetadataProperty {
DOWNLOAD_DATE, DOWNLOADED_FILE, FILE_SIZE_IN_BYTES, FILE_LAST_MOD_DATE, DOWNLOAD_URL, FILE_AGE_IN_DAYS
}

public static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("MM/dd/yyyy");

public void writePropertiesFile(File outputFile) throws IOException {
Properties p = new Properties();
p.setProperty(DownloadMetadataProperty.DOWNLOAD_DATE.name(), DATE_FORMATTER.format(downloadDate.getTime()));
p.setProperty(DownloadMetadataProperty.DOWNLOADED_FILE.name(), downloadedFile.getAbsolutePath());
p.setProperty(DownloadMetadataProperty.FILE_SIZE_IN_BYTES.name(), Long.toString(fileSizeInBytes));
p.setProperty(DownloadMetadataProperty.FILE_LAST_MOD_DATE.name(),
DATE_FORMATTER.format(fileLastModifiedDate.getTime()));
p.setProperty(DownloadMetadataProperty.DOWNLOAD_URL.name(), downloadUrl.toString());

long fileAgeInDays = getFileAgeInDays();
p.setProperty(DownloadMetadataProperty.FILE_AGE_IN_DAYS.name(), Long.toString(fileAgeInDays));

BufferedWriter writer = FileWriterUtil.initBufferedWriter(outputFile);
p.store(writer, null);
writer.close();
}

public long getFileAgeInDays() {
long fileAgeInMillis = downloadDate.getTimeInMillis() - fileLastModifiedDate.getTimeInMillis();
long fileAgeInDays = fileAgeInMillis / (24 * 60 * 60 * 1000);
return fileAgeInDays;
}

public static DownloadMetadata loadFromPropertiesFile(File propertiesFile) throws IOException, ParseException {
Properties p = new Properties();
BufferedReader reader = FileReaderUtil.initBufferedReader(propertiesFile, CharacterEncoding.UTF_8);
p.load(reader);
reader.close();

Calendar downloadDate = Calendar.getInstance();
downloadDate.setTime(DATE_FORMATTER.parse(p.getProperty(DownloadMetadataProperty.DOWNLOAD_DATE.name())));

Calendar lastModDate = Calendar.getInstance();
lastModDate.setTime(DATE_FORMATTER.parse(p.getProperty(DownloadMetadataProperty.FILE_LAST_MOD_DATE.name())));

File downloadedFile = new File(p.getProperty(DownloadMetadataProperty.DOWNLOADED_FILE.name()));

long fileSizeInBytes = Long.parseLong(p.getProperty(DownloadMetadataProperty.FILE_SIZE_IN_BYTES.name()));

URL downloadUrl = new URL(p.getProperty(DownloadMetadataProperty.DOWNLOAD_URL.name()));

return new DownloadMetadata(downloadDate, downloadedFile, fileSizeInBytes, lastModDate, downloadUrl);
}

}
64 changes: 41 additions & 23 deletions src/main/java/edu/ucdenver/ccp/common/download/DownloadUtil.java
Expand Up @@ -37,8 +37,10 @@
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URL;
import java.text.SimpleDateFormat;

import lombok.Data;

Expand Down Expand Up @@ -107,28 +109,35 @@ public static void download(Object object, File workDirectory, String userName,
// System.out.println("Downloaded file: " + file.getName());
if (file != null) {
assignField(object, field, file);
if (clean || !readySemaphoreFileExists(file)) {
// if clean = false then it might already exist
writeReadySemaphoreFile(file);
}
// if (clean || !readySemaphoreFileExists(file)) {
// // if clean = false then it might already exist
// writeReadySemaphoreFile(file);
// }
}
}
}

/**
* The creation of a semaphore file indicates the success of a download. It
* also includes metadata regarding the file that was downloaded, including:
* the date of the download, the date of the file on the server if
* available, the size of the file, the name of the file, the file URI
*
* @param file
*/
public static void writeReadySemaphoreFile(File file) {
public static void writeReadySemaphoreFile(File file, URL fileUrl) {
try {
if (!getReadySemaphoreFile(file).exists()) {
if (!getReadySemaphoreFile(file).createNewFile()) {
throw new RuntimeException("Semaphore file could not be created b/c it already exists: "
+ getReadySemaphoreFile(file).getAbsolutePath());
}
FileWriterUtil.printLines(
CollectionsUtil.createList("Downloaded on " + CalendarUtil.getDateStamp("/")),
getReadySemaphoreFile(file), CharacterEncoding.UTF_8, WriteMode.OVERWRITE,
FileSuffixEnforcement.OFF);
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
FileWriterUtil.printLines(CollectionsUtil.createList("download_date=" + CalendarUtil.getDateStamp("/"),
"file_name=" + file.getName(), "file_path=" + file.getParentFile().getAbsolutePath(),
"file_size_in_bytes=" + file.length(), "file_date=" + formatter.format(file.lastModified()),
"file_url=" + fileUrl.toString()), getReadySemaphoreFile(file), CharacterEncoding.UTF_8,
WriteMode.OVERWRITE, FileSuffixEnforcement.OFF);
}
} catch (IOException e) {
throw new RuntimeException(e);
Expand All @@ -139,7 +148,7 @@ public static boolean readySemaphoreFileExists(File file) {
return getReadySemaphoreFile(file).exists();
}

private static File getReadySemaphoreFile(File file) {
public static File getReadySemaphoreFile(File file) {
return new File(file.getAbsolutePath() + READY_SEMAPHORE_SUFFIX);
}

Expand Down Expand Up @@ -168,12 +177,12 @@ public static File download(Class<?> klass, File workDirectory, String userName,
} else if (klass.isAnnotationPresent(FtpDownload.class)) {
f = handleFtpDownload(workDirectory, klass.getAnnotation(FtpDownload.class), userName, password, clean);
}
if (f != null) {
if (clean || !readySemaphoreFileExists(f)) {
// if clean = false then it might already exist
writeReadySemaphoreFile(f);
}
}
// if (f != null) {
// if (clean || !readySemaphoreFileExists(f)) {
// // if clean = false then it might already exist
// writeReadySemaphoreFile(f);
// }
// }
return f;
}

Expand Down Expand Up @@ -201,12 +210,12 @@ public static File download(Field field, File workDirectory, String userName, St
} else if (field.isAnnotationPresent(FtpDownload.class)) {
f = handleFtpDownload(workDirectory, field.getAnnotation(FtpDownload.class), userName, password, clean);
}
if (f != null) {
if (clean || !readySemaphoreFileExists(f)) {
// if clean = false then it might already exist
writeReadySemaphoreFile(f);
}
}
// if (f != null) {
// if (clean || !readySemaphoreFileExists(f)) {
// // if clean = false then it might already exist
// writeReadySemaphoreFile(f);
// }
// }
return f;
}

Expand Down Expand Up @@ -269,6 +278,11 @@ private static File handleHttpDownload(File workDirectory, HttpDownload httpd, b
if (httpd.decompress()) {
return unpackFile(workDirectory, clean, downloadedFile, targetFileName);
}
if (clean || !readySemaphoreFileExists(downloadedFile)) {
if (downloadedFile != null) {
writeReadySemaphoreFile(downloadedFile, url);
}
}
return downloadedFile;
}

Expand Down Expand Up @@ -378,7 +392,7 @@ public static File handleFtpDownload(File workDirectory, FtpInfo ftpInfo, boolea
downloadedFile = unpackFile(workDirectory, clean, downloadedFile, targetFileName);
}
if (clean || !readySemaphoreFileExists(downloadedFile)) {
writeReadySemaphoreFile(downloadedFile);
writeReadySemaphoreFile(downloadedFile, ftpInfo.getUrl());
}
return downloadedFile;
}
Expand All @@ -399,6 +413,10 @@ public static class FtpInfo {
private final FileType fileType;
private final boolean decompress;
private final String targetFileName;

public URL getUrl() throws MalformedURLException {
return new URL("ftp://" + server + (port > 0 ? ":" + Integer.toString(port) : "") + "/" + path + "/" + filename);
}
}

/**
Expand Down
@@ -0,0 +1,87 @@
package edu.ucdenver.ccp.common.download;

/*
* #%L
* Colorado Computational Pharmacology's common module
* %%
* Copyright (C) 2012 - 2017 Regents of the University of Colorado
* %%
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the Regents of the University of Colorado nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Properties;

import org.junit.Test;

import edu.ucdenver.ccp.common.file.CharacterEncoding;
import edu.ucdenver.ccp.common.file.FileReaderUtil;
import edu.ucdenver.ccp.common.test.DefaultTestCase;

public class DownloadMetadataTest extends DefaultTestCase {

@Test
public void testPropertiesFileRoundTrip() throws ParseException, IOException {

Calendar downloadDate = Calendar.getInstance();
downloadDate.setTime(DownloadMetadata.DATE_FORMATTER.parse("12/29/2015"));

Calendar lastModDate = Calendar.getInstance();
lastModDate.setTime(DownloadMetadata.DATE_FORMATTER.parse("12/01/2015"));

File downloadedFile = new File("/tmp/file.txt");

long fileSizeInBytes = 12345;

URL downloadUrl = new URL("ftp://ftp.some.server/path/file.txt");

DownloadMetadata metadata = new DownloadMetadata(downloadDate, downloadedFile, fileSizeInBytes, lastModDate,
downloadUrl);

File propertiesFile = folder.newFile("dload.properties");

metadata.writePropertiesFile(propertiesFile);

assertTrue(propertiesFile.exists());

DownloadMetadata roundTripMetadata = DownloadMetadata.loadFromPropertiesFile(propertiesFile);

assertEquals(metadata, roundTripMetadata);

/* check the validity of the file_age_in_days calculation */
assertEquals(28, metadata.getFileAgeInDays());

}

}

0 comments on commit 98fe5f6

Please sign in to comment.