use of org.cytoscape.app.internal.exception.AppParsingException in project cytoscape-impl by cytoscape.
the class AppManager method setupAlterationMonitor.
private void setupAlterationMonitor() {
// Set up the FileAlterationMonitor to install/uninstall apps when apps are moved in/out of the
// installed/uninstalled app directories
fileAlterationMonitor = new FileAlterationMonitor(2000L);
File installedAppsPath = new File(getInstalledAppsPath());
FileAlterationObserver installAlterationObserver = new FileAlterationObserver(installedAppsPath, new AppFileFilter(installedAppsPath), IOCase.SYSTEM);
final AppManager appManager = this;
// Listen for events on the "installed apps" folder
installAlterationObserver.addListener(new FileAlterationListenerAdaptor() {
@Override
public void onFileCreate(File file) {
App parsedApp = null;
try {
parsedApp = appParser.parseApp(file);
} catch (AppParsingException e) {
userLogger.error("Could not parse app from newly discovered file '" + file.getAbsolutePath() + "' :", e);
return;
}
boolean startApp = parsedApp.isCompatible(version);
if (!startApp) {
userLogger.error("Newly discovered app '" + parsedApp.getAppName() + "' is not compatible with the running version of Cytoscape (" + version + ").");
}
App registeredApp = null;
for (App app : apps) {
if (parsedApp.heuristicEquals(app)) {
registeredApp = app;
userLogger.warn("Newly discovered app '" + parsedApp.getAppName() + "' in file '" + parsedApp.getAppFile().getAbsolutePath() + "' is equal to an already registered app '" + registeredApp.getAppName() + "' in file '" + (registeredApp.getAppFile() == null ? "N/A" : registeredApp.getAppFile().getAbsolutePath()) + "'");
// Delete old file if it was still there
File oldFile = registeredApp.getAppFile();
if (oldFile != null && oldFile.exists() && !registeredApp.getAppFile().equals(parsedApp.getAppFile())) {
userLogger.info("Trying to delete the installed copy of app '" + registeredApp.getAppName() + "' in file '" + registeredApp.getAppFile().getAbsolutePath() + "' because another copy exists.");
FileUtils.deleteQuietly(oldFile);
}
// Update file reference to reflect file having been moved
registeredApp.setAppFile(file);
registeredApp.setStatus(AppStatus.INACTIVE);
} else if (parsedApp.isCompatible(version) && parsedApp.getAppName().equals(app.getAppName())) {
try {
if (!app.isDetached() && app.isCompatible(version)) {
if (compareApps(parsedApp, app) > 0) {
startApp = false;
userLogger.warn("Not starting newly discovered app '" + parsedApp.getAppName() + "' because a newer version is already loaded.");
} else {
app.unload(AppManager.this);
app.setStatus(AppStatus.INACTIVE);
userLogger.warn("Unloading app '" + app.getAppName() + "' because the newly discovered app '" + parsedApp.getAppName() + "' is a newer version.");
}
}
} catch (AppUnloadingException e) {
// TODO Auto-generated catch block
userLogger.warn("Failed to unload app " + app.getAppName(), e);
}
}
}
App app = null;
if (registeredApp == null) {
app = parsedApp;
apps.add(app);
} else {
app = registeredApp;
}
try {
if (startApp) {
app.load(appManager);
app.start(appManager);
app.setStatus(AppStatus.INSTALLED);
userLogger.info("Started newly discovered app '" + app.getAppName() + "'.");
}
} catch (AppLoadingException e) {
app.setStatus(AppStatus.FAILED_TO_LOAD);
userLogger.error("Failed to load app " + app.getAppName(), e);
} catch (AppStartupException e) {
app.setStatus(AppStatus.FAILED_TO_START);
userLogger.error("Failed to start app " + app.getAppName(), e);
}
fireAppsChangedEvent();
}
@Override
public void onFileChange(File file) {
// Can treat file replacements/changes as old file deleted, new file added
this.onFileDelete(file);
this.onFileCreate(file);
fireAppsChangedEvent();
}
@Override
public void onFileDelete(File file) {
// System.out.println(file + " on delete");
DebugHelper.print(this + " installObserverDelete", file.getAbsolutePath() + " deleted.");
App registeredApp = null;
for (App app : apps) {
if (file.equals(app.getAppFile())) {
app.setAppFile(null);
registeredApp = app;
break;
}
}
if (registeredApp == null)
return;
try {
registeredApp.unload(appManager);
registeredApp.setStatus(AppStatus.FILE_MOVED);
userLogger.info("Unloaded app '" + registeredApp.getAppName() + "', because its file is no longer available.");
} catch (AppUnloadingException e) {
userLogger.warn("Failed to unload app " + registeredApp.getAppName(), e);
}
// Do this so that we don't reload an old app when responding to change events
if (file.exists()) {
App parsedApp = null;
try {
parsedApp = appParser.parseApp(file);
} catch (AppParsingException e) {
return;
}
if (parsedApp.isCompatible(version) && registeredApp.getAppName().equalsIgnoreCase(parsedApp.getAppName()))
return;
}
App appToStart = null;
for (App app : apps) {
if (!app.isDetached() && app.isCompatible(version) && app.getAppName().equalsIgnoreCase(registeredApp.getAppName())) {
if (appToStart == null || compareApps(appToStart, app) > 0)
appToStart = app;
}
}
if (appToStart != null) {
try {
appToStart.load(appManager);
appToStart.start(appManager);
appToStart.setStatus(AppStatus.INSTALLED);
userLogger.info("Started app " + appToStart.getAppName() + " because a different version has been unloaded.");
} catch (AppLoadingException e) {
appToStart.setStatus(AppStatus.FAILED_TO_LOAD);
userLogger.error("Failed to load app " + appToStart.getAppName(), e);
} catch (AppStartupException e) {
appToStart.setStatus(AppStatus.FAILED_TO_START);
userLogger.error("Failed to start app " + appToStart.getAppName(), e);
}
}
fireAppsChangedEvent();
}
});
FileAlterationObserver disableAlterationObserver = new FileAlterationObserver(getDisabledAppsPath(), new AppFileFilter(new File(getDisabledAppsPath())), IOCase.SYSTEM);
// Listen for events on the "disabled apps" folder
disableAlterationObserver.addListener(new FileAlterationListenerAdaptor() {
@Override
public void onFileCreate(File file) {
App parsedApp = null;
try {
parsedApp = appParser.parseApp(file);
} catch (AppParsingException e) {
return;
}
DebugHelper.print(this + " disableObserver Create", parsedApp.getAppName() + " parsed");
App registeredApp = null;
for (App app : apps) {
if (parsedApp.heuristicEquals(app)) {
registeredApp = app;
// Delete old file if it was still there
// TODO: Possible rename from filename-2 to filename?
File oldFile = registeredApp.getAppFile();
if (oldFile != null && oldFile.exists() && !registeredApp.getAppFile().equals(parsedApp.getAppFile())) {
DebugHelper.print(this + " disableObserverCreate", registeredApp.getAppName() + " moved from " + registeredApp.getAppFile().getAbsolutePath() + " to " + parsedApp.getAppFile().getAbsolutePath() + ". deleting: " + oldFile);
FileUtils.deleteQuietly(oldFile);
}
// Update file reference to reflect file having been moved
registeredApp.setAppFile(file);
}
}
App app = null;
if (registeredApp == null) {
app = parsedApp;
apps.add(app);
} else {
app = registeredApp;
}
app.setStatus(AppStatus.DISABLED);
fireAppsChangedEvent();
// System.out.println(file + " on create");
}
@Override
public void onFileChange(File file) {
// Can treat file replacements/changes as old file deleted, new file added
this.onFileDelete(file);
this.onFileCreate(file);
fireAppsChangedEvent();
}
@Override
public void onFileDelete(File file) {
// System.out.println(file + " on delete");
DebugHelper.print(this + " disableObserverDelete", file.getAbsolutePath() + " deleted.");
for (App app : apps) {
// System.out.println("checking " + app.getAppFile().getAbsolutePath());
if (file.equals(app.getAppFile())) {
app.setAppFile(null);
app.setStatus(AppStatus.FILE_MOVED);
break;
}
}
fireAppsChangedEvent();
}
});
FileAlterationObserver uninstallAlterationObserver = new FileAlterationObserver(getUninstalledAppsPath(), new AppFileFilter(new File(getUninstalledAppsPath())), IOCase.SYSTEM);
// Listen for events on the "uninstalled apps" folder
uninstallAlterationObserver.addListener(new FileAlterationListenerAdaptor() {
@Override
public void onFileCreate(File file) {
App parsedApp = null;
try {
parsedApp = appParser.parseApp(file);
} catch (AppParsingException e) {
return;
}
DebugHelper.print(this + " uninstallObserverCreate", parsedApp.getAppName() + " parsed");
App registeredApp = null;
for (App app : apps) {
if (parsedApp.heuristicEquals(app)) {
registeredApp = app;
// Delete old file if it was still there
// TODO: Possible rename from filename-2 to filename?
File oldFile = registeredApp.getAppFile();
if (oldFile != null && oldFile.exists() && !registeredApp.getAppFile().equals(parsedApp.getAppFile())) {
DebugHelper.print(this + " uninstallObserverCreate", registeredApp.getAppName() + " moved from " + registeredApp.getAppFile().getAbsolutePath() + " to " + parsedApp.getAppFile().getAbsolutePath() + ". deleting: " + oldFile);
FileUtils.deleteQuietly(oldFile);
}
// Update file reference to reflect file having been moved
registeredApp.setAppFile(file);
}
}
App app = null;
if (registeredApp == null) {
app = parsedApp;
apps.add(app);
} else {
app = registeredApp;
}
app.setStatus(AppStatus.UNINSTALLED);
fireAppsChangedEvent();
// System.out.println(file + " on create");
}
@Override
public void onFileChange(File file) {
// Can treat file replacements/changes as old file deleted, new file added
this.onFileDelete(file);
this.onFileCreate(file);
fireAppsChangedEvent();
}
@Override
public void onFileDelete(File file) {
// System.out.println(file + " on delete");
DebugHelper.print(this + " uninstallObserverDelete", file.getAbsolutePath() + " deleted.");
for (App app : apps) {
// System.out.println("checking " + app.getAppFile().getAbsolutePath());
if (file.equals(app.getAppFile())) {
app.setAppFile(null);
app.setStatus(AppStatus.FILE_MOVED);
break;
}
}
fireAppsChangedEvent();
}
});
try {
installAlterationObserver.initialize();
fileAlterationMonitor.addObserver(installAlterationObserver);
disableAlterationObserver.initialize();
fileAlterationMonitor.addObserver(disableAlterationObserver);
uninstallAlterationObserver.initialize();
fileAlterationMonitor.addObserver(uninstallAlterationObserver);
fileAlterationMonitor.start();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
use of org.cytoscape.app.internal.exception.AppParsingException in project cytoscape-impl by cytoscape.
the class AppParser method parseApp.
/**
* Attempt to parse a given {@link File} object as an {@link App} object.
* @param file The file to use for parsing
* @return An {@link App} object representing the given file if parsing was successful
* @throws AppParsingException If there was an error during parsing, such as missing data from the manifest file
*/
public App parseApp(File file) throws AppParsingException {
App parsedApp = new SimpleApp();
DebugHelper.print("Parsing: " + file.getPath());
if (!file.exists()) {
throw new AppParsingException("No file with path: " + file.getAbsolutePath());
}
if (!file.isFile()) {
throw new AppParsingException("The given file, " + file + ", is not a file.");
}
// Attempt to parse the file as a jar file
JarFile jarFile = null;
try {
jarFile = new JarFile(file);
} catch (IOException e) {
throw new AppParsingException("Error parsing given file as a jar file: " + e.getMessage());
}
boolean bundleApp = false;
boolean xmlParseFailed = false;
// Treat the jar as an OSGi bundle if OSGi metadata is found
boolean osgiMetadataFound = false;
// Check if a manifest that contains OSGi metadata is present
try {
Manifest osgiManifest = jarFile.getManifest();
if (osgiManifest != null) {
if (osgiManifest.getMainAttributes().getValue("Bundle-SymbolicName") != null) {
osgiMetadataFound = true;
}
}
} catch (IOException e) {
}
if (osgiMetadataFound) {
bundleApp = true;
parsedApp = new BundleApp();
}
// Attempt to obtain manifest file from jar
Manifest manifest = null;
try {
manifest = jarFile.getManifest();
} catch (IOException e) {
throw new AppParsingException("Error obtaining manifest from app jar", e);
} finally {
try {
jarFile.close();
} catch (IOException e) {
throw new AppParsingException("Error closing file", e);
}
}
// Make sure the getManifest() call didn't return null
if (manifest == null) {
throw new AppParsingException("No manifest was found in the jar file.");
}
// Bundle apps are instantiated by OSGi using their activator classes
String entryClassName = null;
if (!bundleApp) {
// Obtain the fully-qualified name of the class to instantiate upon app installation
entryClassName = manifest.getMainAttributes().getValue(APP_CLASS_TAG);
if (entryClassName == null || entryClassName.trim().length() == 0) {
throw new AppParsingException("Jar is missing value for entry " + APP_CLASS_TAG + " in its manifest file.");
}
} else {
// Obtain the fully-qualified name of the class to instantiate upon app installation
entryClassName = manifest.getMainAttributes().getValue("Bundle-Activator");
if (entryClassName == null || entryClassName.trim().length() == 0) {
throw new AppParsingException("Jar is missing value for entry Bundle-Activator");
}
}
// Obtain the human-readable name of the app
String readableName = null;
if (!bundleApp) {
readableName = manifest.getMainAttributes().getValue(APP_READABLE_NAME_TAG);
if (readableName == null || readableName.trim().length() == 0) {
throw new AppParsingException("Jar is missing value for entry " + APP_READABLE_NAME_TAG + " in its manifest file.");
}
} else {
readableName = manifest.getMainAttributes().getValue("Bundle-Name");
if (readableName == null || readableName.trim().length() == 0) {
readableName = manifest.getMainAttributes().getValue("Bundle-SymbolicName");
}
if (readableName == null || readableName.trim().length() == 0) {
throw new AppParsingException("Bundle jar manifest had no entry for Bundle-Name, and no entry for Bundle-SymbolicName");
}
}
// Obtain the version of the app, in major.minor.patch[-tag] format, ie. 3.0.0-SNAPSHOT or 1.2.3
String appVersion = null;
if (!bundleApp) {
appVersion = manifest.getMainAttributes().getValue(APP_VERSION_TAG);
if (appVersion == null || appVersion.trim().length() == 0) {
throw new AppParsingException("Jar is missing value for entry " + APP_VERSION_TAG + " in its manifiest file.");
} else if (!APP_VERSION_TAG_REGEX.matcher(appVersion).matches()) {
throw new AppParsingException("The app version specified in its manifest file under the key " + APP_VERSION_TAG + " was found to not match the format major.minor[.patch][-tag], eg. 2.1, 2.1-test, 3.0.0 or 3.0.0-SNAPSHOT");
}
} else {
appVersion = manifest.getMainAttributes().getValue("Bundle-Version");
if (appVersion == null || appVersion.trim().length() == 0) {
// For now, while it hasn't been decided, accept values for Cytoscape-App-Version if Bundle-Version is not found
appVersion = manifest.getMainAttributes().getValue(APP_VERSION_TAG);
if (appVersion == null || appVersion.trim().length() == 0) {
throw new AppParsingException("Bundle jar manifest has no entry for Bundle-Version");
}
}
}
String compatibleVersions = null;
if (bundleApp) {
compatibleVersions = manifest.getMainAttributes().getValue("Import-Package");
if (compatibleVersions == null || compatibleVersions.trim().length() == 0) {
throw new AppParsingException("Jar is missing value for entry Import-Package in its manifest file.");
}
} else {
compatibleVersions = manifest.getMainAttributes().getValue(APP_COMPATIBLE_TAG);
if (compatibleVersions == null || compatibleVersions.trim().length() == 0) {
// For now, accept the deprecated field Cytoscape-App-Works-With if the official field was not found
compatibleVersions = manifest.getMainAttributes().getValue("Cytoscape-App-Works-With");
}
if (compatibleVersions == null || compatibleVersions.trim().length() == 0) {
throw new AppParsingException("Jar is missing value for entry " + APP_COMPATIBLE_TAG + " in its manifest file.");
} else if (!compatibleVersions.matches(APP_COMPATIBLE_TAG_REGEX)) {
throw new AppParsingException("The known compatible versions of Cytoscape specified in the manifest under the" + " key " + APP_COMPATIBLE_TAG + " does not match the form of a comma-delimited list of versions of the form" + " major[.minor] (eg. 1 or 1.0) with variable whitespace around versions");
}
}
List<App.Dependency> deps = null;
final String depsStr = manifest.getMainAttributes().getValue("Cytoscape-App-Dependencies");
if (depsStr != null && depsStr.trim().length() != 0) {
deps = new ArrayList<App.Dependency>();
final String[] depsPieces = splitSmart(',', depsStr);
for (final String depPiece : depsPieces) {
final String[] depPieces = splitSmart(';', depPiece);
if (depPieces.length < 2)
throw new AppParsingException("Each dependency must have a name and version");
deps.add(new App.Dependency(depPieces[0], depPieces[1]));
}
}
String fileHash;
try {
fileHash = getChecksum(file);
parsedApp.setSha512Checksum(fileHash);
} catch (ChecksumException e) {
parsedApp.setSha512Checksum(null);
}
parsedApp.setAppFile(file);
parsedApp.setAppName(readableName);
parsedApp.setEntryClassName(entryClassName);
parsedApp.setVersion(appVersion);
parsedApp.setCompatibleVersions(compatibleVersions);
parsedApp.setAppValidated(true);
parsedApp.setDependencies(deps);
return parsedApp;
}
use of org.cytoscape.app.internal.exception.AppParsingException in project cytoscape-impl by cytoscape.
the class AppManager method obtainAppsFromDirectory.
/**
* Obtain a set of {@link App} objects through attempting to parse files found in the first level of the given directory.
* @param directory The directory used to parse {@link App} objects
* @return A set of all {@link App} objects that were successfully parsed from files in the given directory
*/
private Set<App> obtainAppsFromDirectory(File directory, boolean isBundled) {
// Obtain all files in the given directory with supported extensions, perform a non-recursive search
Collection<File> files = FileUtils.listFiles(directory, APP_EXTENSIONS, false);
Set<App> parsedApps = new HashSet<App>();
App app;
for (File file : files) {
app = null;
try {
app = appParser.parseApp(file);
app.setBundledApp(isBundled);
} catch (AppParsingException e) {
app = null;
} finally {
if (app != null) {
parsedApps.add(app);
DebugHelper.print("App parsed: " + app);
}
}
}
return parsedApps;
}
Aggregations