[java-metadata-aggregator] branch main updated: MDA-271 - Refactor to avoid JVM exit, correctly handle context lifetime

Ian Young ian at iay.org.uk
Thu Oct 20 10:57:53 UTC 2022


This is an automated email from the git hooks/post-receive script.

iay pushed a commit to branch main
in repository java-metadata-aggregator.

View the commit online:
http://git.shibboleth.net/view/?p=java-metadata-aggregator.git;a=commit;h=9e3450b62024e16e0896eded42a5eb36383f0b4d

The following commit(s) were added to refs/heads/main by this push:
     new 9e3450b  MDA-271 - Refactor to avoid JVM exit, correctly handle context lifetime
9e3450b is described below

commit 9e3450b62024e16e0896eded42a5eb36383f0b4d
Author: Ian Young <ian at iay.org.uk>
AuthorDate: Thu Oct 20 11:57:49 2022 +0100

    MDA-271 - Refactor to avoid JVM exit, correctly handle context lifetime
    
    https://shibboleth.atlassian.net/browse/MDA-271
---
 .../shibboleth/metadata/cli/SimpleCommandLine.java | 147 ++++++++++++---------
 1 file changed, 87 insertions(+), 60 deletions(-)

diff --git a/mda-cli/src/main/java/net/shibboleth/metadata/cli/SimpleCommandLine.java b/mda-cli/src/main/java/net/shibboleth/metadata/cli/SimpleCommandLine.java
index b6c16f8..288d1df 100644
--- a/mda-cli/src/main/java/net/shibboleth/metadata/cli/SimpleCommandLine.java
+++ b/mda-cli/src/main/java/net/shibboleth/metadata/cli/SimpleCommandLine.java
@@ -42,24 +42,47 @@ import org.springframework.context.support.FileSystemXmlApplicationContext;
  * All logging is done in accordance with the logback.xml file included in command line JAR file. 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.
