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.