[spring-extensions] branch master updated: JSE-38 - Provide a command line wrapper for Spring contexts
Scott Cantor
cantor.2 at osu.edu
Wed Jul 1 16:23:20 UTC 2020
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch master
in repository spring-extensions.
View the commit online:
http://git.shibboleth.net/view/?p=spring-extensions.git;a=commit;h=b4c3367900b18c4e5720ab88d982421b0c1b6863
The following commit(s) were added to refs/heads/master by this push:
new b4c3367 JSE-38 - Provide a command line wrapper for Spring contexts
b4c3367 is described below
commit b4c3367900b18c4e5720ab88d982421b0c1b6863
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Jul 1 12:23:15 2020 -0400
JSE-38 - Provide a command line wrapper for Spring contexts
https://issues.shibboleth.net/jira/browse/JSE-38
---
pom.xml | 6 +
.../ext/spring/cli/AbstractCommandLine.java | 202 +++++++++++++++++++++
.../spring/cli/AbstractCommandLineArguments.java | 135 ++++++++++++++
.../ext/spring/cli/CommandLineArguments.java | 89 +++++++++
.../shibboleth/ext/spring/cli/package-info.java | 22 +++
src/main/resources/logger-normal.xml | 15 ++
src/main/resources/logger-quiet.xml | 15 ++
src/main/resources/logger-verbose.xml | 15 ++
8 files changed, 499 insertions(+)
diff --git a/pom.xml b/pom.xml
index 4220e04..13ce697 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,6 +82,12 @@
<!-- Required for the DomDocumentFactoryBean and Duration conversion classes. -->
<optional>true</optional>
</dependency>
+ <dependency>
+ <groupId>com.beust</groupId>
+ <artifactId>jcommander</artifactId>
+ <!-- Required for command line classes. -->
+ <optional>true</optional>
+ </dependency>
<dependency>
<groupId>${spring.groupId}</groupId>
<artifactId>spring-context</artifactId>
diff --git a/src/main/java/net/shibboleth/ext/spring/cli/AbstractCommandLine.java b/src/main/java/net/shibboleth/ext/spring/cli/AbstractCommandLine.java
new file mode 100644
index 0000000..664a936
--- /dev/null
+++ b/src/main/java/net/shibboleth/ext/spring/cli/AbstractCommandLine.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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 net.shibboleth.ext.spring.cli;
+
+import java.lang.reflect.Constructor;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.springframework.context.support.GenericApplicationContext;
+import org.springframework.core.io.Resource;
+
+import com.beust.jcommander.JCommander;
+
+import net.shibboleth.ext.spring.resource.PreferFileSystemResourceLoader;
+import net.shibboleth.ext.spring.util.ApplicationContextBuilder;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+
+/**
+ * A simple driver for a Spring-based CLI.
+ *
+ * This class handles a single parameters, the primary Spring configuration resource. Additional parameters may be
+ * handled by subclasses.
+ *
+ * All logging is done in accordance with the logback.xml file included in the library. If you wish to use a
+ * different logging configuration you may do so using the <code>-Dlogback.configurationFile=/path/to/logback.xml</code>
+ * JVM configuration option.
+ *
+ * @param <T> argument object type
+ */
+public abstract class AbstractCommandLine<T extends CommandLineArguments> {
+
+ /** Name of system property for command line argument class. */
+ @Nonnull @NotEmpty public static final String ARGS_PROPERTY = "net.shibboleth.ext.spring.cli.arguments";
+
+ /** Return code indicating command completed successfully, {@value} . */
+ public static final int RC_OK = 0;
+
+ /** Return code indicating an initialization error, {@value} . */
+ public static final int RC_INIT = 1;
+
+ /** Return code indicating an error reading files, {@value} . */
+ public static final int RC_IO = 2;
+
+ /** Return code indicating an unknown error occurred, {@value} . */
+ public static final int RC_UNKNOWN = -1;
+
+ /** Spring context. */
+ @Nullable private GenericApplicationContext applicationContext;
+
+ /**
+ * Get the Spring context.
+ *
+ * @return Spring context
+ */
+ @Nonnull protected GenericApplicationContext getApplicationContext() {
+ if (applicationContext == null) {
+ throw new IllegalStateException("No application context installed");
+ }
+ return applicationContext;
+ }
+
+ /**
+ * Run method.
+ *
+ * @param args command line arguments
+ *
+ * @return exit code
+ */
+ protected int run(@Nonnull final String[] args) {
+
+ final T argObject;
+
+ try {
+ final Constructor<T> construct = getArgumentClass().getConstructor();
+ argObject = construct.newInstance();
+ final JCommander jc = new JCommander(argObject);
+ jc.parse(args);
+ if (argObject.isHelp()) {
+ argObject.printHelp(System.out);
+ return RC_OK;
+ } else if (argObject.isVersion()) {
+ System.out.println(getVersion());
+ return RC_OK;
+ }
+
+ if (argObject.getOtherArgs().size() == 0) {
+ error("Missing Spring config argument");
+ return RC_INIT;
+ }
+
+ initLogging(argObject);
+
+ argObject.validate();
+
+ } catch (final Exception e) {
+ error(e.getMessage());
+ return RC_INIT;
+ }
+
+ return doRun(argObject);
+ }
+
+ /**
+ * Initialize the logging subsystem.
+ *
+ * @param args command line arguments
+ */
+ protected void initLogging(@Nonnull final T args) {
+ if (args.getLoggingConfiguration() != null) {
+ System.setProperty("logback.configurationFile", args.getLoggingConfiguration());
+ } else if (args.isVerboseOutput()) {
+ System.setProperty("logback.configurationFile", "logger-verbose.xml");
+ } else if (args.isQuietOutput()) {
+ System.setProperty("logback.configurationFile", "logger-quiet.xml");
+ } else {
+ System.setProperty("logback.configurationFile", "logger-normal.xml");
+ }
+ }
+
+ /**
+ * The execution method to override.
+ *
+ * The default implementation handles Spring context creation.
+ *
+ * @param args input arguments
+ *
+ * @return exit code
+ */
+ protected int doRun(@Nonnull final T args) {
+ try {
+ final Resource config = new PreferFileSystemResourceLoader().getResource(args.getOtherArgs().get(0));
+
+ getLogger().debug("Initializing Spring context with configuration file {}", config.getURI());
+
+ applicationContext = new ApplicationContextBuilder().setServiceConfiguration(config).build();
+
+ // Register a shutdown hook for the context, so that beans will be
+ // correctly destroyed before the CLI exits.
+ applicationContext.registerShutdownHook();
+ } catch (final Exception e) {
+ if (args.isVerboseOutput()) {
+ getLogger().error("Unable to initialize Spring context", e);
+ } else {
+ getLogger().error("Unable to initialize Spring context", e.getMessage());
+ }
+ return RC_INIT;
+ }
+
+ return RC_OK;
+ }
+
+ /**
+ * Get the class of the argument object to instantiate.
+ *
+ * @return argument class
+ */
+ @Nonnull protected abstract Class<T> getArgumentClass();
+
+ /**
+ * Return an appropriate version value.
+ *
+ * @return a version string
+ */
+ @Nonnull @NotEmpty protected abstract String getVersion();
+
+ /**
+ * Get logger.
+ *
+ * @return logger
+ */
+ @Nonnull protected abstract Logger getLogger();
+
+ /**
+ * Prints the error message to STDERR.
+ *
+ * @param error the error message
+ */
+ private static void error(@Nonnull @NotEmpty final String error) {
+ System.err.println(error);
+ System.err.flush();
+ System.out.println();
+ System.out.flush();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/shibboleth/ext/spring/cli/AbstractCommandLineArguments.java b/src/main/java/net/shibboleth/ext/spring/cli/AbstractCommandLineArguments.java
new file mode 100644
index 0000000..a3d04d5
--- /dev/null
+++ b/src/main/java/net/shibboleth/ext/spring/cli/AbstractCommandLineArguments.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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 net.shibboleth.ext.spring.cli;
+
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.beust.jcommander.Parameter;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+
+/** Command line arguments base class for the {@link AbstractCommandLine} class. */
+public abstract class AbstractCommandLineArguments implements CommandLineArguments {
+
+ // Non-option arguments
+
+ /**
+ * Command-line arguments which are not part of options.
+ */
+ @Parameter
+ @Nonnull private List<String> otherArgs = new ArrayList<>();
+
+ // Logging
+
+ /**
+ * Verbose logging has been requested.
+ */
+ @Parameter(names = "--verbose")
+ private boolean verbose;
+
+ /**
+ * Quiet logging has been requested.
+ */
+ @Parameter(names = "--quiet")
+ private boolean quiet;
+
+ /**
+ * Name of a specific logging configuration, if one has been requested.
+ */
+ @Parameter(names = "--logConfig")
+ @Nullable private String logConfig;
+
+ // Help
+
+ /**
+ * Help has been requested.
+ */
+ @Parameter(names = "--help", help=true)
+ private boolean help;
+
+ // Version
+
+ /**
+ * Version has been requested.
+ */
+ @Parameter(names = "--version")
+ private boolean version;
+
+ /** {@inheritDoc} */
+ public boolean isVerboseOutput() {
+ return verbose;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isQuietOutput() {
+ return quiet;
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public String getLoggingConfiguration() {
+ return logConfig;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isHelp() {
+ return help;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isVersion() {
+ return version;
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull @Unmodifiable @NotLive public List<String> getOtherArgs() {
+ return otherArgs;
+ }
+
+ /** {@inheritDoc} */
+ public void validate() throws IllegalArgumentException {
+ if (isVerboseOutput() && isQuietOutput()) {
+ throw new IllegalArgumentException("Verbose and quiet output are mutually exclusive");
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void printHelp(final PrintStream out) {
+ out.println();
+ out.println("==== Command Line Options ====");
+ out.println();
+ out.println(String.format(" --%-20s %s", "help", "Prints this help information"));
+ out.println(String.format(" --%-20s %s", "version", "Prints version"));
+ out.println();
+
+ out.println("Logging Options - these options are mutually exclusive");
+ out.println(String.format(" --%-20s %s", "verbose", "Turn on verbose messages."));
+ out.println(String.format(" --%-20s %s", "quiet",
+ "Restrict output messages to errors and warnings."));
+ out.println();
+ out.println(String.format(" --%-20s %s", "logConfig",
+ "Specifies a logback configuration file to use to configure logging."));
+ out.println();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/shibboleth/ext/spring/cli/CommandLineArguments.java b/src/main/java/net/shibboleth/ext/spring/cli/CommandLineArguments.java
new file mode 100644
index 0000000..e859c3c
--- /dev/null
+++ b/src/main/java/net/shibboleth/ext/spring/cli/CommandLineArguments.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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 net.shibboleth.ext.spring.cli;
+
+import java.io.PrintStream;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+
+/** Command line arguments interface for the {@link CLI} command line tool. */
+public interface CommandLineArguments {
+
+ /**
+ * Indicates the presence of the <code>--verbose</code> option.
+ *
+ * @return <code>true</code> if the user requested verbose logging.
+ */
+ boolean isVerboseOutput();
+
+ /**
+ * Indicates the presence of the <code>--quiet</code> option.
+ *
+ * @return <code>true</code> if the user requested quiet logging.
+ */
+ boolean isQuietOutput();
+
+ /**
+ * Gets the name of the requested logging configuration file
+ * from the command line.
+ *
+ * @return the logging configuration file name, or <code>null</code>.
+ */
+ @Nullable String getLoggingConfiguration();
+
+ /**
+ * Indicates the presence of the <code>--help</code> option.
+ *
+ * @return <code>true</code> if the user requested help.
+ */
+ boolean isHelp();
+
+ /**
+ * Indicates the presence of the <code>--version</code> option.
+ *
+ * @return <code>true</code> if the user requested the version be printed.
+ */
+ boolean isVersion();
+
+ /**
+ * Get unparsed arguments.
+ *
+ * @return unparsed arguments
+ */
+ @Nonnull @Unmodifiable @NotLive public List<String> getOtherArgs();
+
+ /**
+ * Validate the parameter set.
+ *
+ * @throws IllegalArgumentException if the parameters are invalid
+ */
+ void validate() throws IllegalArgumentException;
+
+ /**
+ * Print default command line help instructions.
+ *
+ * @param out location where to print the output
+ */
+ void printHelp(@Nonnull final PrintStream out);
+
+}
\ No newline at end of file
diff --git a/src/main/java/net/shibboleth/ext/spring/cli/package-info.java b/src/main/java/net/shibboleth/ext/spring/cli/package-info.java
new file mode 100644
index 0000000..a4a077f
--- /dev/null
+++ b/src/main/java/net/shibboleth/ext/spring/cli/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID 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.
+ */
+
+/**
+ * Command line functionality.
+ */
+
+package net.shibboleth.ext.spring.cli;
\ No newline at end of file
diff --git a/src/main/resources/logger-normal.xml b/src/main/resources/logger-normal.xml
new file mode 100644
index 0000000..89bd0bb
--- /dev/null
+++ b/src/main/resources/logger-normal.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+ <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <charset>UTF-8</charset>
+ <Pattern>%-5level - %msg%n</Pattern>
+ </encoder>
+ </appender>
+
+ <root level="INFO">
+ <appender-ref ref="CONSOLE"/>
+ </root>
+
+</configuration>
diff --git a/src/main/resources/logger-quiet.xml b/src/main/resources/logger-quiet.xml
new file mode 100644
index 0000000..22eb3af
--- /dev/null
+++ b/src/main/resources/logger-quiet.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+ <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <charset>UTF-8</charset>
+ <Pattern>%-5level - %msg%n</Pattern>
+ </encoder>
+ </appender>
+
+ <root level="WARN">
+ <appender-ref ref="CONSOLE"/>
+ </root>
+
+</configuration>
diff --git a/src/main/resources/logger-verbose.xml b/src/main/resources/logger-verbose.xml
new file mode 100644
index 0000000..362d1b7
--- /dev/null
+++ b/src/main/resources/logger-verbose.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+ <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <charset>UTF-8</charset>
+ <Pattern>%date{ISO8601} - %level [%logger:%line] - %msg%n</Pattern>
+ </encoder>
+ </appender>
+
+ <root level="DEBUG">
+ <appender-ref ref="CONSOLE"/>
+ </root>
+
+</configuration>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list