/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.ant.mirrors.get;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipFile;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Checksum;
/**
* @author Peter Yoo
*/
public class MirrorsGetTask extends Task {
@Override
public void execute() throws BuildException {
try {
doExecute();
}
catch (IOException ioe) {
throw new BuildException(ioe);
}
}
public void setDest(File dest) {
_dest = dest;
}
public void setForce(boolean force) {
_force = force;
}
public void setIgnoreErrors(boolean ignoreErrors) {
_ignoreErrors = ignoreErrors;
}
public void setSkipChecksum(boolean skipChecksum) {
_skipChecksum = skipChecksum;
}
public void setSrc(String src) {
Matcher matcher = _pattern.matcher(src);
if (!matcher.find()) {
throw new RuntimeException("Invalid src attribute: " + src);
}
_fileName = matcher.group(2);
_path = matcher.group(1);
if (_path.startsWith("mirrors/")) {
_path = _path.replace("mirrors/", _HOSTNAME);
}
while (_path.endsWith("/")) {
_path = _path.substring(0, _path.length() - 1);
}
}
public void setTryLocalNetwork(boolean tryLocalNetwork) {
_tryLocalNetwork = tryLocalNetwork;
}
public void setVerbose(boolean verbose) {
_verbose = verbose;
}
protected void copyFile(File sourceFile, File targetFile)
throws IOException {
StringBuilder sb = new StringBuilder();
sb.append("Copying ");
sb.append(sourceFile.getPath());
sb.append(" to ");
sb.append(targetFile.getPath());
sb.append(".");
System.out.println(sb.toString());
URL sourceFileURL = new URL("file:" + sourceFile.getAbsolutePath());
long time = System.currentTimeMillis();
int size = toFile(sourceFileURL, targetFile);
if (_verbose) {
sb = new StringBuilder();
sb.append("Copied ");
sb.append(size);
sb.append(" bytes in ");
sb.append(System.currentTimeMillis() - time);
sb.append(" milliseconds.");
System.out.println(sb.toString());
}
}
protected void doExecute() throws IOException {
if (_tryLocalNetwork && _path.startsWith(_HOSTNAME)) {
System.out.println(
"The src attribute has an unnecessary reference to " +
_HOSTNAME);
_path = _path.substring(_HOSTNAME.length());
while (_path.startsWith("/")) {
_path = _path.substring(1);
}
}
StringBuilder sb = new StringBuilder();
sb.append(System.getProperty("user.home"));
sb.append(File.separator);
sb.append(".liferay");
sb.append(File.separator);
sb.append("mirrors");
sb.append(File.separator);
sb.append(getPlatformIndependentPath(_path));
File localCacheDir = new File(sb.toString());
File localCacheFile = new File(localCacheDir, _fileName);
if (localCacheFile.exists() && !_force && isZipFileName(_fileName)) {
_force = !isValidZip(localCacheFile);
}
if (localCacheFile.exists() && _force) {
localCacheFile.delete();
}
if (!localCacheFile.exists()) {
URL sourceURL = null;
if (_tryLocalNetwork) {
sb = new StringBuilder();
sb.append("http://");
sb.append(_HOSTNAME);
sb.append("/");
sb.append(_path);
sb.append("/");
sb.append(_fileName);
sourceURL = new URL(sb.toString());
try {
downloadFile(sourceURL, localCacheFile);
}
catch (IOException ioe) {
sb = new StringBuilder();
sb.append("http://");
sb.append(_path);
sb.append("/");
sb.append(_fileName);
sourceURL = new URL(sb.toString());
downloadFile(sourceURL, localCacheFile);
}
}
else {
sb = new StringBuilder();
sb.append("http://");
sb.append(_path);
sb.append("/");
sb.append(_fileName);
sourceURL = new URL(sb.toString());
downloadFile(sourceURL, localCacheFile);
}
}
if (_dest.exists() && _dest.isDirectory()) {
copyFile(localCacheFile, new File(_dest, _fileName));
}
else {
copyFile(localCacheFile, _dest);
}
}
protected void downloadFile(URL sourceURL, File targetFile)
throws IOException {
StringBuilder sb = new StringBuilder();
sb.append("Downloading ");
sb.append(sourceURL.toExternalForm());
sb.append(" to ");
sb.append(targetFile.getPath());
sb.append(".");
System.out.println(sb.toString());
long time = System.currentTimeMillis();
int size = 0;
try {
size = toFile(sourceURL, targetFile);
}
catch (IOException ioe) {
if (!_ignoreErrors) {
throw ioe;
}
else {
ioe.printStackTrace();
}
}
if (_verbose) {
sb = new StringBuilder();
sb.append("Downloaded ");
sb.append(sourceURL.toExternalForm());
sb.append(". ");
sb.append(size);
sb.append(" bytes in ");
sb.append(System.currentTimeMillis() - time);
sb.append(" milliseconds.");
System.out.println(sb.toString());
}
if (!isValidMD5(
targetFile, new URL(sourceURL.toExternalForm() + ".md5"))) {
targetFile.delete();
throw new IOException(
targetFile.getAbsolutePath() + " failed checksum.");
}
if (isZipFileName(targetFile.getName()) && !isValidZip(targetFile)) {
targetFile.delete();
throw new IOException(
targetFile.getAbsolutePath() + " is an invalid zip file.");
}
}
protected String getPlatformIndependentPath(String path) {
String[] separators = {"/", "\\"};
for (String separator : separators) {
if (!separator.equals(File.separator)) {
path = path.replace(separator, File.separator);
}
}
return path;
}
protected boolean isValidMD5(File file, URL url) throws IOException {
if (_skipChecksum) {
return true;
}
if ((file == null) || !file.exists()) {
return false;
}
String remoteMD5 = null;
try {
remoteMD5 = toString(url);
}
catch (FileNotFoundException fnfe) {
if (_verbose) {
System.out.println("URL does not point to a valid MD5 file.");
}
return true;
}
Checksum checksum = new Checksum();
checksum.setAlgorithm("MD5");
checksum.setFile(file);
checksum.setProject(new Project());
checksum.setProperty("md5");
checksum.execute();
Project project = checksum.getProject();
String localMD5 = project.getProperty("md5");
return remoteMD5.contains(localMD5);
}
protected boolean isValidZip(File file) throws IOException {
if (!file.exists()) {
return false;
}
ZipFile zipFile = null;
try {
zipFile = new ZipFile(file, ZipFile.OPEN_READ);
int count = 0;
Enumeration<?> enumeration = zipFile.entries();
while (enumeration.hasMoreElements()) {
enumeration.nextElement();
count++;
}
StringBuilder sb = new StringBuilder();
sb.append(file.getPath());
sb.append(" is a valid zip file with ");
sb.append(count);
sb.append(" entries.");
System.out.println(sb.toString());
return true;
}
catch (IOException ioe) {
System.out.println(file.getPath() + " is an invalid zip file.");
return false;
}
finally {
if (zipFile != null) {
zipFile.close();
}
}
}
protected boolean isZipFileName(String fileName) {
if (fileName.endsWith(".ear") || fileName.endsWith(".jar") ||
fileName.endsWith(".war") || fileName.endsWith(".zip")) {
return true;
}
return false;
}
protected int toFile(URL url, File file) throws IOException {
if (file.exists()) {
file.delete();
}
File dir = file.getParentFile();
if ((dir != null) && !dir.exists()) {
dir.mkdirs();
}
OutputStream outputStream = new FileOutputStream(file);
try {
return toOutputStream(url, outputStream);
}
catch (IOException ioe) {
if (file.exists()) {
file.delete();
}
throw ioe;
}
finally {
if (outputStream != null) {
outputStream.close();
}
}
}
protected int toOutputStream(URL url, OutputStream outputStream)
throws IOException {
URLConnection urlConnection = url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
try {
byte[] bytes = new byte[1024 * 16];
int read = 0;
int size = 0;
long time = System.currentTimeMillis();
while ((read = inputStream.read(bytes)) > 0) {
outputStream.write(bytes, 0, read);
size += read;
if (_verbose && ((System.currentTimeMillis() - time) > 100)) {
System.out.print(".");
time = System.currentTimeMillis();
}
}
if (_verbose) {
System.out.println("\n");
}
return size;
}
finally {
if (inputStream != null) {
inputStream.close();
}
}
}
protected String toString(URL url) throws IOException {
OutputStream outputStream = new ByteArrayOutputStream();
try {
toOutputStream(url, outputStream);
return outputStream.toString();
}
finally {
if (outputStream != null) {
outputStream.close();
}
}
}
private static final String _HOSTNAME = "mirrors.lax.liferay.com";
private static final Pattern _pattern = Pattern.compile(
"https?://(.+/)(.+)");
private File _dest;
private String _fileName;
private boolean _force;
private boolean _ignoreErrors;
private String _path;
private boolean _skipChecksum;
private boolean _tryLocalNetwork = true;
private boolean _verbose;
}