001/** 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the terms of the GNU 005 * Lesser General Public Licence. This should be distributed with the code. If 006 * you do not have a copy, see: 007 * 008 * http://www.gnu.org/copyleft/lesser.html 009 * 010 * Copyright for this code is held jointly by the individual authors. These 011 * should be listed in @author doc comments. 012 * 013 * For more information on the BioJava project and its aims, or to join the 014 * biojava-l mailing list, visit the home page at: 015 * 016 * http://www.biojava.org/ 017 * 018 * Created on Feb 23, 2012 Created by Andreas Prlic 019 * 020 * @since 3.0.2 021 */ 022package org.biojava.nbio.core.util; 023 024import org.slf4j.Logger; 025import org.slf4j.LoggerFactory; 026 027import java.io.File; 028import java.io.FileInputStream; 029import java.io.FileOutputStream; 030import java.io.IOException; 031import java.io.InputStream; 032import java.net.HttpURLConnection; 033import java.net.SocketTimeoutException; 034import java.net.URL; 035import java.net.URLConnection; 036import java.nio.channels.Channels; 037import java.nio.channels.FileChannel; 038import java.nio.channels.ReadableByteChannel; 039 040public class FileDownloadUtils { 041 042 private static final Logger logger = LoggerFactory.getLogger(FileDownloadUtils.class); 043 044 /** 045 * Copy the content of file src to dst TODO since java 1.7 this is provided 046 * in java.nio.file.Files 047 * 048 * @param src 049 * @param dst 050 * @throws IOException 051 */ 052 @SuppressWarnings("resource") 053 public static void copy(File src, File dst) throws IOException { 054 055 // Took following recipe from 056 // http://stackoverflow.com/questions/106770/standard-concise-way-to-copy-a-file-in-java 057 // The nio package seems to be the most efficient way to copy a file 058 FileChannel source = null; 059 FileChannel destination = null; 060 061 try { 062 // we need the supress warnings here (the warning that the stream is not closed is harmless) 063 // see http://stackoverflow.com/questions/12970407/does-filechannel-close-close-the-underlying-stream 064 source = new FileInputStream(src).getChannel(); 065 destination = new FileOutputStream(dst).getChannel(); 066 destination.transferFrom(source, 0, source.size()); 067 } finally { 068 if (source != null) { 069 source.close(); 070 } 071 if (destination != null) { 072 destination.close(); 073 } 074 } 075 } 076 077 public static String getFileExtension(File f) { 078 String fileName = f.getName(); 079 String ext = ""; 080 int mid = fileName.lastIndexOf("."); 081 ext = fileName.substring(mid + 1, fileName.length()); 082 return ext; 083 } 084 085 public static String getFilePrefix(File f) { 086 String fileName = f.getName(); 087 String fname = ""; 088 089 int mid = fileName.indexOf("."); 090 fname = fileName.substring(0, mid); 091 092 return fname; 093 } 094 095 /** 096 * Download the content provided at URL url and store the result to a local 097 * file, using a temp file to cache the content in case something goes wrong 098 * in download 099 * 100 * @param url 101 * @param destination 102 * @throws IOException 103 */ 104 public static void downloadFile(URL url, File destination) throws IOException { 105 int count = 0; 106 int maxTries = 10; 107 int timeout = 60000; //60 sec 108 109 File tempFile = File.createTempFile(getFilePrefix(destination), "." + getFileExtension(destination)); 110 111 // Took following recipe from stackoverflow: 112 // http://stackoverflow.com/questions/921262/how-to-download-and-save-a-file-from-internet-using-java 113 // It seems to be the most efficient way to transfer a file 114 // See: http://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileChannel.html 115 ReadableByteChannel rbc = null; 116 FileOutputStream fos = null; 117 while (true) { 118 try { 119 URLConnection connection = prepareURLConnection(url.toString(), timeout); 120 connection.connect(); 121 InputStream inputStream = connection.getInputStream(); 122 123 rbc = Channels.newChannel(inputStream); 124 fos = new FileOutputStream(tempFile); 125 fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 126 break; 127 } catch (SocketTimeoutException e) { 128 if (++count == maxTries) throw e; 129 } finally { 130 if (rbc != null) { 131 rbc.close(); 132 } 133 if (fos != null) { 134 fos.close(); 135 } 136 } 137 } 138 139 logger.debug("Copying temp file {} to final location {}", tempFile, destination); 140 copy(tempFile, destination); 141 142 // delete the tmp file 143 tempFile.delete(); 144 145 } 146 147 /** 148 * Converts path to Unix convention and adds a terminating slash if it was 149 * omitted 150 * 151 * @param path original platform dependent path 152 * @return path in Unix convention 153 * @author Peter Rose 154 * @since 3.2 155 */ 156 public static String toUnixPath(String path) { 157 String uPath = path; 158 if (uPath.contains("\\")) { 159 uPath = uPath.replaceAll("\\\\", "/"); 160 } 161 // this should be removed, it's need since "\" is added AtomCache code 162 if (uPath.endsWith("//")) { 163 uPath = uPath.substring(0, uPath.length() - 1); 164 } 165 if (!uPath.endsWith("/")) { 166 uPath = uPath + "/"; 167 } 168 return uPath; 169 } 170 171 /** 172 * Expands ~ in paths to the user's home directory. 173 * 174 * <p> 175 * This does not work for some special cases for paths: Other users' homes 176 * (~user/...), and Tilde expansion within the path (/.../~/...) 177 * 178 * @param file 179 * @return 180 */ 181 public static String expandUserHome(String file) { 182 if (file.startsWith("~" + File.separator)) { 183 file = System.getProperty("user.home") + file.substring(1); 184 } 185 return file; 186 } 187 188 /** 189 * Pings a HTTP URL. This effectively sends a HEAD request and returns 190 * <code>true</code> if the response code is in the 200-399 range. 191 * 192 * @param url The HTTP URL to be pinged. 193 * @param timeout The timeout in millis for both the connection timeout and 194 * the response read timeout. Note that the total timeout is effectively two 195 * times the given timeout. 196 * @return <code>true</code> if the given HTTP URL has returned response 197 * code 200-399 on a HEAD request within the given timeout, otherwise 198 * <code>false</code>. 199 * @author BalusC, 200 * http://stackoverflow.com/questions/3584210/preferred-java-way-to-ping-a-http-url-for-availability 201 */ 202 public static boolean ping(String url, int timeout) { 203 //url = url.replaceFirst("https", "http"); // Otherwise an exception may be thrown on invalid SSL certificates. 204 205 try { 206 HttpURLConnection connection = (HttpURLConnection) prepareURLConnection(url, timeout); 207 connection.setRequestMethod("HEAD"); 208 int responseCode = connection.getResponseCode(); 209 return (200 <= responseCode && responseCode <= 399); 210 } catch (IOException exception) { 211 return false; 212 } 213 } 214 215 /** 216 * Prepare {@link URLConnection} with customised timeouts. 217 * 218 * @param url The URL 219 * @param timeout The timeout in millis for both the connection timeout and 220 * the response read timeout. Note that the total timeout is effectively two 221 * times the given timeout. 222 * 223 * <p> 224 * Example of code. <code> 225 * UrlConnection conn = prepareURLConnection("http://www.google.com/", 20000); 226 * conn.connect(); 227 * conn.getInputStream(); 228 * </code> 229 * <p> 230 * 231 * <bold>NB. User should execute connect() method before getting input 232 * stream.</bold> 233 * @return 234 * @throws IOException 235 * @author Jacek Grzebyta 236 */ 237 public static URLConnection prepareURLConnection(String url, int timeout) throws IOException { 238 URLConnection connection = new URL(url).openConnection(); 239 connection.setReadTimeout(timeout); 240 connection.setConnectTimeout(timeout); 241 return connection; 242 } 243 244 public static void main(String[] args) { 245 String url; 246 url = "http://scop.mrc-lmb.cam.ac.uk/scop/parse/"; 247 System.out.format("%s\t%s%n", ping(url, 200), url); 248 url = "http://scop.mrc-lmb.cam.ac.uk/scop/parse/foo"; 249 System.out.format("%s\t%s%n", ping(url, 200), url); 250 url = "http://scopzzz.mrc-lmb.cam.ac.uk/scop/parse/"; 251 System.out.format("%s\t%s%n", ping(url, 200), url); 252 url = "scop.mrc-lmb.cam.ac.uk"; 253 System.out.format("%s\t%s%n", ping(url, 200), url); 254 url = "http://scop.mrc-lmb.cam.ac.uk"; 255 System.out.format("%s\t%s%n", ping(url, 200), url); 256 } 257 258}