changeset 1008:6f45fbbf26a6

Massively improved offline abilities.
author Jiri Vanek <jvanek@redhat.com>
date Thu, 07 Aug 2014 18:39:40 +0200
parents 247a09f2cd10
children 7b775a8557e9
files ChangeLog NEWS netx/net/sourceforge/jnlp/JNLPFile.java netx/net/sourceforge/jnlp/Launcher.java netx/net/sourceforge/jnlp/cache/ResourceTracker.java netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java netx/net/sourceforge/jnlp/util/XDesktopEntry.java
diffstat 7 files changed, 125 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Aug 01 11:25:44 2014 +0200
+++ b/ChangeLog	Thu Aug 07 18:39:40 2014 +0200
@@ -1,3 +1,22 @@
+2014-08-05  Jiri Vanek  <jvanek@redhat.com>
+
+	Massively improved offline abilities. Added Xoffline switch to force work without inet connection.
+	* NEWS: updated
+	* netx/net/sourceforge/jnlp/JNLPFile.java: (openURL) is now using properly 
+	cached file instead of direct online one.
+	* netx/net/sourceforge/jnlp/Launcher.java: launcher is now using JNLPRuntime
+	isOnline* set of methods
+	* netx/net/sourceforge/jnlp/cache/ResourceTracker.java: misleading 
+	(getInputStream) method removed (initializeResource) check for connection
+	before downlaodin (unless Xforceoffline specified). If environment is offline
+	it do not attempt any url connections or writing to cache
+	* netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java: added flags of (offlineForced)
+	and (onlineDetected) with getters and setters. Added utility method (detectOnline)
+	to recognize whether environment is onliune by resovling inet addres of	host
+	of not file url.
+	* netx/net/sourceforge/jnlp/util/XDesktopEntry.java: now writes real url into
+	desktop icon
+
 2014-08-01  Jiri Vanek  <jvanek@redhat.com>
 
 	* plugin/icedteanp/java/sun/applet/PluginAppletViewer.java: casts to
--- a/NEWS	Fri Aug 01 11:25:44 2014 +0200
+++ b/NEWS	Thu Aug 07 18:39:40 2014 +0200
@@ -9,6 +9,7 @@
 CVE-XXXX-YYYY: http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=XXXX-YYYY
 
 New in release 1.5.1 (YYYY-MM-DD):
+* Massively improved offline abilities.
 * Improved to be able to run with any JDK
 * JDK 8 support added (URLPermission granted if applicable)
 * Added DE and PL localizations
--- a/netx/net/sourceforge/jnlp/JNLPFile.java	Fri Aug 01 11:25:44 2014 +0200
+++ b/netx/net/sourceforge/jnlp/JNLPFile.java	Thu Aug 07 18:39:40 2014 +0200
@@ -16,6 +16,8 @@
 
 package net.sourceforge.jnlp;
 
+import java.io.File;
+import java.io.FileInputStream;
 import static net.sourceforge.jnlp.runtime.Translator.R;
 
 import java.io.IOException;
@@ -301,8 +303,8 @@
         try {
             ResourceTracker tracker = new ResourceTracker(false); // no prefetch
             tracker.addResource(location, version, null, policy);
-
-            return tracker.getInputStream(location);
+            File f = tracker.getCacheFile(location);
+            return new FileInputStream(f);
         } catch (Exception ex) {
             throw new IOException(ex.getMessage());
         }
--- a/netx/net/sourceforge/jnlp/Launcher.java	Fri Aug 01 11:25:44 2014 +0200
+++ b/netx/net/sourceforge/jnlp/Launcher.java	Thu Aug 07 18:39:40 2014 +0200
@@ -227,16 +227,10 @@
         //First checks whether offline-allowed tag is specified inside the jnlp
         //file.
         if (!file.getInformation().isOfflineAllowed()) {
-            try {
-                //Checks the offline/online status of the system.
-                //If system is offline do not launch.
-                InetAddress.getByName(file.getSourceLocation().getHost());
-
-            } catch (UnknownHostException ue) {
+            //offline status should be already known from jnlp downloading
+            if (!JNLPRuntime.isOnlineDetected()) {
                 OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "File cannot be launched because offline-allowed tag not specified and system currently offline.");
                 return null;
-            } catch (Exception e) {
-                OutputController.getLogger().log(e);
             }
         }
 
--- a/netx/net/sourceforge/jnlp/cache/ResourceTracker.java	Fri Aug 01 11:25:44 2014 +0200
+++ b/netx/net/sourceforge/jnlp/cache/ResourceTracker.java	Thu Aug 07 18:39:40 2014 +0200
@@ -25,9 +25,11 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.HttpURLConnection;
+import java.net.InetAddress;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
+import java.net.UnknownHostException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.ArrayList;
@@ -404,33 +406,7 @@
         }
     }
 
-    /**
-     * Returns an input stream that reads the contents of the
-     * resource.  For non-cacheable resources, an InputStream that
-     * reads from the source location is returned.  Otherwise the
-     * InputStream reads the cached resource.
-     * <p>
-     * This method will block while the resource is downloaded to
-     * the cache.
-     * </p>
-     *
-     * @throws IOException if there was an error opening the stream
-     * @throws IllegalResourceDescriptorException if the resource is not being tracked
-     */
-    public InputStream getInputStream(URL location) throws IOException {
-        try {
-            Resource resource = getResource(location);
-            if (!resource.isSet(DOWNLOADED | ERROR))
-                waitForResource(location, 0);
 
-            if (resource.localFile != null)
-                return new FileInputStream(resource.localFile);
-
-            return resource.location.openStream();
-        } catch (InterruptedException ex) {
-            throw new IOException("wait was interrupted");
-        }
-    }
 
     /**
      * Wait for a group of resources to be downloaded and made
@@ -776,6 +752,10 @@
      * fields.
      */
     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.location, resource.requestVersion);
