diff --git a/data-hub/src/main/java/com/marklogic/hub/Mlcp.java b/data-hub/src/main/java/com/marklogic/hub/Mlcp.java new file mode 100644 index 0000000000..fc0f882d86 --- /dev/null +++ b/data-hub/src/main/java/com/marklogic/hub/Mlcp.java @@ -0,0 +1,211 @@ +/* + * Copyright 2012-2016 MarkLogic Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.marklogic.hub; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.marklogic.hub.util.IOUtil; +import com.marklogic.hub.util.IOUtil.LogLevel; + +public class Mlcp { + private static final Logger LOGGER = LoggerFactory.getLogger(Mlcp.class); + + private List sources = new ArrayList<>(); + + private String mlcpPath; + + private String host; + + private String port; + + private String user; + + private String password; + + public Mlcp(String mlcpHome, String host, String port, String user, String password) { + this.host = host; + this.port = port; + this.user = user; + this.password = password; + + // set the mlcp executable path based on OS + this.mlcpPath = mlcpHome; + String osName = System.getProperty("os.name"); + if (osName != null && osName.toLowerCase().startsWith("windows")) { + mlcpPath += "/bin/mlcp.bat"; + } + else { + mlcpPath += "/bin/mlcp.sh"; + } + } + + public void addSourceDirectory(String directoryPath, SourceOptions options) { + MlcpSource source = new MlcpSource(directoryPath, options); + sources.add(source); + } + + public void loadContent() { + for (MlcpSource source : sources) { + Thread inputThread = null; + Thread errorThread = null; + try { + List arguments = new ArrayList<>(); + + arguments.add(mlcpPath); + arguments.add("import"); + arguments.add("-mode"); + arguments.add("local"); + arguments.add("-host"); + arguments.add(host); + arguments.add("-port"); + arguments.add(port); + arguments.add("-username"); + arguments.add(user); + arguments.add("-password"); + arguments.add(password); + + // add arguments related to the source + List sourceArguments = source.getMlcpArguments(); + arguments.addAll(sourceArguments); + + ProcessBuilder pb = new ProcessBuilder(arguments.toArray(new String[0])); + Process process = pb.start(); + + inputThread = IOUtil.createInputStreamSink(process.getInputStream(), LOGGER, LogLevel.DEBUG); + errorThread = IOUtil.createInputStreamSink(process.getErrorStream(), LOGGER, LogLevel.ERROR); + + inputThread.start(); + errorThread.start(); + + process.waitFor(); + } + catch (Exception e) { + LOGGER.error("Failed to load {}", source.getSourcePath(), e); + } + finally { + if (inputThread != null) { + inputThread.interrupt(); + } + if (errorThread != null) { + errorThread.interrupt(); + } + } + } + } + + private static class MlcpSource { + private String sourcePath; + private SourceOptions sourceOptions; + + public MlcpSource(String sourcePath, SourceOptions sourceOptions) { + this.sourcePath = sourcePath; + this.sourceOptions = sourceOptions; + } + + public String getSourcePath() { + return sourcePath; + } + + public List getMlcpArguments() throws IOException { + File file = new File(sourcePath); + String canonicalPath = file.getCanonicalPath(); + + List arguments = new ArrayList<>(); + arguments.add("-input_file_path"); + arguments.add(canonicalPath); + arguments.add("-input_file_type"); + if (sourceOptions.getInputFileType() == null) { + arguments.add("documents"); + } + else { + arguments.add(sourceOptions.getInputFileType()); + } + + if (sourceOptions.getInputFilePattern() != null) { + arguments.add("-input_file_pattern"); + arguments.add(sourceOptions.getInputFilePattern()); + } + + // by default, cut the source directory path to make URIs shorter + String uriReplace = "/" + canonicalPath + ",''"; + uriReplace = uriReplace.replaceAll("\\\\", "/"); + + arguments.add("-output_uri_replace"); + arguments.add(uriReplace); + + arguments.add("-transform_module"); + arguments.add("/com.marklogic.hub/mlcp-flow-transform.xqy"); + arguments.add("-transform_namespace"); + arguments.add("http://marklogic.com/hub-in-a-box/mlcp-flow-transform"); + arguments.add("-transform_param"); + arguments.add("\"" + sourceOptions.getTransformParams() + "\""); + + return arguments; + } + } + + public static class SourceOptions { + private String domainName; + private String flowName; + private String flowType; + private String inputFileType; + private String inputFilePattern; + + public SourceOptions(String domainName, String flowName, String flowType) { + this.domainName = domainName; + this.flowName = flowName; + this.flowType = flowType; + } + + public String getDomainName() { + return domainName; + } + + public String getFlowName() { + return flowName; + } + + public String getFlowType() { + return flowType; + } + + public String getInputFileType() { + return inputFileType; + } + + public void setInputFileType(String inputFileType) { + this.inputFileType = inputFileType; + } + + public String getInputFilePattern() { + return inputFilePattern; + } + + public void setInputFilePattern(String inputFilePattern) { + this.inputFilePattern = inputFilePattern; + } + + protected String getTransformParams() { + return String.format("%s%s%s", domainName, flowName, flowType); + } + } +} diff --git a/data-hub/src/main/java/com/marklogic/hub/Scaffolding.java b/data-hub/src/main/java/com/marklogic/hub/Scaffolding.java index 5107419481..74ce1c8f69 100644 --- a/data-hub/src/main/java/com/marklogic/hub/Scaffolding.java +++ b/data-hub/src/main/java/com/marklogic/hub/Scaffolding.java @@ -29,29 +29,36 @@ public static void createDomain(String domainName, File userlandPath) { domainDir.mkdirs(); } - public static void createFlow(String name, String type, File domainPath) throws IOException { + public static void createFlow(String name, String type, File domainPath) + throws IOException { File typeDir = new File(domainPath, type); File flowDir = new File(typeDir, name); File collectorDir = new File(flowDir, "collector"); collectorDir.mkdirs(); - writeFile("scaffolding/collector.xqy", Paths.get(collectorDir.getPath(), "collector.xqy")); + writeFile("scaffolding/collector.xqy", + Paths.get(collectorDir.getPath(), "collector.xqy")); File contentDir = new File(flowDir, "content"); contentDir.mkdirs(); - writeFile("scaffolding/content.xqy", Paths.get(contentDir.getPath(), "content.xqy")); + writeFile("scaffolding/content.xqy", + Paths.get(contentDir.getPath(), "content.xqy")); - File headerDir = new File(flowDir, "header"); + File headerDir = new File(flowDir, "headers"); headerDir.mkdirs(); - writeFile("scaffolding/header.xqy", Paths.get(contentDir.getPath(), "header.xqy")); + writeFile("scaffolding/headers.xqy", + Paths.get(headerDir.getPath(), "headers.xqy")); File triplesDir = new File(flowDir, "triples"); triplesDir.mkdirs(); - writeFile("scaffolding/triples.xqy", Paths.get(contentDir.getPath(), "triples.xqy")); + writeFile("scaffolding/triples.xqy", + Paths.get(triplesDir.getPath(), "triples.xqy")); } - private static void writeFile(String srcFile, Path dstFile) throws IOException { - InputStream inputStream = Scaffolding.class.getClassLoader().getResourceAsStream(srcFile); + private static void writeFile(String srcFile, Path dstFile) + throws IOException { + InputStream inputStream = Scaffolding.class.getClassLoader() + .getResourceAsStream(srcFile); Files.copy(inputStream, dstFile); } } diff --git a/data-hub/src/main/java/com/marklogic/hub/util/IOUtil.java b/data-hub/src/main/java/com/marklogic/hub/util/IOUtil.java new file mode 100644 index 0000000000..1cd2d9b7ba --- /dev/null +++ b/data-hub/src/main/java/com/marklogic/hub/util/IOUtil.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012-2016 MarkLogic Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.marklogic.hub.util; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import org.slf4j.Logger; + +public class IOUtil { + + public static Thread createInputStreamSink(InputStream inputStream) { + return IOUtil.createInputStreamSink(inputStream, null, LogLevel.DEBUG); + } + + public static Thread createInputStreamSink(InputStream inputStream, Logger logger, LogLevel logLevel) { + return new InputStreamSinkThread(inputStream, logger, logLevel); + } + + public static enum LogLevel { + WARN + ,INFO + ,DEBUG + ,ERROR + } + + private static class InputStreamSinkThread extends Thread { + + private InputStream inputStream; + private Logger logger; + private LogLevel logLevel; + + public InputStreamSinkThread(InputStream inputStream, Logger logger, LogLevel logLevel) { + super("InputStreamSinkThread(" + inputStream + ")"); + + this.inputStream = inputStream; + this.logger = logger; + this.logLevel = logLevel; + } + + @Override + public void run() { + BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); + String line = null; + try { + while ((line = br.readLine()) != null) { + if (logger != null) { + if (logLevel == LogLevel.DEBUG) { + logger.debug(line); + } + else if (logLevel == LogLevel.ERROR) { + logger.error(line); + } + else if (logLevel == LogLevel.WARN) { + logger.error(line); + } + else if (logLevel == LogLevel.INFO) { + logger.info(line); + } + } + } + } catch (IOException e) { + if (logger != null) { + logger.error("Error encountered while reading stream", e); + } + } + } + } +} diff --git a/data-hub/src/main/resources/ml-modules/root/com.marklogic.hub/lib/flow-lib.xqy b/data-hub/src/main/resources/ml-modules/root/com.marklogic.hub/lib/flow-lib.xqy index c74456bdc8..51daa78410 100644 --- a/data-hub/src/main/resources/ml-modules/root/com.marklogic.hub/lib/flow-lib.xqy +++ b/data-hub/src/main/resources/ml-modules/root/com.marklogic.hub/lib/flow-lib.xqy @@ -405,7 +405,9 @@ declare function flow:run-flow( map:get($content, "triple"), $options) return - map:put($content, $destination, $resp) + if (fn:empty($destination)) + then () + else map:put($content, $destination, $resp) }, map:new(( map:entry("isolation", "different-transaction"), @@ -456,12 +458,17 @@ declare function flow:run-plugin( $options as map:map) { let $module-uri := $plugin/@module - let $destination := $plugin/@dest - let $module-name := hul:get-module-name($module-uri) - let $ns := $PLUGIN-NS || fn:lower-case($module-name) - let $func := xdmp:function(fn:QName($ns, "create-" || $destination), $module-uri) return - $func($identifier, $content, $headers, $triples, $options) + if (fn:empty($module-uri)) + then + () + else + let $destination := $plugin/@dest + let $module-name := hul:get-module-name($module-uri) + let $ns := $PLUGIN-NS || fn:lower-case($module-name) + let $func := xdmp:function(fn:QName($ns, "create-" || $destination), $module-uri) + return + $func($identifier, $content, $headers, $triples, $options) }; (:~ diff --git a/data-hub/src/main/resources/ml-modules/root/com.marklogic.hub/mlcp-flow-transform.xqy b/data-hub/src/main/resources/ml-modules/root/com.marklogic.hub/mlcp-flow-transform.xqy new file mode 100644 index 0000000000..cd1c9ae5fa --- /dev/null +++ b/data-hub/src/main/resources/ml-modules/root/com.marklogic.hub/mlcp-flow-transform.xqy @@ -0,0 +1,32 @@ +xquery version "1.0-ml"; + +module namespace mlcpFlow = "http://marklogic.com/hub-in-a-box/mlcp-flow-transform"; + +import module namespace flowLib = "http://marklogic.com/hub-in-a-box/flow-lib" at "/com.marklogic.hub/lib/flow-lib.xqy"; + +declare function mlcpFlow:transform( + $content as map:map, + $context as map:map +) as map:map* +{ + let $uri := map:get($content, "uri") + let $_ := xdmp:log('mlcp-flow-transform received: ' || $uri) + + let $paramNodes := xdmp:unquote(map:get($context, 'transform_param'))/node()/* + let $paramMap := map:new() + let $_ := $paramNodes ! map:put($paramMap, fn:local-name(.), ./string()) + + let $_ := xdmp:log($paramMap) + + let $flow := flowLib:get-flow(map:get($paramMap, 'domain-name'), map:get($paramMap, 'flow-name'), map:get($paramMap, 'flow-type')) + let $_ := xdmp:log('Flow:') + let $_ := xdmp:log($flow) + + let $_ := xdmp:log('Running flow with: ' || $uri) + + let $flowResult := flowLib:run-flow($flow, $uri, $paramMap) + let $_ := xdmp:log('Flow Result:') + let $_ := xdmp:log($flowResult) + + return () +}; \ No newline at end of file diff --git a/quick-start/src/main/java/com/marklogic/hub/config/EnvironmentConfiguration.java b/quick-start/src/main/java/com/marklogic/hub/config/EnvironmentConfiguration.java index c5384cd26e..df03bd1c1c 100644 --- a/quick-start/src/main/java/com/marklogic/hub/config/EnvironmentConfiguration.java +++ b/quick-start/src/main/java/com/marklogic/hub/config/EnvironmentConfiguration.java @@ -114,6 +114,19 @@ public String getUserPluginDir() { } return this.environment.getProperty("userPluginDir.default"); } + + public String getMlcpHomeDir() { + String value = this.properties.getProperty("mlcpHome"); + if (value != null) { + return value; + } + value = this.environment.getProperty("mlcpHome"); + if (value != null) { + this.properties.setProperty("mlcpHome", value); + return value; + } + return "./mlcp"; + } public void setMLHost(String mlHost) { this.properties.setProperty("mlHost", mlHost); @@ -135,6 +148,10 @@ public void setUserPluginDir(String userPluginDir) { this.properties.setProperty("userPluginDir", userPluginDir); } + public void setMlcpHome(String mlcpHomeDir) { + this.properties.setProperty("mlcpHome", mlcpHomeDir); + } + public void loadConfigurationFromFile() { InputStream is = null; try { diff --git a/quick-start/src/main/java/com/marklogic/hub/exception/DomainManagerException.java b/quick-start/src/main/java/com/marklogic/hub/exception/DomainManagerException.java new file mode 100644 index 0000000000..a3d3c9174a --- /dev/null +++ b/quick-start/src/main/java/com/marklogic/hub/exception/DomainManagerException.java @@ -0,0 +1,12 @@ +package com.marklogic.hub.exception; + +public class DomainManagerException extends RuntimeException { + + private static final long serialVersionUID = 4767780854692156195L; + + public DomainManagerException(String message, Throwable cause) { + super( + "Error in connecting to the Domain Manager API with the following message: " + + message, cause); + } +} diff --git a/quick-start/src/main/java/com/marklogic/hub/exception/FormValidationException.java b/quick-start/src/main/java/com/marklogic/hub/exception/FormValidationException.java new file mode 100644 index 0000000000..080b4fb447 --- /dev/null +++ b/quick-start/src/main/java/com/marklogic/hub/exception/FormValidationException.java @@ -0,0 +1,14 @@ +package com.marklogic.hub.exception; + +public class FormValidationException extends RuntimeException { + + private static final long serialVersionUID = 7251931269628838437L; + + public FormValidationException(String message, Throwable cause) { + super(message, cause); + } + + public FormValidationException(String message) { + super(message); + } +} diff --git a/quick-start/src/main/java/com/marklogic/hub/factory/DirectoryModelFactory.java b/quick-start/src/main/java/com/marklogic/hub/factory/DirectoryModelFactory.java deleted file mode 100644 index 56d3d8aad4..0000000000 --- a/quick-start/src/main/java/com/marklogic/hub/factory/DirectoryModelFactory.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.marklogic.hub.factory; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; - -import com.marklogic.hub.model.DirectoryModel; -import com.marklogic.hub.util.FileUtil; - -public class DirectoryModelFactory { - - private DirectoryModel directoryModel; - - public DirectoryModelFactory(String parentDirPath, String directoryName) { - directoryModel = new DirectoryModel(parentDirPath, directoryName); - } - - public void addEmptyDirectories(String parentDirPath, - String... directoryNames) { - for (String directoryName : directoryNames) { - this.addEmptyDirectory(parentDirPath, directoryName, directoryModel); - } - } - - private DirectoryModel addEmptyDirectory(String parentDirPath, - String directoryName, DirectoryModel parentDirectory) { - DirectoryModel directory = new DirectoryModel(parentDirPath, - directoryName); - parentDirectory.getDirectories().add(directory); - return directory; - } - - public void addDirectory(String parentDirPath, String directoryName, - String... childDirectoryNames) { - DirectoryModel directory = this.addEmptyDirectory(parentDirPath, - directoryName, directoryModel); - String newDirecoryPath = parentDirPath + File.separator + directoryName; - for (String childDirectoryName : childDirectoryNames) { - this.addEmptyDirectory(newDirecoryPath, childDirectoryName, - directory); - } - } - - public DirectoryModel listFilesAndDirectories() { - if (directoryModel.getFiles().isEmpty()) { - directoryModel.setFiles(FileUtil.listDirectFiles(directoryModel - .getParentDirPath())); - } - if (directoryModel.getDirectories().isEmpty()) { - directoryModel.setDirectories(this.getDirectoryModels( - directoryModel, false)); - } - return directoryModel; - } - - public List listDirectories() { - if (directoryModel.getDirectories().isEmpty()) { - directoryModel.setDirectories(this.getDirectoryModels( - directoryModel, true)); - } - return directoryModel.getDirectories(); - } - - private List getDirectoryModels( - DirectoryModel currentDirectoryModel, boolean folderOnly) { - List directories = new ArrayList<>(); - String parentDirPath = currentDirectoryModel.getParentDirPath() - + File.separator + currentDirectoryModel.getDirectoryName(); - List folders = FileUtil.listDirectFolders(parentDirPath); - for (String folder : folders) { - DirectoryModel childDirectoryModel = new DirectoryModel( - parentDirPath, folder); - directories.add(childDirectoryModel); - childDirectoryModel.setDirectories(this.getDirectoryModels( - childDirectoryModel, folderOnly)); - if (!folderOnly) { - childDirectoryModel.setFiles(FileUtil - .listDirectFiles(childDirectoryModel.getParentDirPath() - + File.separator - + childDirectoryModel.getDirectoryName())); - } - } - return directories; - } - - public void saveDirectories() { - FileUtil.createDirectories(directoryModel); - } -} diff --git a/quick-start/src/main/java/com/marklogic/hub/factory/DomainModelFactory.java b/quick-start/src/main/java/com/marklogic/hub/factory/DomainModelFactory.java index 19f151240f..ee67ee9838 100644 --- a/quick-start/src/main/java/com/marklogic/hub/factory/DomainModelFactory.java +++ b/quick-start/src/main/java/com/marklogic/hub/factory/DomainModelFactory.java @@ -1,11 +1,14 @@ package com.marklogic.hub.factory; import java.io.File; +import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import com.marklogic.hub.Scaffolding; import com.marklogic.hub.domain.Domain; import com.marklogic.hub.model.DomainModel; import com.marklogic.hub.model.FlowModel; @@ -14,89 +17,96 @@ public class DomainModelFactory { - private Map domainsInServer = new LinkedHashMap<>(); - - public DomainModelFactory() { - // use this when creating a new domain in the client - } - - public DomainModelFactory(List domains) { - // use this when comparing domains in the client and server - if (domains != null) { - for (Domain domain : domains) { - domainsInServer.put(domain.getName(), domain); - } - } - } - - public DomainModel createNewDomain(String userPluginDir, String domainName, - String inputFlowName, String conformFlowName) { - DomainModel domainModel = new DomainModel(); - domainModel.setDomainName(domainName); - domainModel.setInputFlows(new ArrayList<>()); - domainModel.setConformFlows(new ArrayList<>()); - - String domainsPath = userPluginDir + File.separator + FileUtil.DOMAINS_FOLDER; - FileUtil.createFolderIfNecessary(domainsPath, domainName); - - FlowModelFactory flowModelFactory = new FlowModelFactory(domainName); - String domainDirPath = domainsPath + File.separator + domainName; - if (inputFlowName != null) { - FlowModel inputFlow = flowModelFactory.createNewFlow(domainDirPath - + File.separator + FlowType.INPUT, inputFlowName, - FlowType.INPUT); + private Map domainsInServer = new LinkedHashMap<>(); + + public DomainModelFactory() { + // use this when creating a new domain in the client + } + + public DomainModelFactory(List domains) { + // use this when comparing domains in the client and server + if (domains != null) { + for (Domain domain : domains) { + domainsInServer.put(domain.getName(), domain); + } + } + } + + public DomainModel createNewDomain(String userPluginDir, String domainName, + String inputFlowName, String conformFlowName) throws IOException { + DomainModel domainModel = new DomainModel(); + domainModel.setDomainName(domainName); + domainModel.setInputFlows(new ArrayList<>()); + domainModel.setConformFlows(new ArrayList<>()); + + String domainsPath = userPluginDir + File.separator + + FileUtil.DOMAINS_FOLDER; + Scaffolding.createDomain(domainName, new File(domainsPath)); + + FlowModelFactory flowModelFactory = new FlowModelFactory(domainName); + String domainDirPath = domainsPath + File.separator + domainName; + if (inputFlowName != null) { + FlowModel inputFlow = flowModelFactory.createNewFlow(domainDirPath, + inputFlowName, FlowType.INPUT); domainModel.getInputFlows().add(inputFlow); - } - - if (conformFlowName != null) { - FlowModel conformFlow = flowModelFactory.createNewFlow(domainDirPath - + File.separator + FlowType.CONFORM, conformFlowName, - FlowType.CONFORM); - - domainModel.getConformFlows().add(conformFlow); - } - - return domainModel; - } - - public DomainModel createDomain(String domainName, String domainFilePath) { - DomainModel domainModel = new DomainModel(); - domainModel.setDomainName(domainName); - domainModel.setSynched(this.domainsInServer.containsKey(domainName)); - - FlowModelFactory flowModelFactory = new FlowModelFactory( - this.domainsInServer.get(domainName), domainName); - domainModel.setInputFlows(this.getInputFlows(flowModelFactory, - domainFilePath)); - domainModel.setConformFlows(this.getConformFlows(flowModelFactory, - domainFilePath)); - - return domainModel; - } - - private List getInputFlows(FlowModelFactory flowModelFactory, - String domainFilePath) { - return this.getFlows(flowModelFactory, domainFilePath, FlowType.INPUT); - } - - private List getConformFlows(FlowModelFactory flowModelFactory, - String domainFilePath) { - return this - .getFlows(flowModelFactory, domainFilePath, FlowType.CONFORM); - } - - private List getFlows(FlowModelFactory flowModelFactory, - String domainFilePath, FlowType flowType) { - List flows = new ArrayList<>(); - String flowsFilePath = domainFilePath + File.separator - + flowType.getName(); - List flowNames = FileUtil.listDirectFolders(flowsFilePath); - for (String flowName : flowNames) { - FlowModel flowModel = flowModelFactory.createFlow(flowsFilePath, - flowName, flowType); - flows.add(flowModel); - } - return flows; - } - + } + + if (conformFlowName != null) { + FlowModel conformFlow = flowModelFactory.createNewFlow( + domainDirPath, conformFlowName, FlowType.CONFORM); + domainModel.getConformFlows().add(conformFlow); + } + + return domainModel; + } + + public DomainModel createDomain(String domainName, String domainFilePath) { + DomainModel domainModel = new DomainModel(); + domainModel.setDomainName(domainName); + domainModel.setSynched(this.domainsInServer.containsKey(domainName)); + + FlowModelFactory flowModelFactory = new FlowModelFactory( + this.domainsInServer.get(domainName), domainName); + domainModel.setInputFlows(this.getInputFlows(flowModelFactory, + domainFilePath)); + domainModel.setConformFlows(this.getConformFlows(flowModelFactory, + domainFilePath)); + + return domainModel; + } + + private List getInputFlows(FlowModelFactory flowModelFactory, + String domainFilePath) { + return this.getFlows(flowModelFactory, domainFilePath, FlowType.INPUT); + } + + private List getConformFlows(FlowModelFactory flowModelFactory, + String domainFilePath) { + return this + .getFlows(flowModelFactory, domainFilePath, FlowType.CONFORM); + } + + private List getFlows(FlowModelFactory flowModelFactory, + String domainFilePath, FlowType flowType) { + List flows = new ArrayList<>(); + String flowsFilePath = domainFilePath + File.separator + + flowType.getName(); + List flowNames = FileUtil.listDirectFolders(flowsFilePath); + for (String flowName : flowNames) { + FlowModel flowModel = flowModelFactory.createFlow(flowsFilePath, + flowName, flowType); + flows.add(flowModel); + } + return flows; + } + + public static Map toDomainModelMap( + List domains) { + Map domainModelMap = new HashMap(); + for (DomainModel model : domains) { + domainModelMap.put(model.getDomainName(), model); + } + + return domainModelMap; + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/factory/FlowModelFactory.java b/quick-start/src/main/java/com/marklogic/hub/factory/FlowModelFactory.java index 19c2c119d4..c51e0ea9de 100644 --- a/quick-start/src/main/java/com/marklogic/hub/factory/FlowModelFactory.java +++ b/quick-start/src/main/java/com/marklogic/hub/factory/FlowModelFactory.java @@ -1,9 +1,12 @@ package com.marklogic.hub.factory; +import java.io.File; +import java.io.IOException; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import com.marklogic.hub.Scaffolding; import com.marklogic.hub.domain.Domain; import com.marklogic.hub.flow.Flow; import com.marklogic.hub.model.FlowModel; @@ -12,75 +15,82 @@ public class FlowModelFactory { - private Map flowsInServer = new LinkedHashMap<>(); - private String domainName; + private Map flowsInServer = new LinkedHashMap<>(); + private String domainName; - public FlowModelFactory(String domainName) { - // use this when creating a new domain in the client - this.domainName = domainName; - } + public FlowModelFactory(String domainName) { + // use this when creating a new domain in the client + this.domainName = domainName; + } - public FlowModelFactory(Domain domain, String domainName) { - // use this when comparing flows in the client and server - this.domainName = domainName; - if (domain != null) { - List flows = domain.getFlows(); - if (flows != null) { - for (Flow flow : flows) { - flowsInServer.put(flow.getName(), flow); - } - } - } - } + public FlowModelFactory(Domain domain, String domainName) { + // use this when comparing flows in the client and server + this.domainName = domainName; + if (domain != null) { + List flows = domain.getFlows(); + if (flows != null) { + for (Flow flow : flows) { + flowsInServer.put(flow.getName(), flow); + } + } + } + } - public FlowModel createNewFlow(String parentDirPath, String flowName, - FlowType flowType) { - FlowModel flowModel = new FlowModel(); - flowModel.setDomainName(domainName); - flowModel.setFlowName(flowName); - flowModel.setSynched(false); - this.createEmptyFlowDirectories(parentDirPath, flowName, flowType); - DirectoryModelFactory directoryModelFactory = new DirectoryModelFactory( - parentDirPath, flowName); - flowModel.setDirectory(directoryModelFactory.listFilesAndDirectories()); - return flowModel; - } + public FlowModel createNewFlow(String domainDirPath, String flowName, + FlowType flowType) throws IOException { + FlowModel flowModel = new FlowModel(); + flowModel.setDomainName(domainName); + flowModel.setFlowName(flowName); + flowModel.setSynched(false); - private void createEmptyFlowDirectories(String parentDirPath, - String flowName, FlowType flowType) { - String newFlowPath = FileUtil.createFolderIfNecessary(parentDirPath, - flowName); - // create empty plugin directories - DirectoryModelFactory directoryModelFactory = new DirectoryModelFactory( - parentDirPath, flowName); - directoryModelFactory.addEmptyDirectories(newFlowPath, new String[] { - "content", "headers", "triples", "validations" }); - if (flowType == FlowType.CONFORM) { - directoryModelFactory.addEmptyDirectories(newFlowPath, - new String[] { "custom-flow", "collector", "writer" }); - directoryModelFactory.addDirectory(newFlowPath, "egress", - new String[] { "document-transforms", "search-options", - "REST-extensions" }); - } - directoryModelFactory.saveDirectories(); - } + Scaffolding.createFlow(flowName, flowType.getName(), new File( + domainDirPath)); - public FlowModel createFlow(String flowsFilePath, String flowName, - FlowType flowType) { - FlowModel flowModel = new FlowModel(); - flowModel.setDomainName(domainName); - flowModel.setFlowName(flowName); - DirectoryModelFactory directoryModelFactory = new DirectoryModelFactory( - flowsFilePath, flowName); - flowModel.setDirectory(directoryModelFactory.listFilesAndDirectories()); - Flow flow = this.flowsInServer.get(flowName); - boolean synched = false; - // TODO: confirm the value of the collector's type - if (flow != null && flow.getCollector() != null - && flowType.getType().equals(flow.getCollector().getType())) { - synched = true; - } - flowModel.setSynched(synched); - return flowModel; - } + String absolutePath = domainDirPath + File.separator + + flowType.getName() + File.separator + flowName; + + TreeDataFactory treeDataFactory = new TreeDataFactory(absolutePath, + flowName); + flowModel.setTreeData(treeDataFactory.listFilesAndDirectories()); + return flowModel; + } + + private void createEmptyFlowDirectories(String parentDirPath, + String flowName, FlowType flowType) { + String newFlowPath = FileUtil.createFolderIfNecessary(parentDirPath, + flowName); + // create empty plugin directories + TreeDataFactory treeDataFactory = new TreeDataFactory(newFlowPath, + flowName); + treeDataFactory.addEmptyDirectories(newFlowPath, new String[] { + "content", "headers", "triples", "validations" }); + if (flowType == FlowType.CONFORM) { + treeDataFactory.addEmptyDirectories(newFlowPath, new String[] { + "custom-flow", "collector", "writer" }); + treeDataFactory.addDirectory(newFlowPath, "egress", + new String[] { "document-transforms", "search-options", + "REST-extensions" }); + } + treeDataFactory.saveDirectories(); + } + + public FlowModel createFlow(String parentDirPath, String flowName, + FlowType flowType) { + FlowModel flowModel = new FlowModel(); + flowModel.setDomainName(domainName); + flowModel.setFlowName(flowName); + String absolutePath = parentDirPath + File.separator + flowName; + TreeDataFactory treeDataFactory = new TreeDataFactory(absolutePath, + flowName); + flowModel.setTreeData(treeDataFactory.listFilesAndDirectories()); + Flow flow = this.flowsInServer.get(flowName); + boolean synched = false; + // TODO: confirm the value of the collector's type + if (flow != null && flow.getCollector() != null + && flowType.getType().equals(flow.getCollector().getType())) { + synched = true; + } + flowModel.setSynched(synched); + return flowModel; + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/factory/TreeDataFactory.java b/quick-start/src/main/java/com/marklogic/hub/factory/TreeDataFactory.java new file mode 100644 index 0000000000..595b3d337e --- /dev/null +++ b/quick-start/src/main/java/com/marklogic/hub/factory/TreeDataFactory.java @@ -0,0 +1,62 @@ +package com.marklogic.hub.factory; + +import java.io.File; +import java.util.List; + +import com.marklogic.hub.model.TreeData; +import com.marklogic.hub.util.FileUtil; + +public class TreeDataFactory { + + private TreeData treeData; + + public TreeDataFactory(String absolutePath, String label) { + treeData = new TreeData(absolutePath, label); + } + + public void addEmptyDirectories(String parentDirPath, String... labels) { + for (String label : labels) { + this.addEmptyDirectory(parentDirPath, label, treeData); + } + } + + private TreeData addEmptyDirectory(String parentDirPath, String label, + TreeData parentTreeData) { + String absolutePath = parentDirPath + File.separator + label; + TreeData treeData = new TreeData(absolutePath, label); + parentTreeData.getChildren().add(treeData); + return treeData; + } + + public void addDirectory(String parentDirPath, String label, + String... childLabels) { + TreeData childTreeData = this.addEmptyDirectory(parentDirPath, label, + treeData); + String newDirectoryPath = parentDirPath + File.separator + label; + for (String childLabel : childLabels) { + this.addEmptyDirectory(newDirectoryPath, childLabel, childTreeData); + } + } + + public TreeData listFilesAndDirectories() { + if (treeData.getChildren().isEmpty()) { + treeData.setChildren(this.getChildren(treeData)); + } + return treeData; + } + + private List getChildren(TreeData treeData) { + List children = FileUtil.listDirectFilesAndFolders(treeData + .getData().get(TreeData.KEY_ABSOLUTE_PATH)); + for (TreeData childTreeData : children) { + if (childTreeData.isNoLeaf()) { + childTreeData.setChildren(this.getChildren(childTreeData)); + } + } + return children; + } + + public void saveDirectories() { + FileUtil.createDirectories(treeData); + } +} diff --git a/quick-start/src/main/java/com/marklogic/hub/model/DirectoryModel.java b/quick-start/src/main/java/com/marklogic/hub/model/DirectoryModel.java deleted file mode 100644 index 6016c82e11..0000000000 --- a/quick-start/src/main/java/com/marklogic/hub/model/DirectoryModel.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.marklogic.hub.model; - -import java.util.ArrayList; -import java.util.List; - -public class DirectoryModel { - - private String parentDirPath; - private String directoryName; - private List directories = new ArrayList<>(); - private List files = new ArrayList<>(); - - public DirectoryModel() { - - } - - public DirectoryModel(String parentDirPath, String directoryName) { - this.parentDirPath = parentDirPath; - this.directoryName = directoryName; - } - - public String getDirectoryName() { - return directoryName; - } - - public void setDirectoryName(String directoryName) { - this.directoryName = directoryName; - } - - public List getDirectories() { - return directories; - } - - public void setDirectories(List directories) { - this.directories = directories; - } - - public List getFiles() { - return files; - } - - public void setFiles(List files) { - this.files = files; - } - - public String getParentDirPath() { - return parentDirPath; - } - - public void setParentDirPath(String parentDirPath) { - this.parentDirPath = parentDirPath; - } - - public String toString() { - return directoryName; - } -} diff --git a/quick-start/src/main/java/com/marklogic/hub/model/DomainModel.java b/quick-start/src/main/java/com/marklogic/hub/model/DomainModel.java index 25a4172347..0c10dee189 100644 --- a/quick-start/src/main/java/com/marklogic/hub/model/DomainModel.java +++ b/quick-start/src/main/java/com/marklogic/hub/model/DomainModel.java @@ -1,6 +1,8 @@ package com.marklogic.hub.model; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class DomainModel { @@ -20,6 +22,18 @@ public void setDomainName(String domainName) { public List getInputFlows() { return inputFlows; } + + public Map getInputFlowsAsMap() { + Map flowModels = new HashMap<>(); + + if (inputFlows != null) { + for (FlowModel model : inputFlows) { + flowModels.put(model.getFlowName(), model); + } + } + + return flowModels; + } public void setInputFlows(List inputFlows) { this.inputFlows = inputFlows; @@ -28,6 +42,18 @@ public void setInputFlows(List inputFlows) { public List getConformFlows() { return conformFlows; } + + public Map getConformFlowsAsMap() { + Map flowModels = new HashMap<>(); + + if (conformFlows != null) { + for (FlowModel model : conformFlows) { + flowModels.put(model.getFlowName(), model); + } + } + + return flowModels; + } public void setConformFlows(List conformFlows) { this.conformFlows = conformFlows; @@ -41,4 +67,63 @@ public void setSynched(boolean isSynched) { this.isSynched = isSynched; } + public void setInputFlowsSynched(boolean synched) { + if (inputFlows != null) { + for (FlowModel model : inputFlows) { + model.setSynched(synched); + } + } + } + + public void setConformFlowsSynched(boolean synched) { + if (conformFlows != null) { + for (FlowModel model : conformFlows) { + model.setSynched(synched); + } + } + } + + public void copySyncStatusFrom(DomainModel oldModel) { + if (oldModel == null) { + return; + } + if (!domainName.equals(oldModel.getDomainName())) { + return; + } + + setSynched(oldModel.isSynched()); + + Map inputFlowModels = oldModel.getInputFlowsAsMap(); + if (inputFlows != null) { + for (FlowModel model : inputFlows) { + FlowModel oldFlow = inputFlowModels.get(model.getFlowName()); + if (oldFlow != null) { + model.setSynched(oldFlow.isSynched()); + } + } + } + + Map conformFlowModels = oldModel.getConformFlowsAsMap(); + if (conformFlows != null) { + for (FlowModel model : conformFlows) { + FlowModel oldFlow = conformFlowModels.get(model.getFlowName()); + if (oldFlow != null) { + model.setSynched(oldFlow.isSynched()); + } + } + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + sb.append("domainName="); + sb.append(domainName); + sb.append("isSynched="); + sb.append(isSynched); + sb.append("}"); + + return sb.toString(); + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/model/FlowModel.java b/quick-start/src/main/java/com/marklogic/hub/model/FlowModel.java index 8a5b2f0424..dcbef6b754 100644 --- a/quick-start/src/main/java/com/marklogic/hub/model/FlowModel.java +++ b/quick-start/src/main/java/com/marklogic/hub/model/FlowModel.java @@ -1,44 +1,57 @@ package com.marklogic.hub.model; - public class FlowModel { - private String domainName; - private String flowName; - private boolean isSynched; - private DirectoryModel directory; - - public String getDomainName() { - return domainName; - } - - public void setDomainName(String domainName) { - this.domainName = domainName; - - } - - public String getFlowName() { - return flowName; - } - - public void setFlowName(String flowName) { - this.flowName = flowName; - } - - public boolean isSynched() { - return isSynched; - } - - public void setSynched(boolean isSynched) { - this.isSynched = isSynched; - } - - public DirectoryModel getDirectory() { - return directory; - } - - public void setDirectory(DirectoryModel directory) { - this.directory = directory; - } - + private String domainName; + private String flowName; + private boolean isSynched; + private TreeData treeData; + + public String getDomainName() { + return domainName; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + + } + + public String getFlowName() { + return flowName; + } + + public void setFlowName(String flowName) { + this.flowName = flowName; + } + + public boolean isSynched() { + return isSynched; + } + + public void setSynched(boolean isSynched) { + this.isSynched = isSynched; + } + + public TreeData getTreeData() { + return treeData; + } + + public void setTreeData(TreeData treeData) { + this.treeData = treeData; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("{"); + sb.append("domainName="); + sb.append(domainName); + sb.append("flowName="); + sb.append(flowName); + sb.append("isSynched="); + sb.append(isSynched); + sb.append("}"); + + return sb.toString(); + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/model/FlowType.java b/quick-start/src/main/java/com/marklogic/hub/model/FlowType.java index 509af7c531..4bd478c848 100644 --- a/quick-start/src/main/java/com/marklogic/hub/model/FlowType.java +++ b/quick-start/src/main/java/com/marklogic/hub/model/FlowType.java @@ -22,7 +22,7 @@ public String getType() { public static FlowType getFlowType(String type) { for (FlowType flowType : FlowType.values()) { - if (flowType.getType().equals(type)) { + if (flowType.getName().equals(type)) { return flowType; } } diff --git a/quick-start/src/main/java/com/marklogic/hub/model/RunFlowModel.java b/quick-start/src/main/java/com/marklogic/hub/model/RunFlowModel.java new file mode 100644 index 0000000000..1be3058555 --- /dev/null +++ b/quick-start/src/main/java/com/marklogic/hub/model/RunFlowModel.java @@ -0,0 +1,15 @@ +package com.marklogic.hub.model; + +public class RunFlowModel { + private String domainName; + private String flowName; + + public String getDomainName() { + return domainName; + } + + public String getFlowName() { + return flowName; + } + +} diff --git a/quick-start/src/main/java/com/marklogic/hub/model/TreeData.java b/quick-start/src/main/java/com/marklogic/hub/model/TreeData.java new file mode 100644 index 0000000000..606998ce6e --- /dev/null +++ b/quick-start/src/main/java/com/marklogic/hub/model/TreeData.java @@ -0,0 +1,58 @@ +package com.marklogic.hub.model; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class TreeData { + + public static final String KEY_ABSOLUTE_PATH = "absolutePath"; + + private Map data = new HashMap<>(); + private String label; + private List children = new ArrayList<>(); + private boolean noLeaf; + + public TreeData() { + + } + + public TreeData(String absolutePath, String label) { + data.put(KEY_ABSOLUTE_PATH, absolutePath); + this.label = label; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + + public boolean isNoLeaf() { + return noLeaf; + } + + public void setNoLeaf(boolean noLeaf) { + this.noLeaf = noLeaf; + } + + public Map getData() { + return data; + } + + public void setData(Map data) { + this.data = data; + } + +} diff --git a/quick-start/src/main/java/com/marklogic/hub/service/DomainManagerService.java b/quick-start/src/main/java/com/marklogic/hub/service/DomainManagerService.java index d4d567d4a5..bdbe6dec90 100644 --- a/quick-start/src/main/java/com/marklogic/hub/service/DomainManagerService.java +++ b/quick-start/src/main/java/com/marklogic/hub/service/DomainManagerService.java @@ -1,6 +1,7 @@ package com.marklogic.hub.service; import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -16,6 +17,7 @@ import com.marklogic.hub.DomainManager; import com.marklogic.hub.config.EnvironmentConfiguration; import com.marklogic.hub.domain.Domain; +import com.marklogic.hub.exception.DomainManagerException; import com.marklogic.hub.factory.DomainModelFactory; import com.marklogic.hub.model.DomainModel; import com.marklogic.hub.util.FileUtil; @@ -23,66 +25,71 @@ @Service public class DomainManagerService { - private static final Logger LOGGER = LoggerFactory - .getLogger(DomainManagerService.class); + private static final Logger LOGGER = LoggerFactory + .getLogger(DomainManagerService.class); - @Autowired - private EnvironmentConfiguration environmentConfiguration; + @Autowired + private EnvironmentConfiguration environmentConfiguration; - public DomainManager getDomainManager() { + public DomainManager getDomainManager() { - Authentication authMethod = Authentication - .valueOf(environmentConfiguration.getMLAuth().toUpperCase()); - DatabaseClient client = DatabaseClientFactory.newClient( - environmentConfiguration.getMLHost(), - Integer.parseInt(environmentConfiguration.getMLRestPort()), - environmentConfiguration.getMLUsername(), - environmentConfiguration.getMLPassword(), authMethod); - return new DomainManager(client); + Authentication authMethod = Authentication + .valueOf(environmentConfiguration.getMLAuth().toUpperCase()); + DatabaseClient client = DatabaseClientFactory.newClient( + environmentConfiguration.getMLHost(), + Integer.parseInt(environmentConfiguration.getMLRestPort()), + environmentConfiguration.getMLUsername(), + environmentConfiguration.getMLPassword(), authMethod); + return new DomainManager(client); - } + } - public List getDomains() { - List domains = new ArrayList<>(); - List domainsInServer = this.getDomainsInServer(); - String domainsPath = FileUtil.createFolderIfNecessary( - environmentConfiguration.getUserPluginDir(), - FileUtil.DOMAINS_FOLDER); - List domainNames = FileUtil.listDirectFolders(domainsPath); - DomainModelFactory domainModelFactory = new DomainModelFactory( - domainsInServer); - for (String domainName : domainNames) { - LOGGER.debug("Domain : " + domainName); - domains.add(domainModelFactory.createDomain(domainName, domainsPath - + File.separator + domainName)); - } - return domains; - } + public List getDomains() { + List domains = new ArrayList<>(); + List domainsInServer = this.getDomainsInServer(); + String domainsPath = FileUtil.createFolderIfNecessary( + environmentConfiguration.getUserPluginDir(), + FileUtil.DOMAINS_FOLDER); + List domainNames = FileUtil.listDirectFolders(domainsPath); + DomainModelFactory domainModelFactory = new DomainModelFactory( + domainsInServer); + for (String domainName : domainNames) { + LOGGER.debug("Domain : " + domainName); + domains.add(domainModelFactory.createDomain(domainName, domainsPath + + File.separator + domainName)); + } + return domains; + } - private List getDomainsInServer() { - List domainsInServer = new ArrayList<>(); - try { - DomainManager domainManager = getDomainManager(); - domainsInServer = domainManager.getDomains(); - } catch (MarkLogicServerException e) { - // TODO catch this temporarily - // This should not return an error as the deploy to server should - // validate the plugins beforehand - } - return domainsInServer; - } + private List getDomainsInServer() { + List domainsInServer = new ArrayList<>(); + try { + DomainManager domainManager = getDomainManager(); + domainsInServer = domainManager.getDomains(); + } catch (MarkLogicServerException e) { + // TODO catch this temporarily + // This should not return an error as the deploy to server should + // validate the plugins beforehand + } + return domainsInServer; + } - public Domain getDomain(String domainName) { - DomainManager domainManager = getDomainManager(); - return domainManager.getDomain(domainName); - } + public Domain getDomain(String domainName) { + DomainManager domainManager = getDomainManager(); + return domainManager.getDomain(domainName); + } - public DomainModel createDomain(String domainName, String inputFlowName, - String conformFlowName) { - DomainModelFactory domainModelFactory = new DomainModelFactory(); - DomainModel domainModel = domainModelFactory.createNewDomain( - environmentConfiguration.getUserPluginDir(), domainName, - inputFlowName, conformFlowName); - return domainModel; - } + public DomainModel createDomain(String domainName, String inputFlowName, + String conformFlowName) { + DomainModelFactory domainModelFactory = new DomainModelFactory(); + DomainModel domainModel; + try { + domainModel = domainModelFactory.createNewDomain( + environmentConfiguration.getUserPluginDir(), domainName, + inputFlowName, conformFlowName); + } catch (IOException e) { + throw new DomainManagerException(e.getMessage(), e); + } + return domainModel; + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/service/FlowManagerService.java b/quick-start/src/main/java/com/marklogic/hub/service/FlowManagerService.java index 5a13954fee..fee0329be4 100644 --- a/quick-start/src/main/java/com/marklogic/hub/service/FlowManagerService.java +++ b/quick-start/src/main/java/com/marklogic/hub/service/FlowManagerService.java @@ -1,6 +1,7 @@ package com.marklogic.hub.service; import java.io.File; +import java.io.IOException; import java.util.List; import org.slf4j.Logger; @@ -13,6 +14,7 @@ import com.marklogic.client.DatabaseClientFactory.Authentication; import com.marklogic.hub.FlowManager; import com.marklogic.hub.config.EnvironmentConfiguration; +import com.marklogic.hub.exception.FlowManagerException; import com.marklogic.hub.factory.FlowModelFactory; import com.marklogic.hub.flow.Flow; import com.marklogic.hub.model.FlowModel; @@ -22,68 +24,73 @@ @Service public class FlowManagerService { - private static final Logger LOGGER = LoggerFactory - .getLogger(FlowManagerService.class); - - @Autowired - private EnvironmentConfiguration environmentConfiguration; - - public FlowManager getFlowManager() { - - Authentication authMethod = Authentication - .valueOf(environmentConfiguration.getMLAuth().toUpperCase()); - DatabaseClient client = DatabaseClientFactory.newClient( - environmentConfiguration.getMLHost(), - Integer.parseInt(environmentConfiguration.getMLRestPort()), - environmentConfiguration.getMLUsername(), - environmentConfiguration.getMLPassword(), authMethod); - return new FlowManager(client); - - } - - public List getFlows(String domainName) { - FlowManager flowManager = getFlowManager(); - return flowManager.getFlows(domainName); - } - - public Flow getFlow(String domainName, String flowName) { - FlowManager flowManager = getFlowManager(); - return flowManager.getFlow(domainName, flowName); - } - - public void installFlow(Flow flow) { - FlowManager flowManager = getFlowManager(); - flowManager.installFlow(flow); - } - - public void uninstallFlow(String flowName) { - FlowManager flowManager = getFlowManager(); - flowManager.uninstallFlow(flowName); - } - - public void testFlow(Flow flow) { - FlowManager flowManager = getFlowManager(); - flowManager.testFlow(flow); - } - - public void runFlow(Flow flow, int batchSize) { - FlowManager flowManager = getFlowManager(); - flowManager.runFlow(flow, batchSize); - } - - public void runFlowsInParallel(Flow... flows) { - FlowManager flowManager = getFlowManager(); - flowManager.runFlowsInParallel(flows); - } - - public FlowModel createFlow(String domainName, String flowName, - String flowType) { - FlowModelFactory flowModelFactory = new FlowModelFactory(domainName); - String parentDirPath = environmentConfiguration.getUserPluginDir() - + File.separator + FileUtil.DOMAINS_FOLDER + File.separator - + domainName + File.separator + flowType; - FlowModel flowModel = flowModelFactory.createNewFlow(parentDirPath, - flowName, FlowType.getFlowType(flowType)); - return flowModel; - } + private static final Logger LOGGER = LoggerFactory + .getLogger(FlowManagerService.class); + + @Autowired + private EnvironmentConfiguration environmentConfiguration; + + public FlowManager getFlowManager() { + + Authentication authMethod = Authentication + .valueOf(environmentConfiguration.getMLAuth().toUpperCase()); + DatabaseClient client = DatabaseClientFactory.newClient( + environmentConfiguration.getMLHost(), + Integer.parseInt(environmentConfiguration.getMLRestPort()), + environmentConfiguration.getMLUsername(), + environmentConfiguration.getMLPassword(), authMethod); + return new FlowManager(client); + + } + + public List getFlows(String domainName) { + FlowManager flowManager = getFlowManager(); + return flowManager.getFlows(domainName); + } + + public Flow getFlow(String domainName, String flowName) { + FlowManager flowManager = getFlowManager(); + return flowManager.getFlow(domainName, flowName); + } + + public void installFlow(Flow flow) { + FlowManager flowManager = getFlowManager(); + flowManager.installFlow(flow); + } + + public void uninstallFlow(String flowName) { + FlowManager flowManager = getFlowManager(); + flowManager.uninstallFlow(flowName); + } + + public void testFlow(Flow flow) { + FlowManager flowManager = getFlowManager(); + flowManager.testFlow(flow); + } + + public void runFlow(Flow flow, int batchSize) { + FlowManager flowManager = getFlowManager(); + flowManager.runFlow(flow, batchSize); + } + + public void runFlowsInParallel(Flow... flows) { + FlowManager flowManager = getFlowManager(); + flowManager.runFlowsInParallel(flows); + } + + public FlowModel createFlow(String domainName, String flowName, + String flowType) { + FlowModelFactory flowModelFactory = new FlowModelFactory(domainName); + String domainDirPath = environmentConfiguration.getUserPluginDir() + + File.separator + FileUtil.DOMAINS_FOLDER + File.separator + + domainName; + FlowModel flowModel; + try { + flowModel = flowModelFactory.createNewFlow(domainDirPath, flowName, + FlowType.getFlowType(flowType)); + } catch (IOException e) { + throw new FlowManagerException(e.getMessage(), e); + } + return flowModel; + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/util/FileUtil.java b/quick-start/src/main/java/com/marklogic/hub/util/FileUtil.java index c588cf6ca5..2ac59b5f3b 100644 --- a/quick-start/src/main/java/com/marklogic/hub/util/FileUtil.java +++ b/quick-start/src/main/java/com/marklogic/hub/util/FileUtil.java @@ -7,67 +7,84 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.marklogic.hub.model.DirectoryModel; +import com.marklogic.hub.model.TreeData; public class FileUtil { - private static final Logger LOGGER = LoggerFactory - .getLogger(FileUtil.class); + private static final Logger LOGGER = LoggerFactory + .getLogger(FileUtil.class); - public static final String DOMAINS_FOLDER = "domains"; + public static final String DOMAINS_FOLDER = "domains"; - public static List listDirectFolders(String path) { - List folders = new ArrayList<>(); - File rootDirectory = new File(path); - if (rootDirectory.exists() && rootDirectory.isDirectory()) { - File[] files = rootDirectory.listFiles(); - for (File file : files) { - if (file.isDirectory() && !file.isHidden()) { - folders.add(file.getName()); - } - } - } - return folders; - } + public static List listDirectFolders(String path) { + List folders = new ArrayList<>(); + File rootDirectory = new File(path); + if (rootDirectory.exists() && rootDirectory.isDirectory()) { + File[] files = rootDirectory.listFiles(); + for (File file : files) { + if (file.isDirectory() && !file.isHidden()) { + folders.add(file.getName()); + } + } + } + return folders; + } - public static List listDirectFiles(String path) { - List filenames = new ArrayList<>(); - File rootDirectory = new File(path); - if (rootDirectory.exists() && rootDirectory.isDirectory()) { - File[] files = rootDirectory.listFiles(); - for (File file : files) { - if (!file.isDirectory() && !file.isHidden()) { - filenames.add(file.getName()); - } - } - } - return filenames; - } + public static List listDirectFiles(String path) { + List filenames = new ArrayList<>(); + File rootDirectory = new File(path); + if (rootDirectory.exists() && rootDirectory.isDirectory()) { + File[] files = rootDirectory.listFiles(); + for (File file : files) { + if (!file.isDirectory() && !file.isHidden()) { + filenames.add(file.getName()); + } + } + } + return filenames; + } - public static String createFolderIfNecessary(String path, String folderName) { - File rootDirectory = new File(path); - if (!rootDirectory.exists()) { - LOGGER.debug("New folder is created at " - + rootDirectory.getAbsolutePath()); - rootDirectory.mkdir(); - } - if (rootDirectory.exists() && rootDirectory.isDirectory()) { - File folder = new File(rootDirectory.getAbsolutePath() - + File.separator + folderName); - if (!folder.exists()) { - folder.mkdir(); - LOGGER.debug("New folder is created at " - + folder.getAbsolutePath()); - } - } - return path + File.separator + folderName; - } + public static List listDirectFilesAndFolders(String path) { + List treeDataList = new ArrayList<>(); + File rootDirectory = new File(path); + if (rootDirectory.exists() && rootDirectory.isDirectory()) { + File[] files = rootDirectory.listFiles(); + for (File file : files) { + if (!file.isHidden()) { + TreeData treeData = new TreeData(file.getAbsolutePath(), + file.getName()); + treeData.setNoLeaf(file.isDirectory()); + treeDataList.add(treeData); + } + } + } + return treeDataList; + } - public static void createDirectories(DirectoryModel directoryModel) { - FileUtil.createFolderIfNecessary(directoryModel.getParentDirPath(), - directoryModel.getDirectoryName()); - for (DirectoryModel childDirectory : directoryModel.getDirectories()) { - FileUtil.createDirectories(childDirectory); - } - } + public static String createFolderIfNecessary(String path, String folderName) { + File rootDirectory = new File(path); + if (!rootDirectory.exists()) { + LOGGER.debug("New folder is created at " + + rootDirectory.getAbsolutePath()); + rootDirectory.mkdir(); + } + if (rootDirectory.exists() && rootDirectory.isDirectory()) { + File folder = new File(rootDirectory.getAbsolutePath() + + File.separator + folderName); + if (!folder.exists()) { + folder.mkdir(); + LOGGER.debug("New folder is created at " + + folder.getAbsolutePath()); + } + } + return path + File.separator + folderName; + } + + public static void createDirectories(TreeData treeData) { + File file = new File(treeData.getData().get(TreeData.KEY_ABSOLUTE_PATH)); + FileUtil.createFolderIfNecessary(file.getParent(), treeData.getLabel()); + for (TreeData childTreeData : treeData.getChildren()) { + FileUtil.createDirectories(childTreeData); + } + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/web/bean/SyncStatusBean.java b/quick-start/src/main/java/com/marklogic/hub/web/bean/SyncStatusBean.java new file mode 100644 index 0000000000..0c0188da0d --- /dev/null +++ b/quick-start/src/main/java/com/marklogic/hub/web/bean/SyncStatusBean.java @@ -0,0 +1,66 @@ +package com.marklogic.hub.web.bean; + +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; + +import javax.annotation.ManagedBean; + +import org.springframework.context.annotation.Scope; +import org.springframework.web.context.WebApplicationContext; + +@ManagedBean +@Scope(scopeName=WebApplicationContext.SCOPE_SESSION) +public class SyncStatusBean { + private Set modifiedDomains = Collections.synchronizedSet(new LinkedHashSet<>()); + private Map> modifiedInputFlows = Collections.synchronizedMap(new HashMap<>()); + private Map> modifiedConformFlows = Collections.synchronizedMap(new HashMap<>()); + + public Set getModifiedDomains() { + return modifiedDomains; + } + + public void addModifiedDomain(String domain) { + modifiedDomains.add(domain); + } + + public Map> getModifiedInputFlows() { + return modifiedInputFlows; + } + + public void addModifiedInputFlow(String domain, String flow) { + synchronized (modifiedInputFlows) { + Set domainFlows = modifiedInputFlows.get(domain); + if (domainFlows == null) { + domainFlows = new LinkedHashSet<>(); + modifiedInputFlows.put(domain, domainFlows); + } + + domainFlows.add(flow); + } + } + + public Map> getModifiedConformFlows() { + return modifiedConformFlows; + } + + public void addModifiedConformFlow(String domain, String flow) { + synchronized (modifiedConformFlows) { + Set domainFlows = modifiedConformFlows.get(domain); + if (domainFlows == null) { + domainFlows = new LinkedHashSet<>(); + modifiedConformFlows.put(domain, domainFlows); + } + + domainFlows.add(flow); + } + } + + public void clearModifications() { + modifiedDomains.clear(); + modifiedInputFlows.clear(); + modifiedConformFlows.clear(); + } +} diff --git a/quick-start/src/main/java/com/marklogic/hub/web/controller/api/DataHubServerApiController.java b/quick-start/src/main/java/com/marklogic/hub/web/controller/api/DataHubServerApiController.java index 37a1e513fc..75360cc3f0 100644 --- a/quick-start/src/main/java/com/marklogic/hub/web/controller/api/DataHubServerApiController.java +++ b/quick-start/src/main/java/com/marklogic/hub/web/controller/api/DataHubServerApiController.java @@ -1,6 +1,7 @@ package com.marklogic.hub.web.controller.api; import java.io.File; +import java.util.List; import java.util.Set; import javax.servlet.http.HttpServletRequest; @@ -9,6 +10,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; import org.springframework.http.MediaType; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.RequestBody; @@ -18,13 +20,16 @@ import com.marklogic.hub.config.EnvironmentConfiguration; import com.marklogic.hub.exception.DataHubException; +import com.marklogic.hub.model.DomainModel; import com.marklogic.hub.service.DataHubService; import com.marklogic.hub.service.DomainManagerService; +import com.marklogic.hub.web.bean.SyncStatusBean; import com.marklogic.hub.web.controller.BaseController; import com.marklogic.hub.web.form.LoginForm; @RestController @RequestMapping("/api/data-hub") +@Scope("session") public class DataHubServerApiController extends BaseController { private static final Logger LOGGER = LoggerFactory .getLogger(DataHubServerApiController.class); @@ -37,6 +42,9 @@ public class DataHubServerApiController extends BaseController { @Autowired private DomainManagerService domainManagerService; + + @Autowired + private SyncStatusBean syncStatus; @RequestMapping(value = "login", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_UTF8_VALUE }, produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }) public LoginForm postLogin(@RequestBody LoginForm loginForm, @@ -123,8 +131,27 @@ public void uninstall() { } @RequestMapping(value = "install-user-modules", method = RequestMethod.POST) - public Set installUserModules() { - return dataHubService.installUserModules(); + public Set installUserModules(HttpSession session) { + synchronized (syncStatus) { + Set files = dataHubService.installUserModules(); + + // refresh the list of domains saved in the session + List domains = domainManagerService.getDomains(); + LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); + loginForm.refreshDomains(domains); + + // set synched = true + for (DomainModel domainModel : loginForm.getDomains()) { + domainModel.setSynched(true); + domainModel.setInputFlowsSynched(true); + domainModel.setConformFlowsSynched(true); + } + + syncStatus.clearModifications(); + syncStatus.notifyAll(); + + return files; + } } private void updateEnvironmentConfiguration(LoginForm loginForm) { diff --git a/quick-start/src/main/java/com/marklogic/hub/web/controller/api/DomainApiController.java b/quick-start/src/main/java/com/marklogic/hub/web/controller/api/DomainApiController.java index d7d90def5e..771105aef6 100644 --- a/quick-start/src/main/java/com/marklogic/hub/web/controller/api/DomainApiController.java +++ b/quick-start/src/main/java/com/marklogic/hub/web/controller/api/DomainApiController.java @@ -5,13 +5,12 @@ import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.WatchEvent; -import java.util.Collections; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; import javax.servlet.http.HttpSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; @@ -26,9 +25,11 @@ import com.marklogic.hub.config.EnvironmentConfiguration; import com.marklogic.hub.model.DomainModel; +import com.marklogic.hub.model.FlowType; import com.marklogic.hub.service.DomainManagerService; import com.marklogic.hub.service.FileSystemEventListener; import com.marklogic.hub.service.FileSystemWatcherService; +import com.marklogic.hub.web.bean.SyncStatusBean; import com.marklogic.hub.web.form.DomainForm; import com.marklogic.hub.web.form.LoginForm; @@ -36,151 +37,156 @@ @RequestMapping("/api/domains") @Scope("session") public class DomainApiController implements InitializingBean, DisposableBean, - FileSystemEventListener { - - @Autowired - private EnvironmentConfiguration environmentConfiguration; - - @Autowired - private DomainManagerService domainManagerService; - - @Autowired - private FileSystemWatcherService watcherService; - - // TODO: this list of modified domains should be cleared when the user - // deploys the user modules - // also, this should also get notified when the user deploys the user - // modules so we can update the UI - private Set modifiedDomains = Collections - .synchronizedSet(new LinkedHashSet<>()); - - @RequestMapping(method = RequestMethod.GET) - @ResponseBody - public List getDomains(HttpSession session) { - LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); - List domains = domainManagerService.getDomains(); - loginForm.setDomains(domains); - return domains; - } - - @RequestMapping(value = "display", method = RequestMethod.POST) - @ResponseBody - public DomainModel displayDomain(@RequestBody String domainName, - HttpSession session) { - LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); - List domains = domainManagerService.getDomains(); - DomainModel domainModel = this.getDomainFromList(domains, domainName); - loginForm.setSelectedDomain(domainModel); - return domainModel; - } - - private DomainModel getDomainFromList(List domains, - String domainName) { - for (DomainModel domainModel : domains) { - if (domainModel.getDomainName().equalsIgnoreCase(domainName)) { - return domainModel; - } - } - return null; - } - - @RequestMapping(method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_UTF8_VALUE }, produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }) - @ResponseBody - public List saveDomain(@RequestBody DomainForm domainForm, - BindingResult bindingResult, HttpSession session) { - DomainModel domainModel = domainManagerService.createDomain( - domainForm.getDomainName(), domainForm.getInputFlowName(), - domainForm.getConformFlowName()); - LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); - List domains = loginForm.getDomains(); - domains.add(domainModel); - return domains; - } - - /** - * Get a list of domains that has changed. This API does not return until a - * change has occurred. - * - * @param session - * @return - */ - @RequestMapping(value = "change-list", method = RequestMethod.GET) - public List getDomainChangeList(HttpSession session) { - synchronized (this) { - try { - this.wait(); - } catch (InterruptedException e) { - } - } - - LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); - - List domains = domainManagerService.getDomains(); - synchronized (modifiedDomains) { - for (String domain : modifiedDomains) { - for (DomainModel domainModel : domains) { - if (domain.equals(domainModel.getDomainName())) { - domainModel.setSynched(false); - } - } - } - modifiedDomains.clear(); - } - - loginForm.setDomains(domains); - session.setAttribute("loginForm", loginForm); - - return domains; - } - - @Override - public void afterPropertiesSet() throws Exception { - String pluginDir = environmentConfiguration.getUserPluginDir(); - watcherService.watch(pluginDir, this); - } - - @Override - public void destroy() throws Exception { - synchronized (this) { - this.notify(); - } - } - - @Override - public void onWatchEvent(Path path, WatchEvent event) { - synchronized (this) { - try { - String realPath = path.toRealPath(LinkOption.NOFOLLOW_LINKS) - .toString(); - String modifiedDomain = getDomainName(realPath); - if (modifiedDomain != null) { - modifiedDomains.add(modifiedDomain); - } - - this.notify(); - } catch (IOException e) { - } - } - } - - private String getDomainName(String path) { - try { - String domainsPath = new File( - environmentConfiguration.getUserPluginDir() - + File.separator + "domains").toPath() - .toRealPath(LinkOption.NOFOLLOW_LINKS).toString(); - - if (path.indexOf(domainsPath) == 0) { - String suffix = path.substring(domainsPath.length()); - String[] pathTokens = suffix.split("[/\\\\]"); - - return pathTokens != null && pathTokens.length > 1 ? pathTokens[1] - : null; - } else { - return null; - } - } catch (IOException e) { - return null; - } - } + FileSystemEventListener { + private static final Logger LOGGER = LoggerFactory + .getLogger(DomainApiController.class); + + @Autowired + private EnvironmentConfiguration environmentConfiguration; + + @Autowired + private DomainManagerService domainManagerService; + + @Autowired + private FileSystemWatcherService watcherService; + + @Autowired + private SyncStatusBean syncStatus; + + @RequestMapping(method = RequestMethod.GET) + @ResponseBody + public List getDomains(HttpSession session) { + LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); + List domains = domainManagerService.getDomains(); + loginForm.setDomains(domains); + return domains; + } + + @RequestMapping(value = "display", method = RequestMethod.POST) + @ResponseBody + public DomainModel displayDomain(@RequestBody String domainName, + HttpSession session) { + LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); + loginForm.selectDomain(domainName); + + return loginForm.getSelectedDomain(); + } + + @RequestMapping(method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_UTF8_VALUE }, produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }) + @ResponseBody + public LoginForm saveDomain(@RequestBody DomainForm domainForm, + BindingResult bindingResult, HttpSession session) { + LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); + List domains = loginForm.getDomains(); + + domainForm.validate(domains); + + DomainModel domainModel = domainManagerService.createDomain( + domainForm.getDomainName(), domainForm.getInputFlowName(), + domainForm.getConformFlowName()); + + domains.add(domainModel); + loginForm.setSelectedDomain(domainModel); + return loginForm; + } + + /** + * Get a list of domains that has changed. This API does not return until a + * change has occurred. + * + * @param session + * @return + */ + @RequestMapping(value = "status-change", method = RequestMethod.GET) + public LoginForm getStatusChange(HttpSession session) { + synchronized (syncStatus) { + try { + syncStatus.wait(); + } catch (InterruptedException e) { + } + + // refresh the list of domains saved in the session + List domains = domainManagerService.getDomains(); + LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); + loginForm.refreshDomains(domains); + loginForm.updateWithSyncStatus(syncStatus); + + // clear all pending updates + syncStatus.clearModifications(); + + // refresh the session loginForm + session.setAttribute("loginForm", loginForm); + + return loginForm; + } + } + + @Override + public void afterPropertiesSet() throws Exception { + String pluginDir = environmentConfiguration.getUserPluginDir(); + watcherService.watch(pluginDir, this); + } + + @Override + public void destroy() throws Exception { + synchronized (syncStatus) { + syncStatus.notifyAll(); + } + } + + @Override + public void onWatchEvent(Path path, WatchEvent event) { + synchronized (syncStatus) { + try { + String realPath = path.toRealPath(LinkOption.NOFOLLOW_LINKS) + .toString(); + UserPluginFileInfo info = new UserPluginFileInfo(realPath); + + if (info.domainName != null) { + syncStatus.addModifiedDomain(info.domainName); + } + if (info.domainName != null && info.flowName != null) { + if (info.flowType == FlowType.INPUT) { + syncStatus.addModifiedInputFlow(info.domainName, info.flowName); + } + else if (info.flowType == FlowType.CONFORM) { + syncStatus.addModifiedConformFlow(info.domainName, info.flowName); + } + } + + syncStatus.notifyAll(); + } catch (IOException e) { + } + } + } + private class UserPluginFileInfo { + private String domainName; + private String flowName; + private FlowType flowType; + + public UserPluginFileInfo(String path) { + try { + String domainsPath = new File( + environmentConfiguration.getUserPluginDir() + + File.separator + "domains").toPath() + .toRealPath(LinkOption.NOFOLLOW_LINKS).toString(); + + if (path.indexOf(domainsPath) == 0) { + String suffix = path.substring(domainsPath.length()); + String[] pathTokens = suffix.split("[/\\\\]"); + + if (pathTokens != null) { + this.domainName = pathTokens.length >= 2 ? pathTokens[1] : null; + this.flowName = pathTokens.length >= 4 ? pathTokens[3] : null; + + String flowType = pathTokens.length >= 3 ? pathTokens[2] : null; + this.flowType = flowType != null ? FlowType.getFlowType(flowType) : null; + } + + } + } catch (IOException e) { + LOGGER.error("Cannot get info from path: " + path, e); + } + } + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/web/controller/api/FlowApiController.java b/quick-start/src/main/java/com/marklogic/hub/web/controller/api/FlowApiController.java index 4f5c9506ad..051df64017 100644 --- a/quick-start/src/main/java/com/marklogic/hub/web/controller/api/FlowApiController.java +++ b/quick-start/src/main/java/com/marklogic/hub/web/controller/api/FlowApiController.java @@ -17,10 +17,14 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; +import com.marklogic.hub.Mlcp; +import com.marklogic.hub.Mlcp.SourceOptions; +import com.marklogic.hub.config.EnvironmentConfiguration; import com.marklogic.hub.flow.Flow; import com.marklogic.hub.model.DomainModel; import com.marklogic.hub.model.FlowModel; import com.marklogic.hub.model.FlowType; +import com.marklogic.hub.model.RunFlowModel; import com.marklogic.hub.service.FlowManagerService; import com.marklogic.hub.web.controller.BaseController; import com.marklogic.hub.web.form.FlowForm; @@ -30,80 +34,113 @@ @RequestMapping("/api/flows") public class FlowApiController extends BaseController { - private static final Logger LOGGER = LoggerFactory - .getLogger(FlowApiController.class); - - @Autowired - private FlowManagerService flowManagerService; - - @RequestMapping(value = "/flow", method = RequestMethod.GET) - @ResponseBody - public Flow getFlow(HttpServletRequest request) { - final String domainName = request.getParameter("domainName"); - final String flowName = request.getParameter("flowName"); - return flowManagerService.getFlow(domainName, flowName); - } - - @RequestMapping(method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_UTF8_VALUE }, produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }) - @ResponseBody - public DomainModel saveFlow(@RequestBody FlowForm flowForm, - BindingResult bindingResult, HttpSession session) { - FlowModel flowModel = flowManagerService.createFlow( - flowForm.getDomainName(), flowForm.getFlowName(), - flowForm.getFlowType()); - LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); - DomainModel selectedDomain = loginForm.getSelectedDomain(); - if (FlowType.getFlowType(flowForm.getFlowType()) == FlowType.CONFORM) { - selectedDomain.getConformFlows().add(flowModel); - } else { - selectedDomain.getInputFlows().add(flowModel); - } - return selectedDomain; - } - - @RequestMapping(value = "/install", method = RequestMethod.POST) - public void installFlow(HttpServletRequest request) { - final String domainName = request.getParameter("domainName"); - final String flowName = request.getParameter("flowName"); - final Flow flow = flowManagerService.getFlow(domainName, flowName); - flowManagerService.installFlow(flow); - } - - @RequestMapping(value = "/uninstall", method = RequestMethod.POST) - public void uninstallFlow(HttpServletRequest request) { - final String flowName = request.getParameter("flowName"); - flowManagerService.uninstallFlow(flowName); - } - - @RequestMapping(value = "/test", method = RequestMethod.POST) - public void testFlow(HttpServletRequest request) { - final String domainName = request.getParameter("domainName"); - final String flowName = request.getParameter("flowName"); - final Flow flow = flowManagerService.getFlow(domainName, flowName); - flowManagerService.testFlow(flow); - } - - @RequestMapping(value = "/run", method = RequestMethod.POST) - public void runFlow(HttpServletRequest request) { - final String domainName = request.getParameter("domainName"); - final String flowName = request.getParameter("flowName"); - final Flow flow = flowManagerService.getFlow(domainName, flowName); - // TODO update and move BATCH SIZE TO a constant or config - confirm - // desired behavior - flowManagerService.runFlow(flow, 100); - } - - @RequestMapping(value = "/runInParallel", method = RequestMethod.POST) - public void runFlowsInParallel(HttpServletRequest request) { - final String domainName = request.getParameter("domainName"); - String[] flowNames = request.getParameterValues("flowName"); - List flows = new ArrayList(); - for (String flowName : flowNames) { - final Flow flow = flowManagerService.getFlow(domainName, flowName); - flows.add(flow); - } - flowManagerService.runFlowsInParallel(flows.toArray(new Flow[flows - .size()])); - } + private static final Logger LOGGER = LoggerFactory + .getLogger(FlowApiController.class); + + @Autowired + private EnvironmentConfiguration environmentConfiguration; + + @Autowired + private FlowManagerService flowManagerService; + + @RequestMapping(value = "/flow", method = RequestMethod.GET) + @ResponseBody + public Flow getFlow(HttpServletRequest request) { + final String domainName = request.getParameter("domainName"); + final String flowName = request.getParameter("flowName"); + return flowManagerService.getFlow(domainName, flowName); + } + + @RequestMapping(method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_UTF8_VALUE }, produces = { MediaType.APPLICATION_JSON_UTF8_VALUE }) + @ResponseBody + public DomainModel saveFlow(@RequestBody FlowForm flowForm, + BindingResult bindingResult, HttpSession session) { + LoginForm loginForm = (LoginForm) session.getAttribute("loginForm"); + DomainModel selectedDomain = loginForm.getSelectedDomain(); + List flowList = this + .getAllFlowsOfSelectedDomain(selectedDomain); + + flowForm.validate(flowList); + + FlowModel flowModel = flowManagerService.createFlow( + flowForm.getDomainName(), flowForm.getFlowName(), + flowForm.getFlowType()); + + if (FlowType.getFlowType(flowForm.getFlowType()) == FlowType.CONFORM) { + selectedDomain.getConformFlows().add(flowModel); + } else { + selectedDomain.getInputFlows().add(flowModel); + } + return selectedDomain; + } + + private List getAllFlowsOfSelectedDomain( + DomainModel selectedDomain) { + List flowList = new ArrayList<>(); + flowList.addAll(selectedDomain.getInputFlows()); + flowList.addAll(selectedDomain.getConformFlows()); + return flowList; + } + + @RequestMapping(value = "/install", method = RequestMethod.POST) + public void installFlow(HttpServletRequest request) { + final String domainName = request.getParameter("domainName"); + final String flowName = request.getParameter("flowName"); + final Flow flow = flowManagerService.getFlow(domainName, flowName); + flowManagerService.installFlow(flow); + } + + @RequestMapping(value = "/uninstall", method = RequestMethod.POST) + public void uninstallFlow(HttpServletRequest request) { + final String flowName = request.getParameter("flowName"); + flowManagerService.uninstallFlow(flowName); + } + + @RequestMapping(value = "/test", method = RequestMethod.POST) + public void testFlow(HttpServletRequest request) { + final String domainName = request.getParameter("domainName"); + final String flowName = request.getParameter("flowName"); + final Flow flow = flowManagerService.getFlow(domainName, flowName); + flowManagerService.testFlow(flow); + } + + @RequestMapping(value = "/run", method = RequestMethod.POST) + public void runFlow(@RequestBody RunFlowModel runFlow) { + final Flow flow = flowManagerService.getFlow(runFlow.getDomainName(), runFlow.getFlowName()); + // TODO update and move BATCH SIZE TO a constant or config - confirm + // desired behavior + flowManagerService.runFlow(flow, 100); + } + + @RequestMapping(value="/run/input", method = RequestMethod.POST) + public void runInputFlow(@RequestBody RunFlowModel runFlow) { + // TODO: this must come from UI, but we don't have a mockup yet + String inputPath = "./plugins/input"; + + Mlcp mlcp = new Mlcp( + environmentConfiguration.getMlcpHomeDir() + ,environmentConfiguration.getMLHost() + ,environmentConfiguration.getMLRestPort() + ,environmentConfiguration.getMLUsername() + ,environmentConfiguration.getMLPassword() + ); + + SourceOptions sourceOptions = new SourceOptions(runFlow.getDomainName(), runFlow.getFlowName(), FlowType.INPUT.getName()); + mlcp.addSourceDirectory(inputPath, sourceOptions); + mlcp.loadContent(); + } + + @RequestMapping(value = "/runInParallel", method = RequestMethod.POST) + public void runFlowsInParallel(HttpServletRequest request) { + final String domainName = request.getParameter("domainName"); + String[] flowNames = request.getParameterValues("flowName"); + List flows = new ArrayList(); + for (String flowName : flowNames) { + final Flow flow = flowManagerService.getFlow(domainName, flowName); + flows.add(flow); + } + flowManagerService.runFlowsInParallel(flows.toArray(new Flow[flows + .size()])); + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/web/form/DomainForm.java b/quick-start/src/main/java/com/marklogic/hub/web/form/DomainForm.java index e1db9d6191..3d4ed1842c 100644 --- a/quick-start/src/main/java/com/marklogic/hub/web/form/DomainForm.java +++ b/quick-start/src/main/java/com/marklogic/hub/web/form/DomainForm.java @@ -1,29 +1,55 @@ package com.marklogic.hub.web.form; +import java.util.List; + +import com.marklogic.hub.exception.FormValidationException; +import com.marklogic.hub.model.DomainModel; + public class DomainForm extends BaseForm { - private String domainName; - private String inputFlowName; - private String conformFlowName; - - public String getDomainName() { - return domainName; - } - public void setDomainName(String domainName) { - this.domainName = domainName; - } - public String getInputFlowName() { - return inputFlowName; - } - public void setInputFlowName(String inputFlowName) { - this.inputFlowName = inputFlowName; - } - public String getConformFlowName() { - return conformFlowName; - } - public void setConformFlowName(String conformFlowName) { - this.conformFlowName = conformFlowName; - } - - + private String domainName; + private String inputFlowName; + private String conformFlowName; + + public String getDomainName() { + return domainName; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + public String getInputFlowName() { + return inputFlowName; + } + + public void setInputFlowName(String inputFlowName) { + this.inputFlowName = inputFlowName; + } + + public String getConformFlowName() { + return conformFlowName; + } + + public void setConformFlowName(String conformFlowName) { + this.conformFlowName = conformFlowName; + } + + public void validate(List domainList) { + if (this.domainName == null || "".equals(this.domainName.trim())) { + throw new FormValidationException("Domain Name is required."); + } + for (DomainModel domainModel : domainList) { + if (domainModel.getDomainName().equals(this.domainName)) { + throw new FormValidationException( + "Domain Name should be unique."); + } + } + if ((this.inputFlowName == null || "".equals(this.inputFlowName.trim())) + && (this.conformFlowName == null || "" + .equals(this.conformFlowName.trim()))) { + throw new FormValidationException( + "Either the Ingest Flow Name or the Conformance Flow Name must be supplied."); + } + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/web/form/FlowForm.java b/quick-start/src/main/java/com/marklogic/hub/web/form/FlowForm.java index 45faa7237f..48b3ca13c7 100644 --- a/quick-start/src/main/java/com/marklogic/hub/web/form/FlowForm.java +++ b/quick-start/src/main/java/com/marklogic/hub/web/form/FlowForm.java @@ -1,33 +1,49 @@ package com.marklogic.hub.web.form; -public class FlowForm extends BaseForm { - - private String domainName; - private String flowType; - private String flowName; - - public String getDomainName() { - return domainName; - } - - public void setDomainName(String domainName) { - this.domainName = domainName; - } +import java.util.List; - public String getFlowType() { - return flowType; - } +import com.marklogic.hub.exception.FormValidationException; +import com.marklogic.hub.model.FlowModel; - public void setFlowType(String flowType) { - this.flowType = flowType; - } - - public String getFlowName() { - return flowName; - } - - public void setFlowName(String flowName) { - this.flowName = flowName; - } +public class FlowForm extends BaseForm { + private String domainName; + private String flowType; + private String flowName; + + public String getDomainName() { + return domainName; + } + + public void setDomainName(String domainName) { + this.domainName = domainName; + } + + public String getFlowType() { + return flowType; + } + + public void setFlowType(String flowType) { + this.flowType = flowType; + } + + public String getFlowName() { + return flowName; + } + + public void setFlowName(String flowName) { + this.flowName = flowName; + } + + public void validate(List flowList) + throws FormValidationException { + if (this.flowName == null || "".equals(this.flowName.trim())) { + throw new FormValidationException("Flow Name is required."); + } + for (FlowModel flowModel : flowList) { + if (flowModel.getFlowName().equals(this.flowName)) { + throw new FormValidationException("Flow Name should be unique."); + } + } + } } diff --git a/quick-start/src/main/java/com/marklogic/hub/web/form/LoginForm.java b/quick-start/src/main/java/com/marklogic/hub/web/form/LoginForm.java index c7cd57eb75..0f8e45ad58 100644 --- a/quick-start/src/main/java/com/marklogic/hub/web/form/LoginForm.java +++ b/quick-start/src/main/java/com/marklogic/hub/web/form/LoginForm.java @@ -1,8 +1,13 @@ package com.marklogic.hub.web.form; import java.util.List; +import java.util.Map; +import java.util.Set; +import com.marklogic.hub.factory.DomainModelFactory; import com.marklogic.hub.model.DomainModel; +import com.marklogic.hub.model.FlowModel; +import com.marklogic.hub.web.bean.SyncStatusBean; public class LoginForm extends BaseForm { @@ -88,6 +93,99 @@ public List getDomains() { public void setDomains(List domains) { this.domains = domains; } + + public void refreshDomains(List domains) { + Map domainMap = DomainModelFactory.toDomainModelMap(this.domains); + Map newDomainMap = DomainModelFactory.toDomainModelMap(domains); + + for (DomainModel model : domains) { + DomainModel oldModel = domainMap.get(model.getDomainName()); + model.copySyncStatusFrom(oldModel); + } + + if (selectedDomain != null) { + DomainModel oldModel = domainMap.get(selectedDomain.getDomainName()); + DomainModel newDomainModel = newDomainMap.get(selectedDomain.getDomainName()); + if (newDomainModel != null) { + newDomainModel.copySyncStatusFrom(oldModel); + selectedDomain = newDomainModel; + } + } + + this.domains = domains; + } + + public void updateWithSyncStatus(SyncStatusBean syncStatus) { + updateModifiedDomains(syncStatus.getModifiedDomains()); + updateModifiedInputFlows(syncStatus.getModifiedInputFlows()); + updateModifiedConformFlows(syncStatus.getModifiedConformFlows()); + } + + public void updateModifiedDomains(Set modifiedDomains) { + if (modifiedDomains.isEmpty()) { + return; + } + + for (DomainModel domainModel : domains) { + if (modifiedDomains.contains(domainModel.getDomainName())) { + domainModel.setSynched(false); + } + } + + if (selectedDomain != null) { + if (modifiedDomains.contains(selectedDomain.getDomainName())) { + selectedDomain.setSynched(false); + } + } + } + + public void updateModifiedInputFlows(Map> modifiedInputFlows) { + if (modifiedInputFlows.isEmpty()) { + return; + } + + for (DomainModel domainModel : domains) { + Set modifiedFlows = modifiedInputFlows.get(domainModel.getDomainName()); + if (modifiedFlows == null || modifiedFlows.isEmpty()) { + continue; + } + + List flowList = domainModel.getInputFlows(); + if (flowList == null || flowList.isEmpty()) { + continue; + } + + for (FlowModel flow : flowList) { + if (modifiedFlows.contains(flow.getFlowName())) { + flow.setSynched(false); + } + } + } + } + + public void updateModifiedConformFlows(Map> modifiedConformFlows) { + if (modifiedConformFlows.isEmpty()) { + return; + } + + for (DomainModel domainModel : domains) { + Set modifiedFlows = modifiedConformFlows.get(domainModel.getDomainName()); + if (modifiedFlows == null || modifiedFlows.isEmpty()) { + continue; + } + + List flowList = domainModel.getConformFlows(); + if (flowList == null || flowList.isEmpty()) { + continue; + } + + for (FlowModel flow : flowList) { + if (modifiedFlows.contains(flow.getFlowName())) { + flow.setSynched(false); + } + } + } + } public DomainModel getSelectedDomain() { return selectedDomain; @@ -97,4 +195,13 @@ public void setSelectedDomain(DomainModel selectedDomain) { this.selectedDomain = selectedDomain; } + public void selectDomain(String domainName) { + if (domains != null) { + for (DomainModel domain : domains) { + if (domain.getDomainName().equals(domainName)) { + setSelectedDomain(domain); + } + } + } + } } diff --git a/quick-start/src/main/webapp/WEB-INF/static/app/quickStartApp.js b/quick-start/src/main/webapp/WEB-INF/static/app/quickStartApp.js index ca96d989ed..96b5718eb8 100644 --- a/quick-start/src/main/webapp/WEB-INF/static/app/quickStartApp.js +++ b/quick-start/src/main/webapp/WEB-INF/static/app/quickStartApp.js @@ -4,6 +4,7 @@ var dependencies = [ ,'dhib.quickstart.controller.top' ,'dhib.quickstart.directives.header' ,'dhib.quickstart.directives.footer' + ,'angularBootstrapNavTree' ]; var module = angular.module('quickStartApp', dependencies); diff --git a/quick-start/src/main/webapp/WEB-INF/static/app/services/dataHubService.js b/quick-start/src/main/webapp/WEB-INF/static/app/services/dataHubService.js index 7e24b38c5d..3e1efaaae8 100644 --- a/quick-start/src/main/webapp/WEB-INF/static/app/services/dataHubService.js +++ b/quick-start/src/main/webapp/WEB-INF/static/app/services/dataHubService.js @@ -69,11 +69,11 @@ module.factory('DataHub', [ ,saveDomain : function(domainForm) { var promise = $http.post('api/domains', domainForm) - .success(function (domains) { - service.status.domains = domains; + .success(function (status) { + service.status = status; }) - .error(function () { - //notify error + .error(function (error) { + service.displayMessage(error.message, 'error', 'domainModalMessage', true); }); return promise; @@ -83,8 +83,8 @@ module.factory('DataHub', [ return $http.post('api/domains/display', domainName); } - ,getDomainChangeList : function() { - return $http.get('api/domains/change-list'); + ,getStatusChange : function() { + return $http.get('api/domains/status-change'); } ,runFlow : function(domainName, flowName) { @@ -103,6 +103,22 @@ module.factory('DataHub', [ return promise; } + ,runInputFlow : function(domainName, flowName) { + var data = { + domainName: domainName, + flowName: flowName + }; + var promise = $http.post('api/flows/run/input', data) + .success(function () { + service.displayMessage('Flow run is successful.', 'success', 'notification', false); + }) + .error(function () { + service.displayMessage('Flow run is successful.', 'success', 'notification', false); + }); + + return promise; + } + ,testFlow : function(domainName, flowName) { var data = { domainName: domainName, @@ -125,8 +141,8 @@ module.factory('DataHub', [ .success(function (selectedDomain) { service.status.selectedDomain = selectedDomain; }) - .error(function () { - //notify error + .error(function (error) { + service.displayMessage(error.message, 'error', 'flowModalMessage', true); }); return promise; @@ -138,16 +154,16 @@ module.factory('DataHub', [ if(typeof elementId === 'undefined') { elementId = 'messageDiv'; } - var messageClass = "alert"; + var messageClass = 'alert'; if(messageType === 'error') { - messageClass + " alert-error alert-danger"; + messageClass += ' alert-error alert-danger'; } else if (messageType === 'success') { - messageClass + " alert-success"; + messageClass += ' alert-success'; } else if (messageType === 'warning') { - messageClass + " alert-warning"; + messageClass += ' alert-warning'; } $('#'+elementId).html('
'+ - '×'+message+'
'); + '×'+message+''); if(isModal) { $('.modal-body').scrollTop(0); diff --git a/quick-start/src/main/webapp/WEB-INF/static/css/quick-start.css b/quick-start/src/main/webapp/WEB-INF/static/css/quick-start.css index 410cfd8d14..d0cac80abc 100644 --- a/quick-start/src/main/webapp/WEB-INF/static/css/quick-start.css +++ b/quick-start/src/main/webapp/WEB-INF/static/css/quick-start.css @@ -48,7 +48,7 @@ div#header .alert { color: #fff; } -.alert-info, .brand-info, .btn-success { +.alert-info, .alert-success, .brand-info, .btn-success { background-color: #4a9e43; } @@ -184,4 +184,17 @@ li.folder, li.file { display: -webkit-flex; display: -ms-flexbox; display: flex; +} + +ul.abn-tree { + padding-left: 30px; +} + +ul.abn-tree li.abn-tree-row a { + color: #2a2d2b; + font-size: 18px; +} + +ul.nav.abn-tree i { + font-size: 18px; } \ No newline at end of file diff --git a/quick-start/src/main/webapp/WEB-INF/static/index.html b/quick-start/src/main/webapp/WEB-INF/static/index.html index 8a47094292..57381e363f 100644 --- a/quick-start/src/main/webapp/WEB-INF/static/index.html +++ b/quick-start/src/main/webapp/WEB-INF/static/index.html @@ -18,6 +18,7 @@ + @@ -32,6 +33,7 @@ + diff --git a/quick-start/src/main/webapp/WEB-INF/static/lib/abn_tree/css/abn_tree.css b/quick-start/src/main/webapp/WEB-INF/static/lib/abn_tree/css/abn_tree.css new file mode 100644 index 0000000000..48864e9f3a --- /dev/null +++ b/quick-start/src/main/webapp/WEB-INF/static/lib/abn_tree/css/abn_tree.css @@ -0,0 +1,121 @@ +/* + abn-tree.css + + style for the angular-bootstrap-nav-tree + for both Bootstrap 2 and Bootstrap 3 + +*/ + + + +/* ------------------------------------------ +AngularJS Animations... + +The first selector is for Angular 1.1.5 +The second selector is for Angular 1.2.0 + +*/ +.abn-tree-animate-enter, +li.abn-tree-row.ng-enter { + transition: 200ms linear all; + position: relative; + display: block; + opacity: 0; + max-height:0px; +} +.abn-tree-animate-enter.abn-tree-animate-enter-active, +li.abn-tree-row.ng-enter-active{ + opacity: 1; + max-height:30px; +} + +.abn-tree-animate-leave, +li.abn-tree-row.ng-leave { + transition: 200ms linear all; + position: relative; + display: block; + height:30px; + max-height: 30px; + opacity: 1; +} +.abn-tree-animate-leave.abn-tree-animate-leave-active, +li.abn-tree-row.ng-leave-active { + height: 0px; + max-height:0px; + opacity: 0; +} + + +/* +------------------------------------------ +Angular 1.2.0 Animation +*/ + + +.abn-tree-animate.ng-enter{ + +} +.abn-tree-animate.ng-enter{ + +} + + + + +/* + end animation stuff +----------------------------------------- + begin normal css stuff +*/ +ul.abn-tree li.abn-tree-row { + padding: 0px; + margin:0px; +} + +ul.abn-tree li.abn-tree-row a { + padding: 3px 10px; +} + +ul.abn-tree i.indented { + padding: 2px; +} + +.abn-tree { + cursor: pointer; +} +ul.nav.abn-tree .level-1 .indented { + position: relative; + left: 0px; +} +ul.nav.abn-tree .level-2 .indented { + position: relative; + left: 20px; +} +ul.nav.abn-tree .level-3 .indented { + position: relative; + left: 40px; +} +ul.nav.abn-tree .level-4 .indented { + position: relative; + left: 60px; +} +ul.nav.abn-tree .level-5 .indented { + position: relative; + left: 80px; +} +ul.nav.abn-tree .level-6 .indented { + position: relative; + left: 100px; +} +ul.nav.nav-list.abn-tree .level-7 .indented { + position: relative; + left: 120px; +} +ul.nav.nav-list.abn-tree .level-8 .indented { + position: relative; + left: 140px; +} +ul.nav.nav-list.abn-tree .level-9 .indented { + position: relative; + left: 160px; +} diff --git a/quick-start/src/main/webapp/WEB-INF/static/lib/abn_tree/js/abn_tree_directive.js b/quick-start/src/main/webapp/WEB-INF/static/lib/abn_tree/js/abn_tree_directive.js new file mode 100644 index 0000000000..f309995334 --- /dev/null +++ b/quick-start/src/main/webapp/WEB-INF/static/lib/abn_tree/js/abn_tree_directive.js @@ -0,0 +1,492 @@ +(function() { + var module, + __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + module = angular.module('angularBootstrapNavTree', []); + + module.directive('abnTree', [ + '$timeout', function($timeout) { + return { + restrict: 'E', + template: "", + replace: true, + scope: { + treeData: '=', + onSelect: '&', + initialSelection: '@', + treeControl: '=' + }, + link: function(scope, element, attrs) { + var error, expand_all_parents, expand_level, for_all_ancestors, for_each_branch, get_parent, n, on_treeData_change, select_branch, selected_branch, tree; + error = function(s) { + console.log('ERROR:' + s); + debugger; + return void 0; + }; + if (attrs.iconExpand == null) { + attrs.iconExpand = 'icon-plus glyphicon glyphicon-plus fa fa-plus'; + } + if (attrs.iconCollapse == null) { + attrs.iconCollapse = 'icon-minus glyphicon glyphicon-minus fa fa-minus'; + } + if (attrs.iconLeaf == null) { + attrs.iconLeaf = 'icon-file glyphicon glyphicon-file fa fa-file'; + } + if (attrs.expandLevel == null) { + attrs.expandLevel = '3'; + } + expand_level = parseInt(attrs.expandLevel, 10); + if (!scope.treeData) { + alert('no treeData defined for the tree!'); + return; + } + if (scope.treeData.length == null) { + if (treeData.label != null) { + scope.treeData = [treeData]; + } else { + alert('treeData should be an array of root branches'); + return; + } + } + for_each_branch = function(f) { + var do_f, root_branch, _i, _len, _ref, _results; + do_f = function(branch, level) { + var child, _i, _len, _ref, _results; + f(branch, level); + if (branch.children != null) { + _ref = branch.children; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + _results.push(do_f(child, level + 1)); + } + return _results; + } + }; + _ref = scope.treeData; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + root_branch = _ref[_i]; + _results.push(do_f(root_branch, 1)); + } + return _results; + }; + selected_branch = null; + select_branch = function(branch) { + if (!branch) { + if (selected_branch != null) { + selected_branch.selected = false; + } + selected_branch = null; + return; + } + if (branch !== selected_branch) { + if (selected_branch != null) { + selected_branch.selected = false; + } + branch.selected = true; + selected_branch = branch; + expand_all_parents(branch); + if (branch.onSelect != null) { + return $timeout(function() { + return branch.onSelect(branch); + }); + } else { + if (scope.onSelect != null) { + return $timeout(function() { + return scope.onSelect({ + branch: branch + }); + }); + } + } + } + }; + scope.user_clicks_branch = function(branch) { + if (branch !== selected_branch) { + return select_branch(branch); + } + }; + get_parent = function(child) { + var parent; + parent = void 0; + if (child.parent_uid) { + for_each_branch(function(b) { + if (b.uid === child.parent_uid) { + return parent = b; + } + }); + } + return parent; + }; + for_all_ancestors = function(child, fn) { + var parent; + parent = get_parent(child); + if (parent != null) { + fn(parent); + return for_all_ancestors(parent, fn); + } + }; + expand_all_parents = function(child) { + return for_all_ancestors(child, function(b) { + return b.expanded = true; + }); + }; + scope.tree_rows = []; + on_treeData_change = function() { + var add_branch_to_list, root_branch, _i, _len, _ref, _results; + for_each_branch(function(b, level) { + if (!b.uid) { + return b.uid = "" + Math.random(); + } + }); + console.log('UIDs are set.'); + for_each_branch(function(b) { + var child, _i, _len, _ref, _results; + if (angular.isArray(b.children)) { + _ref = b.children; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + _results.push(child.parent_uid = b.uid); + } + return _results; + } + }); + scope.tree_rows = []; + for_each_branch(function(branch) { + var child, f; + if (branch.children) { + if (branch.children.length > 0) { + f = function(e) { + if (typeof e === 'string') { + return { + label: e, + children: [] + }; + } else { + return e; + } + }; + return branch.children = (function() { + var _i, _len, _ref, _results; + _ref = branch.children; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + _results.push(f(child)); + } + return _results; + })(); + } + } else { + return branch.children = []; + } + }); + add_branch_to_list = function(level, branch, visible) { + var child, child_visible, tree_icon, _i, _len, _ref, _results; + if (branch.expanded == null) { + branch.expanded = false; + } + if (branch.classes == null) { + branch.classes = []; + } + if (!branch.noLeaf && (!branch.children || branch.children.length === 0)) { + tree_icon = attrs.iconLeaf; + if (__indexOf.call(branch.classes, "leaf") < 0) { + branch.classes.push("leaf"); + } + } else { + if (branch.expanded) { + tree_icon = attrs.iconCollapse; + } else { + tree_icon = attrs.iconExpand; + } + } + scope.tree_rows.push({ + level: level, + branch: branch, + label: branch.label, + classes: branch.classes, + tree_icon: tree_icon, + visible: visible + }); + if (branch.children != null) { + _ref = branch.children; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + child = _ref[_i]; + child_visible = visible && branch.expanded; + _results.push(add_branch_to_list(level + 1, child, child_visible)); + } + return _results; + } + }; + _ref = scope.treeData; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + root_branch = _ref[_i]; + _results.push(add_branch_to_list(1, root_branch, true)); + } + return _results; + }; + scope.$watch('treeData', on_treeData_change, true); + if (attrs.initialSelection != null) { + for_each_branch(function(b) { + if (b.label === attrs.initialSelection) { + return $timeout(function() { + return select_branch(b); + }); + } + }); + } + n = scope.treeData.length; + console.log('num root branches = ' + n); + for_each_branch(function(b, level) { + b.level = level; + return b.expanded = b.level < expand_level; + }); + if (scope.treeControl != null) { + if (angular.isObject(scope.treeControl)) { + tree = scope.treeControl; + tree.expand_all = function() { + return for_each_branch(function(b, level) { + return b.expanded = true; + }); + }; + tree.collapse_all = function() { + return for_each_branch(function(b, level) { + return b.expanded = false; + }); + }; + tree.get_first_branch = function() { + n = scope.treeData.length; + if (n > 0) { + return scope.treeData[0]; + } + }; + tree.select_first_branch = function() { + var b; + b = tree.get_first_branch(); + return tree.select_branch(b); + }; + tree.get_selected_branch = function() { + return selected_branch; + }; + tree.get_parent_branch = function(b) { + return get_parent(b); + }; + tree.select_branch = function(b) { + select_branch(b); + return b; + }; + tree.get_children = function(b) { + return b.children; + }; + tree.select_parent_branch = function(b) { + var p; + if (b == null) { + b = tree.get_selected_branch(); + } + if (b != null) { + p = tree.get_parent_branch(b); + if (p != null) { + tree.select_branch(p); + return p; + } + } + }; + tree.add_branch = function(parent, new_branch) { + if (parent != null) { + parent.children.push(new_branch); + parent.expanded = true; + } else { + scope.treeData.push(new_branch); + } + return new_branch; + }; + tree.add_root_branch = function(new_branch) { + tree.add_branch(null, new_branch); + return new_branch; + }; + tree.expand_branch = function(b) { + if (b == null) { + b = tree.get_selected_branch(); + } + if (b != null) { + b.expanded = true; + return b; + } + }; + tree.collapse_branch = function(b) { + if (b == null) { + b = selected_branch; + } + if (b != null) { + b.expanded = false; + return b; + } + }; + tree.get_siblings = function(b) { + var p, siblings; + if (b == null) { + b = selected_branch; + } + if (b != null) { + p = tree.get_parent_branch(b); + if (p) { + siblings = p.children; + } else { + siblings = scope.treeData; + } + return siblings; + } + }; + tree.get_next_sibling = function(b) { + var i, siblings; + if (b == null) { + b = selected_branch; + } + if (b != null) { + siblings = tree.get_siblings(b); + n = siblings.length; + i = siblings.indexOf(b); + if (i < n) { + return siblings[i + 1]; + } + } + }; + tree.get_prev_sibling = function(b) { + var i, siblings; + if (b == null) { + b = selected_branch; + } + siblings = tree.get_siblings(b); + n = siblings.length; + i = siblings.indexOf(b); + if (i > 0) { + return siblings[i - 1]; + } + }; + tree.select_next_sibling = function(b) { + var next; + if (b == null) { + b = selected_branch; + } + if (b != null) { + next = tree.get_next_sibling(b); + if (next != null) { + return tree.select_branch(next); + } + } + }; + tree.select_prev_sibling = function(b) { + var prev; + if (b == null) { + b = selected_branch; + } + if (b != null) { + prev = tree.get_prev_sibling(b); + if (prev != null) { + return tree.select_branch(prev); + } + } + }; + tree.get_first_child = function(b) { + var _ref; + if (b == null) { + b = selected_branch; + } + if (b != null) { + if (((_ref = b.children) != null ? _ref.length : void 0) > 0) { + return b.children[0]; + } + } + }; + tree.get_closest_ancestor_next_sibling = function(b) { + var next, parent; + next = tree.get_next_sibling(b); + if (next != null) { + return next; + } else { + parent = tree.get_parent_branch(b); + return tree.get_closest_ancestor_next_sibling(parent); + } + }; + tree.get_next_branch = function(b) { + var next; + if (b == null) { + b = selected_branch; + } + if (b != null) { + next = tree.get_first_child(b); + if (next != null) { + return next; + } else { + next = tree.get_closest_ancestor_next_sibling(b); + return next; + } + } + }; + tree.select_next_branch = function(b) { + var next; + if (b == null) { + b = selected_branch; + } + if (b != null) { + next = tree.get_next_branch(b); + if (next != null) { + tree.select_branch(next); + return next; + } + } + }; + tree.last_descendant = function(b) { + var last_child; + if (b == null) { + debugger; + } + n = b.children.length; + if (n === 0) { + return b; + } else { + last_child = b.children[n - 1]; + return tree.last_descendant(last_child); + } + }; + tree.get_prev_branch = function(b) { + var parent, prev_sibling; + if (b == null) { + b = selected_branch; + } + if (b != null) { + prev_sibling = tree.get_prev_sibling(b); + if (prev_sibling != null) { + return tree.last_descendant(prev_sibling); + } else { + parent = tree.get_parent_branch(b); + return parent; + } + } + }; + return tree.select_prev_branch = function(b) { + var prev; + if (b == null) { + b = selected_branch; + } + if (b != null) { + prev = tree.get_prev_branch(b); + if (prev != null) { + tree.select_branch(prev); + return prev; + } + } + }; + } + } + } + }; + } + ]); + +}).call(this); diff --git a/quick-start/src/main/webapp/WEB-INF/static/top/flows.html b/quick-start/src/main/webapp/WEB-INF/static/top/flows.html index 98b1cdf97a..f4e303190f 100644 --- a/quick-start/src/main/webapp/WEB-INF/static/top/flows.html +++ b/quick-start/src/main/webapp/WEB-INF/static/top/flows.html @@ -4,19 +4,11 @@

Input Flows

-
    -
  • -

    {{directory.directoryName}}

    -
  • -
-
    -
  • -

    {{file}}

    -
  • -
+
@@ -25,19 +17,10 @@

Conformance Flows

- + + -
    -
  • -

    {{directory.directoryName}}

    -
  • -
-
    -
  • -

    {{file}}

    -
  • -
+
diff --git a/quick-start/src/main/webapp/WEB-INF/static/top/modal/domainModal.html b/quick-start/src/main/webapp/WEB-INF/static/top/modal/domainModal.html index cfc9ffc587..cff9fd7704 100644 --- a/quick-start/src/main/webapp/WEB-INF/static/top/modal/domainModal.html +++ b/quick-start/src/main/webapp/WEB-INF/static/top/modal/domainModal.html @@ -6,12 +6,8 @@ - + + - diff --git a/quick-start/src/main/webapp/WEB-INF/static/top/modal/flowModal.html b/quick-start/src/main/webapp/WEB-INF/static/top/modal/flowModal.html index 1d29ed21b5..cae2062672 100644 --- a/quick-start/src/main/webapp/WEB-INF/static/top/modal/flowModal.html +++ b/quick-start/src/main/webapp/WEB-INF/static/top/modal/flowModal.html @@ -1,4 +1,4 @@ -