All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rathravane.till.console.ConsoleProgram Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
/*
 *	Copyright 2006-2012, Rathravane LLC
 *
 *	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.rathravane.till.console;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.rathravane.till.nv.rrNvReadable;
import com.rathravane.till.nv.rrNvWriteable;
import com.rathravane.till.nv.impl.nvEnvProperties;
import com.rathravane.till.nv.impl.nvInstallTypeWrapper;
import com.rathravane.till.nv.impl.nvReadableStack;
import com.rathravane.till.nv.impl.nvWriteableTable;

/**
 * A console program runs on the command line.
 * 

* The console class expects the program's main() routine to call its * runFromMain() method to start the system. * * @author peter */ public class ConsoleProgram { public static class usageException extends Exception { public usageException ( String correctUsage ) { super(correctUsage); } public usageException ( Exception cause ) { super(cause); } private static final long serialVersionUID = 1L; } public static class startupFailureException extends Exception { public startupFailureException ( Exception x ) { super(x); } public startupFailureException ( String msg ) { super(msg); } public startupFailureException ( String msg, Exception x ) { super(msg,x); } private static final long serialVersionUID = 1L; } /** * A looper is an object that is run repeatedly (in a loop). This class is * what the main thread of the program does between startup and exit. * * @author peter * */ public interface looper { /** * setup the looper and return true to continue. Called once. * @param prefs * @param cmdLine * @return true/false */ boolean setup ( rrNvReadable prefs, CmdLinePrefs cmdLine ); /** * Run a loop iteration, return true to continue, false to exit. (Note * that nothing requires this implementation to do a small amount of * work vs. lengthy processing.) * @return true to continue, false to exit */ boolean loop ( rrNvReadable prefs ); /** * teardown the looper. called once. * @param prefs */ void teardown ( rrNvReadable prefs ); } protected CmdLineParser getCmdLineParser () { return fCmdLineParser; } protected ConsoleProgram () { fHostInfo = new nvWriteableTable (); fDefaults = new nvWriteableTable (); fCmdLineParser = new CmdLineParser (); } public void runFromMain ( String[] args ) throws Exception { // get setup installShutdownHook (); setupHostInfo (); setupDefaults ( fDefaults ); setupOptions ( fCmdLineParser ); // parse the command line final CmdLinePrefs cmdLine = fCmdLineParser.processArgs ( args ); // build a preferences stack final nvReadableStack stack = new nvReadableStack (); stack.push ( fHostInfo ); // sets 'hostname' stack.push ( new nvEnvProperties() ); // makes system environment available stack.push ( fDefaults ); // app defaults stack.push ( cmdLine ); // settings from command line // wrap the settings stack with the install-type suffix check, // which lets you set -Drr.installation=foo on the Java cmd line // and then have settings like mySetting[foo]=bar as specialization // over mySetting=theUsualValue. final nvInstallTypeWrapper wrapper = new nvInstallTypeWrapper ( stack ); // optionally load more configuration from the app. If provided, // it fits in the stack below command line settings final rrNvReadable config = loadAdditionalConfig ( wrapper ); if ( config != null ) { stack.pushBelow ( config, cmdLine ); wrapper.rescan (); } // init and get the run loop final looper l = init ( wrapper, cmdLine ); if ( l != null ) { if ( l.setup ( wrapper, cmdLine ) ) { while ( l.loop ( wrapper ) ) {} l.teardown ( wrapper ); } } cleanup (); } /** * Override this to handle an abrupt shutdown. This method is called when the system exits. */ protected void onShutdown () { } /** * Override this to setup default settings for the program. * @param pt */ protected ConsoleProgram setupDefaults ( rrNvWriteable pt ) { return this; } /** * Override this to setup recognized command line options. Note that default values * provided to the command line reader are NOT available from init's settings instance. * That's because the settings system doesn't have a way to differentiate between having * a key and having a key as a default value. When stacked, if the command line parser * states that it has a key, then any explicit setting further down the stack will not * be used. * @param p */ protected ConsoleProgram setupOptions ( CmdLineParser p ) { return this; } /** * Override this to load additional configuration. If a non-null config is returned, * it's inserted into the preferences stack between the default settings and the command line * settings. That way, the command line arguments have precedence. * @param currentPrefs * @throws rrNvReadable.loadException * @throws rrNvReadable.missingReqdSetting */ protected rrNvReadable loadAdditionalConfig ( rrNvReadable currentPrefs ) throws rrNvReadable.loadException, rrNvReadable.missingReqdSetting { return null; } /** * Init the program and return a loop instance if the program should continue. The base * class returns null, so you have to override this to do anything beyond init. * @param p settings * @param cmdLine command line values * @return non-null to continue, null to exit * @throws rrNvReadable.missingReqdSetting * @throws rrNvReadable.invalidSettingValue */ protected looper init ( rrNvReadable p, CmdLinePrefs cmdLine ) throws rrNvReadable.missingReqdSetting, rrNvReadable.invalidSettingValue, startupFailureException { return null; } /** * Override this to run any cleanup code after the main loop. */ protected void cleanup () {} /** * expand a file argument ("*" matches, etc.) * @param arg * @return * @throws FileNotFoundException */ protected List expandFileArg ( String arg ) throws FileNotFoundException { final LinkedList fileList= new LinkedList (); final File file = new File ( arg ); final File parentDir = file.getParentFile (); if ( parentDir != null ) { final String matchPart = file.getName ().replace ( "*", ".*" ); // cmd line regex to java regex final Pattern p = Pattern.compile ( matchPart ); final File[] files = parentDir.listFiles ( new FilenameFilter () { @Override public boolean accept ( File dir, String name ) { return p.matcher ( name ).matches (); } } ); if ( files != null ) { for ( File f : files ) { fileList.add ( f ); } } } return fileList; } private final CmdLineParser fCmdLineParser; private final nvWriteableTable fDefaults; private final nvWriteableTable fHostInfo; private static final Logger log = LoggerFactory.getLogger ( ConsoleProgram.class ); private void setupHostInfo () { try { fHostInfo.set ( "hostname", InetAddress.getLocalHost().getHostName() ); } catch ( UnknownHostException e ) { log.warn ( "Couldn't establish hostname.", e ); } } private void installShutdownHook () { Runtime.getRuntime ().addShutdownHook ( new Thread () { @Override public void run () { onShutdown (); } } ); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy