Java tutorial
package de.fhg.iais.asc.xslt.binaries.download; /****************************************************************************** * Copyright 2011 (c) Fraunhofer IAIS Netmedia http://www.iais.fraunhofer.de * * ************************************************************************** * * Licensed under the Apache License, Version 2.0 (the "License"); you may * * not use this file except in compliance with the License. * * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * * software distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * ******************************************************************************/ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Charsets; import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import de.fhg.iais.asc.commons.AscConfiguration; import de.fhg.iais.asc.commons.ParentDirectoryUtils; import de.fhg.iais.asc.commons.exceptions.AscTechnicalErrorException; import de.fhg.iais.asc.transformer.TransformationContext; import de.fhg.iais.commons.stream.AtomicFileOutputStream; public class Downloader { private static final Logger LOG = LoggerFactory.getLogger(Downloader.class); private static final List<String> ALLOWED_SCHEMES = Arrays.asList("http", "https"); private static final Pattern START_SLASHES_PATTERN = Pattern.compile("^\\/+"); private static final long BROKEN_IMAGE_THRESHOLD = 5; // bytes private static int MAX_DOWNLOAD_RETRIES; private static int DOWNLOAD_BINARY_TIMEOUT; private static AscConfiguration config; private static Client client; public static Downloader forContext(TransformationContext transContext) { config = transContext.getConfig(); MAX_DOWNLOAD_RETRIES = Downloader.config.get(AscConfiguration.DOWNLOAD_BINARIES_RETRIES, 5); DOWNLOAD_BINARY_TIMEOUT = Downloader.config.get(AscConfiguration.DOWNLOAD_BINARIES_TIMEOUT, 60000); Downloader result; synchronized (transContext) { result = transContext.getObject(Downloader.class); if (result == null) { result = new Downloader(); transContext.putObject(Downloader.class, result); } } return result; } public static void init(Client httpClient) { client = httpClient; } private Downloader() { } public static URI createDownloadableURI(String path) { URI uri; try { try { uri = new URI(path); } catch (URISyntaxException e) { String decoded = URLDecoder.decode(path, Charsets.UTF_8.name()); URL url = new URL(decoded); uri = createURI(url); } } catch (Exception e) { // give up return null; } return isDownloadableURI(uri) ? uri : null; } private static URI createURI(URL url) throws URISyntaxException { return new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); } private static boolean isDownloadableURI(URI uri) { String scheme = uri.getScheme(); return ALLOWED_SCHEMES.contains(scheme); } public static String createPathFromURI(final URI uri) { String rawPath = uri.getRawPath(); return START_SLASHES_PATTERN.matcher(rawPath).replaceFirst(""); } public void downloadBinary(URI uri, File target) { InputStream contentStream = null; try { ClientResponse response = Downloader.client.resource(uri).get(ClientResponse.class); int retries = 0; while (!checkStatusCode(response) && retries < MAX_DOWNLOAD_RETRIES) { ++retries; try { Thread.sleep(DOWNLOAD_BINARY_TIMEOUT); } catch (InterruptedException e) { LOG.debug("Sleeping thread interrupted!"); } response = Downloader.client.resource(uri).get(ClientResponse.class); } if (!checkStatusCode(response)) { String msg = "Downloading of \"" + uri.toASCIIString() + "\" failed with status " + response.getStatus(); throw new AscTechnicalErrorException(msg); } contentStream = response.getEntityInputStream(); if (contentStream == null) { throw new IOException("No response entity"); } writeStreamToFile(contentStream, target); if (!checkContentLength(target)) { String msg = "Content of response \"" + uri.toASCIIString() + "\" has a length of zero!"; throw new AscTechnicalErrorException(msg); } } catch (Exception e) { if (target.exists() && !target.delete()) { LOG.warn(String.format("Could not delete invalid file \"%s\"", target.getAbsolutePath())); } String msg = "Exception downloading \"" + uri.toASCIIString() + "\""; LOG.error(msg, e); throw AscTechnicalErrorException.wrap(msg, e); } finally { IOUtils.closeQuietly(contentStream); } } private boolean checkContentLength(File target) { boolean hasValidContent = false; try { if (target.length() > BROKEN_IMAGE_THRESHOLD) { hasValidContent = true; } } catch (IllegalStateException e) { ; } catch (NullPointerException e) { ; } return hasValidContent; } private boolean checkStatusCode(final ClientResponse response) { int statusCode = response.getStatus(); return (statusCode / 100) == 2; } private static void writeStreamToFile(InputStream contentStream, File target) throws IOException { ParentDirectoryUtils.forceCreateParentDirectoryOf(target); AtomicFileOutputStream aos = null; try { aos = new AtomicFileOutputStream(target); IOUtils.copyLarge(contentStream, aos); aos.closeAsCompleted(); } finally { IOUtils.closeQuietly(aos); } } public boolean existsBinary(URI uri) throws IOException { final ClientResponse response = Downloader.client.resource(uri).head(); return checkStatusCode(response); } }