Java tutorial
/* * (C) Copyright 2015 Boni Garcia (http://bonigarcia.github.io/) * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl-2.1.html * * 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 io.github.bonigarcia.wdm; import static org.apache.commons.lang3.SystemUtils.IS_OS_WINDOWS; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.net.Proxy; import java.net.URL; import java.net.URLConnection; import java.util.Collection; import java.util.Enumeration; import java.util.List; import java.util.StringTokenizer; import java.util.zip.GZIPInputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.commons.io.FileUtils; import org.rauschig.jarchivelib.ArchiveFormat; import org.rauschig.jarchivelib.Archiver; import org.rauschig.jarchivelib.ArchiverFactory; import org.rauschig.jarchivelib.CompressionType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.io.Files; /** * Downloader class. * * @author Boni Garcia (boni.gg@gmail.com) * @since 1.0.0 */ public class Downloader { protected static final Logger log = LoggerFactory.getLogger(Downloader.class); private static final String HOME = "~"; public static Proxy createProxy() { String proxyString = System.getenv("HTTPS_PROXY"); if (proxyString == null || proxyString.length() < 1) proxyString = System.getenv("HTTP_PROXY"); if (proxyString == null || proxyString.length() < 1) { return null; } proxyString = proxyString.replace("http://", ""); proxyString = proxyString.replace("https://", ""); StringTokenizer st = new StringTokenizer(proxyString, ":"); if (st.countTokens() != 2) return null; String host = st.nextToken(); String portString = st.nextToken(); try { int port = Integer.parseInt(portString); return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(host, port)); } catch (NumberFormatException e) { return null; } } public static final synchronized void download(URL url, String version, String export, List<String> driverName) throws IOException { File targetFile = new File(getTarget(version, url)); File binary = null; // Check if binary exists boolean download = !targetFile.getParentFile().exists() || (targetFile.getParentFile().exists() && targetFile.getParentFile().list().length == 0) || WdmConfig.getBoolean("wdm.override"); if (!download) { // Check if existing binary is valid Collection<File> listFiles = FileUtils.listFiles(targetFile.getParentFile(), null, true); for (File file : listFiles) { for (String s : driverName) { if (file.getName().startsWith(s) && file.canExecute()) { binary = file; log.debug("Using binary driver previously downloaded {}", binary); download = false; break; } else { download = true; } } if (!download) { break; } } } if (download) { log.info("Downloading {} to {}", url, targetFile); HttpURLConnection conn = getConnection(url); int responseCode = conn.getResponseCode(); log.debug("Response HTTP {}", responseCode); if (responseCode == HttpURLConnection.HTTP_MOVED_TEMP || responseCode == HttpURLConnection.HTTP_MOVED_PERM || responseCode == HttpURLConnection.HTTP_SEE_OTHER) { // HTTP Redirect URL newUrl = new URL(conn.getHeaderField("Location")); log.debug("Redirect to {}", newUrl); conn = getConnection(newUrl); } FileUtils.copyInputStreamToFile(conn.getInputStream(), targetFile); if (!export.contains("edge")) { binary = extract(targetFile, export); targetFile.delete(); } else { binary = targetFile; } } if (export != null) { BrowserManager.exportDriver(export, binary.toString()); } } private static HttpURLConnection getConnection(URL url) throws IOException { Proxy proxy = createProxy(); URLConnection conn1 = proxy != null ? url.openConnection(proxy) : url.openConnection(); HttpURLConnection conn = (HttpURLConnection) conn1; conn.setRequestProperty("User-Agent", "Mozilla/5.0"); conn.addRequestProperty("Connection", "keep-alive"); conn.setInstanceFollowRedirects(true); HttpURLConnection.setFollowRedirects(true); conn.connect(); return conn; } public static final File extractMsi(File msi) throws IOException { File tmpMsi = new File(Files.createTempDir().getAbsoluteFile() + File.separator + msi.getName()); Files.move(msi, tmpMsi); log.trace("Temporal msi file: {}", tmpMsi); Process process = Runtime.getRuntime() .exec(new String[] { "msiexec", "/a", tmpMsi.toString(), "/qb", "TARGETDIR=" + msi.getParent() }); try { process.waitFor(); } catch (InterruptedException e) { log.error("Exception waiting to msiexec to be finished", e); } finally { process.destroy(); } tmpMsi.delete(); Collection<File> listFiles = FileUtils.listFiles(new File(msi.getParent()), new String[] { "exe" }, true); return listFiles.iterator().next(); } public static final File extract(File compressedFile, String export) throws IOException { log.trace("Compressed file {}", compressedFile); File file = null; if (compressedFile.getName().toLowerCase().endsWith("tar.bz2")) { file = unBZip2(compressedFile); } else if (compressedFile.getName().toLowerCase().endsWith("tar.gz")) { file = unTarGz(compressedFile); } else if (compressedFile.getName().toLowerCase().endsWith("gz")) { file = unGzip(compressedFile); } else { ZipFile zipFolder = new ZipFile(compressedFile); Enumeration<?> enu = zipFolder.entries(); while (enu.hasMoreElements()) { ZipEntry zipEntry = (ZipEntry) enu.nextElement(); String name = zipEntry.getName(); long size = zipEntry.getSize(); long compressedSize = zipEntry.getCompressedSize(); log.trace("Unzipping {} (size: {} KB, compressed size: {} KB)", name, size, compressedSize); file = new File(compressedFile.getParentFile() + File.separator + name); if (!file.exists() || WdmConfig.getBoolean("wdm.override")) { if (name.endsWith("/")) { file.mkdirs(); continue; } File parent = file.getParentFile(); if (parent != null) { parent.mkdirs(); } InputStream is = zipFolder.getInputStream(zipEntry); FileOutputStream fos = new FileOutputStream(file); byte[] bytes = new byte[1024]; int length; while ((length = is.read(bytes)) >= 0) { fos.write(bytes, 0, length); } is.close(); fos.close(); file.setExecutable(true); } else { log.debug(file + " already exists"); } } zipFolder.close(); } file = checkPhantom(compressedFile, export); log.trace("Resulting binary file {}", file.getAbsoluteFile()); return file.getAbsoluteFile(); } public static File unGzip(File archive) throws IOException { log.trace("UnGzip {}", archive); String fileName = archive.getName(); int iDash = fileName.indexOf("-"); if (iDash != -1) { fileName = fileName.substring(0, iDash); } int iDot = fileName.indexOf("."); if (iDot != -1) { fileName = fileName.substring(0, iDot); } File target = new File(archive.getParentFile() + File.separator + fileName); try (GZIPInputStream in = new GZIPInputStream(new FileInputStream(archive))) { try (FileOutputStream out = new FileOutputStream(target)) { for (int c = in.read(); c != -1; c = in.read()) { out.write(c); } } } if (!target.getName().toLowerCase().contains(".exe") && target.exists()) { target.setExecutable(true); } return target; } public static File unTarGz(File archive) throws IOException { Archiver archiver = ArchiverFactory.createArchiver(ArchiveFormat.TAR, CompressionType.GZIP); archiver.extract(archive, archive.getParentFile()); log.trace("unTarGz {}", archive); return archive; } public static File unBZip2(File archive) throws IOException { Archiver archiver = ArchiverFactory.createArchiver(ArchiveFormat.TAR, CompressionType.BZIP2); archiver.extract(archive, archive.getParentFile()); log.trace("Unbzip2 {}", archive); return archive; } private static File checkPhantom(File archive, String export) throws IOException { File target = null; String phantomName = "phantomjs"; if (export.contains(phantomName)) { String fileNoExtension = archive.getName().replace(".tar.bz2", "").replace(".zip", ""); File phantomjs = null; try { phantomjs = new File(archive.getParentFile().getAbsolutePath() + File.separator + fileNoExtension + File.separator + "bin" + File.separator).listFiles()[0]; } catch (Exception e) { String extension = IS_OS_WINDOWS ? ".exe" : ""; phantomjs = new File(archive.getParentFile().getAbsolutePath() + File.separator + fileNoExtension + File.separator + phantomName + extension); } target = new File(archive.getParentFile().getAbsolutePath() + File.separator + phantomjs.getName()); phantomjs.renameTo(target); File delete = new File(archive.getParentFile().getAbsolutePath() + File.separator + fileNoExtension); log.trace("Folder to be deleted: {}", delete); FileUtils.deleteDirectory(delete); } else { File[] ls = archive.getParentFile().listFiles(); for (File f : ls) { if (IS_OS_WINDOWS) { if (f.getName().endsWith(".exe")) { target = f; break; } } else if (f.canExecute()) { target = f; break; } } } return target; } public static final String getTarget(String version, URL url) throws IOException { log.trace("getTarget {} {}", version, url); String zip = url.getFile().substring(url.getFile().lastIndexOf("/")); int iFirst = zip.indexOf("_"); int iSecond = zip.indexOf("-"); int iLast = iFirst != zip.lastIndexOf("_") ? zip.lastIndexOf("_") : iSecond != -1 ? iSecond : zip.length(); String folder = zip.substring(0, iLast).replace(".zip", "").replace(".tar.bz2", "").replace(".tar.gz", "") .replace(".msi", "").replace(".exe", "").replace("_", File.separator); String target = getTargetPath() + folder + File.separator + version + zip; // Exception for PhantomJS if (target.contains("phantomjs")) { int iSeparator = target.indexOf(version) - 1; int iDash = target.lastIndexOf(version) + version.length(); int iPoint = target.lastIndexOf(".tar") != -1 ? target.lastIndexOf(".tar") : target.lastIndexOf(".zip"); target = target.substring(0, iSeparator + 1) + target.substring(iDash + 1, iPoint) + target.substring(iSeparator); } // Exception for Marionette else if (target.contains("wires") || target.contains("geckodriver")) { int iSeparator = target.indexOf(version) - 1; int iDash = target.lastIndexOf(version) + version.length(); int iPoint = target.lastIndexOf("tar.gz") != -1 ? target.lastIndexOf(".tar.gz") : target.lastIndexOf(".gz") != -1 ? target.lastIndexOf(".gz") : target.lastIndexOf(".zip"); target = target.substring(0, iSeparator + 1) + target.substring(iDash + 1, iPoint).toLowerCase() + target.substring(iSeparator); } log.trace("Target file for URL {} version {} = {}", url, version, target); return target; } public static String getTargetPath() { String targetPath = WdmConfig.getString("wdm.targetPath"); if (targetPath.contains(HOME)) { targetPath = targetPath.replace(HOME, System.getProperty("user.home")); } // Create repository folder if not exits File repository = new File(targetPath); if (!repository.exists()) { repository.mkdirs(); } return targetPath; } }