Author: paperwing
Date: 2012-04-02 16:10:33 -0700 (Mon, 02 Apr 2012)
New Revision: 28717
Modified:
csplugins/trunk/toronto/yuedong/app_manager/impl/app-impl/src/main/java/org/cytoscape/app/internal/manager/App.java
csplugins/trunk/toronto/yuedong/app_manager/impl/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppManager.java
Log:
Completed AppManager methods for installing and uninstalling simple apps; apps
are installed to the subdirectory for installed apps and moved to the
subdirectory for uninstalled apps when uninstalled. App installation now uses a
URLClassLoader to obtain and load the appropriate classes from the app jar file.
Modified:
csplugins/trunk/toronto/yuedong/app_manager/impl/app-impl/src/main/java/org/cytoscape/app/internal/manager/App.java
===================================================================
---
csplugins/trunk/toronto/yuedong/app_manager/impl/app-impl/src/main/java/org/cytoscape/app/internal/manager/App.java
2012-04-02 22:45:09 UTC (rev 28716)
+++
csplugins/trunk/toronto/yuedong/app_manager/impl/app-impl/src/main/java/org/cytoscape/app/internal/manager/App.java
2012-04-02 23:10:33 UTC (rev 28717)
@@ -1,6 +1,7 @@
package org.cytoscape.app.internal.manager;
import java.io.File;
+import java.net.URL;
import org.cytoscape.app.AbstractCyApp;
@@ -21,6 +22,31 @@
*/
private String entryClassName;
+ /**
+ * The URL to the jar file containing the app.
+ */
+ private URL jarURL;
+
+ /**
+ * A reference to the instance of the app's class that extends {@link
AbstractCyApp}.
+ */
+ private AbstractCyApp appInstance;
+
+ /**
+ * Whether this App object represents an app that has been checked to
have valid packaging (such as containing
+ * necessary tags in its manifest file) and contains valid fields,
making it loadable by the {@link AppManager} service.
+ */
+ private boolean appValidated;
+
+ private AppStatus status;
+
+ /**
+ * An enumeration that indicates the status of a given app, such as
whether it is installed or uninstalled.
+ */
+ public enum AppStatus{
+ INSTALLED
+ }
+
public App(String appName, String version, String authors, String
description, File appFile, String entryClassName) {
this.appName = appName;
this.version = version;
@@ -28,6 +54,8 @@
this.description = description;
this.appFile = appFile;
this.entryClassName = entryClassName;
+
+ this.setAppValidated(false);
}
public String getAppName() {
@@ -53,4 +81,39 @@
public String getEntryClassName() {
return entryClassName;
}
+
+ public URL getJarURL() {
+ return jarURL;
+ }
+
+ public AbstractCyApp getAppInstance() {
+ return appInstance;
+ }
+
+ public boolean isAppValidated() {
+ return appValidated;
+ }
+
+ public AppStatus getStatus() {
+ return status;
+ }
+
+ public void setAppFile(File appFile) {
+ this.appFile = appFile;
+ }
+
+ public void setAppInstance(AbstractCyApp appInstance) {
+ this.appInstance = appInstance;
+ }
+
+ public void setAppValidated(boolean appValidated) {
+ this.appValidated = appValidated;
+ }
+
+ public void setStatus(AppStatus status) {
+ this.status = status;
+ }
+
+
+
}
Modified:
csplugins/trunk/toronto/yuedong/app_manager/impl/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppManager.java
===================================================================
---
csplugins/trunk/toronto/yuedong/app_manager/impl/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppManager.java
2012-04-02 22:45:09 UTC (rev 28716)
+++
csplugins/trunk/toronto/yuedong/app_manager/impl/app-impl/src/main/java/org/cytoscape/app/internal/manager/AppManager.java
2012-04-02 23:10:33 UTC (rev 28717)
@@ -5,6 +5,7 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
+import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarFile;
@@ -13,6 +14,7 @@
import org.cytoscape.app.AbstractCyApp;
import org.cytoscape.app.CyAppAdapter;
import org.cytoscape.app.internal.exception.AppCopyException;
+import org.cytoscape.app.internal.manager.App.AppStatus;
import org.cytoscape.application.CyApplicationConfiguration;
/**
@@ -20,6 +22,14 @@
* also provides functionalities for installing and uninstalling apps.
*/
public class AppManager {
+ /** Installed apps are copied to this subdirectory under the local app
storage directory. */
+ private static final String INSTALLED_APPS_DIRECTORY_NAME = "Installed";
+
+ /** Uninstalled apps are copied to this subdirectory under the local
app storage directory. */
+ private static final String UNINSTALLED_APPS_DIRECTORY_NAME =
"Uninstalled";
+
+ /** The name of the key in the app jar's manifest file that indicates
the fully-qualified name
+ * of the class to instantiate upon app installation. */
private static final String APP_CLASS_TAG = "Cytoscape-App";
private Set<App> installedApps;
@@ -46,58 +56,133 @@
}
/**
- * Installs an app; first makes a copy of the app file and places it in
the directory used to hold all installed and uninstalled apps.
- * Then, the app is created by instancing its {@link AbstractCyApp}
class that implements.
+ * Attempts to install an app. Makes a copy of the app file and places
it in the directory
+ * used to hold all installed and uninstalled apps. Then, the app is
created by instancing
+ * its class that extends {@link AbstractCyApp}.
+ *
+ * Before the app is installed, it is checked if it contains valid
packaging by its isAppValidated() method.
+ * Apps that have not been validated are ignored.
+ *
* @param app The {@link App} object representing and providing
information about the app to install
* @throws AppCopyException If there was an IO-related error during the
copy operation that prevents the app from
* being successfully installed.
*/
public void installApp(App app) throws AppCopyException {
- File appFile = app.getAppFile();
+ // Check if the app has been verified to contain proper
packaging.
+ if (!app.isAppValidated()) {
+
+ // 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.
+ return;
+ }
- // Copy app to local storage directory using utilities provided
by the Apache Commons library.
+ // Attempt to copy the app to the directory for installed apps.
try {
- // Overwrites files with the same name.
- FileUtils.copyFileToDirectory(appFile, getAppPath());
+ // Uses Apache Commons library; overwrites files with
the same name.
+ FileUtils.copyFileToDirectory(app.getAppFile(), new
File(getInstalledAppsPath()));
+
+ // Update the app's path
+ String fileName = app.getAppFile().getName();
+ app.setAppFile(new File(getInstalledAppsPath() +
File.separator + fileName));
+
} catch (IOException e) {
throw new AppCopyException();
}
// TODO: Currently uses the CyAppAdapter's loader to load apps'
classes. Is there reason to use a different one?
- ClassLoader appClassLoader =
appAdapter.getClass().getClassLoader();
+ ClassLoader appClassLoader = new URLClassLoader(
+ new URL[]{app.getJarURL()},
appAdapter.getClass().getClassLoader());
+ String entryClassName = app.getEntryClassName();
+
+ // Attempt to load the class
Class<?> appEntryClass = null;
try {
- appEntryClass =
appClassLoader.loadClass(app.getEntryClassName());
+ appEntryClass =
appClassLoader.loadClass(entryClassName);
} catch (ClassNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+
+ throw new IllegalStateException("Class " +
entryClassName + " not found in URL: " + app.getJarURL());
}
+ // Attempt to obtain the constructor
Constructor<?> constructor = null;
try {
constructor =
appEntryClass.getConstructor(CyAppAdapter.class);
} catch (SecurityException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ throw new IllegalStateException("Access to the
constructor for " + appEntryClass + " denied.");
} catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ throw new IllegalStateException("Unable to find a
constructor for " + appEntryClass + " that takes a CyAppAdapter as its
argument.");
}
+ // Attempt to instantiate the app's class that extends
AbstractCyActivator.
+ Object appInstance = null;
try {
- Object object = constructor.newInstance(appAdapter);
+ appInstance = constructor.newInstance(appAdapter);
} catch (IllegalArgumentException e) {
+ throw new IllegalStateException("Illegal arguments
passed to the constructor for the app's entry class: " + e.getMessage());
} catch (InstantiationException e) {
+ throw new RuntimeException("Error instantiating the
class " + appEntryClass + ": " + e.getMessage());
} catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
} catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
}
+ // Keep a reference to the newly created instance
+ app.setAppInstance((AbstractCyApp) appInstance);
+ app.setStatus(AppStatus.INSTALLED);
+
installedApps.add(app);
}
+ /**
+ * Uninstalls an app. If it was located in the subdirectory containing
currently installed apps in the
+ * local storage directory, it will be moved to the subdirectory
containing currently uninstalled apps.
+ *
+ * The app will only be uninstalled if it is currently installed.
+ *
+ * @param app The app to be uninstalled.
+ */
+ public void uninstallApp(App app) {
+ // Check if the app is installed before attempting to uninstall.
+ if (app.getStatus() != AppStatus.INSTALLED) {
+ // If it is not installed, do not attempt to uninstall
it.
+ return;
+ }
+
+ // Check if the app is inside the directory containing
currently installed apps.
+ // If so, prepare to move it to the uninstalled directory.
+ File appParentDirectory = app.getAppFile().getParentFile();
+ try {
+ // Obtain the path of the "installed apps" subdirectory.
+ String uninstalledAppsPath = getUninstalledAppsPath();
+
+ if (appParentDirectory.getCanonicalPath().equals(
+ getInstalledAppsPath())) {
+
+ try {
+ // Use the Apache commons library to
move the file, overwriting an existing file if needed.
+
FileUtils.copyFileToDirectory(app.getAppFile(), new File(uninstalledAppsPath));
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to
copy file: " + e.getMessage());
+ }
+
+ // Delete the source file after the copy
operation
+ String fileName = app.getAppFile().getName();
+ app.getAppFile().delete();
+ app.setAppFile(new File(uninstalledAppsPath +
File.separator + fileName));
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to obtain path: " +
e.getMessage());
+ }
+ }
+
+ /**
+ * Return the set of all currently installed apps.
+ * @return
+ */
public Set<App> getInstalledApps() {
return installedApps;
}
@@ -106,8 +191,32 @@
* Return the path of the directory used to contain all apps.
* @return The path of the root directory containing all installed and
uninstalled apps.
*/
- private File getAppPath() {
+ private File getBaseAppPath() {
// TODO: At time of writing, CyApplicationConfiguration always
returns the home directory for directory location.
return
applicationConfiguration.getConfigurationDirectoryLocation();
}
+
+ /**
+ * Return the canonical path of the subdirectory in the local storage
directory containing installed apps.
+ * @return The canonical path of the subdirectory in the local storage
directory containing currently installed apps.
+ */
+ private String getInstalledAppsPath() {
+ try {
+ return getBaseAppPath().getCanonicalPath() +
File.separator + INSTALLED_APPS_DIRECTORY_NAME;
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to obtain canonical
path for installed apps directory: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Return the canonical path of the subdirectory in the local storage
directory containing uninstalled apps.
+ * @return The canonical path of the subdirectory in the local storage
directory containing uninstalled apps.
+ */
+ private String getUninstalledAppsPath() {
+ try {
+ return getBaseAppPath().getCanonicalPath() +
File.separator + UNINSTALLED_APPS_DIRECTORY_NAME;
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to obtain canonical
path for uninstalled apps directory: " + e.getMessage());
+ }
+ }
}
--
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.