Mercurial > hg > release > icedtea-web-1.6
changeset 1143:16760ac4a689
Refactor initialize/download runnable out of ResourceTracker and add tests
2015-01-28 Jie Kang <jkang@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
author | Jie Kang <jkang@redhat.com> |
---|---|
date | Wed, 28 Jan 2015 10:12:28 -0500 |
parents | 918fb141b815 |
children | 382fb9c6634f |
files | ChangeLog netx/net/sourceforge/jnlp/cache/Resource.java netx/net/sourceforge/jnlp/cache/ResourceDownloader.java netx/net/sourceforge/jnlp/cache/ResourceTracker.java tests/netx/unit/net/sourceforge/jnlp/cache/ResourceDownloaderTest.java tests/netx/unit/net/sourceforge/jnlp/cache/ResourceTrackerTest.java |
diffstat | 6 files changed, 991 insertions(+), 848 deletions(-) [+] |
line wrap: on
line diff
--- 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@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@redhat.com> Returned accidentally removed creation of shortcuts for jnlp applications.
--- 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(); } - - - }
--- /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; + + /** + * @return whether the result code is redirect one. Rigth now 301-303 and 307-308 + */ + public boolean shouldRedirect() { + return (result == 301 + || result == 302 + || result == 303/*?*/ + || result == 307 + || result == 308); + } + + /** + * @return whether the return code is OK one - anything except <200,300) + */ + public boolean isInvalid() { + return (result < 200 || result >= 300); + } + } + + private static class RedirectionException extends RuntimeException { + + public RedirectionException(String string) { + super(string); + } + + public RedirectionException(Throwable cause) { + super(cause); + } + + } + + +}
--- a/netx/net/sourceforge/jnlp/cache/ResourceTracker.java Fri Jan 23 15:35:46 2015 +0100 +++ b/netx/net/sourceforge/jnlp/cache/ResourceTracker.java Wed Jan 28 10:12:28 2015 -0500 @@ -25,42 +25,21 @@ import static net.sourceforge.jnlp.cache.Resource.Status.PREDOWNLOAD; import static net.sourceforge.jnlp.cache.Resource.Status.PROCESSING; -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.MalformedURLException; import java.net.URL; -import java.net.URLConnection; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; import java.util.EnumSet; -import java.util.HashMap; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -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.event.DownloadEvent; import net.sourceforge.jnlp.event.DownloadListener; -import net.sourceforge.jnlp.runtime.JNLPRuntime; -import net.sourceforge.jnlp.security.ConnectionFactory; -import net.sourceforge.jnlp.util.HttpUtils; import net.sourceforge.jnlp.util.UrlUtils; -import net.sourceforge.jnlp.util.WeakList; import net.sourceforge.jnlp.util.logging.OutputController; /** @@ -121,8 +100,6 @@ public static RequestMethods[] getValidRequestMethods() { return requestMethods; } - - } /** notified on initialization or download of a resource */ @@ -130,16 +107,6 @@ private static final ExecutorService threadPool = Executors.newCachedThreadPool(); - /** weak list of resource trackers with resources to prefetch */ - private static final WeakList<ResourceTracker> prefetchTrackers = - new WeakList<>(); - - /** resources requested to be downloaded */ - private static final ArrayList<Resource> queue = new ArrayList<>(); - - private static final ConcurrentHashMap<Resource, DownloadOptions> downloadOptions = - new ConcurrentHashMap<>(); - /** the resources known about by this resource tracker */ private final List<Resource> resources = new ArrayList<>(); @@ -147,7 +114,7 @@ private final List<DownloadListener> listeners = new ArrayList<>(); /** whether to download parts before requested */ - private boolean prefetch; + private final boolean prefetch; /** * Creates a resource tracker that does not prefetch resources. @@ -163,13 +130,6 @@ */ public ResourceTracker(boolean prefetch) { this.prefetch = prefetch; - - if (prefetch) { - synchronized (prefetchTrackers) { - prefetchTrackers.add(this); - prefetchTrackers.trimToSize(); - } - } } /** @@ -203,7 +163,7 @@ if (options == null) { options = new DownloadOptions(false, false); } - downloadOptions.put(resource, options); + resource.setDownloadOptions(options); // checkCache may take a while (loads properties file). this // should really be synchronized on resources, but the worst @@ -213,7 +173,7 @@ if (!downloaded) { if (prefetch) { - startDownloadThread(); + startResource(resource); } } } @@ -320,7 +280,7 @@ * @param resource resource on which event is fired */ protected void fireDownloadEvent(Resource resource) { - DownloadListener l[] = null; + DownloadListener l[]; synchronized (listeners) { l = listeners.toArray(new DownloadListener[0]); } @@ -508,7 +468,7 @@ * @throws IllegalResourceDescriptorException if the resource is not being tracked */ private boolean startResource(Resource resource) { - boolean enqueue = false; + boolean enqueue; synchronized (resource) { if (resource.isSet(ERROR)) @@ -526,7 +486,7 @@ } if (enqueue) - queueResource(resource); + startDownloadThread(resource); return !enqueue; } @@ -549,542 +509,8 @@ * Calls to this method should be synchronized on lock. * </p> */ - protected void startDownloadThread() { - threadPool.execute(new Downloader()); - } - - /** - * A thread is ending, called by the thread itself. - * <p> - * Calls to this method should be synchronized. - * </p> - */ - private void endThread() { - synchronized (prefetchTrackers) { - queue.trimToSize(); // these only accessed by threads so no sync needed - prefetchTrackers.trimToSize(); - } - } - - /** - * Add a resource to the queue and start a thread to download or - * initialize it. - */ - private void queueResource(Resource resource) { - synchronized (lock) { - if (!(resource.isSet(PRECONNECT) || resource.isSet(PREDOWNLOAD))) - throw new IllegalResourceDescriptorException("Invalid resource state (resource: " + resource + ")"); - - queue.add(resource); - startDownloadThread(); - } - } - - /** - * Process the resource by either downloading it or initializing - * it. - */ - private void processResource(Resource resource) { - boolean doConnect = false; - boolean doDownload = false; - - synchronized (resource) { - if (resource.isSet(CONNECTING)) - doConnect = true; - } - if (doConnect) - initializeResource(resource); - - synchronized (resource) { - // return to queue if we just initalized but it still needs - // to download (not cached locally / out of date) - if (resource.isSet(PREDOWNLOAD)) // would be DOWNLOADING if connected before this method - queueResource(resource); - - if (resource.isSet(DOWNLOADING)) - doDownload = true; - } - if (doDownload) - downloadResource(resource); - } - - private void downloadResource(Resource resource) { - resource.fireDownloadEvent(); - - 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(); - } - - /** - * Open a URL connection and get the content length and other - * fields. - * - * @param resource the resource to initialize - */ - private void initializeResource(Resource resource) { - //verify connection - if(!JNLPRuntime.isOfflineForced()){ - JNLPRuntime.detectOnline(resource.getLocation()/*or doenloadLocation*/); - } - resource.fireDownloadEvent(); // fire CONNECTING - - 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)); - - // 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(); - } - } - - static int getUrlResponseCode(URL url, Map<String, String> requestProperties, RequestMethods requestMethod) throws IOException { - return getUrlResponseCodeWithRedirectonResult(url, requestProperties, requestMethod).result; - } - - /** - * Complex wrapper around return code with utility methods - * Default is HTTP_OK - */ - private static class CodeWithRedirect { - - int result = HttpURLConnection.HTTP_OK; - URL URL; - - /** - * @return whether the result code is redirect one. Rigth now 301-303 and 307-308 - */ - public boolean shouldRedirect() { - return (result == 301 - || result == 302 - || result == 303/*?*/ - || result == 307 - || result == 308); - } - - /** - * @return whether the return code is OK one - anything except <200,300) - */ - public boolean isInvalid() { - return (result < 200 || result >= 300); - } - } - - /** - * 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, 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; - - } - - - /** - * 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 - */ - URL findBestUrl(Resource resource) { - DownloadOptions options = downloadOptions.get(resource); - 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 (RequestMethods requestMethod : RequestMethods.getValidRequestMethods()) { - for (int i = 0; i < urls.size(); i++) { - URL url = urls.get(i); - try { - Map<String, String> requestProperties = new HashMap<String, String>(); - 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; - } - - /** - * Pick the next resource to download or initialize. If there - * are no more resources requested then one is taken from a - * resource tracker with prefetch enabled. - * <p> - * The resource state is advanced before it is returned - * (PRECONNECT->CONNECTING). - * </p> - * <p> - * Calls to this method should be synchronized on lock. - * </p> - * - * @return the resource to initialize or download, or {@code null} - */ - private static Resource selectNextResource() { - Resource result; - - // pick from queue - result = selectByStatus(queue, PRECONNECT, ERROR); // connect but not error - if (result == null) - result = selectByStatus(queue, EnumSet.of(PREDOWNLOAD), EnumSet.of(ERROR, PRECONNECT, CONNECTING)); - - // remove from queue if found - if (result != null) - queue.remove(result); - - // prefetch if nothing found so far - if (result == null) - result = getPrefetch(); - - if (result == null) - return null; - - synchronized (result) { - if (result.isSet(PRECONNECT)) { - result.changeStatus(EnumSet.of(PRECONNECT), EnumSet.of(CONNECTING)); - } else if (result.isSet(PREDOWNLOAD)) { - // only download if *not* connecting, when done connecting - // select next will pick up the download part. This makes - // all requested connects happen before any downloads, so - // the size is known as early as possible. - result.changeStatus(EnumSet.of(PREDOWNLOAD), EnumSet.of(DOWNLOADING)); - } - } - - return result; - } - - /** - * Returns the next resource to be prefetched before - * requested. - * <p> - * Calls to this method should be synchronized on lock. - * </p> - */ - private static Resource getPrefetch() { - Resource result = null; - Resource alternate = null; - - // first find one to initialize - synchronized (prefetchTrackers) { - for (int i = 0; i < prefetchTrackers.size() && result == null; i++) { - ResourceTracker tracker = prefetchTrackers.get(i); - if (tracker == null) - continue; - - synchronized (tracker.resources) { - result = selectByFilter(tracker.resources, new Filter<Resource>() { - @Override - public boolean test(Resource t) { - return !t.isInitialized() && !t.isSet(ERROR); - } - }); - - if (result == null && alternate == null) - alternate = selectByStatus(tracker.resources, EnumSet.of(CONNECTED), EnumSet.of(ERROR, DOWNLOADED, DOWNLOADING, PREDOWNLOAD)); - } - } - } - - // if none to initialize, switch to download - if (result == null) - result = alternate; - - if (result == null) - return null; - - synchronized (result) { - ResourceTracker tracker = result.getTracker(); - if (tracker == null) - return null; // GC of tracker happened between above code and here - - // prevents startResource from putting it on queue since - // we're going to return it. - result.changeStatus(EnumSet.noneOf(Resource.Status.class), EnumSet.of(PROCESSING)); - - tracker.startResource(result); - } - - return result; + protected void startDownloadThread(Resource resource) { + threadPool.execute(new ResourceDownloader(resource, lock)); } static Resource selectByFilter(Collection<Resource> source, Filter<Resource> filter) { @@ -1098,7 +524,7 @@ } if (selectable) { - result = resource; + result = resource; } } @@ -1207,56 +633,4 @@ interface Filter<T> { public boolean test(T t); } - - private static class RedirectionException extends RuntimeException { - - public RedirectionException(String string) { - super(string); - } - - public RedirectionException(Throwable cause) { - super(cause); - } - - } - - // inner classes - - /** - * This class downloads and initializes the queued resources. - */ - private class Downloader implements Runnable { - Resource resource = null; - - public void run() { - while (true) { - synchronized (lock) { - resource = selectNextResource(); - - if (resource == null) { - endThread(); - break; - } - } - - try { - // Resource processing involves writing to files - // (cache entry trackers, the files themselves, etc.) - // and it therefore needs to be privileged - final Resource fResource = resource; - AccessController.doPrivileged(new PrivilegedAction<Void>() { - @Override - public Void run() { - processResource(fResource); - return null; - } - }); - } catch (Exception ex) { - OutputController.getLogger().log(ex); - } - } - // should have a finally in case some exception is thrown by - // selectNextResource(); - } - }; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/netx/unit/net/sourceforge/jnlp/cache/ResourceDownloaderTest.java Wed Jan 28 10:12:28 2015 -0500 @@ -0,0 +1,498 @@ +package net.sourceforge.jnlp.cache; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.jar.Attributes; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.jar.Pack200; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import javax.smartcardio.ATR; + +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import net.sourceforge.jnlp.DownloadOptions; +import net.sourceforge.jnlp.ServerAccess; +import net.sourceforge.jnlp.ServerLauncher; +import net.sourceforge.jnlp.Version; +import net.sourceforge.jnlp.config.DeploymentConfiguration; +import net.sourceforge.jnlp.runtime.JNLPRuntime; +import net.sourceforge.jnlp.util.JarFile; +import net.sourceforge.jnlp.util.logging.OutputController; + +public class ResourceDownloaderTest { + + public static ServerLauncher testServer; + public static ServerLauncher testServerWithBrokenHead; + public static ServerLauncher downloadServer; + + private static final PrintStream[] backedUpStream = new PrintStream[4]; + private static ByteArrayOutputStream currentErrorStream; + + private static final String nameStub1 = "itw-server"; + private static final String nameStub2 = "test-file"; + + private static String cacheDir; + + @BeforeClass + //keeping silent outputs from launched jvm + public static void redirectErr() throws IOException { + for (int i = 0; i < backedUpStream.length; i++) { + if (backedUpStream[i] == null) { + switch (i) { + case 0: + backedUpStream[i] = System.out; + break; + case 1: + backedUpStream[i] = System.err; + break; + case 2: + backedUpStream[i] = OutputController.getLogger().getOut(); + break; + case 3: + backedUpStream[i] = OutputController.getLogger().getErr(); + break; + } + + } + + } + currentErrorStream = new ByteArrayOutputStream(); + System.setOut(new PrintStream(currentErrorStream)); + System.setErr(new PrintStream(currentErrorStream)); + OutputController.getLogger().setOut(new PrintStream(currentErrorStream)); + OutputController.getLogger().setErr(new PrintStream(currentErrorStream)); + + + } + + @AfterClass + public static void redirectErrBack() throws IOException { + ServerAccess.logErrorReprint(currentErrorStream.toString("utf-8")); + System.setOut(backedUpStream[0]); + System.setErr(backedUpStream[1]); + OutputController.getLogger().setOut(backedUpStream[2]); + OutputController.getLogger().setErr(backedUpStream[3]); + } + + @BeforeClass + public static void onDebug() { + JNLPRuntime.setDebug(true); + } + + @AfterClass + public static void offDebug() { + JNLPRuntime.setDebug(false); + } + + @BeforeClass + public static void startServer() throws Exception { + redirectErr(); + testServer = ServerAccess.getIndependentInstance(System.getProperty("java.io.tmpdir"), ServerAccess.findFreePort()); + redirectErrBack(); + } + + @BeforeClass + public static void startServer2() throws Exception { + redirectErr(); + testServerWithBrokenHead = ServerAccess.getIndependentInstance(System.getProperty("java.io.tmpdir"), ServerAccess.findFreePort()); + testServerWithBrokenHead.setSupportingHeadRequest(false); + redirectErrBack(); + } + + @AfterClass + public static void stopServer() { + testServer.stop(); + } + + @AfterClass + public static void stopServer2() { + testServerWithBrokenHead.stop(); + } + + @Test + public void getUrlResponseCodeTestWorkingHeadRequest() throws Exception { + redirectErr(); + try { + File f = File.createTempFile(nameStub1, nameStub2); + int i = ResourceDownloader.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.HEAD); Assert.assertEquals(HttpURLConnection.HTTP_OK, i); + f.delete(); + i = ResourceDownloader.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.HEAD); + Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, i); + } finally { + redirectErrBack(); + } + } + + @Test + public void getUrlResponseCodeTestNotWorkingHeadRequest() throws Exception { + redirectErr(); + try { + File f = File.createTempFile(nameStub1, nameStub2); + int i = ResourceDownloader.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.HEAD); + Assert.assertEquals(HttpURLConnection.HTTP_NOT_IMPLEMENTED, i); + f.delete(); + i = ResourceDownloader.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.HEAD); + Assert.assertEquals(HttpURLConnection.HTTP_NOT_IMPLEMENTED, i); + } finally { + redirectErrBack(); + } + } + + @Test + public void getUrlResponseCodeTestGetRequestOnNotWorkingHeadRequest() throws Exception { + redirectErr(); + try { + File f = File.createTempFile(nameStub1, nameStub2); + int i = ResourceDownloader.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.GET); + Assert.assertEquals(HttpURLConnection.HTTP_OK, i); + f.delete(); + i = ResourceDownloader.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.GET); + Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, i); + } finally { + redirectErrBack(); + } + } + + @Test + public void getUrlResponseCodeTestGetRequest() throws Exception { + redirectErr(); + try { + File f = File.createTempFile(nameStub1, nameStub2); + int i = ResourceDownloader.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.GET); + Assert.assertEquals(HttpURLConnection.HTTP_OK, i); + f.delete(); + i = ResourceDownloader.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.GET); + Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, i); + } finally { + redirectErrBack(); + } + } + + @Test + public void getUrlResponseCodeTestWrongRequest() throws Exception { + redirectErr(); + try { + File f = File.createTempFile(nameStub1, nameStub2); + Exception exception = null; + try { + ResourceDownloader.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.TESTING_UNDEF); + } catch (Exception ex) { + exception = ex; + } + Assert.assertNotNull(exception); + exception = null; + f.delete(); + try { + ResourceDownloader.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.TESTING_UNDEF); + } catch (Exception ex) { + exception = ex; + } + Assert.assertNotNull(exception);; + } finally { + redirectErrBack(); + } + + } + + @Test + public void findBestUrltest() throws Exception { + redirectErr(); + try { + File fileForServerWithHeader = File.createTempFile(nameStub1, nameStub2); + File versionedFileForServerWithHeader = new File(fileForServerWithHeader.getParentFile(), fileForServerWithHeader.getName() + "-2.0"); + versionedFileForServerWithHeader.createNewFile(); + + File fileForServerWithoutHeader = File.createTempFile(nameStub1, nameStub2); + File versionedFileForServerWithoutHeader = new File(fileForServerWithoutHeader.getParentFile(), fileForServerWithoutHeader.getName() + "-2.0"); + versionedFileForServerWithoutHeader.createNewFile(); + + ResourceDownloader resourceDownloader = new ResourceDownloader(null, null); + Resource r1 = Resource.getResource(testServer.getUrl(fileForServerWithHeader.getName()), null, UpdatePolicy.NEVER); + Resource r2 = Resource.getResource(testServerWithBrokenHead.getUrl(fileForServerWithoutHeader.getName()), null, UpdatePolicy.NEVER); + Resource r3 = Resource.getResource(testServer.getUrl(versionedFileForServerWithHeader.getName()), new Version("1.0"), UpdatePolicy.NEVER); + Resource r4 = Resource.getResource(testServerWithBrokenHead.getUrl(versionedFileForServerWithoutHeader.getName()), new Version("1.0"), UpdatePolicy.NEVER); + assertOnServerWithHeader(resourceDownloader.findBestUrl(r1)); + assertVersionedOneOnServerWithHeader(resourceDownloader.findBestUrl(r3)); + assertOnServerWithoutHeader(resourceDownloader.findBestUrl(r2)); + assertVersionedOneOnServerWithoutHeader(resourceDownloader.findBestUrl(r4)); + + fileForServerWithHeader.delete(); + Assert.assertNull(resourceDownloader.findBestUrl(r1)); + assertVersionedOneOnServerWithHeader(resourceDownloader.findBestUrl(r3)); + assertOnServerWithoutHeader(resourceDownloader.findBestUrl(r2)); + assertVersionedOneOnServerWithoutHeader(resourceDownloader.findBestUrl(r4)); + + versionedFileForServerWithHeader.delete(); + Assert.assertNull(resourceDownloader.findBestUrl(r1)); + Assert.assertNull(resourceDownloader.findBestUrl(r3)); + assertOnServerWithoutHeader(resourceDownloader.findBestUrl(r2)); + assertVersionedOneOnServerWithoutHeader(resourceDownloader.findBestUrl(r4)); + + versionedFileForServerWithoutHeader.delete(); + Assert.assertNull(resourceDownloader.findBestUrl(r1)); + Assert.assertNull(resourceDownloader.findBestUrl(r3)); + assertOnServerWithoutHeader(resourceDownloader.findBestUrl(r2)); + Assert.assertNull(resourceDownloader.findBestUrl(r4)); + + + fileForServerWithoutHeader.delete(); + Assert.assertNull(resourceDownloader.findBestUrl(r1)); + Assert.assertNull(resourceDownloader.findBestUrl(r3)); + Assert.assertNull(resourceDownloader.findBestUrl(r2)); + Assert.assertNull(resourceDownloader.findBestUrl(r4)); + } finally { + redirectErrBack(); + } + + } + + private void assertOnServerWithoutHeader(URL u) { + assertCommonComponentsOfUrl(u); + assertPort(u, testServerWithBrokenHead.getPort()); + } + + private void assertVersionedOneOnServerWithoutHeader(URL u) { + assertCommonComponentsOfUrl(u); + assertPort(u, testServerWithBrokenHead.getPort()); + assertVersion(u); + } + + private void assertOnServerWithHeader(URL u) { + assertCommonComponentsOfUrl(u); + assertPort(u, testServer.getPort()); + } + + private void assertVersionedOneOnServerWithHeader(URL u) { + assertCommonComponentsOfUrl(u); + assertPort(u, testServer.getPort()); + assertVersion(u); + } + private void assertCommonComponentsOfUrl(URL u) { + Assert.assertTrue(u.getProtocol().equals("http")); + Assert.assertTrue(u.getHost().equals("localhost")); + Assert.assertTrue(u.getPath().contains(nameStub1)); + Assert.assertTrue(u.getPath().contains(nameStub2)); + ServerAccess.logOutputReprint(u.toExternalForm()); + } + + private void assertPort(URL u, int port) { + Assert.assertTrue(u.getPort() == port); + } + + private void assertVersion(URL u) { + Assert.assertTrue(u.getPath().contains("-2.0")); + Assert.assertTrue(u.getQuery().contains("version-id=1.0")); + } + + @BeforeClass + public static void setupCache() throws IOException { + File dir = new File(System.getProperty("java.io.tmpdir"), "itw-down"); + dir.mkdirs(); + dir.deleteOnExit(); + + redirectErr(); + downloadServer = ServerAccess.getIndependentInstance(dir.getAbsolutePath(), ServerAccess.findFreePort()); + redirectErrBack(); + + cacheDir = JNLPRuntime.getConfiguration().getProperty(DeploymentConfiguration.KEY_USER_CACHE_DIR); + JNLPRuntime.getConfiguration().setProperty(DeploymentConfiguration.KEY_USER_CACHE_DIR, System.getProperty("java.io.tmpdir") + File.separator + "tempcache"); + } + + @AfterClass + public static void teardownCache() { + downloadServer.stop(); + + CacheUtil.clearCache(); + JNLPRuntime.getConfiguration().setProperty(DeploymentConfiguration.KEY_USER_CACHE_DIR, cacheDir); + } + + private File setupFile(String fileName, String text) throws IOException { + File downloadDir = downloadServer.getDir(); + File file = new File(downloadDir, fileName); + file.createNewFile(); + Files.write(file.toPath(), text.getBytes()); + file.deleteOnExit(); + + return file; + } + + private Resource setupResource(String fileName, String text) throws IOException { + File f = setupFile(fileName, text); + URL url = downloadServer.getUrl(fileName); + System.out.println(url); + + Resource resource = Resource.getResource(url, null, UpdatePolicy.NEVER); + return resource; + } + + @Test + public void testDownloadResource() throws IOException { + String expected = "testDownloadResource"; + Resource resource = setupResource("download-resource", expected); + + ResourceDownloader resourceDownloader = new ResourceDownloader(resource, new Object()); + + resource.setStatusFlag(Resource.Status.PRECONNECT); + resourceDownloader.run(); + + File downloadedFile = resource.getLocalFile(); + assertTrue(downloadedFile.exists() && downloadedFile.isFile()); + + String output = new String(Files.readAllBytes(downloadedFile.toPath())); + assertEquals(expected, output); + } + + @Test + public void testDownloadPackGzResource() throws IOException { + String expected = "1.2"; + + setupPackGzFile("download-packgz", expected); + + Resource resource = Resource.getResource(downloadServer.getUrl("download-packgz.jar"), null, UpdatePolicy.NEVER); + + ResourceDownloader resourceDownloader = new ResourceDownloader(resource, new Object()); + + resource.setStatusFlag(Resource.Status.PRECONNECT); + resource.setDownloadOptions(new DownloadOptions(true, false)); + + resourceDownloader.run(); + + File downloadedFile = resource.getLocalFile(); + assertTrue(downloadedFile.exists() && downloadedFile.isFile()); + + JarFile jf = new JarFile(downloadedFile); + Manifest m = jf.getManifest(); + String actual = (String) m.getMainAttributes().get(Attributes.Name.MANIFEST_VERSION); + + assertEquals(expected, actual); + } + + @Test + public void testDownloadVersionedResource() throws IOException { + String expected = "testVersionedResource"; + setupFile("download-version__V1.0.jar", expected); + + URL url = downloadServer.getUrl("download-version.jar"); + Resource resource = Resource.getResource(url, new Version("1.0"), UpdatePolicy.NEVER); + + ResourceDownloader resourceDownloader = new ResourceDownloader(resource, new Object()); + + resource.setStatusFlag(Resource.Status.PRECONNECT); + resource.setDownloadOptions(new DownloadOptions(false, true)); + resourceDownloader.run(); + + File downloadedFile = resource.getLocalFile(); + assertTrue(downloadedFile.exists() && downloadedFile.isFile()); + + String output = new String(Files.readAllBytes(downloadedFile.toPath())); + assertEquals(expected, output); + } + + @Test + public void testDownloadVersionedPackGzResource() throws IOException { + String expected = "1.2"; + + setupPackGzFile("download-packgz__V1.0", expected); + + Resource resource = Resource.getResource(downloadServer.getUrl("download-packgz.jar"), new Version("1.0"), UpdatePolicy.NEVER); + + ResourceDownloader resourceDownloader = new ResourceDownloader(resource, new Object()); + + resource.setStatusFlag(Resource.Status.PRECONNECT); + resource.setDownloadOptions(new DownloadOptions(true, true)); + + resourceDownloader.run(); + + File downloadedFile = resource.getLocalFile(); + assertTrue(downloadedFile.exists() && downloadedFile.isFile()); + + JarFile jf = new JarFile(downloadedFile); + Manifest m = jf.getManifest(); + String actual = (String) m.getMainAttributes().get(Attributes.Name.MANIFEST_VERSION); + + assertEquals(expected, actual); + } + + @Test (expected = IllegalArgumentException.class) + public void testDownloadLocalResourceFails() throws IOException { + String expected = "local-resource"; + File localFile = Files.createTempFile("download-local", ".temp").toFile(); + localFile.createNewFile(); + Files.write(localFile.toPath(), expected.getBytes()); + localFile.deleteOnExit(); + + String stringURL = "file://" + localFile.getAbsolutePath(); + URL url = new URL(stringURL); + + Resource resource = Resource.getResource(url, null, UpdatePolicy.NEVER); + + ResourceDownloader resourceDownloader = new ResourceDownloader(resource, new Object()); + + resource.setStatusFlag(Resource.Status.PRECONNECT); + resourceDownloader.run(); + } + + @Test + public void testDownloadNotExistingResourceFails() throws IOException { + Resource resource = Resource.getResource(new URL(downloadServer.getUrl() + "/notexistingfile"), null, UpdatePolicy.NEVER); + + ResourceDownloader resourceDownloader = new ResourceDownloader(resource, new Object()); + + resource.setStatusFlag(Resource.Status.PRECONNECT); + resourceDownloader.run(); + + assertTrue(resource.hasFlags(EnumSet.of(Resource.Status.ERROR))); + } + + private void setupPackGzFile(String fileName, String version) throws IOException { + File downloadDir = downloadServer.getDir(); + + File orig = new File(downloadDir, fileName + ".jar"); + orig.deleteOnExit(); + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, version); + JarOutputStream target = new JarOutputStream(new FileOutputStream(orig), manifest); + target.close(); + + File pack = new File(downloadDir, fileName + ".jar.pack"); + pack.deleteOnExit(); + + JarFile jarFile = new JarFile(orig.getAbsolutePath()); + FileOutputStream fos = new FileOutputStream(pack); + Pack200.Packer p = Pack200.newPacker(); + p.pack(jarFile, fos); + fos.close(); + + File packgz = new File(downloadDir, fileName + ".jar.pack.gz"); + packgz.deleteOnExit(); + FileOutputStream gzfos = new FileOutputStream(packgz); + GZIPOutputStream gos = new GZIPOutputStream(gzfos); + + gos.write(Files.readAllBytes(pack.toPath())); + gos.finish(); + gos.close(); + } +}
--- a/tests/netx/unit/net/sourceforge/jnlp/cache/ResourceTrackerTest.java Fri Jan 23 15:35:46 2015 +0100 +++ b/tests/netx/unit/net/sourceforge/jnlp/cache/ResourceTrackerTest.java Wed Jan 28 10:12:28 2015 -0500 @@ -47,14 +47,12 @@ import java.io.IOException; import java.io.PrintStream; import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.util.Arrays; import java.util.EnumSet; -import java.util.HashMap; import java.util.List; import org.junit.AfterClass; @@ -72,13 +70,10 @@ public class ResourceTrackerTest { - public static ServerLauncher testServer; - public static ServerLauncher testServerWithBrokenHead; public static ServerLauncher downloadServer; private static final PrintStream[] backedUpStream = new PrintStream[4]; private static ByteArrayOutputStream currentErrorStream; - private static final String nameStub1 = "itw-server"; - private static final String nameStub2 = "test-file"; + private static Resource createResource(final String name) throws MalformedURLException { return Resource.getResource(new URL("http://example.com/" + name + ".jar"), new Version("1.0"), UpdatePolicy.ALWAYS); @@ -230,8 +225,6 @@ System.setErr(backedUpStream[1]); OutputController.getLogger().setOut(backedUpStream[2]); OutputController.getLogger().setErr(backedUpStream[3]); - - } @BeforeClass @@ -244,207 +237,6 @@ JNLPRuntime.setDebug(false); } - @BeforeClass - public static void startServer() throws Exception { - redirectErr(); - testServer = ServerAccess.getIndependentInstance(System.getProperty("java.io.tmpdir"), ServerAccess.findFreePort()); - redirectErrBack(); - } - - @BeforeClass - public static void startServer2() throws Exception { - redirectErr(); - testServerWithBrokenHead = ServerAccess.getIndependentInstance(System.getProperty("java.io.tmpdir"), ServerAccess.findFreePort()); - testServerWithBrokenHead.setSupportingHeadRequest(false); - redirectErrBack(); - } - - @AfterClass - public static void stopServer() { - testServer.stop(); - } - - @AfterClass - public static void stopServer2() { - testServerWithBrokenHead.stop(); - } - - @Test - public void getUrlResponseCodeTestWorkingHeadRequest() throws Exception { - redirectErr(); - try { - File f = File.createTempFile(nameStub1, nameStub2); - int i = ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.HEAD); Assert.assertEquals(HttpURLConnection.HTTP_OK, i); - f.delete(); - i = ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.HEAD); - Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, i); - } finally { - redirectErrBack(); - } - } - - @Test - public void getUrlResponseCodeTestNotWorkingHeadRequest() throws Exception { - redirectErr(); - try { - File f = File.createTempFile(nameStub1, nameStub2); - int i = ResourceTracker.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.HEAD); - Assert.assertEquals(HttpURLConnection.HTTP_NOT_IMPLEMENTED, i); - f.delete(); - i = ResourceTracker.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.HEAD); - Assert.assertEquals(HttpURLConnection.HTTP_NOT_IMPLEMENTED, i); - } finally { - redirectErrBack(); - } - } - - @Test - public void getUrlResponseCodeTestGetRequestOnNotWorkingHeadRequest() throws Exception { - redirectErr(); - try { - File f = File.createTempFile(nameStub1, nameStub2); - int i = ResourceTracker.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.GET); - Assert.assertEquals(HttpURLConnection.HTTP_OK, i); - f.delete(); - i = ResourceTracker.getUrlResponseCode(testServerWithBrokenHead.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.GET); - Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, i); - } finally { - redirectErrBack(); - } - } - - @Test - public void getUrlResponseCodeTestGetRequest() throws Exception { - redirectErr(); - try { - File f = File.createTempFile(nameStub1, nameStub2); - int i = ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.GET); - Assert.assertEquals(HttpURLConnection.HTTP_OK, i); - f.delete(); - i = ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.GET); - Assert.assertEquals(HttpURLConnection.HTTP_NOT_FOUND, i); - } finally { - redirectErrBack(); - } - } - - @Test - public void getUrlResponseCodeTestWrongRequest() throws Exception { - redirectErr(); - try { - File f = File.createTempFile(nameStub1, nameStub2); - Exception exception = null; - try { - ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.TESTING_UNDEF); - } catch (Exception ex) { - exception = ex; - } - Assert.assertNotNull(exception); - exception = null; - f.delete(); - try { - ResourceTracker.getUrlResponseCode(testServer.getUrl(f.getName()), new HashMap<String, String>(), ResourceTracker.RequestMethods.TESTING_UNDEF); - } catch (Exception ex) { - exception = ex; - } - Assert.assertNotNull(exception);; - } finally { - redirectErrBack(); - } - - } - - @Test - public void findBestUrltest() throws Exception { - redirectErr(); - try { - File fileForServerWithHeader = File.createTempFile(nameStub1, nameStub2); - File versionedFileForServerWithHeader = new File(fileForServerWithHeader.getParentFile(), fileForServerWithHeader.getName() + "-2.0"); - versionedFileForServerWithHeader.createNewFile(); - - File fileForServerWithoutHeader = File.createTempFile(nameStub1, nameStub2); - File versionedFileForServerWithoutHeader = new File(fileForServerWithoutHeader.getParentFile(), fileForServerWithoutHeader.getName() + "-2.0"); - versionedFileForServerWithoutHeader.createNewFile(); - - ResourceTracker rt = new ResourceTracker(); - Resource r1 = Resource.getResource(testServer.getUrl(fileForServerWithHeader.getName()), null, UpdatePolicy.NEVER); - Resource r2 = Resource.getResource(testServerWithBrokenHead.getUrl(fileForServerWithoutHeader.getName()), null, UpdatePolicy.NEVER); - Resource r3 = Resource.getResource(testServer.getUrl(versionedFileForServerWithHeader.getName()), new Version("1.0"), UpdatePolicy.NEVER); - Resource r4 = Resource.getResource(testServerWithBrokenHead.getUrl(versionedFileForServerWithoutHeader.getName()), new Version("1.0"), UpdatePolicy.NEVER); - assertOnServerWithHeader(rt.findBestUrl(r1)); - assertVersionedOneOnServerWithHeader(rt.findBestUrl(r3)); - assertOnServerWithoutHeader(rt.findBestUrl(r2)); - assertVersionedOneOnServerWithoutHeader(rt.findBestUrl(r4)); - - fileForServerWithHeader.delete(); - Assert.assertNull(rt.findBestUrl(r1)); - assertVersionedOneOnServerWithHeader(rt.findBestUrl(r3)); - assertOnServerWithoutHeader(rt.findBestUrl(r2)); - assertVersionedOneOnServerWithoutHeader(rt.findBestUrl(r4)); - - versionedFileForServerWithHeader.delete(); - Assert.assertNull(rt.findBestUrl(r1)); - Assert.assertNull(rt.findBestUrl(r3)); - assertOnServerWithoutHeader(rt.findBestUrl(r2)); - assertVersionedOneOnServerWithoutHeader(rt.findBestUrl(r4)); - - versionedFileForServerWithoutHeader.delete(); - Assert.assertNull(rt.findBestUrl(r1)); - Assert.assertNull(rt.findBestUrl(r3)); - assertOnServerWithoutHeader(rt.findBestUrl(r2)); - Assert.assertNull(rt.findBestUrl(r4)); - - - fileForServerWithoutHeader.delete(); - Assert.assertNull(rt.findBestUrl(r1)); - Assert.assertNull(rt.findBestUrl(r3)); - Assert.assertNull(rt.findBestUrl(r2)); - Assert.assertNull(rt.findBestUrl(r4)); - } finally { - redirectErrBack(); - } - - } - - private void assertOnServerWithHeader(URL u) { - assertCommonComponentsOfUrl(u); - assertPort(u, testServer.getPort()); - } - - private void assertVersionedOneOnServerWithHeader(URL u) { - assertCommonComponentsOfUrl(u); - assertPort(u, testServer.getPort()); - assertVersion(u); - } - - private void assertOnServerWithoutHeader(URL u) { - assertCommonComponentsOfUrl(u); - assertPort(u, testServerWithBrokenHead.getPort()); - } - - private void assertVersionedOneOnServerWithoutHeader(URL u) { - assertCommonComponentsOfUrl(u); - assertPort(u, testServerWithBrokenHead.getPort()); - assertVersion(u); - } - - private void assertCommonComponentsOfUrl(URL u) { - Assert.assertTrue(u.getProtocol().equals("http")); - Assert.assertTrue(u.getHost().equals("localhost")); - Assert.assertTrue(u.getPath().contains(nameStub1)); - Assert.assertTrue(u.getPath().contains(nameStub2)); - ServerAccess.logOutputReprint(u.toExternalForm()); - } - - private void assertPort(URL u, int port) { - Assert.assertTrue(u.getPort() == port); - } - - private void assertVersion(URL u) { - Assert.assertTrue(u.getPath().contains("-2.0")); - Assert.assertTrue(u.getQuery().contains("version-id=1.0")); - } - private static String cacheDir; @BeforeClass