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