/*
* Copyright (C) 2011 Laurent Caillette
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.novelang.bootstrap;
import java.io.File;
import java.io.PrintStream;
import com.google.common.collect.ImmutableSet;
import org.apache.commons.lang.SystemUtils;
import org.novelang.batch.CannotStartException;
import org.novelang.batch.DocumentGenerator;
import org.novelang.batch.LevelExploder;
import org.novelang.configuration.parse.ArgumentException;
import org.novelang.configuration.parse.DaemonParameters;
import org.novelang.configuration.parse.DocumentGeneratorParameters;
import org.novelang.configuration.parse.GenericParameters;
import org.novelang.configuration.parse.LevelExploderParameters;
import org.novelang.daemon.HttpDaemon;
import org.novelang.logger.Logger;
import org.novelang.logger.LoggerFactory;
import org.novelang.outfit.EnvironmentTools;
import org.novelang.outfit.LogbackConfigurationTools;
import org.novelang.outfit.TemporaryFileTools;
/**
* The single entry point for launching all Novelang commands.
*
* @author Laurent Caillette
*/
@SuppressWarnings( { "UseOfSystemOutOrSystemErr" } )
public class Main {
private static final Logger LOGGER = LoggerFactory.getLogger( Main.class ) ;
private static final File USER_DIRECTORY = new File( SystemUtils.USER_DIR ) ;
public static void main( final String[] originalArguments ) throws Exception {
new Main().doMainWithSystemSetup( originalArguments ) ;
}
private void doMainWithSystemSetup( final String[] originalArguments ) throws Exception {
final MainCaller caller = findMainCaller( originalArguments ) ;
final GenericParameters parameters = createParametersOrExit( originalArguments, caller ) ;
TemporaryFileTools.setupTemporaryDirectory( parameters.getTemporaryDirectory() ) ;
LogbackConfigurationTools.printLogbackConfigurationFiles() ;
LogbackConfigurationTools.fixLogDirectory( parameters.getLogDirectory() ) ;
// Switch from deferred logging to real one.
LoggerFactory.configurationComplete() ;
EnvironmentTools.logSystemProperties() ;
caller.main( parameters ) ;
}
protected void doMainWithoutSystemSetup( final String[] originalArguments ) throws Exception {
final MainCaller caller = findMainCaller( originalArguments ) ;
final GenericParameters parameters = createParametersOrExit( originalArguments, caller ) ;
caller.main( parameters ) ;
}
private static GenericParameters createParametersOrExit(
final String[] originalArguments,
final MainCaller caller
) throws CannotStartException
{
final String[] trimmedArguments = new String[ originalArguments.length - 1 ] ;
System.arraycopy( originalArguments, 1, trimmedArguments, 0, trimmedArguments.length ) ;
final GenericParameters parameters ;
try {
parameters = caller.createParameters( trimmedArguments ) ;
} catch( ArgumentException e ) {
final String commandLineParametersDescriptor =
caller.getSpecificCommandLineParametersDescriptor() ;
if( e.isHelpRequested() ) {
printHelpOnConsole( caller.commandName, e, commandLineParametersDescriptor ) ;
System.exit( -1 ) ;
throw new CannotStartException( e ) ;
} else {
LOGGER.error( e, "Parameters exception, printing help and exiting." ) ;
printHelpOnConsole( caller.commandName, e, commandLineParametersDescriptor ) ;
System.exit( -2 ) ;
throw new CannotStartException( e ) ;
}
}
return parameters;
}
private MainCaller findMainCaller( final String[] originalArguments ) {
if( 0 == originalArguments.length ) {
justPrintHelp() ;
System.exit( 1 ) ;
}
final String commandName = originalArguments[ 0 ];
final MainCaller caller = getMainCaller( commandName ) ;
if( null == caller ) {
help( commandName ) ;
System.exit( -1 ) ;
}
return caller;
}
// =============
// Help printers
// =============
@SuppressWarnings( { "UseOfSystemOutOrSystemErr" } )
private static void printHelpOnConsole(
final String commandName,
final ArgumentException e,
final String specificCommandLineParametersDescriptor
) {
if( null != e.getMessage() ) {
System.out.println( e.getMessage() ) ;
}
e.getHelpPrinter().print(
System.out,
commandName + " " + specificCommandLineParametersDescriptor,
80
) ;
}
private void justPrintHelp() {
printHelp( System.out ) ;
}
private void help( final String badCommand ) {
printBadCommand( System.out, badCommand ) ;
printHelp( System.out ) ;
}
private static void printBadCommand( final PrintStream out, final String badCommand ) {
out.println( "Unknown command: '" + badCommand + "'" ) ;
}
private void printHelp( final PrintStream out ) {
out.println( "Supported commands: " ) ;
for( final MainCaller mainCaller : COMMANDS ) {
out.println( " " + mainCaller.commandName + " <arguments>" ) ;
}
out.println( "Use <command> --help for help on a particular command." ) ;
}
// ========
// Commands
// ========
private static abstract class MainCaller< PARAMETERS extends GenericParameters > {
private final String commandName ;
protected MainCaller( final String commandName ) {
this.commandName = commandName ;
}
public abstract void main( PARAMETERS parameters ) throws Exception ;
/**
* @param arguments arguments without the command name.
*/
public abstract PARAMETERS createParameters( final String[] arguments )
throws ArgumentException ;
public abstract String getSpecificCommandLineParametersDescriptor() ;
}
private static< PARAMETERS extends GenericParameters > MainCaller< PARAMETERS >
getMainCaller( final String commandName ) {
for( final MainCaller mainCaller : COMMANDS ) {
if( mainCaller.commandName.equals( commandName ) ) {
return mainCaller ;
}
}
return null ;
}
/**
* As an instance variable, this gets initialized right after the {@link #main(String[])}
* method did its initialization job.
* So other classes are not loaded too soon, avoiding them to wake an unconfigured logging
* system up during their static initialization.
*/
private static final ImmutableSet< ? extends MainCaller > COMMANDS = ImmutableSet.of(
new MainCaller< DaemonParameters >( HttpDaemon.COMMAND_NAME ) {
@Override
public void main( final DaemonParameters parameters ) throws Exception {
HttpDaemon.main( parameters ) ;
}
@Override
public DaemonParameters createParameters( final String[] arguments )
throws ArgumentException
{
return HttpDaemon.createParameters( arguments ) ;
}
@Override
public String getSpecificCommandLineParametersDescriptor() {
return " [OPTIONS]" ;
}
}
,
new MainCaller< DocumentGeneratorParameters >( DocumentGenerator.COMMAND_NAME ) {
@Override
public void main( final DocumentGeneratorParameters parameters ) throws Exception {
new DocumentGenerator().main( parameters ) ;
}
@Override
public DocumentGeneratorParameters createParameters( final String[] arguments )
throws ArgumentException {
return DocumentGenerator.createParameters( arguments, USER_DIRECTORY ) ;
}
@Override
public String getSpecificCommandLineParametersDescriptor() {
return DocumentGenerator.getSpecificCommandLineParametersDescriptor() ;
}
}
,
new MainCaller< LevelExploderParameters >( "explodelevels" ) {
@Override
public void main( final LevelExploderParameters parameters ) throws Exception {
new LevelExploder().main( parameters ) ;
}
@Override
public LevelExploderParameters createParameters( final String[] arguments )
throws ArgumentException {
return LevelExploder.createParameters( arguments, USER_DIRECTORY ) ;
}
@Override
public String getSpecificCommandLineParametersDescriptor() {
return LevelExploder.getSpecificCommandLineParametersDescriptor() ;
}
}
) ;
}