package org.springframework.roo.url.stream.jdk; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import java.util.logging.Level; import org.apache.commons.lang3.Validate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.springframework.roo.shell.osgi.AbstractFlashingObject; import org.springframework.roo.url.stream.UrlInputStreamService; import org.springframework.roo.url.stream.UrlInputStreamUtils; import org.springframework.uaa.client.ProxyService; import org.springframework.uaa.client.UaaService; /** * Simple implementation of {@link UrlInputStreamService} that uses the JDK. * * @author Ben Alex * @since 1.1 */ @Component @Service public class JdkUrlInputStreamService extends AbstractFlashingObject implements UrlInputStreamService { private class ProgressIndicatingInputStream extends InputStream { private final InputStream delegate; private long lastNotified; private int lastPercentageIndicated = -1; private float readSoFar; private String text; private final float totalSize; /** * Constructor * * @param connection * @throws IOException */ public ProgressIndicatingInputStream(final HttpURLConnection connection) throws IOException { Validate.notNull(connection, "URL Connection required"); totalSize = connection.getContentLength(); delegate = connection.getInputStream(); text = connection.getURL().getPath(); if ("".equals(text)) { // Fall back to the host name text = connection.getURL().getHost(); } else { // We only want the filename final int lastSlash = text.lastIndexOf("/"); if (lastSlash > -1) { text = text.substring(lastSlash + 1); } } } @Override public void close() throws IOException { flash(Level.FINE, "", MY_SLOT); delegate.close(); } @Override public int read() throws IOException { readSoFar++; if (totalSize > 0) { // Total size is known final int percentageDownloaded = Math.round(readSoFar / totalSize * 100); if (System.currentTimeMillis() > lastNotified + 1000) { if (lastPercentageIndicated != percentageDownloaded) { flash(Level.FINE, "Downloaded " + percentageDownloaded + "% of " + text, MY_SLOT); lastPercentageIndicated = percentageDownloaded; lastNotified = System.currentTimeMillis(); } } } else { // Total size is not known, rely on time-based updates instead if (System.currentTimeMillis() > lastNotified + 1000) { flash(Level.FINE, "Downloaded " + Math.round(readSoFar / 1024) + " kB of " + text, MY_SLOT); lastNotified = System.currentTimeMillis(); } } final int result = delegate.read(); if (result == -1) { if (totalSize > 0) { flash(Level.FINE, "Downloaded 100% of " + text, MY_SLOT); } else { flash(Level.FINE, "Downloaded " + Math.round(readSoFar / 1024) + " kB of " + text, MY_SLOT); } flash(Level.FINE, "", MY_SLOT); } return result; } } @Reference private ProxyService proxyService; @Reference private UaaService uaaService; public String getUrlCannotBeOpenedMessage(final URL httpUrl) { if (uaaService.isCommunicationRestricted(httpUrl)) { if (!uaaService.isUaaTermsOfUseAccepted()) { return UrlInputStreamUtils.SETUP_UAA_REQUIRED; } } // No reason it shouldn't work return null; } public InputStream openConnection(final URL httpUrl) throws IOException { Validate.notNull(httpUrl, "HTTP URL is required"); Validate.isTrue(httpUrl.getProtocol().equals("http"), "Only HTTP is supported (not " + httpUrl + ")"); // Fail if we're banned from accessing this domain Validate.isTrue(getUrlCannotBeOpenedMessage(httpUrl) == null, UrlInputStreamUtils.SETUP_UAA_REQUIRED); final HttpURLConnection connection = proxyService .prepareHttpUrlConnection(httpUrl); return new ProgressIndicatingInputStream(connection); } }