diff options
-rw-r--r-- | ChangeLog | 35 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/cache/CacheUtil.java | 19 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java | 120 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/LocateJnlpClassLoader.java | 111 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/runtime/ManageJnlpResources.java | 140 | ||||
-rw-r--r-- | netx/net/sourceforge/jnlp/services/XDownloadService.java | 80 |
6 files changed, 496 insertions, 9 deletions
@@ -1,3 +1,38 @@ +2012-11-08 Saad Mohammad <[email protected]> + + Core implementation of DownloadService. + * netx/net/sourceforge/jnlp/cache/CacheUtil.java (getCacheParentDirectory): + Returns the parent directory of the cached resource. + * netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java: + (getLoaders): Returns all loaders that this loader uses, including + itself + (addNewJar): Adds a new jar to the classloader with specified + UpdatePolicy. + (removeJars): Remove jars from the filesystem. + (initializeNewJarDownload): Downloads and initializes jars into the + current loader. + (manageExternalJars): Manages jars which are not mentioned in the + JNLP file. + * netx/net/sourceforge/jnlp/runtime/LocateJnlpClassLoader.java: + (getLoaderByJnlpFile): Returns the classloader of the jnlp file + specified. + (getLoaderByResourceUrl): Returns the classloader that contains the + specified jar. + * netx/net/sourceforge/jnlp/runtime/ManageJnlpResources.java: + (findJars): Returns jars from the JNLP file with the specified + partname. + (removeCachedJars): Removes jar from cache. + (downloadJars): Downloads jars identified by part name. + (loadExternalResouceToCache): Download and initalize resources which + are not mentioned in the jnlp file. + (removeExternalCachedResource): Removes resources from cache which + are not mentioned in the jnlp file. + (isExternalResourceCached): Determines if the resource that is not + mentioned in the jnlp file is cached and returns a boolean with the + result. + * netx/net/sourceforge/jnlp/services/XDownloadService.java: + Core implementation of DownloadService. + 2012-11-02 Jiri Vanek <[email protected]> Alexandr Kolouch <[email protected]> diff --git a/netx/net/sourceforge/jnlp/cache/CacheUtil.java b/netx/net/sourceforge/jnlp/cache/CacheUtil.java index b918625..f2988f5 100644 --- a/netx/net/sourceforge/jnlp/cache/CacheUtil.java +++ b/netx/net/sourceforge/jnlp/cache/CacheUtil.java @@ -367,6 +367,25 @@ public class CacheUtil { } /** + * Returns the parent directory of the cached resource. + * @param path The path of the cached resource directory. + */ + public static String getCacheParentDirectory(String filePath) { + String path = filePath; + String tempPath = ""; + + while(path.startsWith(cacheDir) && !path.equals(cacheDir)){ + tempPath = new File(path).getParent(); + + if (tempPath.equals(cacheDir)) + break; + + path = tempPath; + } + return path; + } + + /** * This will create a new entry for the cache item. It is however not * initialized but any future calls to getCacheFile with the source and * version given to here, will cause it to return this item. diff --git a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java index 615b30c..60d4193 100644 --- a/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java +++ b/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java @@ -106,6 +106,11 @@ public class JNLPClassLoader extends URLClassLoader { final public static String TEMPLATE = "JNLP-INF/APPLICATION_TEMPLATE.JNLP"; final public static String APPLICATION = "JNLP-INF/APPLICATION.JNLP"; + /** Actions to specify how cache is to be managed **/ + public static enum DownloadAction { + DOWNLOAD_TO_CACHE, REMOVE_FROM_CACHE, CHECK_CACHE + } + /** True if the application has a signed JNLP File */ private boolean isSignedJNLP = false; @@ -1588,13 +1593,22 @@ public class JNLPClassLoader extends URLClassLoader { * @param desc the JARDesc for the new jar */ private void addNewJar(final JARDesc desc) { + this.addNewJar(desc, JNLPRuntime.getDefaultUpdatePolicy()); + } + + /** + * Adds a new JARDesc into this classloader. + * @param desc the JARDesc for the new jar + * @param updatePolicy the UpdatePolicy for the resource + */ + private void addNewJar(final JARDesc desc, UpdatePolicy updatePolicy) { available.add(desc); tracker.addResource(desc.getLocation(), desc.getVersion(), null, - JNLPRuntime.getDefaultUpdatePolicy() + updatePolicy ); // Give read permissions to the cached jar file @@ -2075,6 +2089,108 @@ public class JNLPClassLoader extends URLClassLoader { } /** + * Returns all loaders that this loader uses, including itself + */ + JNLPClassLoader[] getLoaders() { + return loaders; + } + + /** + * Remove jars from the file system. + * + * @param jars Jars marked for removal. + */ + void removeJars(JARDesc[] jars) { + + for (JARDesc eachJar : jars) { + try { + tracker.removeResource(eachJar.getLocation()); + } catch (Exception e) { + if (JNLPRuntime.isDebug()) { + System.err.println(e.getMessage()); + System.err.println("Failed to remove resource from tracker, continuing.."); + } + } + + File cachedFile = CacheUtil.getCacheFile(eachJar.getLocation(), null); + String directoryUrl = CacheUtil.getCacheParentDirectory(cachedFile.getAbsolutePath()); + + File directory = new File(directoryUrl); + + if (JNLPRuntime.isDebug()) + System.out.println("Deleting cached file: " + cachedFile.getAbsolutePath()); + + cachedFile.delete(); + + if (JNLPRuntime.isDebug()) + System.out.println("Deleting cached directory: " + directory.getAbsolutePath()); + + directory.delete(); + } + } + + /** + * Downloads and initializes jars into this loader. + * + * @param ref Path of the launch or extension JNLP File containing the + * resource. If null, main JNLP's file location will be used instead. + * @param part The name of the path. + * @throws LaunchException + */ + void initializeNewJarDownload(URL ref, String part, Version version) { + JARDesc[] jars = ManageJnlpResources.findJars(this, ref, part, version); + + for (JARDesc eachJar : jars) { + if (JNLPRuntime.isDebug()) + System.out.println("Downloading and initializing jar: " + eachJar.getLocation().toString()); + + this.addNewJar(eachJar, UpdatePolicy.FORCE); + } + } + + /** + * Manages DownloadService jars which are not mentioned in the JNLP file + * @param ref Path to the resource. + * @param version The version of resource. If null, no version is specified. + * @param action The action to perform with the resource. Either DOWNLOADTOCACHE, REMOVEFROMCACHE, or CHECKCACHE. + * @return true if CHECKCACHE and the resource is cached. + */ + boolean manageExternalJars(URL ref, String version, DownloadAction action) { + boolean approved = false; + JNLPClassLoader foundLoader = LocateJnlpClassLoader.getLoaderByResourceUrl(this, ref, version); + Version resourceVersion = (version == null) ? null : new Version(version); + + if (foundLoader != null) + approved = true; + + else if (ref.toString().startsWith(file.getCodeBase().toString())) + approved = true; + else if (SecurityDesc.ALL_PERMISSIONS.equals(security.getSecurityType())) + approved = true; + + if (approved) { + if (foundLoader == null) + foundLoader = this; + + if (action == DownloadAction.DOWNLOAD_TO_CACHE) { + JARDesc jarToCache = new JARDesc(ref, resourceVersion, null, false, true, false, true); + if (JNLPRuntime.isDebug()) + System.out.println("Downloading and initializing jar: " + ref.toString()); + + foundLoader.addNewJar(jarToCache, UpdatePolicy.FORCE); + + } else if (action == DownloadAction.REMOVE_FROM_CACHE) { + JARDesc[] jarToRemove = { new JARDesc(ref, resourceVersion, null, false, true, false, true) }; + foundLoader.removeJars(jarToRemove); + + } else if (action == DownloadAction.CHECK_CACHE) { + return CacheUtil.isCached(ref, resourceVersion); + } + } + return false; + } + + /** * Decrements loader use count by 1 * * If count reaches 0, loader is removed from list of available loaders @@ -2266,4 +2382,6 @@ public class JNLPClassLoader extends URLClassLoader { return null; } } + + } diff --git a/netx/net/sourceforge/jnlp/runtime/LocateJnlpClassLoader.java b/netx/net/sourceforge/jnlp/runtime/LocateJnlpClassLoader.java new file mode 100644 index 0000000..c7e42f0 --- /dev/null +++ b/netx/net/sourceforge/jnlp/runtime/LocateJnlpClassLoader.java @@ -0,0 +1,111 @@ +/* LocateJNLPClassLoader.java +Copyright (C) 2012, 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, version 2. + +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.runtime; + +import java.net.URL; +import net.sourceforge.jnlp.JARDesc; +import net.sourceforge.jnlp.JNLPFile; +import net.sourceforge.jnlp.ResourcesDesc; +import net.sourceforge.jnlp.Version; + +class LocateJnlpClassLoader { + + /** + * Locates the JNLPClassLoader of the JNLP file. + * @param rootClassLoader Root JNLPClassLoader of the application. + * @param urlToJnlpFile Path of the JNLP file. If null, main JNLP's file location + * be used instead + * @return the JNLPClassLoader of the JNLP file. + */ + static JNLPClassLoader getLoaderByJnlpFile(final JNLPClassLoader rootClassLoader, URL urlToJnlpFile) { + + if (rootClassLoader == null) + return null; + + JNLPFile file = rootClassLoader.getJNLPFile(); + + if (urlToJnlpFile == null) + urlToJnlpFile = rootClassLoader.getJNLPFile().getFileLocation(); + + if (file.getFileLocation().equals(urlToJnlpFile)) + return rootClassLoader; + + for (JNLPClassLoader loader : rootClassLoader.getLoaders()) { + if (rootClassLoader != loader) { + JNLPClassLoader foundLoader = LocateJnlpClassLoader.getLoaderByJnlpFile(loader, urlToJnlpFile); + if (foundLoader != null) + return foundLoader; + } + } + + return null; + } + + /** + * Locates the JNLPClassLoader of the JNLP file's resource. + * @param rootClassLoader Root JNLPClassLoader of the application. + * @param urlToJnlpFile Path of the launch or extension JNLP File. If null, + * main JNLP's file location will be used instead. + * @param version The version of resource. Is null if no version is specified + * @return the JNLPClassLoader of the JNLP file's resource. + */ + static JNLPClassLoader getLoaderByResourceUrl(final JNLPClassLoader rootClassLoader, final URL ref, final String version) { + Version resourceVersion = (version == null) ? null : new Version(version); + + for (JNLPClassLoader loader : rootClassLoader.getLoaders()) { + ResourcesDesc resources = loader.getJNLPFile().getResources(); + + for (JARDesc eachJar : resources.getJARs()) { + if (ref.equals(eachJar.getLocation()) && + (resourceVersion == null || resourceVersion.equals(eachJar.getVersion()))) + return loader; + } + } + + for (JNLPClassLoader loader : rootClassLoader.getLoaders()) { + if (rootClassLoader != loader) { + JNLPClassLoader foundLoader = LocateJnlpClassLoader.getLoaderByResourceUrl(loader, ref, version); + + if (foundLoader != null) + return foundLoader; + } + } + + return null; + } +} diff --git a/netx/net/sourceforge/jnlp/runtime/ManageJnlpResources.java b/netx/net/sourceforge/jnlp/runtime/ManageJnlpResources.java new file mode 100644 index 0000000..266e633 --- /dev/null +++ b/netx/net/sourceforge/jnlp/runtime/ManageJnlpResources.java @@ -0,0 +1,140 @@ +/* ManageJnlpResources.java +Copyright (C) 2012, 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, version 2. + +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.runtime; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.jnlp.JARDesc; +import net.sourceforge.jnlp.ResourcesDesc; +import net.sourceforge.jnlp.Version; +import net.sourceforge.jnlp.runtime.JNLPClassLoader.DownloadAction; + +public class ManageJnlpResources { + + /** + * Returns jars from the JNLP file with the part name provided. + * @param rootClassLoader Root JNLPClassLoader of the application. + * @param ref Path of the launch or extension JNLP File containing the + * resource. If null, main JNLP's file location will be used instead. + * @param part The name of the part. + * @return jars found. + */ + public static JARDesc[] findJars(final JNLPClassLoader rootClassLoader, final URL ref, final String part, final Version version) { + JNLPClassLoader foundLoader = LocateJnlpClassLoader.getLoaderByJnlpFile(rootClassLoader, ref); + + if (foundLoader != null) { + List<JARDesc> foundJars = new ArrayList<JARDesc>(); + ResourcesDesc resources = foundLoader.getJNLPFile().getResources(); + + for (JARDesc eachJar : resources.getJARs(part)) { + if (version == null || version.equals(eachJar.getVersion())) + foundJars.add(eachJar); + } + + return foundJars.toArray(new JARDesc[foundJars.size()]); + } + + return new JARDesc[] {}; + } + + /** + * Removes jars from cache. + * @param classLoader JNLPClassLoader of the application that is associated to the resource. + * @param ref Path of the launch or extension JNLP File containing the + * resource. If null, main JNLP's file location will be used instead. + * @param jars Jars marked for removal. + */ + public static void removeCachedJars(final JNLPClassLoader classLoader, final URL ref, final JARDesc[] jars) { + JNLPClassLoader foundLoader = LocateJnlpClassLoader.getLoaderByJnlpFile(classLoader, ref); + + if (foundLoader != null) + foundLoader.removeJars(jars); + } + + /** + * Downloads jars identified by part name. + * @param classLoader JNLPClassLoader of the application that is associated to the resource. + * @param ref Path of the launch or extension JNLP File containing the + * resource. If null, main JNLP's file location will be used instead. + * @param part The name of the path. + */ + public static void downloadJars(final JNLPClassLoader classLoader, final URL ref, final String part, final Version version) { + JNLPClassLoader foundLoader = LocateJnlpClassLoader.getLoaderByJnlpFile(classLoader, ref); + + if (foundLoader != null) + foundLoader.initializeNewJarDownload(ref, part, version); + } + + /** + * Downloads and initializes resources which are not mentioned in the jnlp file. + * Used by DownloadService. + * @param rootClassLoader Root JNLPClassLoader of the application. + * @param ref Path to the resource. + * @param version The version of resource. If null, no version is specified. + */ + + public static void loadExternalResouceToCache(final JNLPClassLoader rootClassLoader, final URL ref, final String version) { + rootClassLoader.manageExternalJars(ref, version, DownloadAction.DOWNLOAD_TO_CACHE); + } + + /** + * Removes resource which are not mentioned in the jnlp file. + * Used by DownloadService. + * @param rootClassLoader Root JNLPClassLoader of the application. + * @param ref Path to the resource. + * @param version The version of resource. If null, no version is specified. + */ + public static void removeExternalCachedResource(final JNLPClassLoader rootClassLoader, final URL ref, final String version) { + rootClassLoader.manageExternalJars(ref, version, DownloadAction.REMOVE_FROM_CACHE); + } + + /** + * Returns true if the resource (not mentioned in the jnlp file) is cached, otherwise false + * Used by DownloadService. + * @param rootClassLoader Root JNLPClassLoader of the application. + * @param ref Path to the resource. + * @param version The version of resource. If null, no version is specified. + * @return + */ + public static boolean isExternalResourceCached(final JNLPClassLoader rootClassLoader, final URL ref, final String version) { + return rootClassLoader.manageExternalJars(ref, version, DownloadAction.CHECK_CACHE); + } + +} diff --git a/netx/net/sourceforge/jnlp/services/XDownloadService.java b/netx/net/sourceforge/jnlp/services/XDownloadService.java index 0a64326..12cfbbd 100644 --- a/netx/net/sourceforge/jnlp/services/XDownloadService.java +++ b/netx/net/sourceforge/jnlp/services/XDownloadService.java @@ -20,6 +20,13 @@ import java.io.*; import java.net.*; import javax.jnlp.*; +import net.sourceforge.jnlp.JARDesc; +import net.sourceforge.jnlp.Version; +import net.sourceforge.jnlp.cache.CacheUtil; +import net.sourceforge.jnlp.runtime.JNLPClassLoader; +import net.sourceforge.jnlp.runtime.ManageJnlpResources; +import net.sourceforge.jnlp.runtime.JNLPRuntime; + /** * The DownloadService JNLP service. * @@ -28,11 +35,14 @@ import javax.jnlp.*; */ class XDownloadService implements DownloadService { - protected XDownloadService() { + /** + * Returns the JNLPClassLoader of the application + * @return + */ + JNLPClassLoader getClassLoader() { + return (JNLPClassLoader) JNLPRuntime.getApplication().getClassLoader(); } - // comments copied from DownloadService interface - /** * Returns a listener that will automatically display download * progress to the user. @@ -46,7 +56,19 @@ class XDownloadService implements DownloadService { * url and version) is cached locally. */ public boolean isExtensionPartCached(URL ref, String version, String part) { - return true; + boolean allCached = true; + Version resourceVersion = (version == null) ? null : new Version(version); + + JARDesc[] jars = ManageJnlpResources.findJars(this.getClassLoader(), ref, part, resourceVersion); + + if (jars.length <= 0) + return false; + + for (int i = 0; i < jars.length && allCached; i++) { + allCached = CacheUtil.isCached(jars[i].getLocation(), resourceVersion); + } + + return allCached; } /** @@ -54,7 +76,14 @@ class XDownloadService implements DownloadService { * url and version) are cached locally. */ public boolean isExtensionPartCached(URL ref, String version, String[] parts) { - return true; + boolean allCached = true; + if (parts.length <= 0) + return false; + + for (String eachPart : parts) + allCached = this.isExtensionPartCached(ref, version, eachPart); + + return allCached; } /** @@ -64,7 +93,17 @@ class XDownloadService implements DownloadService { * the application. */ public boolean isPartCached(String part) { - return true; + boolean allCached = true; + JARDesc[] jars = ManageJnlpResources.findJars(this.getClassLoader(), null, part, null); + + if (jars.length <= 0) + return false; + + for (int i = 0; i < jars.length && allCached; i++) { + allCached = CacheUtil.isCached(jars[i].getLocation(), null); + } + + return allCached; } /** @@ -74,7 +113,14 @@ class XDownloadService implements DownloadService { * application. */ public boolean isPartCached(String[] parts) { - return true; + boolean allCached = true; + if (parts.length <= 0) + return false; + + for (String eachPart : parts) + allCached = this.isPartCached(eachPart); + + return allCached; } /** @@ -83,7 +129,7 @@ class XDownloadService implements DownloadService { * application or extension. */ public boolean isResourceCached(URL ref, String version) { - return true; + return ManageJnlpResources.isExternalResourceCached(this.getClassLoader(), ref, version); } /** @@ -92,6 +138,8 @@ class XDownloadService implements DownloadService { * @throws IOException */ public void loadExtensionPart(URL ref, String version, String[] parts, DownloadServiceListener progress) throws IOException { + for (String eachPart : parts) + this.loadExtensionPart(ref, version, eachPart, progress); } /** @@ -100,6 +148,8 @@ class XDownloadService implements DownloadService { * @throws IOException */ public void loadExtensionPart(URL ref, String version, String part, DownloadServiceListener progress) throws IOException { + Version resourceVersion = (version == null) ? null : new Version(version); + ManageJnlpResources.downloadJars(this.getClassLoader(), ref, part, resourceVersion); } /** @@ -108,6 +158,8 @@ class XDownloadService implements DownloadService { * @throws IOException */ public void loadPart(String[] parts, DownloadServiceListener progress) throws IOException { + for (String eachPart : parts) + this.loadPart(eachPart, progress); } /** @@ -116,6 +168,7 @@ class XDownloadService implements DownloadService { * @throws IOException */ public void loadPart(String part, DownloadServiceListener progress) throws IOException { + ManageJnlpResources.downloadJars(this.getClassLoader(), null, part, null); } /** @@ -124,6 +177,7 @@ class XDownloadService implements DownloadService { * @throws IOException */ public void loadResource(URL ref, String version, DownloadServiceListener progress) throws IOException { + ManageJnlpResources.loadExternalResouceToCache(this.getClassLoader(), ref, version); } /** @@ -133,6 +187,9 @@ class XDownloadService implements DownloadService { * @throws IOException */ public void removeExtensionPart(URL ref, String version, String part) throws IOException { + Version resourceVersion = (version == null) ? null : new Version(version); + JARDesc[] jars = ManageJnlpResources.findJars(this.getClassLoader(), ref, part, resourceVersion); + ManageJnlpResources.removeCachedJars(this.getClassLoader(), ref, jars); } /** @@ -142,6 +199,8 @@ class XDownloadService implements DownloadService { * @throws IOException */ public void removeExtensionPart(URL ref, String version, String[] parts) throws IOException { + for (String eachPart : parts) + this.removeExtensionPart(ref, version, eachPart); } /** @@ -151,6 +210,8 @@ class XDownloadService implements DownloadService { * @throws IOException */ public void removePart(String part) throws IOException { + JARDesc[] jars = ManageJnlpResources.findJars(this.getClassLoader(), null, part, null); + ManageJnlpResources.removeCachedJars(this.getClassLoader(), null, jars); } /** @@ -160,6 +221,8 @@ class XDownloadService implements DownloadService { * @throws IOException */ public void removePart(String[] parts) throws IOException { + for (String eachPart : parts) + this.removePart(eachPart); } /** @@ -169,6 +232,7 @@ class XDownloadService implements DownloadService { * @throws IOException */ public void removeResource(URL ref, String version) throws IOException { + ManageJnlpResources.removeExternalCachedResource(this.getClassLoader(), ref, version); } } |