taverna-dependency-activity
Project: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/commit/a5d4f899 Tree: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/tree/a5d4f899 Diff: http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/diff/a5d4f899 Branch: refs/heads/master Commit: a5d4f8994853fd6716d2f80886d5c444c450e3ef Parents: eaa15e2 Author: Stian Soiland-Reyes <[email protected]> Authored: Fri Mar 6 16:04:55 2015 +0000 Committer: Stian Soiland-Reyes <[email protected]> Committed: Fri Mar 6 16:04:55 2015 +0000 ---------------------------------------------------------------------- .gitignore | 23 - .travis.yml | 1 - README.md | 3 - pom.xml | 59 --- .../AbstractAsynchronousDependencyActivity.java | 445 ------------------- .../DependencyActivityConfigurationBean.java | 123 ----- .../dependencyactivity/NewArtifactDialog.java | 207 --------- src/main/resources/schema.json | 25 -- taverna-dependency-activity/pom.xml | 59 +++ .../AbstractAsynchronousDependencyActivity.java | 445 +++++++++++++++++++ .../DependencyActivityConfigurationBean.java | 123 +++++ .../dependencyactivity/NewArtifactDialog.java | 207 +++++++++ .../src/main/resources/schema.json | 25 ++ 13 files changed, 859 insertions(+), 886 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/.gitignore ---------------------------------------------------------------------- diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 6d2ce9e..0000000 --- a/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# ignore project files # -.classpath -.project -.settings/ -catalog-v001.xml -# ignore target files # -target/ -bin/ -build/ -dist/ -apidoc/ -*.swp - -# ignore svn files if there -.svn - -# ignore log files # -*.log -/logs/* -*/logs/* - - - http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/.travis.yml ---------------------------------------------------------------------- diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index dff5f3a..0000000 --- a/.travis.yml +++ /dev/null @@ -1 +0,0 @@ -language: java http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/README.md ---------------------------------------------------------------------- diff --git a/README.md b/README.md deleted file mode 100644 index abb8c19..0000000 --- a/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Taverna Workflow system Dependency Activity: data model and execution implementation - -This code was previously hosted at http://taverna.googlecode.com/svn/taverna/engine/net.sf.taverna.t2.activities/ http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml deleted file mode 100644 index 1c138d0..0000000 --- a/pom.xml +++ /dev/null @@ -1,59 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <parent> - <groupId>net.sf.taverna</groupId> - <artifactId>taverna-parent</artifactId> - <version>3.0.1-SNAPSHOT</version> - </parent> - <groupId>net.sf.taverna.t2.activities</groupId> - <artifactId>dependency-activity</artifactId> - <packaging>bundle</packaging> - <name>Taverna 2 Activity with Dependencies</name> - <version>2.0.1-SNAPSHOT</version> - <dependencies> - <dependency> - <groupId>net.sf.taverna.t2.core</groupId> - <artifactId>workflowmodel-api</artifactId> - <version>${t2.core.version}</version> - </dependency> - <dependency> - <groupId>uk.org.taverna.configuration</groupId> - <artifactId>taverna-app-configuration-api</artifactId> - <version>${taverna.configuration.version}</version> - </dependency> - <dependency> - <groupId>com.fasterxml.jackson.core</groupId> - <artifactId>jackson-databind</artifactId> - <version>${jackson-databind.version}</version> - </dependency> - </dependencies> - <repositories> - <repository> - <releases /> - <snapshots> - <enabled>false</enabled> - </snapshots> - <id>mygrid-repository</id> - <name>myGrid Repository</name> - <url>http://www.mygrid.org.uk/maven/repository</url> - </repository> - <repository> - <releases> - <enabled>false</enabled> - </releases> - <snapshots /> - <id>mygrid-snapshot-repository</id> - <name>myGrid Snapshot Repository</name> - <url>http://www.mygrid.org.uk/maven/snapshot-repository</url> - </repository> - </repositories> - <scm> - <connection>scm:git:https://github.com/taverna/taverna-dependency-activity.git</connection> - <developerConnection>scm:git:ssh://[email protected]:taverna/taverna-dependency-activity.git</developerConnection> - <url>https://github.com/taverna/taverna-dependency-activity</url> - <tag>HEAD</tag> - </scm> - -</project> - http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/AbstractAsynchronousDependencyActivity.java ---------------------------------------------------------------------- diff --git a/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/AbstractAsynchronousDependencyActivity.java b/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/AbstractAsynchronousDependencyActivity.java deleted file mode 100644 index e2d5143..0000000 --- a/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/AbstractAsynchronousDependencyActivity.java +++ /dev/null @@ -1,445 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.activities.dependencyactivity; - -import java.io.File; -import java.io.FilenameFilter; -import java.lang.ref.WeakReference; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.HashSet; -import java.util.WeakHashMap; - -import net.sf.taverna.t2.facade.WorkflowInstanceFacade; -import net.sf.taverna.t2.workflowmodel.Dataflow; -import net.sf.taverna.t2.workflowmodel.Processor; -import net.sf.taverna.t2.workflowmodel.processor.activity.AbstractAsynchronousActivity; -import net.sf.taverna.t2.workflowmodel.processor.activity.Activity; -import net.sf.taverna.t2.workflowmodel.processor.activity.NestedDataflow; - -import org.apache.log4j.Logger; - -import uk.org.taverna.configuration.app.ApplicationConfiguration; - -import com.fasterxml.jackson.databind.JsonNode; - -/** - * A parent abstract class for activities that require dependency management, such as - * API Consumer and Beanshell. Defines dependencies on local JAR files - * and Raven artifacts. - * - * @author Alex Nenadic - * @author Tom Oinn - * @author Stian Soiland-Reyes - */ -public abstract class AbstractAsynchronousDependencyActivity extends AbstractAsynchronousActivity<JsonNode> { - - private static final String LOCAL_JARS = "Local jars"; - - private static final String ARTIFACTS = "Artifacts"; - - private static Logger logger = Logger.getLogger(AbstractAsynchronousDependencyActivity.class); - - /** - * For persisting class loaders across a whole workflow run (when classloader sharing - * is set to 'workflow'). The key in the map is the workflow run ID and we are using - * a WeakHashMap so we don't keep up references to classloaders of old workflow runs. - */ - private static WeakHashMap<String, ClassLoader> workflowClassLoaders = - new WeakHashMap<String, ClassLoader>(); - - /** - * System classloader, in case when classloader sharing is set to 'system'. - */ - private static ClassLoader systemClassLoader = null; - - /** - * Classloader to be used for 'executing' this activity, depending on the activity's - * class loader sharing policy. - */ - protected ClassLoader classLoader = null; - - /** - * The location of the <code>lib</code> directory in TAVERNA_HOME, - * where local JAR files the activity depends on should be located. - */ - public File libDir; - - /** - * Different ways to share a class loader among activities: - * - * <dl> - * <dt>workflow</dt> - * <dd>Same classloader for all activities using the <code>workflow</code> classloader sharing policy</dd> - * <dt>system</dt> - * <dd>System classloader</dd> - * </dl> - * - */ - public static enum ClassLoaderSharing { - workflow, system; - public static final ClassLoaderSharing DEFAULT = workflow; - public static ClassLoaderSharing fromString(String str) { - if (str == null || str.isEmpty()) { - return DEFAULT; - } - return valueOf(str.toLowerCase()); - } - } - - public AbstractAsynchronousDependencyActivity(ApplicationConfiguration applicationConfiguration) { - if (applicationConfiguration != null) { - libDir = new File(applicationConfiguration.getApplicationHomeDir(), "lib"); - } - } - - /** - * Finds or constructs the classloader. The classloader depends on the - * current classloader sharing policy as defined by {@link #ClassLoaderSharing}. - * <p> - * If the classloader sharing is {@link ClassLoaderSharing#workflow}, a - * common classloader will be used for the whole workflow for all activities - * with the same (i.e. {@link ClassLoaderSharing#workflow}) policy. - * The dependencies will be constructed as union of local and artifact dependencies - * of all 'workflow' classloader sharing activities at the point of the first - * call to {@link #getClassLoader()}. - * <p> - * If the classloader sharing is {@link ClassLoaderSharing#system}, the - * system classloader will be used. Note that both local and artifact dependencies - * configured on the activity will be ignored. Local dependencies can be set by - * using <code>-classpath</code> when starting the workbench. - * This is useful in combination with JNI based libraries, which would also - * require <code>-Djava.library.path</code> and possibly the operating - * system's PATH / LD_LIBRARY_PATH / DYLD_LIBRARY_PATH environment variable. - * @param classLoaderSharing - * - * @return A new or existing {@link ClassLoader} according to the - * classloader sharing policy - */ - protected ClassLoader findClassLoader(JsonNode json, String workflowRunID) throws RuntimeException{ - ClassLoaderSharing classLoaderSharing; - if (json.has("classLoaderSharing")) { - classLoaderSharing = ClassLoaderSharing.fromString(json.get("classLoaderSharing").textValue()); - } else { - classLoaderSharing = ClassLoaderSharing.workflow; - } - - if (classLoaderSharing == ClassLoaderSharing.workflow) { - synchronized (workflowClassLoaders) { - ClassLoader cl = workflowClassLoaders.get(workflowRunID); - if (cl == null) { - cl = makeClassLoader(json, workflowRunID); - workflowClassLoaders.put(workflowRunID, cl); - } - return cl; - } - } - if (classLoaderSharing == ClassLoaderSharing.system) { -// if (systemClassLoader == null) -// systemClassLoader = PreLauncher.getInstance().getLaunchingClassLoader(); - -// if (systemClassLoader instanceof BootstrapClassLoader){ -// // Add local and artifact dependencies to the classloader -// updateBootstrapClassLoader( -// (BootstrapClassLoader) systemClassLoader, -// configurationBean, workflowRunID); -// return systemClassLoader; -// } -// else{ - // Local dependencies will have to be set with the -classpath option - // We cannot have artifact dependencies in this case - String message = "System classloader is not Taverna's BootstrapClassLoader, so local dependencies " + - "have to defined with -classpath. Artifact dependencies are ignored completely."; - logger.warn(message); - return systemClassLoader; -// } - } - String message = "Unknown classloader sharing policy named '"+ classLoaderSharing+ "' for " + this.getClass(); - logger.error(message); - throw new RuntimeException(message); - } - - /** - * Constructs a classloader capable of finding both local jar and artifact dependencies. - * Called when classloader sharing policy is set to 'workflow'. - * - * @return A {@link ClassLoader} capable of accessing all the dependencies (both local jar and artifact) - */ - private ClassLoader makeClassLoader(JsonNode json, String workflowID) { - // Find all artifact dependencies -// HashSet<URL> urls = findDependencies(ARTIFACTS, configurationBean, workflowID); - - // Add all local jar dependencies - HashSet<URL> urls = findDependencies(LOCAL_JARS, json, workflowID); - - // Create the classloader capable of loading both local jar and artifact dependencies - ClassLoader parent = this.getClass().getClassLoader(); // this will be a LocalArtifactClassLoader - - return new URLClassLoader(urls.toArray(new URL[0]), parent) { - - // For finding native libraries that have to be stored in TAVERNA_HOME/lib - @Override - protected String findLibrary(String libname) { - String filename = System.mapLibraryName(libname); - File libraryFile = new File(libDir, filename); - if (libraryFile.isFile()) { - logger.info("Found library " + libname + ": " + libraryFile.getAbsolutePath()); - return libraryFile.getAbsolutePath(); - } - return super.findLibrary(libname); - } - }; - } - - /** - * Adds local or artifact dependencies identified by {@link #findDependencies()} to the - * {@link BootstrapClassLoader} system classloader. - * Called when classloader sharing policy is set to 'system'. - * - * @param loader The augmented BootstrapClassLoader system classloader - */ -// private void updateBootstrapClassLoader(BootstrapClassLoader loader, -// DependencyActivityConfigurationBean configurationBean, -// String workflowRunID) { -// -// HashSet<URL> depsURLs = new HashSet<URL>(); -// depsURLs.addAll(findDependencies(LOCAL_JARS, configurationBean, workflowRunID)); -// depsURLs.addAll(findDependencies(ARTIFACTS, configurationBean, workflowRunID)); -// -// Set<URL> exists = new HashSet<URL>(Arrays.asList(loader.getURLs())); -// for (URL url : depsURLs) { -// if (exists.contains(url)) { -// continue; -// } -// logger.info("Registering with system classloader: " + url); -// loader.addURL(url); -// exists.add(url); -// } -// } - - /** - * Finds either local jar or artifact dependencies' URLs for the given classloader - * sharing policy (passed inside configuration bean) and a workflowRunID (used to - * retrieve the workflow) that will be added to this activity classloader's list of URLs. - */ - private HashSet<URL> findDependencies(String dependencyType, JsonNode json, String workflowRunID) { - ClassLoaderSharing classLoaderSharing; - if (json.has("classLoaderSharing")) { - classLoaderSharing = ClassLoaderSharing.fromString(json.get("classLoaderSharing").textValue()); - } else { - classLoaderSharing = ClassLoaderSharing.workflow; - } - // Get the WorkflowInstanceFacade which contains the current workflow - WeakReference<WorkflowInstanceFacade> wfFacadeRef = WorkflowInstanceFacade.workflowRunFacades.get(workflowRunID); - WorkflowInstanceFacade wfFacade = null; - if (wfFacadeRef != null) { - wfFacade = wfFacadeRef.get(); - } - Dataflow wf = null; - if (wfFacade != null) { - wf = wfFacade.getDataflow(); - } - - // Files of dependencies for all activities in the workflow that share the classloading policy - HashSet<File> dependencies = new HashSet<File>(); - // Urls of all dependencies - HashSet<URL> dependenciesURLs = new HashSet<URL>(); - - if (wf != null){ - // Merge in dependencies from all activities that have the same classloader-sharing - // as this activity - for (Processor proc : wf.getProcessors()) { - // Nested workflow case - if (!proc.getActivityList().isEmpty() && proc.getActivityList().get(0) instanceof NestedDataflow){ - // Get the nested workflow - Dataflow nestedWorkflow = ((NestedDataflow) proc.getActivityList().get(0)).getNestedDataflow(); - dependenciesURLs.addAll(findNestedDependencies(dependencyType, json, nestedWorkflow)); - } - else{ // Not nested - go through all of the processor's activities - Activity<?> activity = proc.getActivityList().get(0); - if (activity instanceof AbstractAsynchronousDependencyActivity){ - AbstractAsynchronousDependencyActivity dependencyActivity = (AbstractAsynchronousDependencyActivity) activity; -// if (dependencyType.equals(LOCAL_JARS)){ - // Collect the files of all found local dependencies - if (dependencyActivity.getConfiguration().has("localDependency")) { - for (JsonNode jar : dependencyActivity.getConfiguration().get("localDependency")) { - try { - dependencies.add(new File(libDir, jar.textValue())); - } catch (Exception ex) { - logger.warn("Invalid URL for " + jar, ex); - continue; - } - } - } -// } else if (dependencyType.equals(ARTIFACTS) && this.getClass().getClassLoader() instanceof LocalArtifactClassLoader){ -// LocalArtifactClassLoader cl = (LocalArtifactClassLoader) this.getClass().getClassLoader(); // this class is always loaded with LocalArtifactClassLoader -// // Get the LocalReposotpry capable of finding artifact jar files -// LocalRepository rep = (LocalRepository) cl.getRepository(); -// for (BasicArtifact art : ((DependencyActivityConfigurationBean) activity -// .getConfiguration()) -// .getArtifactDependencies()){ -// dependencies.add(rep.jarFile(art)); -// } -// } - } - } - } - } else { // Just add dependencies for this activity since we can't get hold of the whole workflow -// if (dependencyType.equals(LOCAL_JARS)){ - if (json.has("localDependency")) { - for (JsonNode jar : json.get("localDependency")) { - try { - dependencies.add(new File(libDir, jar.textValue())); - } catch (Exception ex) { - logger.warn("Invalid URL for " + jar, ex); - continue; - } - } - } -// } -// else if (dependencyType.equals(ARTIFACTS)){ -// if (this.getClass().getClassLoader() instanceof LocalArtifactClassLoader){ // This should normally be the case -// LocalArtifactClassLoader cl = (LocalArtifactClassLoader)this.getClass().getClassLoader(); -// LocalRepository rep = (LocalRepository)cl.getRepository(); -// if (rep != null){ -// for (BasicArtifact art : configurationBean.getArtifactDependencies()){ -// dependencies.add(rep.jarFile(art)); -// } -// } -// } -// else{ -// // Tests will not be loaded using the LocalArtifactClassLoader as athey are loaded -// // outside Raven so there is nothing we can do about this - some tests -// // with dependencies will probably fail -// } -// } - } - - // Collect the URLs of all found dependencies - for (File file: dependencies){ - try{ - dependenciesURLs.add(file.toURI().toURL()); - } - catch(Exception ex){ - logger.warn("Invalid URL for " + file.getAbsolutePath(), ex); - continue; - } - } - return dependenciesURLs; - } - - /** - * Finds dependencies for a nested workflow. - */ - private HashSet<URL> findNestedDependencies(String dependencyType, JsonNode json, Dataflow nestedWorkflow) { - ClassLoaderSharing classLoaderSharing; - if (json.has("classLoaderSharing")) { - classLoaderSharing = ClassLoaderSharing.fromString(json.get("classLoaderSharing").textValue()); - } else { - classLoaderSharing = ClassLoaderSharing.workflow; - } - - // Files of dependencies for all activities in the nested workflow that share the classloading policy - HashSet<File> dependencies = new HashSet<File>(); - // Urls of all dependencies - HashSet<URL> dependenciesURLs = new HashSet<URL>(); - - for (Processor proc : nestedWorkflow.getProcessors()) { - // Another nested workflow - if (!proc.getActivityList().isEmpty() && proc.getActivityList().get(0) instanceof NestedDataflow){ - // Get the nested workflow - Dataflow nestedNestedWorkflow = ((NestedDataflow) proc.getActivityList().get(0)).getNestedDataflow(); - dependenciesURLs.addAll(findNestedDependencies(dependencyType, json, nestedNestedWorkflow)); - } - else{ // Not nested - go through all of the processor's activities - Activity<?> activity = proc.getActivityList().get(0); - if (activity instanceof AbstractAsynchronousDependencyActivity){ - AbstractAsynchronousDependencyActivity dependencyActivity = (AbstractAsynchronousDependencyActivity) activity; -// if (dependencyType.equals(LOCAL_JARS)){ - // Collect the files of all found local dependencies - if (dependencyActivity.getConfiguration().has("localDependency")) { - for (JsonNode jar : dependencyActivity.getConfiguration().get("localDependency")) { - try { - dependencies.add(new File(libDir, jar.textValue())); - } catch (Exception ex) { - logger.warn("Invalid URL for " + jar, ex); - continue; - } - } - } -// } else if (dependencyType.equals(ARTIFACTS) && this.getClass().getClassLoader() instanceof LocalArtifactClassLoader){ -// LocalArtifactClassLoader cl = (LocalArtifactClassLoader) this.getClass().getClassLoader(); // this class is always loaded with LocalArtifactClassLoader -// LocalRepository rep = (LocalRepository) cl.getRepository(); -// for (BasicArtifact art : ((DependencyActivityConfigurationBean) activity -// .getConfiguration()) -// .getArtifactDependencies()){ -// dependencies.add(rep.jarFile(art)); -// } -// } - } - } - } - - // Collect the URLs of all found dependencies - for (File file: dependencies){ - try{ - dependenciesURLs.add(file.toURI().toURL()); - } - catch(Exception ex){ - logger.warn("Invalid URL for " + file.getAbsolutePath(), ex); - continue; - } - } - return dependenciesURLs; - } - - /** - * File filter. - */ - public static class FileExtFilter implements FilenameFilter { - - String ext = null; - - public FileExtFilter(String ext) { - this.ext = ext; - } - - public boolean accept(File dir, String name) { - return name.endsWith(ext); - } - } - - /** - * @param classLoader the classLoader to set - */ - public void setClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - /** - * @return the classLoader - */ - public ClassLoader getClassLoader() { - return classLoader; - } -} - - http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/DependencyActivityConfigurationBean.java ---------------------------------------------------------------------- diff --git a/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/DependencyActivityConfigurationBean.java b/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/DependencyActivityConfigurationBean.java deleted file mode 100644 index afe75e2..0000000 --- a/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/DependencyActivityConfigurationBean.java +++ /dev/null @@ -1,123 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.activities.dependencyactivity; - -import java.util.LinkedHashSet; - -import net.sf.taverna.t2.activities.dependencyactivity.AbstractAsynchronousDependencyActivity.ClassLoaderSharing; -import net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityPortsDefinitionBean; -import net.sf.taverna.t2.workflowmodel.processor.config.ConfigurationBean; -import net.sf.taverna.t2.workflowmodel.processor.config.ConfigurationProperty; - -/** - * Parent configuration bean for activities that have local JAR, - * such as API Consumer and Beanshell activity. - * - * @author Alex Nenadic - * @author David Withers - */ -@ConfigurationBean(uri = "http://ns.taverna.org.uk/2010/activity/dependency#Config") -public class DependencyActivityConfigurationBean extends - ActivityPortsDefinitionBean { - - /** - * Activity's classloader sharing policy. - */ - private ClassLoaderSharing classLoaderSharing ;// = ClassLoaderSharing.workflow; - - /** - * Local dependencies, i.e. filenames of JARs the activity depends on. - * The files should be present in {@link AbstractAsynchronousActivityWithDependencies#libDir}, - * and the paths should be relative. - */ - private LinkedHashSet<String> localDependencies ;//= new LinkedHashSet<String>(); - - /** - * Constructor. - */ - public DependencyActivityConfigurationBean(){ - classLoaderSharing = ClassLoaderSharing.DEFAULT; - localDependencies = new LinkedHashSet<String>(); - } - - /** - * As XStream is not calling the default constructor during deserialization, - * we have to set the default values here. This method will be called by XStream - * after instantiating this bean. - */ - private Object readResolve(){ - if (classLoaderSharing == null) - classLoaderSharing = ClassLoaderSharing.DEFAULT; - - if (localDependencies == null) - localDependencies = new LinkedHashSet<String>(); - - return this; - } - - /** - * @param classLoaderSharing the classLoaderSharing to set - */ - @ConfigurationProperty(name = "classLoaderSharing", label = "ClassLoader Sharing Policy", required = false) - public void setClassLoaderSharing(ClassLoaderSharing classLoaderSharing) { - this.classLoaderSharing = classLoaderSharing; - } - - /** - * @return the classLoaderSharing - */ - public ClassLoaderSharing getClassLoaderSharing() { - return classLoaderSharing; - } - - /** - * @param localDependencies the localDependencies to set - */ - @ConfigurationProperty(name = "localDependency", label = "Local Dependencies", required = false) - public void setLocalDependencies(LinkedHashSet<String> localDependencies) { - this.localDependencies = localDependencies; - } - - /** - * @return the localDependencies - */ - public LinkedHashSet<String> getLocalDependencies() { - return localDependencies; - } - - /** - * Adds a dependency to the list of local dependencies. - * @param dep - */ - public void addLocalDependency(String dep){ - localDependencies.add(dep); - } - - /** - * Removes a dependency from the list of local dependencies. - * @param dep - */ - public void removeLocalDependency(String dep){ - localDependencies.remove(dep); - } - -} - http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/NewArtifactDialog.java ---------------------------------------------------------------------- diff --git a/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/NewArtifactDialog.java b/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/NewArtifactDialog.java deleted file mode 100644 index 9d04135..0000000 --- a/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/NewArtifactDialog.java +++ /dev/null @@ -1,207 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.activities.dependencyactivity; - -import java.awt.BorderLayout; -import java.awt.FlowLayout; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; - -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JTextField; -import javax.swing.border.EmptyBorder; - -/** - * Dialog used for entering an artifact. - * - * @author Alex Nenadic - */ -@SuppressWarnings("serial") -public class NewArtifactDialog - extends JDialog -{ - private JTextField jtfGroupID; - - private JTextField jtfArtifactID; - - private JTextField jtfVersion; - - /** Stores new group ID entered */ - private String groupID = null; - - /** Stores new artifact ID entered */ - private String artifactID = null; - - /** Stores new version entered */ - private String version = null; - - - /** - * Creates new NewArtifactDialog. - */ - public NewArtifactDialog(String sTitle, boolean bModal) - { - super(); - setTitle(sTitle); - setModal(bModal); - initComponents(); - } - - public String getGroupID() - { - return groupID; - } - - public String getArtifatcID() - { - return artifactID; - } - - public String getVersion() - { - return version; - } - - /** - * Initialise the dialog's GUI components. - */ - private void initComponents() - { - getContentPane().setLayout(new BorderLayout()); - - JLabel jlGroupID = new JLabel("Group ID:"); - JLabel jlArtifactID = new JLabel("Artifact ID:"); - JLabel jlVersion = new JLabel("Version"); - - jtfGroupID = new JTextField(15); - jtfArtifactID = new JTextField(15); - jtfVersion = new JTextField(15); - - JButton jbOK = new JButton("OK"); - jbOK.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent evt) - { - okPressed(); - } - }); - - JButton jbCancel = new JButton("Cancel"); - jbCancel.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent evt) - { - cancelPressed(); - } - }); - - JPanel jpPassword = new JPanel(new GridLayout(3, 2, 5, 5)); - jpPassword.add(jlGroupID); - jpPassword.add(jtfGroupID); - jpPassword.add(jlArtifactID); - jpPassword.add(jtfArtifactID); - jpPassword.add(jlVersion); - jpPassword.add(jtfVersion); - jpPassword.setBorder(new EmptyBorder(5, 5, 5, 5)); - - JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER)); - jpButtons.add(jbOK); - jpButtons.add(jbCancel); - - getContentPane().add(jpPassword, BorderLayout.CENTER); - getContentPane().add(jpButtons, BorderLayout.SOUTH); - - addWindowListener(new WindowAdapter() - { - public void windowClosing(WindowEvent evt) - { - closeDialog(); - } - }); - - setResizable(false); - - getRootPane().setDefaultButton(jbOK); - - pack(); - } - - private boolean checkFields() - { - groupID = jtfGroupID.getText(); - artifactID = jtfArtifactID.getText(); - version = jtfVersion.getText(); - - if ((!groupID.equals("")) && (!artifactID.equals("")) && (!version.equals(""))){ - return true; - } - else { - JOptionPane.showMessageDialog(this, - "Field(s) may not be empty", - "ERROR", - JOptionPane.ERROR_MESSAGE); - - return false; - } - } - - /** - * OK button pressed or otherwise activated. - */ - private void okPressed() - { - if (checkFields()) { - closeDialog(); - } - } - - /** - * Cancel button pressed or otherwise activated. - */ - private void cancelPressed() - { - // Set the fields to null as it might have changed in the meantime - // if user entered something previously - groupID = null; - artifactID = null; - version = null; - closeDialog(); - } - - /** - * Close the dialog. - */ - private void closeDialog() - { - setVisible(false); - dispose(); - } -} - - - http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/src/main/resources/schema.json ---------------------------------------------------------------------- diff --git a/src/main/resources/schema.json b/src/main/resources/schema.json deleted file mode 100644 index c30459f..0000000 --- a/src/main/resources/schema.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-03/schema#", - "id": "http://ns.taverna.org.uk/2010/activity/dependency.schema.json", - "title": "Dependency activity configuration", - "type": "object", - "properties": { - "@context": { - "description": "JSON-LD context for interpreting the configuration as RDF", - "required": true, - "enum": ["http://ns.taverna.org.uk/2010/activity/dependency.context.json"] - }, - "classLoaderSharing": { - "title": "ClassLoader Sharing Policy", - "description": "Policy for sharing class loaders across multiple beanshell activities", - "default": "workflow", - "enum": ["workflow", "system"] - }, - "localDependency": { - "title": "Local Dependencies", - "description": "Location of jar files to be added to the beanshell class loader", - "type": "array", - "items": { "type" : "string" } - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/taverna-dependency-activity/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-dependency-activity/pom.xml b/taverna-dependency-activity/pom.xml new file mode 100644 index 0000000..1c138d0 --- /dev/null +++ b/taverna-dependency-activity/pom.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>net.sf.taverna</groupId> + <artifactId>taverna-parent</artifactId> + <version>3.0.1-SNAPSHOT</version> + </parent> + <groupId>net.sf.taverna.t2.activities</groupId> + <artifactId>dependency-activity</artifactId> + <packaging>bundle</packaging> + <name>Taverna 2 Activity with Dependencies</name> + <version>2.0.1-SNAPSHOT</version> + <dependencies> + <dependency> + <groupId>net.sf.taverna.t2.core</groupId> + <artifactId>workflowmodel-api</artifactId> + <version>${t2.core.version}</version> + </dependency> + <dependency> + <groupId>uk.org.taverna.configuration</groupId> + <artifactId>taverna-app-configuration-api</artifactId> + <version>${taverna.configuration.version}</version> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + <version>${jackson-databind.version}</version> + </dependency> + </dependencies> + <repositories> + <repository> + <releases /> + <snapshots> + <enabled>false</enabled> + </snapshots> + <id>mygrid-repository</id> + <name>myGrid Repository</name> + <url>http://www.mygrid.org.uk/maven/repository</url> + </repository> + <repository> + <releases> + <enabled>false</enabled> + </releases> + <snapshots /> + <id>mygrid-snapshot-repository</id> + <name>myGrid Snapshot Repository</name> + <url>http://www.mygrid.org.uk/maven/snapshot-repository</url> + </repository> + </repositories> + <scm> + <connection>scm:git:https://github.com/taverna/taverna-dependency-activity.git</connection> + <developerConnection>scm:git:ssh://[email protected]:taverna/taverna-dependency-activity.git</developerConnection> + <url>https://github.com/taverna/taverna-dependency-activity</url> + <tag>HEAD</tag> + </scm> + +</project> + http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/AbstractAsynchronousDependencyActivity.java ---------------------------------------------------------------------- diff --git a/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/AbstractAsynchronousDependencyActivity.java b/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/AbstractAsynchronousDependencyActivity.java new file mode 100644 index 0000000..e2d5143 --- /dev/null +++ b/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/AbstractAsynchronousDependencyActivity.java @@ -0,0 +1,445 @@ +/******************************************************************************* + * Copyright (C) 2007 The University of Manchester + * + * Modifications to the initial code base are copyright of their + * respective authors, or their employers as appropriate. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + ******************************************************************************/ +package net.sf.taverna.t2.activities.dependencyactivity; + +import java.io.File; +import java.io.FilenameFilter; +import java.lang.ref.WeakReference; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.HashSet; +import java.util.WeakHashMap; + +import net.sf.taverna.t2.facade.WorkflowInstanceFacade; +import net.sf.taverna.t2.workflowmodel.Dataflow; +import net.sf.taverna.t2.workflowmodel.Processor; +import net.sf.taverna.t2.workflowmodel.processor.activity.AbstractAsynchronousActivity; +import net.sf.taverna.t2.workflowmodel.processor.activity.Activity; +import net.sf.taverna.t2.workflowmodel.processor.activity.NestedDataflow; + +import org.apache.log4j.Logger; + +import uk.org.taverna.configuration.app.ApplicationConfiguration; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * A parent abstract class for activities that require dependency management, such as + * API Consumer and Beanshell. Defines dependencies on local JAR files + * and Raven artifacts. + * + * @author Alex Nenadic + * @author Tom Oinn + * @author Stian Soiland-Reyes + */ +public abstract class AbstractAsynchronousDependencyActivity extends AbstractAsynchronousActivity<JsonNode> { + + private static final String LOCAL_JARS = "Local jars"; + + private static final String ARTIFACTS = "Artifacts"; + + private static Logger logger = Logger.getLogger(AbstractAsynchronousDependencyActivity.class); + + /** + * For persisting class loaders across a whole workflow run (when classloader sharing + * is set to 'workflow'). The key in the map is the workflow run ID and we are using + * a WeakHashMap so we don't keep up references to classloaders of old workflow runs. + */ + private static WeakHashMap<String, ClassLoader> workflowClassLoaders = + new WeakHashMap<String, ClassLoader>(); + + /** + * System classloader, in case when classloader sharing is set to 'system'. + */ + private static ClassLoader systemClassLoader = null; + + /** + * Classloader to be used for 'executing' this activity, depending on the activity's + * class loader sharing policy. + */ + protected ClassLoader classLoader = null; + + /** + * The location of the <code>lib</code> directory in TAVERNA_HOME, + * where local JAR files the activity depends on should be located. + */ + public File libDir; + + /** + * Different ways to share a class loader among activities: + * + * <dl> + * <dt>workflow</dt> + * <dd>Same classloader for all activities using the <code>workflow</code> classloader sharing policy</dd> + * <dt>system</dt> + * <dd>System classloader</dd> + * </dl> + * + */ + public static enum ClassLoaderSharing { + workflow, system; + public static final ClassLoaderSharing DEFAULT = workflow; + public static ClassLoaderSharing fromString(String str) { + if (str == null || str.isEmpty()) { + return DEFAULT; + } + return valueOf(str.toLowerCase()); + } + } + + public AbstractAsynchronousDependencyActivity(ApplicationConfiguration applicationConfiguration) { + if (applicationConfiguration != null) { + libDir = new File(applicationConfiguration.getApplicationHomeDir(), "lib"); + } + } + + /** + * Finds or constructs the classloader. The classloader depends on the + * current classloader sharing policy as defined by {@link #ClassLoaderSharing}. + * <p> + * If the classloader sharing is {@link ClassLoaderSharing#workflow}, a + * common classloader will be used for the whole workflow for all activities + * with the same (i.e. {@link ClassLoaderSharing#workflow}) policy. + * The dependencies will be constructed as union of local and artifact dependencies + * of all 'workflow' classloader sharing activities at the point of the first + * call to {@link #getClassLoader()}. + * <p> + * If the classloader sharing is {@link ClassLoaderSharing#system}, the + * system classloader will be used. Note that both local and artifact dependencies + * configured on the activity will be ignored. Local dependencies can be set by + * using <code>-classpath</code> when starting the workbench. + * This is useful in combination with JNI based libraries, which would also + * require <code>-Djava.library.path</code> and possibly the operating + * system's PATH / LD_LIBRARY_PATH / DYLD_LIBRARY_PATH environment variable. + * @param classLoaderSharing + * + * @return A new or existing {@link ClassLoader} according to the + * classloader sharing policy + */ + protected ClassLoader findClassLoader(JsonNode json, String workflowRunID) throws RuntimeException{ + ClassLoaderSharing classLoaderSharing; + if (json.has("classLoaderSharing")) { + classLoaderSharing = ClassLoaderSharing.fromString(json.get("classLoaderSharing").textValue()); + } else { + classLoaderSharing = ClassLoaderSharing.workflow; + } + + if (classLoaderSharing == ClassLoaderSharing.workflow) { + synchronized (workflowClassLoaders) { + ClassLoader cl = workflowClassLoaders.get(workflowRunID); + if (cl == null) { + cl = makeClassLoader(json, workflowRunID); + workflowClassLoaders.put(workflowRunID, cl); + } + return cl; + } + } + if (classLoaderSharing == ClassLoaderSharing.system) { +// if (systemClassLoader == null) +// systemClassLoader = PreLauncher.getInstance().getLaunchingClassLoader(); + +// if (systemClassLoader instanceof BootstrapClassLoader){ +// // Add local and artifact dependencies to the classloader +// updateBootstrapClassLoader( +// (BootstrapClassLoader) systemClassLoader, +// configurationBean, workflowRunID); +// return systemClassLoader; +// } +// else{ + // Local dependencies will have to be set with the -classpath option + // We cannot have artifact dependencies in this case + String message = "System classloader is not Taverna's BootstrapClassLoader, so local dependencies " + + "have to defined with -classpath. Artifact dependencies are ignored completely."; + logger.warn(message); + return systemClassLoader; +// } + } + String message = "Unknown classloader sharing policy named '"+ classLoaderSharing+ "' for " + this.getClass(); + logger.error(message); + throw new RuntimeException(message); + } + + /** + * Constructs a classloader capable of finding both local jar and artifact dependencies. + * Called when classloader sharing policy is set to 'workflow'. + * + * @return A {@link ClassLoader} capable of accessing all the dependencies (both local jar and artifact) + */ + private ClassLoader makeClassLoader(JsonNode json, String workflowID) { + // Find all artifact dependencies +// HashSet<URL> urls = findDependencies(ARTIFACTS, configurationBean, workflowID); + + // Add all local jar dependencies + HashSet<URL> urls = findDependencies(LOCAL_JARS, json, workflowID); + + // Create the classloader capable of loading both local jar and artifact dependencies + ClassLoader parent = this.getClass().getClassLoader(); // this will be a LocalArtifactClassLoader + + return new URLClassLoader(urls.toArray(new URL[0]), parent) { + + // For finding native libraries that have to be stored in TAVERNA_HOME/lib + @Override + protected String findLibrary(String libname) { + String filename = System.mapLibraryName(libname); + File libraryFile = new File(libDir, filename); + if (libraryFile.isFile()) { + logger.info("Found library " + libname + ": " + libraryFile.getAbsolutePath()); + return libraryFile.getAbsolutePath(); + } + return super.findLibrary(libname); + } + }; + } + + /** + * Adds local or artifact dependencies identified by {@link #findDependencies()} to the + * {@link BootstrapClassLoader} system classloader. + * Called when classloader sharing policy is set to 'system'. + * + * @param loader The augmented BootstrapClassLoader system classloader + */ +// private void updateBootstrapClassLoader(BootstrapClassLoader loader, +// DependencyActivityConfigurationBean configurationBean, +// String workflowRunID) { +// +// HashSet<URL> depsURLs = new HashSet<URL>(); +// depsURLs.addAll(findDependencies(LOCAL_JARS, configurationBean, workflowRunID)); +// depsURLs.addAll(findDependencies(ARTIFACTS, configurationBean, workflowRunID)); +// +// Set<URL> exists = new HashSet<URL>(Arrays.asList(loader.getURLs())); +// for (URL url : depsURLs) { +// if (exists.contains(url)) { +// continue; +// } +// logger.info("Registering with system classloader: " + url); +// loader.addURL(url); +// exists.add(url); +// } +// } + + /** + * Finds either local jar or artifact dependencies' URLs for the given classloader + * sharing policy (passed inside configuration bean) and a workflowRunID (used to + * retrieve the workflow) that will be added to this activity classloader's list of URLs. + */ + private HashSet<URL> findDependencies(String dependencyType, JsonNode json, String workflowRunID) { + ClassLoaderSharing classLoaderSharing; + if (json.has("classLoaderSharing")) { + classLoaderSharing = ClassLoaderSharing.fromString(json.get("classLoaderSharing").textValue()); + } else { + classLoaderSharing = ClassLoaderSharing.workflow; + } + // Get the WorkflowInstanceFacade which contains the current workflow + WeakReference<WorkflowInstanceFacade> wfFacadeRef = WorkflowInstanceFacade.workflowRunFacades.get(workflowRunID); + WorkflowInstanceFacade wfFacade = null; + if (wfFacadeRef != null) { + wfFacade = wfFacadeRef.get(); + } + Dataflow wf = null; + if (wfFacade != null) { + wf = wfFacade.getDataflow(); + } + + // Files of dependencies for all activities in the workflow that share the classloading policy + HashSet<File> dependencies = new HashSet<File>(); + // Urls of all dependencies + HashSet<URL> dependenciesURLs = new HashSet<URL>(); + + if (wf != null){ + // Merge in dependencies from all activities that have the same classloader-sharing + // as this activity + for (Processor proc : wf.getProcessors()) { + // Nested workflow case + if (!proc.getActivityList().isEmpty() && proc.getActivityList().get(0) instanceof NestedDataflow){ + // Get the nested workflow + Dataflow nestedWorkflow = ((NestedDataflow) proc.getActivityList().get(0)).getNestedDataflow(); + dependenciesURLs.addAll(findNestedDependencies(dependencyType, json, nestedWorkflow)); + } + else{ // Not nested - go through all of the processor's activities + Activity<?> activity = proc.getActivityList().get(0); + if (activity instanceof AbstractAsynchronousDependencyActivity){ + AbstractAsynchronousDependencyActivity dependencyActivity = (AbstractAsynchronousDependencyActivity) activity; +// if (dependencyType.equals(LOCAL_JARS)){ + // Collect the files of all found local dependencies + if (dependencyActivity.getConfiguration().has("localDependency")) { + for (JsonNode jar : dependencyActivity.getConfiguration().get("localDependency")) { + try { + dependencies.add(new File(libDir, jar.textValue())); + } catch (Exception ex) { + logger.warn("Invalid URL for " + jar, ex); + continue; + } + } + } +// } else if (dependencyType.equals(ARTIFACTS) && this.getClass().getClassLoader() instanceof LocalArtifactClassLoader){ +// LocalArtifactClassLoader cl = (LocalArtifactClassLoader) this.getClass().getClassLoader(); // this class is always loaded with LocalArtifactClassLoader +// // Get the LocalReposotpry capable of finding artifact jar files +// LocalRepository rep = (LocalRepository) cl.getRepository(); +// for (BasicArtifact art : ((DependencyActivityConfigurationBean) activity +// .getConfiguration()) +// .getArtifactDependencies()){ +// dependencies.add(rep.jarFile(art)); +// } +// } + } + } + } + } else { // Just add dependencies for this activity since we can't get hold of the whole workflow +// if (dependencyType.equals(LOCAL_JARS)){ + if (json.has("localDependency")) { + for (JsonNode jar : json.get("localDependency")) { + try { + dependencies.add(new File(libDir, jar.textValue())); + } catch (Exception ex) { + logger.warn("Invalid URL for " + jar, ex); + continue; + } + } + } +// } +// else if (dependencyType.equals(ARTIFACTS)){ +// if (this.getClass().getClassLoader() instanceof LocalArtifactClassLoader){ // This should normally be the case +// LocalArtifactClassLoader cl = (LocalArtifactClassLoader)this.getClass().getClassLoader(); +// LocalRepository rep = (LocalRepository)cl.getRepository(); +// if (rep != null){ +// for (BasicArtifact art : configurationBean.getArtifactDependencies()){ +// dependencies.add(rep.jarFile(art)); +// } +// } +// } +// else{ +// // Tests will not be loaded using the LocalArtifactClassLoader as athey are loaded +// // outside Raven so there is nothing we can do about this - some tests +// // with dependencies will probably fail +// } +// } + } + + // Collect the URLs of all found dependencies + for (File file: dependencies){ + try{ + dependenciesURLs.add(file.toURI().toURL()); + } + catch(Exception ex){ + logger.warn("Invalid URL for " + file.getAbsolutePath(), ex); + continue; + } + } + return dependenciesURLs; + } + + /** + * Finds dependencies for a nested workflow. + */ + private HashSet<URL> findNestedDependencies(String dependencyType, JsonNode json, Dataflow nestedWorkflow) { + ClassLoaderSharing classLoaderSharing; + if (json.has("classLoaderSharing")) { + classLoaderSharing = ClassLoaderSharing.fromString(json.get("classLoaderSharing").textValue()); + } else { + classLoaderSharing = ClassLoaderSharing.workflow; + } + + // Files of dependencies for all activities in the nested workflow that share the classloading policy + HashSet<File> dependencies = new HashSet<File>(); + // Urls of all dependencies + HashSet<URL> dependenciesURLs = new HashSet<URL>(); + + for (Processor proc : nestedWorkflow.getProcessors()) { + // Another nested workflow + if (!proc.getActivityList().isEmpty() && proc.getActivityList().get(0) instanceof NestedDataflow){ + // Get the nested workflow + Dataflow nestedNestedWorkflow = ((NestedDataflow) proc.getActivityList().get(0)).getNestedDataflow(); + dependenciesURLs.addAll(findNestedDependencies(dependencyType, json, nestedNestedWorkflow)); + } + else{ // Not nested - go through all of the processor's activities + Activity<?> activity = proc.getActivityList().get(0); + if (activity instanceof AbstractAsynchronousDependencyActivity){ + AbstractAsynchronousDependencyActivity dependencyActivity = (AbstractAsynchronousDependencyActivity) activity; +// if (dependencyType.equals(LOCAL_JARS)){ + // Collect the files of all found local dependencies + if (dependencyActivity.getConfiguration().has("localDependency")) { + for (JsonNode jar : dependencyActivity.getConfiguration().get("localDependency")) { + try { + dependencies.add(new File(libDir, jar.textValue())); + } catch (Exception ex) { + logger.warn("Invalid URL for " + jar, ex); + continue; + } + } + } +// } else if (dependencyType.equals(ARTIFACTS) && this.getClass().getClassLoader() instanceof LocalArtifactClassLoader){ +// LocalArtifactClassLoader cl = (LocalArtifactClassLoader) this.getClass().getClassLoader(); // this class is always loaded with LocalArtifactClassLoader +// LocalRepository rep = (LocalRepository) cl.getRepository(); +// for (BasicArtifact art : ((DependencyActivityConfigurationBean) activity +// .getConfiguration()) +// .getArtifactDependencies()){ +// dependencies.add(rep.jarFile(art)); +// } +// } + } + } + } + + // Collect the URLs of all found dependencies + for (File file: dependencies){ + try{ + dependenciesURLs.add(file.toURI().toURL()); + } + catch(Exception ex){ + logger.warn("Invalid URL for " + file.getAbsolutePath(), ex); + continue; + } + } + return dependenciesURLs; + } + + /** + * File filter. + */ + public static class FileExtFilter implements FilenameFilter { + + String ext = null; + + public FileExtFilter(String ext) { + this.ext = ext; + } + + public boolean accept(File dir, String name) { + return name.endsWith(ext); + } + } + + /** + * @param classLoader the classLoader to set + */ + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * @return the classLoader + */ + public ClassLoader getClassLoader() { + return classLoader; + } +} + + http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/DependencyActivityConfigurationBean.java ---------------------------------------------------------------------- diff --git a/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/DependencyActivityConfigurationBean.java b/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/DependencyActivityConfigurationBean.java new file mode 100644 index 0000000..afe75e2 --- /dev/null +++ b/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/DependencyActivityConfigurationBean.java @@ -0,0 +1,123 @@ +/******************************************************************************* + * Copyright (C) 2007 The University of Manchester + * + * Modifications to the initial code base are copyright of their + * respective authors, or their employers as appropriate. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + ******************************************************************************/ +package net.sf.taverna.t2.activities.dependencyactivity; + +import java.util.LinkedHashSet; + +import net.sf.taverna.t2.activities.dependencyactivity.AbstractAsynchronousDependencyActivity.ClassLoaderSharing; +import net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityPortsDefinitionBean; +import net.sf.taverna.t2.workflowmodel.processor.config.ConfigurationBean; +import net.sf.taverna.t2.workflowmodel.processor.config.ConfigurationProperty; + +/** + * Parent configuration bean for activities that have local JAR, + * such as API Consumer and Beanshell activity. + * + * @author Alex Nenadic + * @author David Withers + */ +@ConfigurationBean(uri = "http://ns.taverna.org.uk/2010/activity/dependency#Config") +public class DependencyActivityConfigurationBean extends + ActivityPortsDefinitionBean { + + /** + * Activity's classloader sharing policy. + */ + private ClassLoaderSharing classLoaderSharing ;// = ClassLoaderSharing.workflow; + + /** + * Local dependencies, i.e. filenames of JARs the activity depends on. + * The files should be present in {@link AbstractAsynchronousActivityWithDependencies#libDir}, + * and the paths should be relative. + */ + private LinkedHashSet<String> localDependencies ;//= new LinkedHashSet<String>(); + + /** + * Constructor. + */ + public DependencyActivityConfigurationBean(){ + classLoaderSharing = ClassLoaderSharing.DEFAULT; + localDependencies = new LinkedHashSet<String>(); + } + + /** + * As XStream is not calling the default constructor during deserialization, + * we have to set the default values here. This method will be called by XStream + * after instantiating this bean. + */ + private Object readResolve(){ + if (classLoaderSharing == null) + classLoaderSharing = ClassLoaderSharing.DEFAULT; + + if (localDependencies == null) + localDependencies = new LinkedHashSet<String>(); + + return this; + } + + /** + * @param classLoaderSharing the classLoaderSharing to set + */ + @ConfigurationProperty(name = "classLoaderSharing", label = "ClassLoader Sharing Policy", required = false) + public void setClassLoaderSharing(ClassLoaderSharing classLoaderSharing) { + this.classLoaderSharing = classLoaderSharing; + } + + /** + * @return the classLoaderSharing + */ + public ClassLoaderSharing getClassLoaderSharing() { + return classLoaderSharing; + } + + /** + * @param localDependencies the localDependencies to set + */ + @ConfigurationProperty(name = "localDependency", label = "Local Dependencies", required = false) + public void setLocalDependencies(LinkedHashSet<String> localDependencies) { + this.localDependencies = localDependencies; + } + + /** + * @return the localDependencies + */ + public LinkedHashSet<String> getLocalDependencies() { + return localDependencies; + } + + /** + * Adds a dependency to the list of local dependencies. + * @param dep + */ + public void addLocalDependency(String dep){ + localDependencies.add(dep); + } + + /** + * Removes a dependency from the list of local dependencies. + * @param dep + */ + public void removeLocalDependency(String dep){ + localDependencies.remove(dep); + } + +} + http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/NewArtifactDialog.java ---------------------------------------------------------------------- diff --git a/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/NewArtifactDialog.java b/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/NewArtifactDialog.java new file mode 100644 index 0000000..9d04135 --- /dev/null +++ b/taverna-dependency-activity/src/main/java/net/sf/taverna/t2/activities/dependencyactivity/NewArtifactDialog.java @@ -0,0 +1,207 @@ +/******************************************************************************* + * Copyright (C) 2007 The University of Manchester + * + * Modifications to the initial code base are copyright of their + * respective authors, or their employers as appropriate. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + ******************************************************************************/ +package net.sf.taverna.t2.activities.dependencyactivity; + +import java.awt.BorderLayout; +import java.awt.FlowLayout; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.border.EmptyBorder; + +/** + * Dialog used for entering an artifact. + * + * @author Alex Nenadic + */ +@SuppressWarnings("serial") +public class NewArtifactDialog + extends JDialog +{ + private JTextField jtfGroupID; + + private JTextField jtfArtifactID; + + private JTextField jtfVersion; + + /** Stores new group ID entered */ + private String groupID = null; + + /** Stores new artifact ID entered */ + private String artifactID = null; + + /** Stores new version entered */ + private String version = null; + + + /** + * Creates new NewArtifactDialog. + */ + public NewArtifactDialog(String sTitle, boolean bModal) + { + super(); + setTitle(sTitle); + setModal(bModal); + initComponents(); + } + + public String getGroupID() + { + return groupID; + } + + public String getArtifatcID() + { + return artifactID; + } + + public String getVersion() + { + return version; + } + + /** + * Initialise the dialog's GUI components. + */ + private void initComponents() + { + getContentPane().setLayout(new BorderLayout()); + + JLabel jlGroupID = new JLabel("Group ID:"); + JLabel jlArtifactID = new JLabel("Artifact ID:"); + JLabel jlVersion = new JLabel("Version"); + + jtfGroupID = new JTextField(15); + jtfArtifactID = new JTextField(15); + jtfVersion = new JTextField(15); + + JButton jbOK = new JButton("OK"); + jbOK.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent evt) + { + okPressed(); + } + }); + + JButton jbCancel = new JButton("Cancel"); + jbCancel.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent evt) + { + cancelPressed(); + } + }); + + JPanel jpPassword = new JPanel(new GridLayout(3, 2, 5, 5)); + jpPassword.add(jlGroupID); + jpPassword.add(jtfGroupID); + jpPassword.add(jlArtifactID); + jpPassword.add(jtfArtifactID); + jpPassword.add(jlVersion); + jpPassword.add(jtfVersion); + jpPassword.setBorder(new EmptyBorder(5, 5, 5, 5)); + + JPanel jpButtons = new JPanel(new FlowLayout(FlowLayout.CENTER)); + jpButtons.add(jbOK); + jpButtons.add(jbCancel); + + getContentPane().add(jpPassword, BorderLayout.CENTER); + getContentPane().add(jpButtons, BorderLayout.SOUTH); + + addWindowListener(new WindowAdapter() + { + public void windowClosing(WindowEvent evt) + { + closeDialog(); + } + }); + + setResizable(false); + + getRootPane().setDefaultButton(jbOK); + + pack(); + } + + private boolean checkFields() + { + groupID = jtfGroupID.getText(); + artifactID = jtfArtifactID.getText(); + version = jtfVersion.getText(); + + if ((!groupID.equals("")) && (!artifactID.equals("")) && (!version.equals(""))){ + return true; + } + else { + JOptionPane.showMessageDialog(this, + "Field(s) may not be empty", + "ERROR", + JOptionPane.ERROR_MESSAGE); + + return false; + } + } + + /** + * OK button pressed or otherwise activated. + */ + private void okPressed() + { + if (checkFields()) { + closeDialog(); + } + } + + /** + * Cancel button pressed or otherwise activated. + */ + private void cancelPressed() + { + // Set the fields to null as it might have changed in the meantime + // if user entered something previously + groupID = null; + artifactID = null; + version = null; + closeDialog(); + } + + /** + * Close the dialog. + */ + private void closeDialog() + { + setVisible(false); + dispose(); + } +} + + + http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/a5d4f899/taverna-dependency-activity/src/main/resources/schema.json ---------------------------------------------------------------------- diff --git a/taverna-dependency-activity/src/main/resources/schema.json b/taverna-dependency-activity/src/main/resources/schema.json new file mode 100644 index 0000000..c30459f --- /dev/null +++ b/taverna-dependency-activity/src/main/resources/schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "http://ns.taverna.org.uk/2010/activity/dependency.schema.json", + "title": "Dependency activity configuration", + "type": "object", + "properties": { + "@context": { + "description": "JSON-LD context for interpreting the configuration as RDF", + "required": true, + "enum": ["http://ns.taverna.org.uk/2010/activity/dependency.context.json"] + }, + "classLoaderSharing": { + "title": "ClassLoader Sharing Policy", + "description": "Policy for sharing class loaders across multiple beanshell activities", + "default": "workflow", + "enum": ["workflow", "system"] + }, + "localDependency": { + "title": "Local Dependencies", + "description": "Location of jar files to be added to the beanshell class loader", + "type": "array", + "items": { "type" : "string" } + } + } +}