@@ -783,31 +763,41 @@
 
         try {
             File localFile = CacheUtil.getCacheFile(resource.location, resource.downloadVersion);
-
-            // connect
-            URL finalLocation = findBestUrl(resource);
+            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.location + ", but failed to connect!");
-                throw new NullPointerException("finalLocation == null"); // Caught below
-            }
-
-            resource.setDownloadLocation(finalLocation);
-            URLConnection connection = finalLocation.openConnection(); // this won't change so should be okay unsynchronized
-            connection.addRequestProperty("Accept-Encoding", "pack200-gzip, gzip");
+                if (finalLocation == null) {
+                    OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "Attempted to download " + resource.location + ", but failed to connect!");
+                    throw new NullPointerException("finalLocation == null"); // Caught below
+                }
 
-            int size = connection.getContentLength();
-            boolean current = CacheUtil.isCurrent(resource.location, resource.requestVersion, connection) && 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.location, resource.downloadVersion);
-                    CacheEntry newEntry = new CacheEntry(resource.location, resource.requestVersion);
-                    newEntry.lock();
-                    entry.unlock();
-                    entry = newEntry;
+                resource.setDownloadLocation(finalLocation);
+                connection = finalLocation.openConnection(); // this won't change so should be okay unsynchronized
+                connection.addRequestProperty("Accept-Encoding", "pack200-gzip, gzip");
+
+                size = connection.getContentLength();
+                current = CacheUtil.isCurrent(resource.location, resource.requestVersion, connection) && 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.location, resource.downloadVersion);
+                        CacheEntry newEntry = new CacheEntry(resource.location, resource.requestVersion);
+                        newEntry.lock();
+                        entry.unlock();
+                        entry = newEntry;
+                    }
                 }
             }
 
@@ -823,7 +813,7 @@
             }
 
             // update cache entry
-            if (!current)
+            if (!current && JNLPRuntime.isOnline())
                 entry.initialize(connection);
 
             entry.setLastUpdated(System.currentTimeMillis());
--- a/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Fri Aug 01 11:25:44 2014 +0200
+++ b/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java	Thu Aug 07 18:39:40 2014 +0200
@@ -24,7 +24,10 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.net.Authenticator;
+import java.net.InetAddress;
 import java.net.ProxySelector;
+import java.net.URL;
+import java.net.UnknownHostException;
 import java.nio.channels.FileChannel;
 import java.nio.channels.FileLock;
 import java.security.AllPermission;
@@ -157,6 +160,12 @@
     
     /** allows 301.302.303.307.308 redirects to be followed when downloading resources*/
     private static boolean allowRedirect = false;;
+    
+    /** when this is true, ITW will not attempt any inet connections and will work only with what is in cache*/
+    private static boolean offlineForced = false;
+
+    private static Boolean onlineDetected = null;
+
 
     /** 
      * Header is not checked and so eg
@@ -377,6 +386,54 @@
         new ParserDelegator();
     }
 
+
+    
+     
+    
+    
+
+    public static boolean isOfflineForced() {
+        return offlineForced;
+    }
+
+    public static void setOnlineDetected(boolean online) {
+        onlineDetected = online;
+        OutputController.getLogger().log(OutputController.Level.MESSAGE_DEBUG, "Detected online set to: " + onlineDetected);
+    }
+
+    public static boolean isOnlineDetected() {
+        if (onlineDetected == null) {
+            //"file" protocol do not do online check
+            //sugest online for this case
+            return true;
+        }
+        return onlineDetected;
+    }
+
+    public static boolean isOnline() {
+        if (isOfflineForced()) {
+            return false;
+        }
+        return isOnlineDetected();
+    }
+
+    public static void detectOnline(URL location) {
+        if (onlineDetected != null) {
+            return;
+        }
+        try {
+            if (location.getProtocol().equals("file")) {
+                return;
+            }
+            //Checks the offline/online status of the system.
+            InetAddress.getByName(location.getHost());
+        } catch (UnknownHostException ue) {
+            OutputController.getLogger().log(OutputController.Level.ERROR_ALL, "The host of " + location.toExternalForm() + " file should be located seems down, or you are simply offline.");
+            JNLPRuntime.setOnlineDetected(false);
+            return;
+        }
+        setOnlineDetected(true);
+    }
    
     /**
      * see <a href="https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java">Double-checked locking in Java</a>
--- a/netx/net/sourceforge/jnlp/util/XDesktopEntry.java	Fri Aug 01 11:25:44 2014 +0200
+++ b/netx/net/sourceforge/jnlp/util/XDesktopEntry.java	Thu Aug 07 18:39:40 2014 +0200
@@ -102,8 +102,8 @@
             fileContents += "Vendor=" + sanitize(file.getInformation().getVendor()) + "\n";
         }
 
-        //Shortcut executes the jnlp from cache and system preferred java..
-        fileContents += "Exec=" + "javaws" + " \"" + cacheFile.getAbsolutePath() + "\"\n";
+        //Shortcut executes the jnlp as it was with system preferred java. It should work fine offline
+        fileContents += "Exec=" + "javaws" + " \"" + file.getSourceLocation() + "\"\n";
 
         return new StringReader(fileContents);