Author: paperwing
Date: 2012-06-25 11:34:27 -0700 (Mon, 25 Jun 2012)
New Revision: 29680

Modified:
   
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/App.java
   
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppManager.java
   
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppParser.java
   
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/BundleApp.java
   
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/SimpleApp.java
Log:
refs #1121 App file should now be properly removed from installed apps folder 
when uninstalling, on platforms such as Windows 7

Modified: 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/App.java
===================================================================
--- 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/App.java
 2012-06-23 23:11:39 UTC (rev 29679)
+++ 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/App.java
 2012-06-25 18:34:27 UTC (rev 29680)
@@ -6,6 +6,7 @@
 import java.net.URL;
 import java.util.Collection;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.Set;
 
 import org.apache.commons.io.FileUtils;
@@ -16,6 +17,8 @@
 import org.cytoscape.app.internal.exception.AppUninstallException;
 import org.cytoscape.app.internal.util.DebugHelper;
 import org.cytoscape.app.swing.CySwingAppAdapter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * This class represents an app, and contains all needed information about the 
app such as its name, version, 
@@ -23,13 +26,24 @@
  */
 public abstract class App {
        
+       private static final Logger logger = 
LoggerFactory.getLogger(AppManager.class);
+       
        private String appName;
        private String version;
        private String authors;
        private String description;
-       private File appFile;
        
        /**
+        * The file containing the app, may be a jar file.
+        */
+       private File appFile;
+
+       /**
+        * The temporary file corresponding to the app that is used to load 
classes from.
+        */
+       private File appTemporaryInstallFile;
+               
+       /**
         * The fully-qualified name of the app's class that extends {@link 
AbstractCyApp} to be instantiated when the app is loaded.
         */
        private String entryClassName;
@@ -142,7 +156,7 @@
                        
                        // If the app is not packaged properly or is missing 
fields in its manifest file, do not install the app
                        // as the install operation will fail.
-                       throw new AppInstallException("Cannot install app; app 
file has not been checked to comply with app specifications");
+                       throw new AppInstallException("Cannot install app; app 
file has not been checked to have proper metadata");
                }
                
                // Check if the app has already been installed.
@@ -182,7 +196,7 @@
                        // Make sure no app with the same filename and app name 
is already installed
                        File installedDirectoryTargetFile = new 
File(installedAppsPath + File.separator + appFile.getName());
                        File uninstalledDirectoryTargetFile = new 
File(uninstalledAppsPath + File.separator + appFile.getName());
-                       
+               
                        String copyDestinationFileName = appFile.getName();
                        
                        // Check for filename collisions in both the installed 
apps directory as well as the 
@@ -260,11 +274,12 @@
                                // Uses Apache Commons library; overwrites 
files with the same name.
                                // FileUtils.copyFileToDirectory(appFile, new 
File(installedAppsPath));
                                
-                               FileUtils.copyFile(appFile, new 
File(installedAppsPath + File.separator + copyDestinationFileName));
-                               
                                // If we copied it from the uninstalled apps 
directory, remove it from that directory
+                               File targetFile = new File(installedAppsPath + 
File.separator + copyDestinationFileName);
                                if 
(appFile.getParentFile().getCanonicalPath().equals(uninstalledAppsPath)) {
-                                       appFile.delete();
+                                       FileUtils.moveFile(appFile, targetFile);
+                               } else {
+                                       FileUtils.copyFile(appFile, 
targetFile);                                
                                }
                                
                                // Update the app's path
@@ -273,6 +288,25 @@
                } catch (IOException e) {
                        throw new AppInstallException("Unable to copy app file 
to installed apps directory: " + e.getMessage());
                }
+               
+               // Make a second copy to be used to load the actual classes
+               // This is used to prevent errors associated with moving jar 
files that have classes loaded from them.
+               if (this.getAppTemporaryInstallFile() == null) {
+                       String temporaryInstallPath = 
appManager.getTemporaryInstallPath();
+                       List<String> temporaryInstallPathCollection = new 
LinkedList<String>();
+                       
temporaryInstallPathCollection.add(temporaryInstallPath);
+                       
+                       // Rename the file if necessary to avoid overwrites
+                       File temporaryInstallTargetFile = new 
File(temporaryInstallPath + File.separator 
+                                       + 
suggestFileName(temporaryInstallPathCollection, appFile.getName()));
+                       try {
+                               FileUtils.copyFile(appFile, 
temporaryInstallTargetFile);
+                               
+                               
this.setAppTemporaryInstallFile(temporaryInstallTargetFile);
+                       } catch (IOException e) {
+                               logger.warn("Failed to make copy of app file to 
be used for loading classes. The problem was: " + e.getMessage());
+                       }
+               }
        
                // Create an app instance only if one was not already created
                if (this.getAppInstance() == null) {
@@ -386,14 +420,16 @@
                                        
                                        // Use the Apache commons library to 
copy over the file, overwriting existing files.
                                        try {
-                                               
FileUtils.copyFileToDirectory(this.getAppFile(), new File(uninstalledAppsPath));
+                                               
FileUtils.moveFileToDirectory(this.getAppFile(), new File(uninstalledAppsPath), 
true);
                                        } catch (IOException e) {
                                                throw new 
AppUninstallException("Unable to move file: " + e.getMessage());
                                        }
                                        
                                        // Delete the source file after the 
copy operation
                                        String fileName = 
this.getAppFile().getName();
-                                       this.getAppFile().delete();
+                                       
+                                       //System.gc();
+                                       //System.out.println("Deleting " + 
this.getAppFile().getPath() + ": " + App.delete(this.getAppFile()));
                                        this.setAppFile(new 
File(uninstalledAppsPath + File.separator + fileName));
                                }
                        } catch (IOException e) {
@@ -454,10 +490,22 @@
                return description;
        }
        
