Repository: nifi Updated Branches: refs/heads/master 77dc18609 -> 5041bea77
http://git-wip-us.apache.org/repos/asf/nifi/blob/9cf9e866/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/session/PersistentSession.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/session/PersistentSession.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/session/PersistentSession.java new file mode 100644 index 0000000..9cf8302 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/session/PersistentSession.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.nifi.toolkit.cli.impl.session; + +import org.apache.commons.lang3.Validate; +import org.apache.nifi.toolkit.cli.api.Session; +import org.apache.nifi.toolkit.cli.api.SessionException; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.util.Properties; +import java.util.Set; + +public class PersistentSession implements Session { + + private final File persistenceFile; + + private final Session wrappedSession; + + public PersistentSession(final File persistenceFile, final Session wrappedSession) { + this.persistenceFile = persistenceFile; + this.wrappedSession = wrappedSession; + Validate.notNull(persistenceFile); + Validate.notNull(wrappedSession); + } + + @Override + public String getNiFiClientID() { + return wrappedSession.getNiFiClientID(); + } + + @Override + public synchronized void set(final String variable, final String value) throws SessionException { + wrappedSession.set(variable, value); + saveSession(); + } + + @Override + public synchronized String get(final String variable) throws SessionException { + return wrappedSession.get(variable); + } + + @Override + public synchronized void remove(final String variable) throws SessionException { + wrappedSession.remove(variable); + saveSession(); + } + + @Override + public synchronized void clear() throws SessionException { + wrappedSession.clear(); + saveSession(); + } + + @Override + public synchronized Set<String> keys() throws SessionException { + return wrappedSession.keys(); + } + + @Override + public synchronized void printVariables(final PrintStream output) throws SessionException { + wrappedSession.printVariables(output); + } + + private void saveSession() throws SessionException { + try (final OutputStream out = new FileOutputStream(persistenceFile)) { + final Properties properties = new Properties(); + for (String variable : wrappedSession.keys()) { + String value = wrappedSession.get(variable); + properties.setProperty(variable, value); + } + properties.store(out, null); + out.flush(); + } catch (Exception e) { + throw new SessionException("Error saving session: " + e.getMessage(), e); + } + } + + public synchronized void loadSession() throws SessionException { + wrappedSession.clear(); + try (final InputStream in = new FileInputStream(persistenceFile)) { + final Properties properties = new Properties(); + properties.load(in); + + for (final String propName : properties.stringPropertyNames()) { + final String propValue = properties.getProperty(propName); + wrappedSession.set(propName, propValue); + } + } catch (Exception e) { + throw new SessionException("Error loading session: " + e.getMessage(), e); + } + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9cf9e866/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/session/SessionVariables.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/session/SessionVariables.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/session/SessionVariables.java new file mode 100644 index 0000000..747588f --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/session/SessionVariables.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.nifi.toolkit.cli.impl.session; + +import java.util.ArrayList; +import java.util.List; + +/** + * Possible variables that can be set in the session. + */ +public enum SessionVariables { + + NIFI_CLIENT_PROPS("nifi.props"), + NIFI_REGISTRY_CLIENT_PROPS("nifi.reg.props"); + + private final String variableName; + + SessionVariables(final String variableName) { + this.variableName = variableName; + } + + public String getVariableName() { + return this.variableName; + } + + public static SessionVariables fromVariableName(final String variableName) { + for (final SessionVariables variable : values()) { + if (variable.getVariableName().equals(variableName)) { + return variable; + } + } + + return null; + } + + public static List<String> getAllVariableNames() { + final List<String> names = new ArrayList<>(); + for (SessionVariables variable : values()) { + names.add(variable.getVariableName()); + } + return names; + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9cf9e866/nifi-toolkit/nifi-toolkit-cli/src/main/resources/nifi-banner.txt ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/resources/nifi-banner.txt b/nifi-toolkit/nifi-toolkit-cli/src/main/resources/nifi-banner.txt new file mode 100644 index 0000000..1a61f76 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/resources/nifi-banner.txt @@ -0,0 +1,8 @@ + _ ___ _ + Apache (_) .' ..](_) , + _ .--. __ _| |_ __ )\ +[ `.-. | [ |'-| |-'[ | / \ +| | | | | | | | | | ' ' +[___||__][___][___] [___]', ,' + `' + CLI v${project.version} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/9cf9e866/nifi-toolkit/nifi-toolkit-cli/src/main/resources/nifi-registry-banner.txt ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/resources/nifi-registry-banner.txt b/nifi-toolkit/nifi-toolkit-cli/src/main/resources/nifi-registry-banner.txt new file mode 100644 index 0000000..685de96 --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/main/resources/nifi-registry-banner.txt @@ -0,0 +1,8 @@ + + Apache NiFi _ _ + _ __ ___ __ _(_)___| |_ _ __ _ _ +| '__/ _ \/ _` | / __| __| '__| | | | +| | | __/ (_| | \__ \ |_| | | |_| | +|_| \___|\__, |_|___/\__|_| \__, | +==========|___/================|___/= + Shell v${project.version} http://git-wip-us.apache.org/repos/asf/nifi/blob/9cf9e866/nifi-toolkit/nifi-toolkit-cli/src/test/java/org/apache/nifi/toolkit/cli/NiFiCLIMainRunner.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-cli/src/test/java/org/apache/nifi/toolkit/cli/NiFiCLIMainRunner.java b/nifi-toolkit/nifi-toolkit-cli/src/test/java/org/apache/nifi/toolkit/cli/NiFiCLIMainRunner.java new file mode 100644 index 0000000..fb7d94f --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/test/java/org/apache/nifi/toolkit/cli/NiFiCLIMainRunner.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.nifi.toolkit.cli; + +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.toolkit.cli.api.ClientFactory; +import org.apache.nifi.toolkit.cli.api.Command; +import org.apache.nifi.toolkit.cli.api.Context; +import org.apache.nifi.toolkit.cli.api.Session; +import org.apache.nifi.toolkit.cli.impl.context.StandardContext; +import org.apache.nifi.toolkit.cli.impl.session.InMemorySession; +import org.apache.nifi.toolkit.cli.impl.client.NiFiClientFactory; +import org.apache.nifi.toolkit.cli.impl.client.NiFiRegistryClientFactory; +import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClient; +import org.apache.nifi.toolkit.cli.impl.command.CommandFactory; +import org.apache.nifi.toolkit.cli.api.CommandGroup; +import org.apache.nifi.toolkit.cli.impl.command.CommandProcessor; + +import java.util.Map; + +public class NiFiCLIMainRunner { + + public static void main(String[] args) { + final String[] cmdArgs = ("nifi-reg create-bucket -bn FOO -p src/test/resources/test.properties " + + "").split("[ ]"); + + final Session session = new InMemorySession(); + final ClientFactory<NiFiClient> niFiClientFactory = new NiFiClientFactory(); + final ClientFactory<NiFiRegistryClient> nifiRegClientFactory = new NiFiRegistryClientFactory(); + + final Context context = new StandardContext.Builder() + .output(System.out) + .session(session) + .nifiClientFactory(niFiClientFactory) + .nifiRegistryClientFactory(nifiRegClientFactory) + .build(); + + final Map<String,Command> commands = CommandFactory.createTopLevelCommands(context); + final Map<String,CommandGroup> commandGroups = CommandFactory.createCommandGroups(context); + + final CommandProcessor processor = new CommandProcessor(commands, commandGroups, context); + processor.process(cmdArgs); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9cf9e866/nifi-toolkit/nifi-toolkit-cli/src/test/java/org/apache/nifi/toolkit/cli/TestCLICompleter.java ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-cli/src/test/java/org/apache/nifi/toolkit/cli/TestCLICompleter.java b/nifi-toolkit/nifi-toolkit-cli/src/test/java/org/apache/nifi/toolkit/cli/TestCLICompleter.java new file mode 100644 index 0000000..93d668c --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/test/java/org/apache/nifi/toolkit/cli/TestCLICompleter.java @@ -0,0 +1,223 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.nifi.toolkit.cli; + +import org.apache.nifi.registry.client.NiFiRegistryClient; +import org.apache.nifi.toolkit.cli.api.ClientFactory; +import org.apache.nifi.toolkit.cli.api.Command; +import org.apache.nifi.toolkit.cli.api.Context; +import org.apache.nifi.toolkit.cli.api.Session; +import org.apache.nifi.toolkit.cli.impl.context.StandardContext; +import org.apache.nifi.toolkit.cli.impl.session.InMemorySession; +import org.apache.nifi.toolkit.cli.impl.session.SessionVariables; +import org.apache.nifi.toolkit.cli.impl.client.NiFiClientFactory; +import org.apache.nifi.toolkit.cli.impl.client.NiFiRegistryClientFactory; +import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClient; +import org.apache.nifi.toolkit.cli.impl.command.CommandFactory; +import org.apache.nifi.toolkit.cli.api.CommandGroup; +import org.jline.reader.Candidate; +import org.jline.reader.LineReader; +import org.jline.reader.impl.DefaultParser; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.Mockito; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class TestCLICompleter { + + private static CLICompleter completer; + private static LineReader lineReader; + + @BeforeClass + public static void setupCompleter() { + final Session session = new InMemorySession(); + final ClientFactory<NiFiClient> niFiClientFactory = new NiFiClientFactory(); + final ClientFactory<NiFiRegistryClient> nifiRegClientFactory = new NiFiRegistryClientFactory(); + + final Context context = new StandardContext.Builder() + .output(System.out) + .session(session) + .nifiClientFactory(niFiClientFactory) + .nifiRegistryClientFactory(nifiRegClientFactory) + .build(); + + final Map<String,Command> commands = CommandFactory.createTopLevelCommands(context); + final Map<String,CommandGroup> commandGroups = CommandFactory.createCommandGroups(context); + + completer = new CLICompleter(commands.values(), commandGroups.values()); + lineReader = Mockito.mock(LineReader.class); + } + + @Test + public void testCompletionWithWordIndexNegative() { + final DefaultParser.ArgumentList parsedLine = new DefaultParser.ArgumentList( + "", Collections.emptyList(), -1, -1, -1); + + final List<Candidate> candidates = new ArrayList<>(); + completer.complete(lineReader, parsedLine, candidates); + assertEquals(0, candidates.size()); + } + + @Test + public void testCompletionWithWordIndexZero() { + final DefaultParser.ArgumentList parsedLine = new DefaultParser.ArgumentList( + "", Collections.emptyList(), 0, -1, -1); + + final List<Candidate> candidates = new ArrayList<>(); + completer.complete(lineReader, parsedLine, candidates); + assertEquals(completer.getTopLevelCommands().size(), candidates.size()); + } + + @Test + public void testCompletionWithWordIndexOneAndMatching() { + final String topCommand = "nifi-reg"; + + final DefaultParser.ArgumentList parsedLine = new DefaultParser.ArgumentList( + "", Collections.singletonList(topCommand), 1, -1, -1); + + final List<Candidate> candidates = new ArrayList<>(); + completer.complete(lineReader, parsedLine, candidates); + assertEquals(completer.getSubCommands(topCommand).size(), candidates.size()); + } + + @Test + public void testCompletionWithWordIndexOneAndNotMatching() { + final String topCommand = "NOT-A-TOP-LEVEL-COMMAND"; + + final DefaultParser.ArgumentList parsedLine = new DefaultParser.ArgumentList( + "", Collections.singletonList(topCommand), 1, -1, -1); + + final List<Candidate> candidates = new ArrayList<>(); + completer.complete(lineReader, parsedLine, candidates); + assertEquals(0, candidates.size()); + } + + @Test + public void testCompletionWithWordIndexTwoAndMatching() { + final String topCommand = "nifi-reg"; + final String subCommand = "list-buckets"; + + final DefaultParser.ArgumentList parsedLine = new DefaultParser.ArgumentList( + "", Arrays.asList(topCommand, subCommand), 2, -1, -1); + + final List<Candidate> candidates = new ArrayList<>(); + completer.complete(lineReader, parsedLine, candidates); + assertTrue(candidates.size() > 0); + assertEquals(completer.getOptions(subCommand).size(), candidates.size()); + } + + @Test + public void testCompletionWithWordIndexTwoAndNotMatching() { + final String topCommand = "nifi-reg"; + final String subCommand = "NOT-A-TOP-LEVEL-COMMAND"; + + final DefaultParser.ArgumentList parsedLine = new DefaultParser.ArgumentList( + "", Arrays.asList(topCommand, subCommand), 2, -1, -1); + + final List<Candidate> candidates = new ArrayList<>(); + completer.complete(lineReader, parsedLine, candidates); + assertEquals(0, candidates.size()); + } + + @Test + public void testCompletionWithMultipleArguments() { + final String topCommand = "nifi-reg"; + final String subCommand = "list-buckets"; + + final DefaultParser.ArgumentList parsedLine = new DefaultParser.ArgumentList( + "", Arrays.asList(topCommand, subCommand, "-ks", "foo", "-kst", "JKS"), 6, -1, -1); + + final List<Candidate> candidates = new ArrayList<>(); + completer.complete(lineReader, parsedLine, candidates); + assertTrue(candidates.size() > 0); + assertEquals(completer.getOptions(subCommand).size(), candidates.size()); + } + + @Test + public void testCompletionWithFileArguments() { + final String topCommand = "nifi-reg"; + final String subCommand = "list-buckets"; + + final DefaultParser.ArgumentList parsedLine = new DefaultParser.ArgumentList( + "", Arrays.asList(topCommand, subCommand, "-p", "src/test/resources/"), 3, -1, -1); + + final List<Candidate> candidates = new ArrayList<>(); + completer.complete(lineReader, parsedLine, candidates); + assertTrue(candidates.size() > 0); + + boolean found = false; + for (Candidate candidate : candidates) { + if (candidate.value().equals("src/test/resources/test.properties")) { + found = true; + break; + } + } + + assertTrue(found); + } + + @Test + public void testCompletionForSessionVariableNames() { + final String topCommand = "session"; + final String subCommand = "set"; + + final DefaultParser.ArgumentList parsedLine = new DefaultParser.ArgumentList( + "", Arrays.asList(topCommand, subCommand), 2, -1, -1); + + final List<Candidate> candidates = new ArrayList<>(); + completer.complete(lineReader, parsedLine, candidates); + assertTrue(candidates.size() > 0); + assertEquals(SessionVariables.values().length, candidates.size()); + } + + @Test + public void testCompletionForSessionVariableWithFiles() { + final String topCommand = "session"; + final String subCommand = "set"; + + final DefaultParser.ArgumentList parsedLine = new DefaultParser.ArgumentList("", + Arrays.asList( + topCommand, + subCommand, + SessionVariables.NIFI_CLIENT_PROPS.getVariableName(), + "src/test/resources/"), + 3, -1, -1); + + final List<Candidate> candidates = new ArrayList<>(); + completer.complete(lineReader, parsedLine, candidates); + assertTrue(candidates.size() > 0); + + boolean found = false; + for (Candidate candidate : candidates) { + if (candidate.value().equals("src/test/resources/test.properties")) { + found = true; + break; + } + } + + assertTrue(found); + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9cf9e866/nifi-toolkit/nifi-toolkit-cli/src/test/resources/test.properties ---------------------------------------------------------------------- diff --git a/nifi-toolkit/nifi-toolkit-cli/src/test/resources/test.properties b/nifi-toolkit/nifi-toolkit-cli/src/test/resources/test.properties new file mode 100644 index 0000000..31a2dfc --- /dev/null +++ b/nifi-toolkit/nifi-toolkit-cli/src/test/resources/test.properties @@ -0,0 +1,33 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# + +# Properties that will be loaded as arguments to the CommandProcessor when specifying the '-p' argument +# with the value being the properties file to load. +# +# Properties specified directly on the command line will override properties with the same name in the properties file. +# +# Property names must correspond with the long argument names (i.e. 'baseUrl' instead of 'u'). + +baseUrl=http://localhost:18080 +keystore= +keystoreType= +keystorePasswd= +keyPasswd= +truststore= +truststoreType= +truststorePasswd= +proxiedEntity= http://git-wip-us.apache.org/repos/asf/nifi/blob/9cf9e866/nifi-toolkit/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-toolkit/pom.xml b/nifi-toolkit/pom.xml index 002a036..20016ed 100644 --- a/nifi-toolkit/pom.xml +++ b/nifi-toolkit/pom.xml @@ -31,6 +31,7 @@ <module>nifi-toolkit-flowfile-repo</module> <module>nifi-toolkit-assembly</module> <module>nifi-toolkit-flowanalyzer</module> + <module>nifi-toolkit-cli</module> </modules> <dependencyManagement> <dependencies> http://git-wip-us.apache.org/repos/asf/nifi/blob/9cf9e866/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index f7b2495..0b4234a 100644 --- a/pom.xml +++ b/pom.xml @@ -900,6 +900,11 @@ </dependency> <dependency> <groupId>org.apache.nifi</groupId> + <artifactId>nifi-toolkit-cli</artifactId> + <version>1.6.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>org.apache.nifi</groupId> <artifactId>nifi-registry-service</artifactId> <version>1.6.0-SNAPSHOT</version> </dependency>
