diff options
Diffstat (limited to 'netx/net/sourceforge')
-rw-r--r-- | netx/net/sourceforge/jnlp/DownloadOptions.java | 64 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/JNLPFile.java | 29 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/Launcher.java | 2 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/cache/CacheUtil.java | 2 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/cache/Resource.java | 22 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/cache/ResourceTracker.java | 146 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/cache/ResourceUrlCreator.java | 163 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java | 28 |
8 files changed, 395 insertions, 61 deletions
diff --git a/netx/net/sourceforge/jnlp/DownloadOptions.java b/netx/net/sourceforge/jnlp/DownloadOptions.java new file mode 100644 index 0000000..e60afb2 --- /dev/null +++ b/netx/net/sourceforge/jnlp/DownloadOptions.java @@ -0,0 +1,64 @@ +/* DownloadOptions.java + Copyright (C) 2011 Red Hat, Inc + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +IcedTea is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package net.sourceforge.jnlp; + +public class DownloadOptions { + + private final boolean usePack200; + private final boolean useVersion; + + public DownloadOptions(boolean usePack, boolean useVersion) { + this.usePack200 = usePack; + this.useVersion = useVersion; + } + + public boolean useExplicitPack() { + return usePack200; + } + + public boolean useExplicitVersion() { + return useVersion; + } + + @Override + public String toString() { + return "DownloadOptions[use pack: " + usePack200 + "; use version: " + + useVersion + "]"; + } + +} diff --git a/netx/net/sourceforge/jnlp/JNLPFile.java b/netx/net/sourceforge/jnlp/JNLPFile.java index bf1c96b..c296a9a 100644 --- a/netx/net/sourceforge/jnlp/JNLPFile.java +++ b/netx/net/sourceforge/jnlp/JNLPFile.java @@ -248,7 +248,7 @@ public class JNLPFile { try { ResourceTracker tracker = new ResourceTracker(false); // no prefetch - tracker.addResource(location, version, policy); + tracker.addResource(location, version, null, policy); return tracker.getInputStream(location); } catch (Exception ex) { @@ -362,7 +362,7 @@ public class JNLPFile { } /** - * Returns the information section of the JNLP file for the + * Returns the resources section of the JNLP file for the * specified locale, os, and arch. */ public ResourcesDesc getResources(final Locale locale, final String os, final String arch) { @@ -392,6 +392,31 @@ public class JNLPFile { } /** + * Returns the resources section of the JNLP file as viewed + * through the default locale and the os.name and os.arch + * properties. + */ + public ResourcesDesc[] getResourceDescs() { + return getResourceDescs(defaultLocale, defaultOS, defaultArch); + } + + /** + * Returns the resources section of the JNLP file for the + * specified locale, os, and arch. + */ + public ResourcesDesc[] getResourceDescs(final Locale locale, final String os, final String arch) { + List<ResourcesDesc> matchingResources = new ArrayList<ResourcesDesc>(); + for (ResourcesDesc rescDesc: resources) { + if (localMatches(locale, rescDesc.getLocales()) + && stringMatches(os, rescDesc.getOS()) + && stringMatches(arch, rescDesc.getArch())) { + matchingResources.add(rescDesc); + } + } + return matchingResources.toArray(new ResourcesDesc[0]); + } + + /** * Returns an object of one of the following types: AppletDesc, * ApplicationDesc and InstallerDesc */ diff --git a/netx/net/sourceforge/jnlp/Launcher.java b/netx/net/sourceforge/jnlp/Launcher.java index cff3ee1..8092840 100644 --- a/netx/net/sourceforge/jnlp/Launcher.java +++ b/netx/net/sourceforge/jnlp/Launcher.java @@ -417,7 +417,7 @@ public class Launcher { IconDesc.SPLASH, preferredWidth, preferredHeight); if (splashImageURL != null) { ResourceTracker resourceTracker = new ResourceTracker(true); - resourceTracker.addResource(splashImageURL, file.getFileVersion(), updatePolicy); + resourceTracker.addResource(splashImageURL, file.getFileVersion(), null, updatePolicy); splashScreen = new JNLPSplashScreen(resourceTracker, null, null); splashScreen.setSplashImageURL(splashImageURL); if (splashScreen.isSplashScreenValid()) { diff --git a/netx/net/sourceforge/jnlp/cache/CacheUtil.java b/netx/net/sourceforge/jnlp/cache/CacheUtil.java index aa40dc0..3e0a966 100644 --- a/netx/net/sourceforge/jnlp/cache/CacheUtil.java +++ b/netx/net/sourceforge/jnlp/cache/CacheUtil.java @@ -76,7 +76,7 @@ public class CacheUtil { */ public static URL getCachedResource(URL location, Version version, UpdatePolicy policy) { ResourceTracker rt = new ResourceTracker(); - rt.addResource(location, version, policy); + rt.addResource(location, version, null, policy); try { File f = rt.getCacheFile(location); // TODO: Should be toURI().toURL() diff --git a/netx/net/sourceforge/jnlp/cache/Resource.java b/netx/net/sourceforge/jnlp/cache/Resource.java index 9818b64..57aa338 100644 --- a/netx/net/sourceforge/jnlp/cache/Resource.java +++ b/netx/net/sourceforge/jnlp/cache/Resource.java @@ -67,6 +67,9 @@ public class Resource { /** the remote location of the resource */ URL location; + /** the location to use when downloading */ + private URL downloadLocation; + /** the local file downloaded to */ File localFile; @@ -96,6 +99,7 @@ public class Resource { */ private Resource(URL location, Version requestVersion, UpdatePolicy updatePolicy) { this.location = location; + this.downloadLocation = location; this.requestVersion = requestVersion; this.updatePolicy = updatePolicy; } @@ -130,6 +134,24 @@ public class Resource { } /** + * Returns the URL to use for downloading the resource. This can be + * different from the original location since it may use a different + * file name to support versioning and compression + * @return the url to use when downloading + */ + public URL getDownloadLocation() { + return downloadLocation; + } + + /** + * Set the url to use for downloading the resource + * @param location + */ + public void setDownloadLocation(URL location) { + downloadLocation = location; + } + + /** * Returns the tracker that first created or monitored the * resource, or null if no trackers are monitoring the resource. */ diff --git a/netx/net/sourceforge/jnlp/cache/ResourceTracker.java b/netx/net/sourceforge/jnlp/cache/ResourceTracker.java index 8db4a4b..93e763e 100644 --- a/netx/net/sourceforge/jnlp/cache/ResourceTracker.java +++ b/netx/net/sourceforge/jnlp/cache/ResourceTracker.java @@ -29,12 +29,15 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; +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.jar.Pack200.Unpacker; 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; @@ -117,6 +120,9 @@ public class ResourceTracker { /** resources requested to be downloaded */ private static ArrayList<Resource> queue = new ArrayList<Resource>(); + private static Map<Resource, DownloadOptions> downloadOptions = + new HashMap<Resource, DownloadOptions>(); + /** resource trackers threads are working for (used for load balancing across multi-tracker downloads) */ private static ArrayList<ResourceTracker> active = new ArrayList<ResourceTracker>(); // @@ -163,7 +169,7 @@ public class ResourceTracker { * @param version the resource version * @param updatePolicy whether to check for updates if already in cache */ - public void addResource(URL location, Version version, UpdatePolicy updatePolicy) { + public void addResource(URL location, Version version, DownloadOptions options, UpdatePolicy updatePolicy) { if (location == null) throw new IllegalArgumentException("location==null"); @@ -177,6 +183,11 @@ public class ResourceTracker { resources.add(resource); } + if (options == null) { + options = new DownloadOptions(false, false); + } + downloadOptions.put(resource, options); + // checkCache may take a while (loads properties file). this // should really be synchronized on resources, but the worst // case should be that the resource will be updated once even @@ -621,7 +632,8 @@ public class ResourceTracker { try { // create out second in case in does not exist - URLConnection con = getVersionedResourceURL(resource).openConnection(); + URL realLocation = resource.getDownloadLocation(); + URLConnection con = realLocation.openConnection(); con.addRequestProperty("Accept-Encoding", "pack200-gzip, gzip"); con.connect(); @@ -636,16 +648,16 @@ public class ResourceTracker { String contentEncoding = con.getContentEncoding(); if (JNLPRuntime.isDebug()) { - System.err.println("Content encoding for " + resource.location + ": " - + contentEncoding); + System.err.println("Downloading" + resource.location + " using " + + realLocation + " (encoding : " + contentEncoding + ")"); + } - if (contentEncoding != null) { - if (contentEncoding.equals("gzip")) { - downloadLocation = new URL(downloadLocation.toString() + ".gz"); - } else if (contentEncoding.equals("pack200-gzip")) { - downloadLocation = new URL(downloadLocation.toString() + ".pack.gz"); - } + if ("gzip".equals(contentEncoding)) { + downloadLocation = new URL(downloadLocation.toString() + ".gz"); + } else if ("pack200-gzip".equals(contentEncoding) || + realLocation.getPath().endsWith(".pack.gz")) { + downloadLocation = new URL(downloadLocation.toString() + ".pack.gz"); } InputStream in = new BufferedInputStream(con.getInputStream()); @@ -668,41 +680,42 @@ public class ResourceTracker { /* * If the file was compressed, uncompress it. */ - if (contentEncoding != null) { - if (contentEncoding.equals("gzip")) { - GZIPInputStream gzInputStream = new GZIPInputStream(new FileInputStream(CacheUtil - .getCacheFile(downloadLocation, resource.downloadVersion))); - InputStream inputStream = new BufferedInputStream(gzInputStream); - - BufferedOutputStream outputStream = new BufferedOutputStream( - new FileOutputStream(CacheUtil.getCacheFile(resource.location, - resource.downloadVersion))); - - while (-1 != (rlen = inputStream.read(buf))) { - outputStream.write(buf, 0, rlen); - } - outputStream.close(); - inputStream.close(); - gzInputStream.close(); + if ("gzip".equals(contentEncoding)) { + GZIPInputStream gzInputStream = new GZIPInputStream(new FileInputStream(CacheUtil + .getCacheFile(downloadLocation, resource.downloadVersion))); + InputStream inputStream = new BufferedInputStream(gzInputStream); - } else if (contentEncoding.equals("pack200-gzip")) { - GZIPInputStream gzInputStream = new GZIPInputStream(new FileInputStream( - CacheUtil.getCacheFile(downloadLocation, resource.downloadVersion))); - InputStream inputStream = new BufferedInputStream(gzInputStream); + BufferedOutputStream outputStream = new BufferedOutputStream( + new FileOutputStream(CacheUtil.getCacheFile(resource.location, + resource.downloadVersion))); - JarOutputStream outputStream = new JarOutputStream(new FileOutputStream( - CacheUtil.getCacheFile(resource.location, resource.downloadVersion))); + while (-1 != (rlen = inputStream.read(buf))) { + outputStream.write(buf, 0, rlen); + } - Unpacker unpacker = Pack200.newUnpacker(); - unpacker.unpack(inputStream, outputStream); + outputStream.close(); + inputStream.close(); + gzInputStream.close(); - outputStream.close(); - inputStream.close(); - gzInputStream.close(); - } + } else if ("pack200-gzip".equals(contentEncoding) || + realLocation.getPath().endsWith(".pack.gz")) { + GZIPInputStream gzInputStream = new GZIPInputStream(new FileInputStream( + CacheUtil.getCacheFile(downloadLocation, resource.downloadVersion))); + InputStream inputStream = new BufferedInputStream(gzInputStream); + + JarOutputStream outputStream = new JarOutputStream(new FileOutputStream( + CacheUtil.getCacheFile(resource.location, resource.downloadVersion))); + + Unpacker unpacker = Pack200.newUnpacker(); + unpacker.unpack(inputStream, outputStream); + + outputStream.close(); + inputStream.close(); + gzInputStream.close(); } + resource.changeStatus(DOWNLOADING, DOWNLOADED); synchronized (lock) { lock.notifyAll(); // wake up wait's to check for completion @@ -731,7 +744,9 @@ public class ResourceTracker { File localFile = CacheUtil.getCacheFile(resource.location, resource.downloadVersion); // connect - URLConnection connection = getVersionedResourceURL(resource).openConnection(); // this won't change so should be okay unsynchronized + URL finalLocation = findBestUrl(resource); + resource.setDownloadLocation(finalLocation); + URLConnection connection = finalLocation.openConnection(); // this won't change so should be okay unsynchronized connection.addRequestProperty("Accept-Encoding", "pack200-gzip, gzip"); int size = connection.getContentLength(); @@ -777,27 +792,46 @@ public class ResourceTracker { } /** - * Returns the versioned url for a resource - * @param resource the resource to get the url for + * Returns the best URL to use for downloading the resource + * + * @param resource the resource + * @return a URL or null */ - private URL getVersionedResourceURL(Resource resource) { - String actualLocation = resource.location.getProtocol() + "://" - + resource.location.getHost(); - if (resource.location.getPort() != -1) { - actualLocation += ":" + resource.location.getPort(); + private URL findBestUrl(Resource resource) { + DownloadOptions options = downloadOptions.get(resource); + if (options == null) { + options = new DownloadOptions(false, false); } - actualLocation += resource.location.getPath(); - if (resource.requestVersion != null - && resource.requestVersion.isVersionId()) { - actualLocation += "?version-id=" + resource.requestVersion; + + List<URL> urls = new ResourceUrlCreator(resource, options).getUrls(); + if (JNLPRuntime.isDebug()) { + System.err.println("All possible urls for " + + resource.toString() + " : " + urls); } - URL versionedURL; - try { - versionedURL = new URL(actualLocation); - } catch (MalformedURLException e) { - return resource.location; + URL bestUrl = null; + for (int i = 0; i < urls.size(); i++) { + URL url = urls.get(i); + try { + URLConnection connection = url.openConnection(); + connection.addRequestProperty("Accept-Encoding", "pack200-gzip, gzip"); + if (connection instanceof HttpURLConnection) { + HttpURLConnection con = (HttpURLConnection)connection; + int responseCode = con.getResponseCode(); + if (responseCode == -1 || responseCode < 200 || responseCode >= 300) { + continue; + } + } + if (JNLPRuntime.isDebug()) { + System.err.println("best url for " + resource.toString() + " is " + url.toString()); + } + bestUrl = url; + break; + } catch (IOException e) { + // continue + } } - return versionedURL; + + return bestUrl; } /** diff --git a/netx/net/sourceforge/jnlp/cache/ResourceUrlCreator.java b/netx/net/sourceforge/jnlp/cache/ResourceUrlCreator.java new file mode 100644 index 0000000..be9844a --- /dev/null +++ b/netx/net/sourceforge/jnlp/cache/ResourceUrlCreator.java @@ -0,0 +1,163 @@ +/* ResourceUrlCreator.java + Copyright (C) 2011 Red Hat, Inc + +This file is part of IcedTea. + +IcedTea is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +IcedTea is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with IcedTea; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package net.sourceforge.jnlp.cache; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.LinkedList; +import java.util.List; + +import net.sourceforge.jnlp.DownloadOptions; + +public class ResourceUrlCreator { + + protected final Resource resource; + protected final DownloadOptions downloadOptions; + + public ResourceUrlCreator(Resource resource, DownloadOptions downloadOptions) { + this.resource = resource; + this.downloadOptions = downloadOptions; + } + + /** + * Returns a list of URLs that the resources might be downloadable from. + * The Resources may not be downloadable from any of them. The returned order is the order + * the urls should be attempted in. + * @return + */ + public List<URL> getUrls() { + List<URL> urls = new LinkedList<URL>(); + URL url = null; + + if (downloadOptions.useExplicitPack() && downloadOptions.useExplicitVersion()) { + url = getUrl(resource, true, true); + if (url != null) { + urls.add(url); + } + url = getUrl(resource, false, true); + if (url != null) { + urls.add(url); + } + url = getUrl(resource, true, false); + if (url != null) { + urls.add(url); + } + } else if (downloadOptions.useExplicitPack()) { + url = getUrl(resource, true, false); + if (url != null) { + urls.add(url); + } + } else if (downloadOptions.useExplicitVersion()) { + url = getUrl(resource, false, true); + if (url != null) { + urls.add(url); + } + } + + url = getVersionedUrlUsingQuery(resource); + urls.add(url); + + urls.add(resource.getLocation()); + + return urls; + } + + /** + * Returns a url for the resource. + * @param resource the resource + * @param usePack whether the URL should point to the pack200 file + * @param useVersion whether the URL should be modified to include the version + * @return a URL for the resource or null if an appropraite URL can not be found + */ + protected URL getUrl(Resource resource, boolean usePack, boolean useVersion) { + if (!(usePack || useVersion)) { + throw new IllegalArgumentException("either pack200 or version required"); + } + + String location = resource.getLocation().toString(); + int lastSlash = resource.getLocation().toString().lastIndexOf('/'); + if (lastSlash == -1) { + return resource.getLocation(); + } + String filename = location.substring(lastSlash + 1); + if (useVersion && resource.requestVersion != null) { + String parts[] = filename.split("\\.", 2); + String name = parts[0]; + String extension = parts[1]; + filename = name + "__V" + resource.requestVersion + "." + extension; + } + if (usePack) { + filename = filename.replace(".jar", ".pack.gz"); + } + + location = location.substring(0, lastSlash + 1) + filename; + try { + URL newUrl = new URL(location); + return newUrl; + } catch (MalformedURLException e) { + return null; + } + } + + /** + * Returns the URL for a resource, relying on HTTP query for getting the + * right version + * + * @param resource the resource to get the url for + */ + protected URL getVersionedUrlUsingQuery(Resource resource) { + String actualLocation = resource.getLocation().getProtocol() + "://" + + resource.getLocation().getHost(); + if (resource.getLocation().getPort() != -1) { + actualLocation += ":" + resource.getLocation().getPort(); + } + actualLocation += resource.getLocation().getPath(); + if (resource.requestVersion != null + && resource.requestVersion.isVersionId()) { + actualLocation += "?version-id=" + resource.requestVersion; + } + URL versionedURL; + try { + versionedURL = new URL(actualLocation); + } catch (MalformedURLException e) { + return resource.getLocation(); + } + return versionedURL; + } + +}
\ No newline at end of file diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java index 30f1af2..a76a3a4 100644 --- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java +++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java @@ -45,6 +45,7 @@ import java.util.Vector; import java.util.jar.JarEntry; import java.util.jar.JarFile; +import net.sourceforge.jnlp.DownloadOptions; import net.sourceforge.jnlp.ExtensionDesc; import net.sourceforge.jnlp.JARDesc; import net.sourceforge.jnlp.JNLPFile; @@ -406,6 +407,7 @@ public class JNLPClassLoader extends URLClassLoader { tracker.addResource(jars[i].getLocation(), jars[i].getVersion(), + getDownloadOptionsForJar(jars[i]), jars[i].isCacheable() ? JNLPRuntime.getDefaultUpdatePolicy() : UpdatePolicy.FORCE ); } @@ -696,7 +698,7 @@ public class JNLPClassLoader extends URLClassLoader { List<JARDesc> jars = new ArrayList<JARDesc>(); JARDesc jarDesc = new JARDesc(new File(extractedJarLocation).toURL(), null, null, false, false, false, false); jars.add(jarDesc); - tracker.addResource(new File(extractedJarLocation).toURL(), null, null); + tracker.addResource(new File(extractedJarLocation).toURL(), null, null, null); signer.verifyJars(jars, tracker); if (signer.anyJarsSigned() && !signer.getAlreadyTrustPublisher()) { @@ -1007,6 +1009,7 @@ public class JNLPClassLoader extends URLClassLoader { tracker.addResource(desc.getLocation(), desc.getVersion(), + null, JNLPRuntime.getDefaultUpdatePolicy() ); @@ -1247,4 +1250,27 @@ public class JNLPClassLoader extends URLClassLoader { jarLocationSecurityMap.put(key, extLoader.jarLocationSecurityMap.get(key)); } } + + private DownloadOptions getDownloadOptionsForJar(JARDesc jar) { + boolean usePack = false; + boolean useVersion = false; + + ResourcesDesc[] descs = file.getResourceDescs(); + for (ResourcesDesc desc: descs) { + JARDesc[] jars = desc.getJARs(); + for (JARDesc aJar: jars) { + if (jar == aJar) { + if (Boolean.valueOf(desc.getPropertiesMap().get("jnlp.packEnabled"))) { + usePack = true; + } + if (Boolean.valueOf(desc.getPropertiesMap().get("jnlp.versionEnabled"))) { + useVersion = true; + } + } + } + } + + return new DownloadOptions(usePack, useVersion); + } + } |