diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fd46532 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/target/ +/.settings/ +/.externalToolBuilders/ +.classpath +.project diff --git a/demo/flows-demo/.gitignore b/demo/flows-demo/.gitignore index b83d222..fd46532 100644 --- a/demo/flows-demo/.gitignore +++ b/demo/flows-demo/.gitignore @@ -1 +1,5 @@ /target/ +/.settings/ +/.externalToolBuilders/ +.classpath +.project diff --git a/demo/flows-web-demo/.gitignore b/demo/flows-web-demo/.gitignore index 150f08f..6cc79f5 100644 --- a/demo/flows-web-demo/.gitignore +++ b/demo/flows-web-demo/.gitignore @@ -1,6 +1,6 @@ -*.DS_Store -bin -target +/target/ +/.settings/ +/.externalToolBuilders/ .classpath .project .settings diff --git a/demo/web-site-demo/.gitignore b/demo/web-site-demo/.gitignore index b83d222..6cc79f5 100644 --- a/demo/web-site-demo/.gitignore +++ b/demo/web-site-demo/.gitignore @@ -1 +1,9 @@ /target/ +/.settings/ +/.externalToolBuilders/ +.classpath +.project +.settings +src/main/webapp/META-INF +.idea +*.iml diff --git a/guice-workflow-adapter/src/test/java/org/neuro4j/workflow/guice/GuiceWithWorkflowTestCase.java b/guice-workflow-adapter/src/test/java/org/neuro4j/workflow/guice/GuiceWithWorkflowTestCase.java index b5a6289..90659b8 100644 --- a/guice-workflow-adapter/src/test/java/org/neuro4j/workflow/guice/GuiceWithWorkflowTestCase.java +++ b/guice-workflow-adapter/src/test/java/org/neuro4j/workflow/guice/GuiceWithWorkflowTestCase.java @@ -17,15 +17,16 @@ import org.neuro4j.workflow.WorkflowRequest; import org.neuro4j.workflow.cache.ActionRegistry; import org.neuro4j.workflow.cache.EmptyWorkflowCache; -import org.neuro4j.workflow.common.ClasspathWorkflowLoader; import org.neuro4j.workflow.common.FlowExecutionException; import org.neuro4j.workflow.common.FlowInitializationException; -import org.neuro4j.workflow.common.RemoteWorkflowLoader; import org.neuro4j.workflow.common.WorkflowEngine; import org.neuro4j.workflow.common.WorkflowEngine; import org.neuro4j.workflow.common.WorkflowEngine.ConfigBuilder; +import org.neuro4j.workflow.common.XmlWorkflowConverter; import org.neuro4j.workflow.guice.flows.CustomBlockWithService; +import org.neuro4j.workflow.loader.ClasspathWorkflowLoader; import org.neuro4j.workflow.loader.DefaultCustomBlockInitStrategy; +import org.neuro4j.workflow.loader.RemoteWorkflowLoader; import org.neuro4j.workflow.log.Logger; import com.google.inject.Module; @@ -64,9 +65,9 @@ public void tearDown() throws Exception { @Test public void testFlow() { // Now all custom blocks will be initialized with Guice. - WorkflowEngine engine = new WorkflowEngine(new ConfigBuilder().withLoader(new ClasspathWorkflowLoader()).withCustomBlockInitStrategy(initStrategy)); + WorkflowEngine engine = new WorkflowEngine(new ConfigBuilder().withLoader(new ClasspathWorkflowLoader(new XmlWorkflowConverter())).withCustomBlockInitStrategy(initStrategy)); - engine.execute("org.neuro4j.workflow.guice.flows.Flow-Start", new HashMap()); + engine.execute("org.neuro4j.workflow.guice.flows.Flow-Start"); } @Test diff --git a/neuro4j-workflow-core/pom.xml b/neuro4j-workflow-core/pom.xml index 8630ee6..b76621c 100644 --- a/neuro4j-workflow-core/pom.xml +++ b/neuro4j-workflow-core/pom.xml @@ -21,7 +21,14 @@ junit 4.8.2 test - + + + org.mockito + mockito-core + 1.10.19 + test + + diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/FlowContext.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/FlowContext.java index d7e2efb..8412af6 100644 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/FlowContext.java +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/FlowContext.java @@ -172,7 +172,7 @@ public String toString() { } public Map getParameters(){ - return new HashMap(parameters); + return Collections.unmodifiableMap(parameters); } } diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/ConcurrentMapWorkflowCache.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/ConcurrentMapWorkflowCache.java index a6b010a..e22e880 100644 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/ConcurrentMapWorkflowCache.java +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/ConcurrentMapWorkflowCache.java @@ -21,7 +21,7 @@ import org.neuro4j.workflow.common.FlowExecutionException; import org.neuro4j.workflow.common.Workflow; -import org.neuro4j.workflow.common.WorkflowLoader; +import org.neuro4j.workflow.loader.WorkflowLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/EmptyWorkflowCache.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/EmptyWorkflowCache.java index 6de7920..f5fc2ba 100644 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/EmptyWorkflowCache.java +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/EmptyWorkflowCache.java @@ -18,8 +18,7 @@ import org.neuro4j.workflow.common.FlowExecutionException; import org.neuro4j.workflow.common.Workflow; -import org.neuro4j.workflow.common.WorkflowLoader; -import org.neuro4j.workflow.common.WorkflowSource; +import org.neuro4j.workflow.loader.WorkflowLoader; /** * Default cache implementation @@ -30,13 +29,12 @@ public enum EmptyWorkflowCache implements WorkflowCache { @Override - public Workflow get(WorkflowLoader loader, String flowName) throws FlowExecutionException { - WorkflowSource workflowSource = loader.load(flowName); - if (workflowSource == null) { + public Workflow get(WorkflowLoader loader, String flowName) throws FlowExecutionException { + Workflow workflow = loader.load(flowName); + if (workflow == null) { throw new FlowExecutionException("Workflow " + flowName + " not loaded"); } - Workflow workflow = workflowSource.content(); return workflow; } diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/WorkflowCache.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/WorkflowCache.java index 64d8213..e32395c 100644 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/WorkflowCache.java +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/cache/WorkflowCache.java @@ -18,7 +18,7 @@ import org.neuro4j.workflow.common.FlowExecutionException; import org.neuro4j.workflow.common.Workflow; -import org.neuro4j.workflow.common.WorkflowLoader; +import org.neuro4j.workflow.loader.WorkflowLoader; /** * Base interface for cache diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/JSONWorkflowConverter.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/JSONWorkflowConverter.java new file mode 100644 index 0000000..a4f87e2 --- /dev/null +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/JSONWorkflowConverter.java @@ -0,0 +1,20 @@ +package org.neuro4j.workflow.common; + +import java.io.Reader; + +import org.neuro4j.workflow.utils.Validation; + +public class JSONWorkflowConverter implements WorkflowConverter{ + + @Override + public Workflow convert(Reader stream, String name) throws FlowExecutionException { + Validation.requireNonNull(stream, () -> new FlowExecutionException("InputStream can not be null")); + throw new UnsupportedOperationException("Not supported yet"); + } + + @Override + public String getFileExt() { + throw new UnsupportedOperationException("Not supported yet"); + } + +} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/RemoteWorkflowLoader.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/RemoteWorkflowLoader.java deleted file mode 100644 index 72dca80..0000000 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/RemoteWorkflowLoader.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.neuro4j.workflow.common; - -import java.net.MalformedURLException; -import java.net.URL; - -public class RemoteWorkflowLoader implements WorkflowLoader { - - final WorkflowLoader delegate; - - public RemoteWorkflowLoader(WorkflowLoader loader) { - this.delegate = loader; - } - - @Override - public WorkflowSource load(final String location) throws FlowExecutionException { - if (location.startsWith("http://") || location.startsWith("https://")) { - try { - - return new RemoteWorkflowSource(location, new URL(location)); - } catch (MalformedURLException e) { - throw new FlowExecutionException(location, e); - } - } - return delegate.load(location); - } - -} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/RemoteWorkflowSource.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/RemoteWorkflowSource.java deleted file mode 100644 index d6d7b87..0000000 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/RemoteWorkflowSource.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.neuro4j.workflow.common; - -import java.net.URL; -import java.net.URLConnection; -import java.util.function.Consumer; - -public class RemoteWorkflowSource extends URLWorkflowSource{ - - private Consumer connectionConsumer; - - public RemoteWorkflowSource(String location, URL resource) { - super(location, resource); - } - - -} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/URLWorkflowLoader.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/URLWorkflowLoader.java deleted file mode 100644 index 081a388..0000000 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/URLWorkflowLoader.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.neuro4j.workflow.common; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.Optional; - -public abstract class URLWorkflowLoader implements WorkflowLoader { - - public final static String DEFAULT_EXT = ".n4j"; - - String fileExt; - - @Override - public WorkflowSource load(final String name) throws FlowExecutionException { - URL resource = null; - String path = normalize(name); - try { - resource = getResource(path); - if (resource == null) { - throw new FlowExecutionException(path + " not found."); - } - return new XMLWorkflowSource(name, resource); - } catch (IOException e) { - throw new FlowExecutionException(name, e); - } - } - - protected abstract URL getResource(String location) throws IOException; - - protected String normalize(String path){ - return path.replaceAll("\\.", File.separator); - } - - protected String getFileExt(){ - return Optional.ofNullable(fileExt).orElse(DEFAULT_EXT); - } - -} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/URLWorkflowSource.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/URLWorkflowSource.java deleted file mode 100644 index ef375d0..0000000 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/URLWorkflowSource.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.neuro4j.workflow.common; - -import java.net.URL; - -public class URLWorkflowSource implements WorkflowSource { - - protected URL resource; - - protected Long lastModified; - - private String name; - - public URLWorkflowSource(String name, URL resource) { - this.name = name; - this.resource = resource; - - } - - @Override - public String name() { - return name; - } - - @Override - public Workflow content() throws FlowExecutionException { - return null; - } - - @Override - public long lastModified() { - return 0; - } - -} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowConverter.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowConverter.java new file mode 100644 index 0000000..0687a93 --- /dev/null +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowConverter.java @@ -0,0 +1,13 @@ +package org.neuro4j.workflow.common; + +import java.io.Reader; + +public interface WorkflowConverter { + + public final static String DEFAULT_EXT = ".n4j"; + + Workflow convert(Reader stream, String name) throws FlowExecutionException; + + String getFileExt(); + +} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowEngine.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowEngine.java index 006c765..1b904e9 100644 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowEngine.java +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowEngine.java @@ -26,8 +26,11 @@ import org.neuro4j.workflow.cache.ConcurrentMapWorkflowCache; import org.neuro4j.workflow.cache.EmptyWorkflowCache; import org.neuro4j.workflow.cache.WorkflowCache; +import org.neuro4j.workflow.loader.ClasspathWorkflowLoader; import org.neuro4j.workflow.loader.CustomBlockInitStrategy; import org.neuro4j.workflow.loader.DefaultCustomBlockInitStrategy; +import org.neuro4j.workflow.loader.RemoteWorkflowLoader; +import org.neuro4j.workflow.loader.WorkflowLoader; import org.neuro4j.workflow.node.WorkflowProcessor; /** @@ -56,7 +59,7 @@ public WorkflowEngine(ConfigBuilder builder) { public WorkflowEngine() { this(new ConfigBuilder().withCustomBlockInitStrategy(new DefaultCustomBlockInitStrategy()) .withWorkflowCache(new ConcurrentMapWorkflowCache()) - .withLoader(new ClasspathWorkflowLoader())); + .withLoader(new ClasspathWorkflowLoader(new XmlWorkflowConverter()))); } @@ -108,9 +111,11 @@ public static class ConfigBuilder { private WorkflowCache workflowCache; private ActionRegistry registry; + + private final WorkflowConverter converter; public ConfigBuilder() { - + converter = new XmlWorkflowConverter(); } public ConfigBuilder withLoader(WorkflowLoader loader) { @@ -134,7 +139,7 @@ public ConfigBuilder withActionRegistry(ActionRegistry registry) { } public WorkflowLoader getLoader() { - return loader != null ? loader : new RemoteWorkflowLoader(new ClasspathWorkflowLoader()); + return loader != null ? loader : new RemoteWorkflowLoader(converter, new ClasspathWorkflowLoader(converter)); } public CustomBlockInitStrategy getCustomInitStrategy() { diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowLoader.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowLoader.java deleted file mode 100644 index 2a672d4..0000000 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowLoader.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.neuro4j.workflow.common; - -/** - * Base interface to load workflow. - */ -public interface WorkflowLoader { - - /** - * Loads workflow by name - * @param name of workflow - * @return WorkflowSource - * @throws FlowExecutionException in case of workflow can not be loaded - */ - public WorkflowSource load(final String name) throws FlowExecutionException; - -} - diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowSource.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowSource.java deleted file mode 100644 index cc59c88..0000000 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/WorkflowSource.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.neuro4j.workflow.common; - -/** - * Base interface to retrieve workflow from stream. - */ -public interface WorkflowSource { - - /** - * Returns name of workflow ex. org.neuro4j.common.LoadProfile - * @return the name - */ - String name(); - - /** - * Returns workflow object retrieved from loader (Remote, Classpath, XMLFile, JSONFile) - * @return Workflow - * @throws FlowExecutionException in case of error - */ - Workflow content() throws FlowExecutionException; - - /** - * Returns lastModified - * @return lastModified time - */ - long lastModified(); - -} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/XMLWorkflowSource.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/XMLWorkflowSource.java deleted file mode 100644 index b9b188e..0000000 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/XMLWorkflowSource.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.neuro4j.workflow.common; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -import org.neuro4j.workflow.loader.f4j.FlowConverter; -import org.neuro4j.workflow.log.Logger; - -/** - * Converts stream from xml-resource to workflow object - */ -public class XMLWorkflowSource extends URLWorkflowSource { - - public XMLWorkflowSource(String name, URL resource) { - super(name, resource); - } - - @Override - public Workflow content() throws FlowExecutionException { - Workflow net = null; - InputStream inputStream = null; - try { - inputStream = getStream(); - if (null != inputStream) - net = FlowConverter.xml2workflow(inputStream, name()); - } catch (Exception e) { - throw new FlowExecutionException(e); - } finally { - try { - if (null != inputStream) - inputStream.close(); - } catch (Exception e) { - Logger.error(this, e); - } - } - return net; - } - - protected InputStream getStream() throws IOException { - return resource.openStream(); - } - -} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/XmlWorkflowConverter.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/XmlWorkflowConverter.java new file mode 100644 index 0000000..5962c33 --- /dev/null +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/XmlWorkflowConverter.java @@ -0,0 +1,37 @@ +package org.neuro4j.workflow.common; + +import java.io.Reader; + +import org.neuro4j.workflow.loader.f4j.FlowConverter; +import org.neuro4j.workflow.utils.Validation; + +public class XmlWorkflowConverter implements WorkflowConverter{ + + final String fileExt; + + public XmlWorkflowConverter(final String ext){ + this.fileExt = ext; + } + + public XmlWorkflowConverter(){ + this(DEFAULT_EXT); + } + + @Override + public Workflow convert(Reader stream, String name) throws FlowExecutionException { + Validation.requireNonNull(stream, () -> new FlowExecutionException("InputStream can not be null")); + try { + return FlowConverter.xml2workflow(stream, name); + } catch (Exception e) { + throw new FlowExecutionException(e); + } + } + + @Override + public String getFileExt() { + return this.fileExt; + } + + + +} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/ClasspathWorkflowLoader.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/ClasspathWorkflowLoader.java similarity index 68% rename from neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/ClasspathWorkflowLoader.java rename to neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/ClasspathWorkflowLoader.java index 7a44c19..486c6d8 100644 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/ClasspathWorkflowLoader.java +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/ClasspathWorkflowLoader.java @@ -14,11 +14,13 @@ * limitations under the License. */ -package org.neuro4j.workflow.common; +package org.neuro4j.workflow.loader; import java.io.IOException; import java.net.URL; +import org.neuro4j.workflow.common.WorkflowConverter; + /** * Loads workflow from classpath. * @@ -26,16 +28,14 @@ public class ClasspathWorkflowLoader extends URLWorkflowLoader{ - public ClasspathWorkflowLoader(final String ext){ - this.fileExt = ext; - } - public ClasspathWorkflowLoader(){ - this(DEFAULT_EXT); + public ClasspathWorkflowLoader(final WorkflowConverter converter){ + super(converter); } @Override - protected URL getResource(String location) throws IOException { - return getClass().getClassLoader().getResource(location + fileExt); + protected URL getResource(String name) throws IOException { + String location = normalize(name); + return getClass().getClassLoader().getResource(location + converter.getFileExt()); } } diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/FileWorkflowLoader.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/FileWorkflowLoader.java similarity index 72% rename from neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/FileWorkflowLoader.java rename to neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/FileWorkflowLoader.java index 92f0681..f96f599 100644 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/common/FileWorkflowLoader.java +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/FileWorkflowLoader.java @@ -14,12 +14,15 @@ * limitations under the License. */ -package org.neuro4j.workflow.common; +package org.neuro4j.workflow.loader; import java.io.File; import java.io.IOException; import java.net.URL; +import org.neuro4j.workflow.common.FlowExecutionException; +import org.neuro4j.workflow.common.WorkflowConverter; + /** * Loads workflow from external folder. * @@ -29,23 +32,21 @@ public class FileWorkflowLoader extends URLWorkflowLoader { final URLWorkflowLoader delegate; final File baseDir; - public FileWorkflowLoader(URLWorkflowLoader loader, File baseDir, final String fileExt) + public FileWorkflowLoader(final WorkflowConverter converter, URLWorkflowLoader loader, File baseDir) throws FlowExecutionException { + super(converter); if (baseDir == null || !baseDir.exists() || !baseDir.isDirectory()) { throw new FlowExecutionException("BaseDir is not valid : " + baseDir); } this.delegate = loader; this.baseDir = baseDir; - this.fileExt = fileExt; } - public FileWorkflowLoader(final File baseDir, final String ext) throws FlowExecutionException { - this(new ClasspathWorkflowLoader(ext), baseDir, ext); - } @Override - protected URL getResource(final String location) throws IOException { - File file = new File(baseDir , location + getFileExt()); + protected URL getResource(final String name) throws IOException { + String location = normalize(name); + File file = new File(baseDir , location + converter.getFileExt()); return file.exists() ? file.toURI().toURL() : delegate.getResource(location); } diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/RemoteWorkflowLoader.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/RemoteWorkflowLoader.java new file mode 100644 index 0000000..f06dd41 --- /dev/null +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/RemoteWorkflowLoader.java @@ -0,0 +1,75 @@ +package org.neuro4j.workflow.loader; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.net.URLConnection; +import java.util.function.Consumer; +import java.util.function.Function; + +import org.neuro4j.workflow.common.FlowExecutionException; +import org.neuro4j.workflow.common.Workflow; +import org.neuro4j.workflow.common.WorkflowConverter; +import org.neuro4j.workflow.log.Logger; + +/** + * Allows to load workflow file from remote host. + * + */ +public class RemoteWorkflowLoader extends URLWorkflowLoader { + + /** + * If requested flow does not start with http:// or https:// delegates execution to next loader + */ + private final WorkflowLoader delegate; + + /** + * Accepts connection before remote call. Can be used to set up connection parameter like timeout or headers + */ + private final Consumer connectionConsumer; + + /** + * Calls this function to transform initial requested location before delegation. Can be used to transform call http://mydomain.com/mycontext/com.mypackage.Flow1 to com.mypackage.Flow1 + */ + private Function onErrorRewrite; + + public RemoteWorkflowLoader(final WorkflowConverter converter, final WorkflowLoader delegate, Consumer connectionConsumer, Function onError) { + super(converter); + this.delegate = delegate; + this.connectionConsumer = connectionConsumer; + this.onErrorRewrite = onError; + } + + public RemoteWorkflowLoader(final WorkflowConverter converter, final WorkflowLoader delegate) { + this(converter, delegate, s->{}, s -> s); + } + + @Override + public Workflow load(final String location) throws FlowExecutionException { + String flow = location; + if (location.startsWith("http://") || location.startsWith("https://")) { + try { + URL url = getResource(location); + flow = url.getFile(); + return content(url, location); + } catch (Exception e) { + Logger.error(this, e); + flow = onErrorRewrite.apply(location); + + } + } + return delegate.load(flow); + } + + @Override + protected URL getResource(String location) throws IOException { + return new URL(location); + } + + protected Reader getReader(URL resource) throws IOException { + URLConnection connection = resource.openConnection(); + connectionConsumer.accept(connection); + return new InputStreamReader(connection.getInputStream(), "UTF-8"); + } +} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/URLWorkflowLoader.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/URLWorkflowLoader.java new file mode 100644 index 0000000..7cce65d --- /dev/null +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/URLWorkflowLoader.java @@ -0,0 +1,68 @@ +package org.neuro4j.workflow.loader; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.util.Optional; + +import org.neuro4j.workflow.common.FlowExecutionException; +import org.neuro4j.workflow.common.Workflow; +import org.neuro4j.workflow.common.WorkflowConverter; +import org.neuro4j.workflow.common.XmlWorkflowConverter; +import org.neuro4j.workflow.log.Logger; + +public abstract class URLWorkflowLoader implements WorkflowLoader { + + protected WorkflowConverter converter; + + public URLWorkflowLoader(final WorkflowConverter converter){ + this.converter = Optional.ofNullable(converter).orElse(new XmlWorkflowConverter()); + } + + @Override + public Workflow load(final String name) throws FlowExecutionException { + try { + URL resource = getResource(name); + if (resource == null) { + throw new FlowExecutionException(name + " not found."); + } + return content(resource, name); + } catch (IOException e) { + throw new FlowExecutionException(name, e); + } + } + + + protected Workflow content(URL resource, final String name) throws FlowExecutionException { + Workflow net = null; + Reader inputStream = null; + try { + inputStream = getReader(resource); + net = converter.convert(inputStream, name); + + } catch (IOException e) { + Logger.error(this, e); + } finally { + try { + if (null != inputStream) + inputStream.close(); + } catch (Exception e) { + Logger.error(this, e); + } + } + return net; + } + + protected abstract URL getResource(String location) throws IOException; + + protected String normalize(String path){ + return path.replaceAll("\\.", File.separator); + } + + protected Reader getReader(URL resource) throws IOException { + return new InputStreamReader(resource.openStream(), "UTF-8"); + } + +} diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/WorkflowLoader.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/WorkflowLoader.java new file mode 100644 index 0000000..4746861 --- /dev/null +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/WorkflowLoader.java @@ -0,0 +1,20 @@ +package org.neuro4j.workflow.loader; + +import org.neuro4j.workflow.common.FlowExecutionException; +import org.neuro4j.workflow.common.Workflow; + +/** + * Base interface to load workflow. + */ +public interface WorkflowLoader { + + /** + * Loads workflow by name + * @param name of workflow + * @return Workflow + * @throws FlowExecutionException in case of workflow can not be loaded + */ + public Workflow load(final String name) throws FlowExecutionException; + +} + diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/f4j/FlowConverter.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/f4j/FlowConverter.java index 856c383..918ff8e 100644 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/f4j/FlowConverter.java +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/loader/f4j/FlowConverter.java @@ -17,6 +17,7 @@ package org.neuro4j.workflow.loader.f4j; import java.io.InputStream; +import java.io.Reader; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; @@ -49,25 +50,43 @@ */ public class FlowConverter { - public static Workflow xml2workflow(InputStream xml, String flow) - throws ConvertationException, FlowInitializationException { - if (null == xml) - return null; - try { - JAXBContext ctx = JAXBContext.newInstance(FlowXML.class); - - Unmarshaller um = ctx.createUnmarshaller(); - FlowXML flowxml = (FlowXML) um.unmarshal(xml); - if (null == flowxml) - return null; - - return netXML2net(flowxml, flow); - - } catch (JAXBException e) { - throw new ConvertationException("Can't convert stream to workflow", - e); - } - } + public static Workflow xml2workflow(Reader xml, String flow) + throws ConvertationException, FlowInitializationException { + if (null == xml) + return null; + try { + JAXBContext ctx = JAXBContext.newInstance(FlowXML.class); + + Unmarshaller um = ctx.createUnmarshaller(); + FlowXML flowxml = (FlowXML) um.unmarshal(xml); + if (null == flowxml) + return null; + + return netXML2net(flowxml, flow); + + } catch (JAXBException e) { + throw new ConvertationException("Can't convert stream to workflow", e); + } + } + + public static Workflow xml2workflow(InputStream xml, String flow) + throws ConvertationException, FlowInitializationException { + if (null == xml) + return null; + try { + JAXBContext ctx = JAXBContext.newInstance(FlowXML.class); + + Unmarshaller um = ctx.createUnmarshaller(); + FlowXML flowxml = (FlowXML) um.unmarshal(xml); + if (null == flowxml) + return null; + + return netXML2net(flowxml, flow); + + } catch (JAXBException e) { + throw new ConvertationException("Can't convert stream to workflow", e); + } + } private static Workflow netXML2net(FlowXML net, String flow) throws FlowInitializationException { diff --git a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/node/WorkflowProcessor.java b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/node/WorkflowProcessor.java index b2cfce8..e2ddbfc 100644 --- a/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/node/WorkflowProcessor.java +++ b/neuro4j-workflow-core/src/main/java/org/neuro4j/workflow/node/WorkflowProcessor.java @@ -10,8 +10,8 @@ import org.neuro4j.workflow.common.FlowInitializationException; import org.neuro4j.workflow.common.Workflow; import org.neuro4j.workflow.common.WorkflowEngine.ConfigBuilder; -import org.neuro4j.workflow.common.WorkflowLoader; import org.neuro4j.workflow.debug.DebugService; +import org.neuro4j.workflow.loader.WorkflowLoader; import org.neuro4j.workflow.log.Logger; /** diff --git a/neuro4j-workflow-core/src/test/java/org/neuro4j/flows/nodes/callnode/CallNodeTestCase.java b/neuro4j-workflow-core/src/test/java/org/neuro4j/flows/nodes/callnode/CallNodeTestCase.java index 1ea4c10..83f7363 100644 --- a/neuro4j-workflow-core/src/test/java/org/neuro4j/flows/nodes/callnode/CallNodeTestCase.java +++ b/neuro4j-workflow-core/src/test/java/org/neuro4j/flows/nodes/callnode/CallNodeTestCase.java @@ -49,7 +49,7 @@ public void testCallWrongNode() { ExecutionResult result = executeFlowAndReturnResult("org.neuro4j.flows.nodes.callnode.CallByNameFlow-StartNode2", null); Assert.assertTrue(result.getException() instanceof FlowExecutionException); - Assert.assertTrue(result.getException().getMessage().equals("org/neuro4j/flows/nodes/CallByNameFlow2 not found.")); + Assert.assertEquals("org.neuro4j.flows.nodes.CallByNameFlow2 not found.", result.getException().getMessage()); } diff --git a/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/ConfigBuilderTest.java b/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/ConfigBuilderTest.java index 7c0708d..e10778c 100644 --- a/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/ConfigBuilderTest.java +++ b/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/ConfigBuilderTest.java @@ -12,7 +12,10 @@ import org.neuro4j.workflow.cache.ConcurrentMapWorkflowCache; import org.neuro4j.workflow.cache.EmptyWorkflowCache; import org.neuro4j.workflow.common.WorkflowEngine.ConfigBuilder; +import org.neuro4j.workflow.loader.ClasspathWorkflowLoader; import org.neuro4j.workflow.loader.DefaultCustomBlockInitStrategy; +import org.neuro4j.workflow.loader.FileWorkflowLoader; +import org.neuro4j.workflow.loader.RemoteWorkflowLoader; public class ConfigBuilderTest { @@ -31,7 +34,8 @@ public void testDefaultConfigBuilder() throws FlowExecutionException{ @Test public void testConfigBuilderWithLoader() throws FlowExecutionException{ - ConfigBuilder builder = new ConfigBuilder().withLoader(new FileWorkflowLoader(new File("/tmp"), ClasspathWorkflowLoader.DEFAULT_EXT)); + WorkflowConverter converter = new XmlWorkflowConverter(); + ConfigBuilder builder = new ConfigBuilder().withLoader(new FileWorkflowLoader(converter, new ClasspathWorkflowLoader(converter), new File("/tmp"))); assertNotNull(builder.getCustomInitStrategy()); assertThat(builder.getCustomInitStrategy(), instanceOf(DefaultCustomBlockInitStrategy.class)); assertNotNull(builder.getLoader()); diff --git a/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/Neuro4jWorkflowTest.java b/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/Neuro4jWorkflowTest.java index 2be4110..2ee21c0 100644 --- a/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/Neuro4jWorkflowTest.java +++ b/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/Neuro4jWorkflowTest.java @@ -1,10 +1,13 @@ package org.neuro4j.workflow.common; +import org.junit.Before; import org.junit.Test; import org.neuro4j.workflow.ExecutionResult; import org.neuro4j.workflow.WorkflowRequest; import org.neuro4j.workflow.cache.ConcurrentMapWorkflowCache; import org.neuro4j.workflow.common.WorkflowEngine.ConfigBuilder; +import org.neuro4j.workflow.loader.ClasspathWorkflowLoader; +import org.neuro4j.workflow.loader.WorkflowLoader; import static junit.framework.Assert.*; @@ -13,120 +16,135 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; - public class Neuro4jWorkflowTest { - + + WorkflowConverter converter; + + @Before + public void setUp() { + converter = new XmlWorkflowConverter(); + } + @Test - public void testCreateEngine() throws FlowExecutionException{ - WorkflowEngine engine = new WorkflowEngine(new ConfigBuilder().withLoader(new ClasspathWorkflowLoader())); - ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); - assertNotNull(result); - assertNull(result.getException()); - assertEquals("End1", result.getLastSuccessfulNodeName()); + public void testCreateEngine() throws FlowExecutionException { + + WorkflowEngine engine = new WorkflowEngine( + new ConfigBuilder().withLoader(new ClasspathWorkflowLoader(converter))); + ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); + assertNotNull(result); + assertNull(result.getException()); + assertEquals("End1", result.getLastSuccessfulNodeName()); } - + @Test public void testCreateEngineWithMapCache() throws FlowExecutionException { - + final AtomicInteger counter = new AtomicInteger(0); - - final ClasspathWorkflowLoader classpathLoader = new ClasspathWorkflowLoader(); - - WorkflowEngine engine = new WorkflowEngine(new ConfigBuilder().withLoader(new WorkflowLoader() { - - @Override - public WorkflowSource load(String name) throws FlowExecutionException { - counter.incrementAndGet(); - return classpathLoader.load(name); - } - }) - .withWorkflowCache(new ConcurrentMapWorkflowCache())); - - - ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); - assertNotNull(result); - assertNull(result.getException()); - assertEquals("End1", result.getLastSuccessfulNodeName()); - - result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); - assertNotNull(result); - assertEquals("End1", result.getLastSuccessfulNodeName()); - engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); - engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); - engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); - - assertEquals(1, counter.get()); + + final ClasspathWorkflowLoader classpathLoader = new ClasspathWorkflowLoader(converter); + + WorkflowEngine engine = new WorkflowEngine(new ConfigBuilder().withLoader(new WorkflowLoader() { + + @Override + public Workflow load(String name) throws FlowExecutionException { + counter.incrementAndGet(); + return classpathLoader.load(name); + } + }).withWorkflowCache(new ConcurrentMapWorkflowCache())); + + ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); + assertNotNull(result); + assertNull(result.getException()); + assertEquals("End1", result.getLastSuccessfulNodeName()); + + result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); + assertNotNull(result); + assertEquals("End1", result.getLastSuccessfulNodeName()); + engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); + engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); + engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); + + assertEquals(1, counter.get()); } - + @Test - public void testDefaultConstructorEngine() throws FlowExecutionException{ - WorkflowEngine engine = new WorkflowEngine(); - ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); - assertNotNull(result); - assertNull(result.getException()); - assertEquals("End1", result.getLastSuccessfulNodeName()); + public void testDefaultConstructorEngine() throws FlowExecutionException { + WorkflowEngine engine = new WorkflowEngine(); + ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"); + assertNotNull(result); + assertNull(result.getException()); + assertEquals("End1", result.getLastSuccessfulNodeName()); } - + @Test - public void testDefaultConstructorWithParameters() throws FlowExecutionException{ - WorkflowEngine engine = new WorkflowEngine(); - Map parameters = new HashMap(); - String randomStr = UUID.randomUUID().toString(); - parameters.put("message", randomStr); - - ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-StartNode2", parameters); - assertNotNull(result); - assertNull(result.getException()); - assertEquals("Hi" + randomStr, result.getFlowContext().get("text")); + public void testDefaultConstructorWithParameters() throws FlowExecutionException { + WorkflowEngine engine = new WorkflowEngine(); + Map parameters = new HashMap(); + String randomStr = UUID.randomUUID().toString(); + parameters.put("message", randomStr); + + ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-StartNode2", + parameters); + assertNotNull(result); + assertNull(result.getException()); + assertEquals("Hi" + randomStr, result.getFlowContext().get("text")); } - + @Test - public void testDefaultConstructorWithParametersAndWorkflowLoader() throws FlowExecutionException{ - WorkflowEngine engine = new WorkflowEngine(new ConfigBuilder().withLoader(new ClasspathWorkflowLoader())); - Map parameters = new HashMap(); - String randomStr = UUID.randomUUID().toString(); - parameters.put("message", randomStr); - - ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-StartNode2", parameters); - assertNotNull(result); - assertNull(result.getException()); - assertEquals("Hi" + randomStr, result.getFlowContext().get("text")); + public void testDefaultConstructorWithParametersAndWorkflowLoader() throws FlowExecutionException { + WorkflowEngine engine = new WorkflowEngine( + new ConfigBuilder().withLoader(new ClasspathWorkflowLoader(converter))); + Map parameters = new HashMap(); + String randomStr = UUID.randomUUID().toString(); + parameters.put("message", randomStr); + + ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-StartNode2", + parameters); + assertNotNull(result); + assertNull(result.getException()); + assertEquals("Hi" + randomStr, result.getFlowContext().get("text")); } - + @Test - public void testDefaultConstructorWithEmptyParameters() throws FlowExecutionException{ - WorkflowEngine engine = new WorkflowEngine(new ConfigBuilder().withLoader(new ClasspathWorkflowLoader())); - Map parameters = new HashMap(); - - ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-StartNode2", parameters); - assertNotNull(result); - assertNull(result.getException()); - assertEquals("Hinull", result.getFlowContext().get("text")); + public void testDefaultConstructorWithEmptyParameters() throws FlowExecutionException { + WorkflowEngine engine = new WorkflowEngine( + new ConfigBuilder().withLoader(new ClasspathWorkflowLoader(converter))); + Map parameters = new HashMap(); + + ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-StartNode2", + parameters); + assertNotNull(result); + assertNull(result.getException()); + assertEquals("Hinull", result.getFlowContext().get("text")); } - + @Test - public void testDefaultConstructorWithNullParameters() throws FlowExecutionException{ - WorkflowEngine engine = new WorkflowEngine(new ConfigBuilder().withLoader(new ClasspathWorkflowLoader())); - Map parameters = null; - - ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-StartNode2", parameters); - assertNotNull(result); - assertNull(result.getException()); - assertEquals("Hinull", result.getFlowContext().get("text")); + public void testDefaultConstructorWithNullParameters() throws FlowExecutionException { + WorkflowEngine engine = new WorkflowEngine( + new ConfigBuilder().withLoader(new ClasspathWorkflowLoader(converter))); + Map parameters = null; + + ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-StartNode2", + parameters); + assertNotNull(result); + assertNull(result.getException()); + assertEquals("Hinull", result.getFlowContext().get("text")); } @Test - public void testDefaultConstructorWithWorkflowRequest() throws FlowExecutionException{ - - WorkflowEngine engine = new WorkflowEngine(new ConfigBuilder().withLoader(new ClasspathWorkflowLoader())); - Map parameters = new HashMap(); - String randomStr = UUID.randomUUID().toString(); - parameters.put("message", randomStr); - - WorkflowRequest request = new WorkflowRequest(parameters); - ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-StartNode2", request); - assertNotNull(result); - assertNull(result.getException()); - assertEquals("Hi" + randomStr, result.getFlowContext().get("text")); + public void testDefaultConstructorWithWorkflowRequest() throws FlowExecutionException { + + WorkflowEngine engine = new WorkflowEngine( + new ConfigBuilder().withLoader(new ClasspathWorkflowLoader(converter))); + Map parameters = new HashMap(); + String randomStr = UUID.randomUUID().toString(); + parameters.put("message", randomStr); + + WorkflowRequest request = new WorkflowRequest(parameters); + ExecutionResult result = engine.execute("org.neuro4j.workflow.flows.FlowForClasspathLoader-StartNode2", + request); + assertNotNull(result); + assertNull(result.getException()); + assertEquals("Hi" + randomStr, result.getFlowContext().get("text")); } } diff --git a/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/WorkflowLoaderMockTest.java b/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/WorkflowLoaderMockTest.java new file mode 100644 index 0000000..a95424c --- /dev/null +++ b/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/WorkflowLoaderMockTest.java @@ -0,0 +1,111 @@ +package org.neuro4j.workflow.common; + +import org.junit.Before; +import org.junit.Test; +import org.neuro4j.workflow.loader.ClasspathWorkflowLoader; +import org.neuro4j.workflow.loader.FileWorkflowLoader; +import org.neuro4j.workflow.loader.RemoteWorkflowLoader; +import org.neuro4j.workflow.loader.WorkflowLoader; +import org.neuro4j.workflow.node.FlowParameter; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.*; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.util.UUID; + +public class WorkflowLoaderMockTest { + + WorkflowConverter converter; + + @Mock + URLConnection mockURLConnection; + + @Mock + Workflow workflow; + + @Mock + WorkflowLoader workflowLoader; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + converter = new XmlWorkflowConverter(); + } + + + @Test + public void testRemoteLoaderGetSucceeds() throws IOException, FlowExecutionException { + + String flowName = "org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"; + + String remoteUrl = "http://example.com/" + flowName; + + URLStreamHandler stubHandler = new URLStreamHandler() { + @Override + protected URLConnection openConnection(URL u) throws IOException { + if (!u.toString().equals(remoteUrl)) { + fail("unexpected url encountered"); + } + + return mockURLConnection; + } + }; + + InputStream fakeInputStream = getClass().getClassLoader() + .getResourceAsStream(FlowParameter.parse(flowName).getFlowName().replace(".", File.separator) + WorkflowConverter.DEFAULT_EXT); + + when(mockURLConnection.getInputStream()).thenReturn(fakeInputStream); + + RemoteWorkflowLoader subject = new RemoteWorkflowLoader(converter, new ClasspathWorkflowLoader(converter), + c -> { + c.setRequestProperty("Accept", "text/xml"); + }, s -> s) { + @Override + protected URL getResource(String location) throws IOException { + return new URL(null, location, stubHandler); + } + }; + + Workflow actual = subject.load(remoteUrl); + + assertNotNull(actual); + + verify(mockURLConnection).getInputStream(); + verify(mockURLConnection, times(1)).setRequestProperty("Accept", "text/xml"); + + } + + @Test + public void testRemoteLoaderDelagatesOnFail() throws IOException, FlowExecutionException { + + String flowName = "org.neuro4j.workflow.flows.FlowForClasspathLoader-Start1"; + + + String remoteUrl = "http://mydomain.com/" + flowName; + + + when(workflowLoader.load(remoteUrl)).thenReturn(workflow); + + RemoteWorkflowLoader subject = new RemoteWorkflowLoader(converter, workflowLoader, + c -> { + throw new RuntimeException("Connection error"); + }, s-> s) { + }; + + Workflow actual = subject.load(remoteUrl); + + assertNotNull(actual); + + verify(workflowLoader, times(1)).load(remoteUrl); + } + +} diff --git a/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/WorkflowLoaderTest.java b/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/WorkflowLoaderTest.java index 5d3acb5..9915e09 100644 --- a/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/WorkflowLoaderTest.java +++ b/neuro4j-workflow-core/src/test/java/org/neuro4j/workflow/common/WorkflowLoaderTest.java @@ -1,76 +1,86 @@ package org.neuro4j.workflow.common; +import org.junit.Before; import org.junit.Test; +import org.neuro4j.workflow.loader.ClasspathWorkflowLoader; +import org.neuro4j.workflow.loader.FileWorkflowLoader; import static junit.framework.Assert.*; +import java.io.ByteArrayInputStream; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.util.UUID; public class WorkflowLoaderTest { - + WorkflowConverter converter; + + @Before + public void setUp() { + converter = new XmlWorkflowConverter(); + } @Test public void testDefaultClassPathLoader() throws FlowExecutionException{ - ClasspathWorkflowLoader loader = new ClasspathWorkflowLoader(); - WorkflowSource workflowSource = loader.load("org.neuro4j.workflow.flows.FlowForClasspathLoader"); + ClasspathWorkflowLoader loader = new ClasspathWorkflowLoader(converter); + Workflow workflowSource = loader.load("org.neuro4j.workflow.flows.FlowForClasspathLoader"); assertNotNull(workflowSource); - Workflow flow = workflowSource.content(); - assertNotNull(flow); } @Test public void testClassPathLoader() throws FlowExecutionException{ - ClasspathWorkflowLoader loader = new ClasspathWorkflowLoader(".n4j"); - WorkflowSource workflowSource = loader.load("org.neuro4j.workflow.flows.FlowForClasspathLoader"); - assertNotNull(workflowSource); - Workflow flow = workflowSource.content(); + ClasspathWorkflowLoader loader = new ClasspathWorkflowLoader(converter); + Workflow flow = loader.load("org.neuro4j.workflow.flows.FlowForClasspathLoader"); assertNotNull(flow); + assertEquals("org.neuro4j.workflow.flows.FlowForClasspathLoader", flow.getFlowName()); assertEquals("org.neuro4j.workflow.flows", flow.getPackage()); } @Test(expected=FlowExecutionException.class) public void testClassPathLoaderNotFound() throws FlowExecutionException{ - ClasspathWorkflowLoader loader = new ClasspathWorkflowLoader(".n4j"); + ClasspathWorkflowLoader loader = new ClasspathWorkflowLoader(converter); loader.load("org.neuro4j.workflow.flows.SomeFlow"); } @Test public void testDefaultFileWorkflowLoader() throws FlowExecutionException{ - ClasspathWorkflowLoader classpathLoader = new ClasspathWorkflowLoader(); + ClasspathWorkflowLoader classpathLoader = new ClasspathWorkflowLoader(converter); File baseDir = getBaseDirectory(); assertTrue(baseDir.exists()); assertTrue(baseDir.isDirectory()); - FileWorkflowLoader loader = new FileWorkflowLoader(classpathLoader, baseDir, ClasspathWorkflowLoader.DEFAULT_EXT); - WorkflowSource workflowSource = loader.load("org.mydomain.FlowForFileWorkflowLoader"); + FileWorkflowLoader loader = new FileWorkflowLoader(converter, classpathLoader, baseDir); + Workflow workflowSource = loader.load("org.mydomain.FlowForFileWorkflowLoader"); assertNotNull(workflowSource); - Workflow flow = workflowSource.content(); - assertNotNull(flow); } @Test(expected=FlowExecutionException.class) public void testDefaultFileWorkflowLoaderWithEmptyBaseDirectory() throws FlowExecutionException { - ClasspathWorkflowLoader classpathLoader = new ClasspathWorkflowLoader(); + ClasspathWorkflowLoader classpathLoader = new ClasspathWorkflowLoader(converter); - new FileWorkflowLoader(classpathLoader, null, ClasspathWorkflowLoader.DEFAULT_EXT); + new FileWorkflowLoader(converter, classpathLoader, null); fail("Should be exception"); } @Test(expected=FlowExecutionException.class) public void testDefaultFileWorkflowLoaderWithFileAsBaseDirectory() throws FlowExecutionException { - ClasspathWorkflowLoader classpathLoader = new ClasspathWorkflowLoader(); + ClasspathWorkflowLoader classpathLoader = new ClasspathWorkflowLoader(converter); File file = getTestFile(); assertTrue(file.exists()); - new FileWorkflowLoader(classpathLoader, file, ClasspathWorkflowLoader.DEFAULT_EXT); + new FileWorkflowLoader(converter, classpathLoader, file); fail("Should be exception"); } + + File getBaseDirectory(){ File someFile = getTestFile(); diff --git a/pom.xml b/pom.xml index 8e5941b..315685d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ pom Workflow System http://neuro4j.org - Light-weight workflow engine + Light-weight workflow engine The Apache Software License, Version 2.0 @@ -20,7 +20,7 @@ scm:git:git://github.com/neuro4j/workflow.git scm:git:ssh://github.com:neuro4j/workflow.git http://github.com/neuro4j/workflow/tree/master - + neuro4j-maven-milestone @@ -50,7 +50,7 @@ support@neuro4j.org Neuro4j http://neuro4j.org - + neuro4j-workflow-core @@ -70,16 +70,15 @@ UTF-8 1.8 - 1.8 - 1.8 + - - ch.qos.logback - logback-classic - 1.1.7 - + + ch.qos.logback + logback-classic + 1.1.7 + commons-beanutils @@ -98,14 +97,14 @@ 1.1 test - + xerces xercesImpl 2.11.0 test - + @@ -134,43 +133,61 @@ - - - org.codehaus.mojo - cobertura-maven-plugin - 2.7 - - xml - 256m - true - - + + + org.codehaus.mojo + cobertura-maven-plugin + 2.7 + + xml + 256m + true + + - - org.eluder.coveralls - coveralls-maven-plugin - 4.3.0 - + + org.eluder.coveralls + coveralls-maven-plugin + 4.3.0 + - +--> org.jacoco jacoco-maven-plugin - 0.7.5.201505241946 + 0.7.7.201606060606 + + ${basedir}/target/coverage-reports/jacoco-unit.exec + ${basedir}/target/coverage-reports/jacoco-unit.exec + + + + jacoco-initialize + + prepare-agent + + + + jacoco-site + package + + report + + + org.apache.maven.plugins diff --git a/tutorials/GuiceWorkflowExample/.gitignore b/tutorials/GuiceWorkflowExample/.gitignore index 934e0e0..fd46532 100644 --- a/tutorials/GuiceWorkflowExample/.gitignore +++ b/tutorials/GuiceWorkflowExample/.gitignore @@ -1,2 +1,5 @@ -/bin -/target +/target/ +/.settings/ +/.externalToolBuilders/ +.classpath +.project diff --git a/tutorials/SpringEmailExample/.gitignore b/tutorials/SpringEmailExample/.gitignore index b83d222..fd46532 100644 --- a/tutorials/SpringEmailExample/.gitignore +++ b/tutorials/SpringEmailExample/.gitignore @@ -1 +1,5 @@ /target/ +/.settings/ +/.externalToolBuilders/ +.classpath +.project diff --git a/tutorials/SpringJmsExample/.gitignore b/tutorials/SpringJmsExample/.gitignore index ea8c4bf..fd46532 100644 --- a/tutorials/SpringJmsExample/.gitignore +++ b/tutorials/SpringJmsExample/.gitignore @@ -1 +1,5 @@ -/target +/target/ +/.settings/ +/.externalToolBuilders/ +.classpath +.project diff --git a/tutorials/SpringMVCExample/.gitignore b/tutorials/SpringMVCExample/.gitignore index ea8c4bf..fd46532 100644 --- a/tutorials/SpringMVCExample/.gitignore +++ b/tutorials/SpringMVCExample/.gitignore @@ -1 +1,5 @@ -/target +/target/ +/.settings/ +/.externalToolBuilders/ +.classpath +.project diff --git a/tutorials/SpringTimerExample/.gitignore b/tutorials/SpringTimerExample/.gitignore index b83d222..fd46532 100644 --- a/tutorials/SpringTimerExample/.gitignore +++ b/tutorials/SpringTimerExample/.gitignore @@ -1 +1,5 @@ /target/ +/.settings/ +/.externalToolBuilders/ +.classpath +.project diff --git a/tutorials/WorkflowExample/.gitignore b/tutorials/WorkflowExample/.gitignore index ea8c4bf..fd46532 100644 --- a/tutorials/WorkflowExample/.gitignore +++ b/tutorials/WorkflowExample/.gitignore @@ -1 +1,5 @@ -/target +/target/ +/.settings/ +/.externalToolBuilders/ +.classpath +.project