001/*
002 * #%L
003 * Netarchivesuite - common
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library,
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023
024package dk.netarkivet.common.tools;
025
026import dk.netarkivet.common.utils.ExceptionUtils;
027
028/**
029 * A simple class that manages and runs an implementation of SimpleCmdlineTool. The class contains an abstract factory
030 * method, which will create the actual implementation when specialized. This could also have been done with generics,
031 * but this is the traditional implementation.
032 */
033public abstract class ToolRunnerBase {
034
035    /**
036     * Factory method. Creates and returns the intended specific implementation of a command line tool.
037     *
038     * @return An implementation of the SimpleCmdlineTool interface.
039     */
040    protected abstract SimpleCmdlineTool makeMyTool();
041
042    /**
043     * Consolidates that behavior on error is System.exit(1) (exit with failure).
044     */
045    private void exitWithFailure() {
046        System.exit(1);
047    }
048
049    /**
050     * A template method implementing default behaviour for showing a message (send to stderr). Can be overridden to
051     * ensure logging.
052     *
053     * @param msg The message to display
054     */
055    protected void showMessage(String msg) {
056        System.err.println(msg);
057    }
058
059    /**
060     * Passes (command line) parameters to the tool. If an error occured (internalRunTool returned false), exit with
061     * failure.
062     *
063     * @param args Usually a straight passing of the command line parameters from a "main" method.
064     */
065    public void runTheTool(String... args) {
066        if (!internalRunTheTool(args)) {
067            exitWithFailure();
068        }
069        System.exit(0);
070    }
071
072    // Private methods follow for doing setup, run and teardown with rudimentary
073    // handling of exceptions. Split up in several methods for clarity.
074
075    private boolean runIt(SimpleCmdlineTool tool, String... args) {
076        try {
077            tool.run(args);
078        } catch (Exception e) {
079            exceptionMessage("An error occurred during processing.", e);
080            return false;
081        }
082        return true;
083    }
084
085    private boolean setupAndRunIt(SimpleCmdlineTool tool, String... args) {
086        try {
087            tool.setUp(args);
088            runIt(tool, args);
089            return true;
090        } catch (Exception e) {
091            exceptionMessage("An error occurred during setup of tool.", e);
092            return false;
093        } finally {
094            tool.tearDown();
095        }
096    }
097
098    private boolean checkArgsSetupAndRun(SimpleCmdlineTool tool, String... args) {
099        try {
100            if (!tool.checkArgs(args)) {
101                usage(tool);
102                return false;
103            }
104            return setupAndRunIt(tool, args);
105        } catch (Exception e) {
106            exceptionMessage("Couldn't check parameters for tool.", e);
107            return false;
108        }
109    }
110
111    private boolean internalRunTheTool(String... args) {
112        try {
113            SimpleCmdlineTool tool = makeMyTool();
114            return checkArgsSetupAndRun(tool, args);
115        } catch (Exception e) {
116            exceptionMessage("Couldn't create the tool to run!", e);
117            return false;
118        }
119    }
120
121    /**
122     * Prints usage, delegating the actual parameter description to the tool.
123     *
124     * @param tool The tool that we have specialized this class to. Know how to run and how to describe itself.
125     */
126    private void usage(SimpleCmdlineTool tool) {
127        showMessage("Usage: java " + this.getClass().getName() + " " + tool.listParameters());
128        exitWithFailure();
129    }
130
131    /**
132     * Centralized, rudimentary exception handling. Only option is to print a message, and a stack trace.
133     *
134     * @param msg A message from the tool manager (this class), notifying the user about where the exception occurred.
135     * @param e The exception that occurred.
136     */
137    private void exceptionMessage(String msg, Exception e) {
138        showMessage(msg);
139        showMessage("Output (if any) is not OK");
140        showMessage("Exception message is:");
141        showMessage(e.getMessage());
142        showMessage("Stack trace:");
143        showMessage(ExceptionUtils.getStackTrace(e));
144        exitWithFailure();
145    }
146
147}