/hg/icedtea-web: Refactor initialize/download runnable out of Re...
jkang at icedtea.classpath.org
jkang at icedtea.classpath.org
Wed Jan 28 15:14:17 UTC 2015
changeset 16760ac4a689 in /hg/icedtea-web
details: http://icedtea.classpath.org/hg/icedtea-web?cmd=changeset;node=16760ac4a689
author: Jie Kang <jkang at redhat.com>
date: Wed Jan 28 10:12:28 2015 -0500
Refactor initialize/download runnable out of ResourceTracker and add tests
2015-01-28 Jie Kang <jkang at redhat.com>
Refactor initialize/download runnable out of ResourceTracker and add tests
* netx/net/sourceforge/jnlp/cache/ResourceTracker.java: moved Downloader
runnable into ResourceDownloader along with initialize and download
functions and their sub-functions. Removed prefetchTracker system and
queue. Moved downloadOptions into Resource.java.
* netx/net/sourceforge/jnlp/cache/Resource.java: added downloadOptions
field and getter/setter
* netx/net/sourceforge/jnlp/cache/ResourceDownloader.java:
(getUrlResponseCode), (getUrlResponseCodeWithRedirectonResult)
(initializeResource), (findBestUrl), (downloadResource),
(getDownloadConnection), (downloadPackGzFile), (downloadGZipFile),
(downloadFile), (storeEntryFields), (writeDownloadToFile)(uncompressGzip),
(uncompressPackGz): new Runnable class for initializing and downloading
resources. Code from ResourceTracker.java
* tests/netx/unit/net/sourceforge/jnlp/cache/ResourceTrackerTest.java:
tests for downloading/initializing functions and their subfunctions moved
to ResourceDownloaderTest.java
* tests/netx/unit/net/sourceforge/jnlp/cache/ResourceDownloaderTest.java:
relevant tests from ResourceTrackerTest.java moved here.
(testDownloadResource), (testDownloadPackGzResource)
(testDownloadVersionedResource), (testDownloadVersionedPackGzResource)
(testDownloadLocalResourceFails), (testDownloadNotExistingResourceFails):
New tests added
diffstat:
ChangeLog | 26 +
netx/net/sourceforge/jnlp/cache/Resource.java | 16 +-
netx/net/sourceforge/jnlp/cache/ResourceDownloader.java | 445 ++++++
netx/net/sourceforge/jnlp/cache/ResourceTracker.java | 644 +---------
tests/netx/unit/net/sourceforge/jnlp/cache/ResourceDownloaderTest.java | 498 +++++++
tests/netx/unit/net/sourceforge/jnlp/cache/ResourceTrackerTest.java | 210 +---
6 files changed, 991 insertions(+), 848 deletions(-)
diffs (truncated from 2037 to 500 lines):
diff -r 918fb141b815 -r 16760ac4a689 ChangeLog
--- a/ChangeLog Fri Jan 23 15:35:46 2015 +0100
+++ b/ChangeLog Wed Jan 28 10:12:28 2015 -0500
@@ -1,3 +1,29 @@
+2015-01-28 Jie Kang <jkang at redhat.com>
+
+ Refactor initialize/download runnable out of ResourceTracker and add tests
+ * netx/net/sourceforge/jnlp/cache/ResourceTracker.java: moved Downloader
+ runnable into ResourceDownloader along with initialize and download
+ functions and their sub-functions. Removed prefetchTracker system and
+ queue. Moved downloadOptions into Resource.java.
+ * netx/net/sourceforge/jnlp/cache/Resource.java: added downloadOptions
+ field and getter/setter
+ * netx/net/sourceforge/jnlp/cache/ResourceDownloader.java:
+ (getUrlResponseCode), (getUrlResponseCodeWithRedirectonResult)
+ (initializeResource), (findBestUrl), (downloadResource),
+ (getDownloadConnection), (downloadPackGzFile), (downloadGZipFile),
+ (downloadFile), (storeEntryFields), (writeDownloadToFile)(uncompressGzip),
+ (uncompressPackGz): new Runnable class for initializing and downloading
+ resources. Code from ResourceTracker.java
+ * tests/netx/unit/net/sourceforge/jnlp/cache/ResourceTrackerTest.java:
+ tests for downloading/initializing functions and their subfunctions moved
+ to ResourceDownloaderTest.java
+ * tests/netx/unit/net/sourceforge/jnlp/cache/ResourceDownloaderTest.java:
+ relevant tests from ResourceTrackerTest.java moved here.
+ (testDownloadResource), (testDownloadPackGzResource)
+ (testDownloadVersionedResource), (testDownloadVersionedPackGzResource)
+ (testDownloadLocalResourceFails), (testDownloadNotExistingResourceFails):
+ New tests added
+
2014-01-23 Jiri Vanek <jvanek at redhat.com>
Returned accidentally removed creation of shortcuts for jnlp applications.
diff -r 918fb141b815 -r 16760ac4a689 netx/net/sourceforge/jnlp/cache/Resource.java
--- a/netx/net/sourceforge/jnlp/cache/Resource.java Fri Jan 23 15:35:46 2015 +0100
+++ b/netx/net/sourceforge/jnlp/cache/Resource.java Wed Jan 28 10:12:28 2015 -0500
@@ -23,6 +23,7 @@
import java.util.List;
import java.util.Set;
+import net.sourceforge.jnlp.DownloadOptions;
import net.sourceforge.jnlp.Version;
import net.sourceforge.jnlp.util.UrlUtils;
import net.sourceforge.jnlp.util.WeakList;
@@ -47,7 +48,6 @@
* @version $Revision: 1.9 $
*/
public class Resource {
-
// todo: fix resources to handle different versions
// todo: IIRC, any resource is checked for being up-to-date
@@ -97,6 +97,9 @@
/** Update policy for this resource */
private final UpdatePolicy updatePolicy;
+ /** Download options for this resource */
+ private DownloadOptions downloadOptions;
+
/**
* Create a resource.
*/
@@ -414,6 +417,14 @@
}
}
+ public void setDownloadOptions(DownloadOptions downloadOptions) {
+ this.downloadOptions = downloadOptions;
+ }
+
+ public DownloadOptions getDownloadOptions() {
+ return this.downloadOptions;
+ }
+
@Override
public int hashCode() {
// FIXME: should probably have a better hashcode than this, but considering
@@ -440,7 +451,4 @@
public String toString() {
return "location=" + location.toString() + " state=" + getStatusString();
}
-
-
-
}
diff -r 918fb141b815 -r 16760ac4a689 netx/net/sourceforge/jnlp/cache/ResourceDownloader.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/netx/net/sourceforge/jnlp/cache/ResourceDownloader.java Wed Jan 28 10:12:28 2015 -0500
@@ -0,0 +1,445 @@
+package net.sourceforge.jnlp.cache;
+
+import static net.sourceforge.jnlp.cache.Resource.Status.CONNECTED;
+import static net.sourceforge.jnlp.cache.Resource.Status.CONNECTING;
+import static net.sourceforge.jnlp.cache.Resource.Status.DOWNLOADED;
+import static net.sourceforge.jnlp.cache.Resource.Status.DOWNLOADING;
+import static net.sourceforge.jnlp.cache.Resource.Status.ERROR;
+import static net.sourceforge.jnlp.cache.Resource.Status.PRECONNECT;
+import static net.sourceforge.jnlp.cache.Resource.Status.PREDOWNLOAD;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Pack200;
+import java.util.zip.GZIPInputStream;
+
+import net.sourceforge.jnlp.DownloadOptions;
+import net.sourceforge.jnlp.Version;
+import net.sourceforge.jnlp.runtime.JNLPRuntime;
+import net.sourceforge.jnlp.security.ConnectionFactory;
+import net.sourceforge.jnlp.util.HttpUtils;
+import net.sourceforge.jnlp.util.logging.OutputController;
+
+public class ResourceDownloader implements Runnable {
+
+ private final Resource resource;
+ private final Object lock;
+
+ public ResourceDownloader(Resource resource, Object lock) {
+ this.resource = resource;
+ this.lock = lock;
+ }
+
+ static int getUrlResponseCode(URL url, Map<String, String> requestProperties, ResourceTracker.RequestMethods requestMethod) throws IOException {
+ return getUrlResponseCodeWithRedirectonResult(url, requestProperties, requestMethod).result;
+ }
+
+ /**
+ * Connects to the given URL, and grabs a response code and redirecton if
+ * the URL uses the HTTP protocol, or returns an arbitrary valid HTTP
+ * response code.
+ *
+ * @return the response code if HTTP connection and redirection value, or
+ * HttpURLConnection.HTTP_OK and null if not.
+ * @throws IOException
+ */
+ static CodeWithRedirect getUrlResponseCodeWithRedirectonResult(URL url, Map<String, String> requestProperties, ResourceTracker.RequestMethods requestMethod) throws IOException {
+ CodeWithRedirect result = new CodeWithRedirect();
+ URLConnection connection = ConnectionFactory.getConnectionFactory().openConnection(url);
+
+ for (Map.Entry<String, String> property : requestProperties.entrySet()) {
+ connection.addRequestProperty(property.getKey(), property.getValue());
+ }
+
+ if (connection instanceof HttpURLConnection) {
+ HttpURLConnection httpConnection = (HttpURLConnection) connection;
+ httpConnection.setRequestMethod(requestMethod.toString());
+
+ int responseCode = httpConnection.getResponseCode();
+
+ /* Fully consuming current request helps with connection re-use
+ * See http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html */
+ HttpUtils.consumeAndCloseConnectionSilently(httpConnection);
+
+ result.result = responseCode;
+ }
+
+ Map<String, List<String>> header = connection.getHeaderFields();
+ for (Map.Entry<String, List<String>> entry : header.entrySet()) {
+ OutputController.getLogger().log("Key : " + entry.getKey() + " ,Value : " + entry.getValue());
+ }
+ /*
+ * Do this only on 301,302,303(?)307,308>
+ * Now setting value for all, and lets upper stack to handle it
+ */
+ String possibleRedirect = connection.getHeaderField("Location");
+ if (possibleRedirect != null && possibleRedirect.trim().length() > 0) {
+ result.URL = new URL(possibleRedirect);
+ }
+ ConnectionFactory.getConnectionFactory().disconnect(connection);
+
+ return result;
+
+ }
+
+ @Override
+ public void run() {
+ if (resource.isSet(PRECONNECT) && !resource.hasFlags(EnumSet.of(ERROR, CONNECTING, CONNECTED))) {
+ resource.changeStatus(EnumSet.noneOf(Resource.Status.class), EnumSet.of(CONNECTING));
+ resource.fireDownloadEvent(); // fire CONNECTING
+ initializeResource();
+ }
+ if (resource.isSet(PREDOWNLOAD) && !resource.hasFlags(EnumSet.of(ERROR, DOWNLOADING, DOWNLOADED))) {
+ resource.changeStatus(EnumSet.noneOf(Resource.Status.class), EnumSet.of(DOWNLOADING));
+ resource.fireDownloadEvent(); // fire CONNECTING
+ downloadResource();
+ }
+ }
+
+ /**
+ * Open a URL connection and get the content length and other
+ * fields.
+ */
+ private void initializeResource() {
+ //verify connection
+ if(!JNLPRuntime.isOfflineForced()){
+ JNLPRuntime.detectOnline(resource.getLocation()/*or doenloadLocation*/);
+ }
+
+ CacheEntry entry = new CacheEntry(resource.getLocation(), resource.getRequestVersion());
+ entry.lock();
+
+ try {
+ File localFile = CacheUtil.getCacheFile(resource.getLocation(), resource.getDownloadVersion());
+ long size = 0;
+ boolean current = true;
+ //this can be null, as it is always filled in online mode, and never read in offline mode
+ URLConnection connection = null;
+ if (localFile != null) {
+ size = localFile.length();
+ } else if (!JNLPRuntime.isOnline()) {
+ OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "You are trying to get resource " + resource.getLocation().toExternalForm() + " but you are in offline mode, and it is not in cache. Attempting to continue, but you may expect failure");
+ }
+ if (JNLPRuntime.isOnline()) {
+ // connect
+ URL finalLocation = findBestUrl(resource);
+
+ if (finalLocation == null) {
+ OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Attempted to download " + resource.getLocation() + ", but failed to connect!");
+ throw new NullPointerException("finalLocation == null"); // Caught below
+ }
+
+ resource.setDownloadLocation(finalLocation);
+ connection = ConnectionFactory.getConnectionFactory().openConnection(finalLocation); // this won't change so should be okay not-synchronized
+ connection.addRequestProperty("Accept-Encoding", "pack200-gzip, gzip");
+
+ size = connection.getContentLength();
+ current = CacheUtil.isCurrent(resource.getLocation(), resource.getRequestVersion(), connection.getLastModified()) && resource.getUpdatePolicy() != UpdatePolicy.FORCE;
+ if (!current) {
+ if (entry.isCached()) {
+ entry.markForDelete();
+ entry.store();
+ // Old entry will still exist. (but removed at cleanup)
+ localFile = CacheUtil.makeNewCacheFile(resource.getLocation(), resource.getDownloadVersion());
+ CacheEntry newEntry = new CacheEntry(resource.getLocation(), resource.getRequestVersion());
+ newEntry.lock();
+ entry.unlock();
+ entry = newEntry;
+ }
+ }
+ }
+ synchronized (resource) {
+ resource.setLocalFile(localFile);
+ // resource.connection = connection;
+ resource.setSize(size);
+ resource.changeStatus(EnumSet.of(PRECONNECT, CONNECTING), EnumSet.of(CONNECTED, PREDOWNLOAD));
+
+ // check if up-to-date; if so set as downloaded
+ if (current)
+ resource.changeStatus(EnumSet.of(PREDOWNLOAD, DOWNLOADING), EnumSet.of(DOWNLOADED));
+ }
+
+ // update cache entry
+ if (!current && JNLPRuntime.isOnline()) {
+ entry.setRemoteContentLength(connection.getContentLengthLong());
+ entry.setLastModified(connection.getLastModified());
+ }
+
+ entry.setLastUpdated(System.currentTimeMillis());
+ entry.store();
+
+ synchronized (lock) {
+ lock.notifyAll(); // wake up wait's to check for completion
+ }
+ resource.fireDownloadEvent(); // fire CONNECTED
+
+ // explicitly close the URLConnection.
+ ConnectionFactory.getConnectionFactory().disconnect(connection);
+ } catch (Exception ex) {
+ OutputController.getLogger().log(ex);
+ resource.changeStatus(EnumSet.noneOf(Resource.Status.class), EnumSet.of(ERROR));
+ synchronized (lock) {
+ lock.notifyAll(); // wake up wait's to check for completion
+ }
+ resource.fireDownloadEvent(); // fire ERROR
+ } finally {
+ entry.unlock();
+ }
+ }
+
+ /**
+ * Returns the 'best' valid URL for the given resource.
+ * This first adjusts the file name to take into account file versioning
+ * and packing, if possible.
+ *
+ * @param resource the resource
+ * @return the best URL, or null if all failed to resolve
+ */
+ protected URL findBestUrl(Resource resource) {
+ DownloadOptions options = resource.getDownloadOptions();
+ if (options == null) {
+ options = new DownloadOptions(false, false);
+ }
+
+ List<URL> urls = new ResourceUrlCreator(resource, options).getUrls();
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Finding best URL for: " + resource.getLocation() + " : " + options.toString());
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "All possible urls for "
+ + resource.toString() + " : " + urls);
+
+ for (ResourceTracker.RequestMethods requestMethod : ResourceTracker.RequestMethods.getValidRequestMethods()) {
+ for (int i = 0; i < urls.size(); i++) {
+ URL url = urls.get(i);
+ try {
+ Map<String, String> requestProperties = new HashMap<>();
+ requestProperties.put("Accept-Encoding", "pack200-gzip, gzip");
+
+ CodeWithRedirect response = getUrlResponseCodeWithRedirectonResult(url, requestProperties, requestMethod);
+ if (response.shouldRedirect()){
+ if (response.URL == null) {
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Although " + resource.toString() + " got redirect " + response.result + " code for " + requestMethod + " request for " + url.toExternalForm() + " the target was null. Not following");
+ } else {
+ OutputController.getLogger().log(OutputController.Level.MESSAGE_DEBUG, "Resource " + resource.toString() + " got redirect " + response.result + " code for " + requestMethod + " request for " + url.toExternalForm() + " adding " + response.URL.toExternalForm()+" to list of possible urls");
+ if (!JNLPRuntime.isAllowRedirect()){
+ throw new RedirectionException("The resource " + url.toExternalForm() + " is being redirected (" + response.result + ") to " + response.URL.toExternalForm() + ". This is disabled by default. If you wont to allow it, run javaws with -allowredirect parameter.");
+ }
+ urls.add(response.URL);
+ }
+ } else if (response.isInvalid()) {
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "For " + resource.toString() + " the server returned " + response.result + " code for " + requestMethod + " request for " + url.toExternalForm());
+ } else {
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "best url for " + resource.toString() + " is " + url.toString() + " by " + requestMethod);
+ return url; /* This is the best URL */
+ }
+ } catch (IOException e) {
+ // continue to next candidate
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "While processing " + url.toString() + " by " + requestMethod + " for resource " + resource.toString() + " got " + e + ": ");
+ OutputController.getLogger().log(e);
+ }
+ }
+ }
+
+ /* No valid URL, return null */
+ return null;
+ }
+
+ private void downloadResource() {
+ URLConnection connection = null;
+ URL downloadFrom = resource.getDownloadLocation(); //Where to download from
+ URL downloadTo = resource.getLocation(); //Where to download to
+
+ try {
+ connection = getDownloadConnection(downloadFrom);
+
+ String contentEncoding = connection.getContentEncoding();
+
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Downloading " + downloadTo + " using " +
+ downloadFrom + " (encoding : " + contentEncoding + ") ");
+
+ boolean packgz = "pack200-gzip".equals(contentEncoding) ||
+ downloadFrom.getPath().endsWith(".pack.gz");
+ boolean gzip = "gzip".equals(contentEncoding);
+
+ // It's important to check packgz first. If a stream is both
+ // pack200 and gz encoded, then con.getContentEncoding() could
+ // return ".gz", so if we check gzip first, we would end up
+ // treating a pack200 file as a jar file.
+
+ if (packgz) {
+ downloadPackGzFile(resource, connection, new URL(downloadFrom + ".pack.gz"), downloadTo);
+ } else if (gzip) {
+ downloadGZipFile(resource, connection, new URL(downloadFrom + ".gz"), downloadTo);
+ } else {
+ downloadFile(resource, connection, downloadTo);
+ }
+
+ resource.changeStatus(EnumSet.of(DOWNLOADING), EnumSet.of(DOWNLOADED));
+ synchronized (lock) {
+ lock.notifyAll(); // wake up wait's to check for completion
+ }
+ resource.fireDownloadEvent(); // fire DOWNLOADED
+ } catch (Exception ex) {
+ OutputController.getLogger().log(ex);
+ resource.changeStatus(EnumSet.noneOf(Resource.Status.class), EnumSet.of(ERROR));
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ resource.fireDownloadEvent(); // fire ERROR
+ } finally {
+ if (connection != null) {
+ ConnectionFactory.getConnectionFactory().disconnect(connection);
+ }
+ }
+ }
+
+ private URLConnection getDownloadConnection(URL location) throws IOException {
+ URLConnection con = ConnectionFactory.getConnectionFactory().openConnection(location);
+ con.addRequestProperty("Accept-Encoding", "pack200-gzip, gzip");
+ con.connect();
+ return con;
+ }
+
+ private void downloadPackGzFile(Resource resource, URLConnection connection, URL downloadFrom, URL downloadTo) throws IOException {
+ downloadFile(resource, connection, downloadFrom);
+
+ uncompressPackGz(downloadFrom, downloadTo, resource.getDownloadVersion());
+ storeEntryFields(new CacheEntry(downloadTo, resource.getDownloadVersion()), connection.getContentLength(), connection.getLastModified());
+ }
+
+ private void downloadGZipFile(Resource resource, URLConnection connection, URL downloadFrom, URL downloadTo) throws IOException {
+ downloadFile(resource, connection, downloadFrom);
+
+ uncompressGzip(downloadFrom, downloadTo, resource.getDownloadVersion());
+ storeEntryFields(new CacheEntry(downloadTo, resource.getDownloadVersion()), connection.getContentLength(), connection.getLastModified());
+ }
+
+ private void downloadFile(Resource resource, URLConnection connection, URL downloadLocation) throws IOException {
+ CacheEntry downloadEntry = new CacheEntry(downloadLocation, resource.getDownloadVersion());
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Downloading file: " + downloadLocation + " into: " + downloadEntry.getCacheFile().getCanonicalPath());
+ if (!downloadEntry.isCurrent(connection.getLastModified())) {
+ writeDownloadToFile(resource, downloadLocation, new BufferedInputStream(connection.getInputStream()));
+ } else {
+ resource.setTransferred(CacheUtil.getCacheFile(downloadLocation, resource.getDownloadVersion()).length());
+ }
+
+ storeEntryFields(downloadEntry, connection.getContentLengthLong(), connection.getLastModified());
+ }
+
+ private void storeEntryFields(CacheEntry entry, long contentLength, long lastModified) {
+ entry.lock();
+ try {
+ entry.setRemoteContentLength(contentLength);
+ entry.setLastModified(lastModified);
+ entry.store();
+ } finally {
+ entry.unlock();
+ }
+ }
+
+ private void writeDownloadToFile(Resource resource, URL downloadLocation, InputStream in) throws IOException {
+ byte buf[] = new byte[1024];
+ int rlen;
+ OutputStream out = CacheUtil.getOutputStream(downloadLocation, resource.getDownloadVersion());
+ while (-1 != (rlen = in.read(buf))) {
+ resource.incrementTransferred(rlen);
+ out.write(buf, 0, rlen);
+ }
+
+ in.close();
+ out.close();
+ }
+
+ private void uncompressGzip(URL compressedLocation, URL uncompressedLocation, Version version) throws IOException {
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Extracting gzip: " + compressedLocation + " to " + uncompressedLocation);
+ byte buf[] = new byte[1024];
+ int rlen;
+
+ GZIPInputStream gzInputStream = new GZIPInputStream(new FileInputStream(CacheUtil
+ .getCacheFile(compressedLocation, version)));
+ InputStream inputStream = new BufferedInputStream(gzInputStream);
+
+ BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(CacheUtil
+ .getCacheFile(uncompressedLocation, version)));
+
+ while (-1 != (rlen = inputStream.read(buf))) {
+ outputStream.write(buf, 0, rlen);
+ }
+
+ outputStream.close();
+ inputStream.close();
+ gzInputStream.close();
+ }
+
+ private void uncompressPackGz(URL compressedLocation, URL uncompressedLocation, Version version) throws IOException {
+ OutputController.getLogger().log(OutputController.Level.ERROR_DEBUG, "Extracting packgz: " + compressedLocation + " to " + uncompressedLocation);
+
+ GZIPInputStream gzInputStream = new GZIPInputStream(new FileInputStream(CacheUtil
+ .getCacheFile(compressedLocation, version)));
+ InputStream inputStream = new BufferedInputStream(gzInputStream);
+
+ JarOutputStream outputStream = new JarOutputStream(new FileOutputStream(CacheUtil
+ .getCacheFile(uncompressedLocation, version)));
+
+ Pack200.Unpacker unpacker = Pack200.newUnpacker();
+ unpacker.unpack(inputStream, outputStream);
+
+ outputStream.close();
+ inputStream.close();
+ gzInputStream.close();
+ }
+
+ /**
+ * Complex wrapper around return code with utility methods
+ * Default is HTTP_OK
+ */
+ private static class CodeWithRedirect {
+
+ int result = HttpURLConnection.HTTP_OK;
+ URL URL;
More information about the distro-pkg-dev
mailing list