- * 
- * This CLI is not terribly robust nor does it really offer much in the way of features. It's mostly meant for testing
- * purposes and will be replaced before the 1.0 release of the software.
  */
 public final class SimpleCommandLine {
 
-    /** Return code indicating command completed successfully, {@value} . */
-    public static final int RC_OK = 0;
+    /**
+     * Exception to be thrown during processing. Carries an error
+     * code to be reported as the CLI result.
+     */
+    private static class ErrorException extends Exception {
+        /** serialVersionUID required for all exceptions. */
+        private static final long serialVersionUID = 1L;
+
+        /** CLI error code to return on exiting the JVM. */
+        private final int error;
+
+        /**
+         * Constructor.
+         *
+         * @param errorCode error code to report on exit
+         * @param message message to report on exit
+         * @param cause underlying cause of the error
+         */
+        ErrorException(final int errorCode, @Nonnull final String message, final Throwable cause) {
+            super(message, cause);
+            error = errorCode;
+        }
+
+        /**
+         * Constructor.
+         *
+         * @param errorCode error code to report on exit
+         * @param message message to report on exit
+         */
+        ErrorException(final int errorCode, @Nonnull final String message) {
+            super(message);
+            error = errorCode;
+        }
+    }
 
     /** 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;
-
     /** Class logger. */
     private static Logger log;
 
@@ -79,69 +102,73 @@ public final class SimpleCommandLine {
 
         if (cli.doHelp()) {
             cli.printHelp(System.out);
-            System.exit(RC_OK);
+            return;
         }
 
         if (cli.doVersion()) {
             System.out.println(Version.getVersion());
-            System.exit(RC_OK);
+            return;
         }
         
         initLogging(cli);
 
-        FileSystemXmlApplicationContext appCtx = null;
         try {
-            final String fileUri = new File(cli.getInputFile()).toURI().toString();
-            log.debug("Initializing Spring context with configuration file {}", fileUri);
-            appCtx = new FileSystemXmlApplicationContext(fileUri);
-            
-            // Register a shutdown hook for the context, so that beans will be
-            // correctly destroyed before the CLI exits.
-            appCtx.registerShutdownHook();
-        } catch (final BeansException e) {
-            log.error("Unable to initialize Spring context", e);
-            System.exit(RC_INIT);
-        }
-
-        log.debug("Retrieving pipeline from Spring context");
-        final String pipelineName = cli.getPipelineName();
-        
-        final Pipeline<?> pipeline = appCtx.getBean(pipelineName, Pipeline.class);
-
-        if (pipeline == null) {
-            log.error("No net.shibboleth.metadata.pipeline.Pipeline, with ID {}, defined in Spring configuration",
-                    pipelineName);
-            System.exit(RC_INIT);
+            process(cli);
+        } catch (final ErrorException e) {
+            log.error(e.getMessage(), e.getCause());
+            System.exit(e.error);
         }
+    }
 
-        try {
-            if (!pipeline.isInitialized()) {
-                log.debug("Retrieved pipeline has not been initialized, initializing it now");
-                pipeline.initialize();
-            } else {
-                log.debug("Retrieved pipeline has already been initialized");
+    /**
+     * Build the context and run the pipeline.
+     *
+     * @param cli command line arguments
+     *
+     * @throws ErrorException if a problem requiring termination occurs
+     */
+    private static void process(@Nonnull final SimpleCommandLineArguments cli) throws ErrorException {
+        final String fileUri = new File(cli.getInputFile()).toURI().toString();
+        log.debug("Initializing Spring context with configuration file {}", fileUri);
+        try (FileSystemXmlApplicationContext appCtx = new FileSystemXmlApplicationContext(fileUri)) {
+
+            log.debug("Retrieving pipeline from Spring context");
+            final String pipelineName = cli.getPipelineName();
+            final Pipeline<?> pipeline = appCtx.getBean(pipelineName, Pipeline.class);
+            if (pipeline == null) {
+                throw new ErrorException(RC_INIT,
+                        "No net.shibboleth.metadata.pipeline.Pipeline, with ID " + pipelineName +
+                        " defined in Spring configuration");
             }
 
-            final Date startTime = new Date();
-            log.info("Pipeline '{}' execution starting at {}", pipelineName, startTime);
-            pipeline.execute(new ArrayList<>());
-            final Date endTime = new Date();
-            log.info("Pipeline '{}' execution completed at {}; run time {} seconds",
-                    new Object[]{pipelineName, endTime, (endTime.getTime()-startTime.getTime())/1000f});
-
-            System.exit(RC_OK);
-            
-        } catch (final TerminationException e) {
-            if (cli.doVerboseOutput()) {
-                log.error("TerminationException during processing", e);
-            } else {
-                log.error("Terminated: {}", e.getMessage());
+            try {
+                if (!pipeline.isInitialized()) {
+                    log.debug("Retrieved pipeline has not been initialized, initializing it now");
+                    pipeline.initialize();
+                } else {
+                    log.debug("Retrieved pipeline has already been initialized");
+                }
+
+                final Date startTime = new Date();
+                log.info("Pipeline '{}' execution starting at {}", pipelineName, startTime);
+                pipeline.execute(new ArrayList<>());
+                final Date endTime = new Date();
+                log.info("Pipeline '{}' execution completed at {}; run time {} seconds",
+                        pipelineName, endTime, (endTime.getTime()-startTime.getTime())/1000f);
+
+            } catch (final TerminationException e) {
+                if (cli.doVerboseOutput()) {
+                    throw new ErrorException(RC_INIT, "TerminationException during processing", e);
+                } else {
+                    throw new ErrorException(RC_INIT, "Terminated: " + e.getMessage());
+                }
+
+            } catch (final Exception e) {
+                throw new ErrorException(RC_INIT, "Error processing information", e);
             }
-            System.exit(RC_INIT);
-            
-        } catch (final Exception e) {
-            log.error("Error processing information", e);
-            System.exit(RC_INIT);
+
+        } catch (final BeansException e) {
+            throw new ErrorException(RC_INIT, "Unable to initialize Spring context", e);
         }
     }
 

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list