+       /**
+        * Return the file containing the app.
+        * @return The file containing the app, such as a jar, zip, or kar file.
+        */
        public File getAppFile() {
                return appFile;
        }
        
+       /**
+        * Return the temporary file associated with the app that is used to 
load classes from.
+        * @return The temporary file corresponding to the app used to load 
classes from
+        */
+       public File getAppTemporaryInstallFile() {
+               return appTemporaryInstallFile;
+       }
+       
        public String getEntryClassName() {
                return entryClassName;
        }
@@ -510,6 +558,10 @@
                this.appFile = appFile;
        }
        
+       public void setAppTemporaryInstallFile(File appTemporaryInstallFile) {
+               this.appTemporaryInstallFile = appTemporaryInstallFile;
+       }
+       
        public void setEntryClassName(String entryClassName) {
                this.entryClassName = entryClassName;
        }
@@ -537,4 +589,46 @@
        public void setStatus(AppStatus status) {
                this.status = status;
        }
+       
+       public static boolean delete( File f )  
+    {  
+        if( ! f.exists() )  
+        {  
+            System.err.println( "Cannont delete, file does not exist: " + 
f.getPath() );  
+            return false;  
+        }  
+        f.setReadable( true );  
+        f.setWritable( true );  
+        if( ! f.canWrite() )  
+        {  
+            System.err.println( "Cannont delete, file is read-only: " + 
f.getPath() );  
+            return false;  
+        }  
+  
+        // Hack attempt  
+        File    parent = f.getParentFile();  
+        parent.setReadable( true );  
+        parent.setWritable( true );  
+        if( ! parent.canWrite() )  
+        {  
+            System.err.println( "Cannont delete, parent folder read-only: " + 
parent.getPath() );  
+            return false;  
+        }  
+  
+        try  
+        {  
+            (new SecurityManager()).checkDelete( f.getPath() );  
+        }  
+        catch( Exception ex )  
+        {  
+            System.err.println( "Cannot delete file, " + ex.getMessage() );  
+            return false;  
+        }  
+  
+        boolean ret = f.delete();  
+        if( ! ret )  
+            System.err.println( "Delete failed: " + f.getPath() );  
+        return ret;  
+    }
+
 }

Modified: 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppManager.java
===================================================================
--- 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppManager.java
  2012-06-23 23:11:39 UTC (rev 29679)
+++ 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppManager.java
  2012-06-25 18:34:27 UTC (rev 29680)
@@ -53,6 +53,9 @@
        /** Apps are downloaded from the web store to this subdirectory under 
local app storage directory. */
        private static final String DOWNLOADED_APPS_DIRECTORY_NAME = 
"download-temp";
        
+       /** Apps that are loaded are stored in this temporary directory. */
+       private static final String TEMPORARY_LOADED_APPS_DIRECTORY_NAME = 
".temp-installed";
+       
        /** This subdirectory in the local Cytoscape storage directory is used 
to store app data, as 
         * well as installed and uninstalled apps. */
        private static final String APPS_DIRECTORY_NAME = "3.0/apps";
@@ -122,7 +125,7 @@
                initializeAppsDirectories();
                
                this.appListeners = new HashSet<AppsChangedListener>();
-
+               
                // Install previously enabled apps
                installAppsInDirectory(new File(getInstalledAppsPath()));
                
@@ -417,21 +420,41 @@
         * or <code>null</code> if there was an error obtaining the canonical 
path.
         */
        public String getInstalledAppsPath() {
+               File path = new File(getBaseAppPath() + File.separator + 
INSTALLED_APPS_DIRECTORY_NAME);
+               
                try {
-                       // Create the directory if it doesn't exist
-                       File path = new File(getBaseAppPath() + File.separator 
+ INSTALLED_APPS_DIRECTORY_NAME);
-                       
+                       // Create the directory if it doesn't exist     
                        if (!path.exists()) {
                                path.mkdirs();
-                               System.out.println("Remaking installed dir");
                        }
                        
                        return path.getCanonicalPath();
                } catch (IOException e) {
                        logger.warn("Failed to obtain path to installed apps 
directory");
-                       return null;
+                       return path.getAbsolutePath();
                }
        }
+
+       /**
+        * Return the canonical path of the temporary directory in the local 
storage directory used to contain apps that
+        * are currently loaded.
+        * @return The canonical path of the temporary directory containing 
apps with classes that are loaded.
+        */
+       public String getTemporaryInstallPath() {
+               File path = new File(getBaseAppPath() + File.separator + 
TEMPORARY_LOADED_APPS_DIRECTORY_NAME);
+               
+               try {
+                       // Create the directory if it doesn't exist
+                       if (!path.exists()) {
+                               path.mkdirs();
+                       }
+                       
+                       return path.getCanonicalPath();
+               } catch (IOException e) {
+                       logger.warn("Failed to obtain canonical path to the 
temporary installed apps directory");
+                       return path.getAbsolutePath();
+               }
+       }
        
        /**
         * Return the canonical path of the subdirectory in the local storage 
directory containing uninstalled apps.
@@ -439,10 +462,10 @@
         * or <code>null</code> if there was an error obtaining the canonical 
path.
         */
        public String getUninstalledAppsPath() {
+               File path = new File(getBaseAppPath() + File.separator + 
UNINSTALLED_APPS_DIRECTORY_NAME);
+               
                try {
                        // Create the directory if it doesn't exist
-                       File path = new File(getBaseAppPath() + File.separator 
+ UNINSTALLED_APPS_DIRECTORY_NAME);
-                       
                        if (!path.exists()) {
                                path.mkdirs();
                        }
@@ -450,7 +473,7 @@
                        return path.getCanonicalPath();
                } catch (IOException e) {
                        logger.warn("Failed to obtain path to uninstalled apps 
directory");
-                       return null;
+                       return path.getAbsolutePath();
                }
        }
        
@@ -461,10 +484,10 @@
         * storing apps downloaded from the app store.
         */
        public String getDownloadedAppsPath() {
+               File path = new File(getBaseAppPath() + File.separator + 
DOWNLOADED_APPS_DIRECTORY_NAME);
+               
                try {
                        // Create the directory if it doesn't exist
-                       File path = new File(getBaseAppPath() + File.separator 
+ DOWNLOADED_APPS_DIRECTORY_NAME);
-                       
                        if (!path.exists()) {
                                path.mkdirs();
                        }
@@ -472,7 +495,7 @@
                        return path.getCanonicalPath();
                } catch (IOException e) {
                        logger.warn("Failed to obtain path to downloaded apps 
directory");
-                       return null;
+                       return path.getAbsolutePath();
                }
        }
        
@@ -482,13 +505,14 @@
        public void purgeTemporaryDirectories() {
                File downloaded = new File(getDownloadedAppsPath());
                File uninstalled = new File(getUninstalledAppsPath());
+               File temporaryInstall = new File(getTemporaryInstallPath());
                
                try {
                        FileUtils.deleteDirectory(downloaded);
                        FileUtils.deleteDirectory(uninstalled);
-                       
+                       FileUtils.deleteDirectory(temporaryInstall);
                } catch (IOException e) {
-                       logger.warn("Unable to completely remove temporary 
directories for downloaded and uninstalled apps.");
+                       logger.warn("Unable to completely remove temporary 
directories for downloaded, loaded, and uninstalled apps.");
                }
        }
        
@@ -548,19 +572,25 @@
                File appDirectory = getBaseAppPath();
                if (!appDirectory.exists()) {
                        created = created && appDirectory.mkdirs();
-                       DebugHelper.print("Creating " + appDirectory + ". 
Success? " + created);
+                       logger.info("Creating " + appDirectory + ". Success? " 
+ created);
                }
                
                File installedDirectory = new File(getInstalledAppsPath());
                if (!installedDirectory.exists()) {
                        created = created && installedDirectory.mkdirs();
-                       DebugHelper.print("Creating " + installedDirectory + ". 
Success? " + created);
+                       logger.info("Creating " + installedDirectory + ". 
Success? " + created);
                }
                
+               File temporaryInstallDirectory = new 
File(getTemporaryInstallPath());
+               if (!temporaryInstallDirectory.exists()) {
+                       created = created && temporaryInstallDirectory.mkdirs();
+                       logger.info("Creating " + temporaryInstallDirectory + 
". Success? " + created);
+               }
+               
                File uninstalledDirectory = new File(getUninstalledAppsPath());
                if (!uninstalledDirectory.exists()) {
                        created = created && uninstalledDirectory.mkdirs();
-                       DebugHelper.print("Creating " + uninstalledDirectory + 
". Success? " + created);
+                       logger.info("Creating " + uninstalledDirectory + ". 
Success? " + created);
                }
                
                File downloadedDirectory = new File(getDownloadedAppsPath());
@@ -569,7 +599,7 @@
                }
                
                if (!created) {
-                       throw new RuntimeException("Failed to create local app 
storage directories.");
+                       logger.error("Failed to create local app storage 
directories.");
                }
        }
        

Modified: 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppParser.java
===================================================================
--- 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppParser.java
   2012-06-23 23:11:39 UTC (rev 29679)
+++ 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppParser.java
   2012-06-25 18:34:27 UTC (rev 29680)
@@ -2,6 +2,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.Enumeration;
 import java.util.LinkedList;
 import java.util.List;
@@ -193,7 +194,16 @@
                                                }
                                        });
                                    
-                                   xmlReader.parse(new 
InputSource(jarFile.getInputStream(jarEntry)));
+                                   InputStream inputStream = null;
+                                   try {
+                                       inputStream = 
jarFile.getInputStream(jarEntry);
+                                       xmlReader.parse(new 
InputSource(inputStream));
+                                       
+                                   } finally {
+                                       if (inputStream != null) {
+                                               inputStream.close();
+                                       }
+                                   }
                                    
                                } catch (SAXException e) {
                                        xmlParseFailed = true;

Modified: 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/BundleApp.java
===================================================================
--- 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/BundleApp.java
   2012-06-23 23:11:39 UTC (rev 29679)
+++ 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/BundleApp.java
   2012-06-25 18:34:27 UTC (rev 29680)
@@ -32,7 +32,7 @@
                BundleContext bundleContext = null;
                Bundle bundle = null;
                try {
-                       bundle = 
bundleContext.installBundle(this.getAppFile().toURI().toURL().toString());
+                       bundle = 
bundleContext.installBundle(this.getAppTemporaryInstallFile().toURI().toURL().toString());
                } catch (MalformedURLException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();

Modified: 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/SimpleApp.java
===================================================================
--- 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/SimpleApp.java
   2012-06-23 23:11:39 UTC (rev 29679)
+++ 
core3/impl/trunk/app-impl/src/main/java/org/cytoscape/app/internal/manager/SimpleApp.java
   2012-06-25 18:34:27 UTC (rev 29680)
@@ -18,13 +18,13 @@
        @Override
        public Object createAppInstance(CySwingAppAdapter appAdapter) throws 
AppInstanceException {
                
-               File appFile = this.getAppFile();
+               File installFile = this.getAppTemporaryInstallFile();
                URL appURL = null;
                try {
-                       appURL = appFile.toURI().toURL();
+                       appURL = installFile.toURI().toURL();
                } catch (MalformedURLException e) {
                        throw new AppInstanceException("Unable to obtain URL 
for file: " 
-                                       + appFile + ". Reason: " + 
e.getMessage());
+                                       + installFile + ". Reason: " + 
e.getMessage());
                }
                
                // TODO: Currently uses the CyAppAdapter's loader to load apps' 
classes. Is there reason to use a different one?

-- 
You received this message because you are subscribed to the Google Groups 
"cytoscape-cvs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/cytoscape-cvs?hl=en.

Reply via email to