/* * 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.nhovestone.driver; import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit; import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import org.apache.commons.lang.StringUtils; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static org.novelang.configuration.parse.GenericParametersConstants.OPTIONPREFIX; import org.novelang.Version; import org.novelang.configuration.parse.GenericParametersConstants; import org.novelang.outfit.DefaultCharset; import org.novelang.outfit.TcpPortBooker; import org.novelang.outfit.shell.DefaultJmxKit; import org.novelang.outfit.shell.JavaClasses; import org.novelang.outfit.shell.JavaShell; import org.novelang.outfit.shell.JavaShellParameters; import org.novelang.outfit.shell.ProcessCreationException; import org.novelang.outfit.shell.ProcessInitializationException; import org.novelang.outfit.shell.ShutdownStyle; /** * Encapsulates a {@link JavaShell}, factoring common code for running either a * {@link org.novelang.daemon.HttpDaemon} or {@link org.novelang.batch.DocumentGenerator}. * * @author Laurent Caillette */ public abstract class EngineDriver { private final JavaShell javaShell; public static final String NOVELANG_BOOTSTRAP_MAIN_CLASS_NAME = "org.novelang.bootstrap.Main"; /** * Constructor. * * @param configuration a non-null object. * @param commandName a command name like * {@value org.novelang.daemon.HttpDaemon#COMMAND_NAME} or * {@value org.novelang.batch.DocumentGenerator#COMMAND_NAME}. * @param startupSensor a non-null object. */ protected EngineDriver( final Configuration< ? > configuration, final String commandName, final Predicate< String > startupSensor ) { checkArgument( ! StringUtils.isBlank( commandName ) ) ; final Version version = configuration.getVersion() ; final String applicationName = "Novelang" + ( version == null ? "" : "-" + version.getName() ) + ":" + commandName ; final ImmutableList.Builder< String > jvmOptionsBuilder = ImmutableList.builder() ; final Iterable< String > otherJvmOptions = configuration.getJvmOtherOptions() ; if( otherJvmOptions != null ) { for( final String processOption : otherJvmOptions ) { if( processOption.startsWith( "-Xmx" ) ) { throw new IllegalArgumentException( "Use method in " + Configuration.class.getName() + " to set -Xmx" ) ; } else { jvmOptionsBuilder.add( checkNotNull( processOption ) ) ; } } } jvmOptionsBuilder.add( "-Xmx" + checkNotNull( configuration.getJvmHeapSizeMegabytes() + "M" ) ) ; jvmOptionsBuilder.add( "-Djava.awt.headless=true" ) ; jvmOptionsBuilder.add( "-server" ) ; if( "64".equals( System.getProperty( "sun.arch.data.model" ) ) ) { jvmOptionsBuilder.add( "-d64" ) ; } final ImmutableList.Builder< String > programOptionsBuilder = ImmutableList.builder() ; programOptionsBuilder.add( commandName ) ; final Iterable< String > otherProgramOptions = configuration.getProgramOtherOptions() ; if( otherProgramOptions != null ) { for( final String programOption : otherProgramOptions ) { programOptionsBuilder.add( checkNotNull( programOption ) ) ; } } if( configuration.getLogDirectory() != null ) { programOptionsBuilder.add( OPTIONPREFIX + GenericParametersConstants.LOG_DIRECTORY_OPTION_NAME ) ; programOptionsBuilder.add( configuration.getLogDirectory().getAbsolutePath() ) ; } programOptionsBuilder.add( OPTIONPREFIX + GenericParametersConstants.OPTIONNAME_CONTENT_ROOT ) ; programOptionsBuilder.add( checkNotNull( configuration.getContentRootDirectory() ).getAbsolutePath() ) ; programOptionsBuilder.add( OPTIONPREFIX + GenericParametersConstants.OPTIONNAME_DEFAULT_SOURCE_CHARSET ) ; programOptionsBuilder.add( DefaultCharset.SOURCE.name() ) ; final Iterable< String > programArguments = configuration.getProgramArguments() ; if( programArguments != null ) { for( final String programArgument : programArguments ) { programOptionsBuilder.add( checkNotNull( programArgument ) ) ; } } JavaShellParameters parameters = org.novelang.outfit.Husk.create( JavaShellParameters.class ); parameters = parameters .withWorkingDirectory( configuration.getWorkingDirectory() ) .withNickname( "Novelang-" + version.getName() ) .withJvmArguments( jvmOptionsBuilder.build() ) .withJavaClasses( configuration.getJavaClasses() ) .withProgramArguments( programOptionsBuilder.build() ) .withStartupSensor( startupSensor ) .withJmxPortConfiguredAtJvmStartup( TcpPortBooker.THIS.find() ) .withJmxKit( new DefaultJmxKit() ) ; javaShell = new JavaShell( parameters ) ; } public void start( final long timeout, final TimeUnit timeUnit ) throws IOException, InterruptedException, ProcessCreationException, ProcessInitializationException { javaShell.start() ; } public Integer shutdown( final boolean force ) throws InterruptedException, IOException { return javaShell.shutdown( force ? ShutdownStyle.FORCED : ShutdownStyle.WAIT ) ; } @org.novelang.outfit.Husk.Converter( converterClass = ConfigurationHelper.class ) public interface Configuration< CONFIGURATION extends Configuration > { JavaClasses getJavaClasses() ; CONFIGURATION withJavaClasses( JavaClasses javaClasses ) ; Version getVersion() ; CONFIGURATION withVersion( Version version ) ; File getWorkingDirectory() ; CONFIGURATION withWorkingDirectory( File directory ) ; File getLogDirectory() ; CONFIGURATION withLogDirectory( File directory ) ; File getContentRootDirectory() ; CONFIGURATION withContentRootDirectory( File directory ) ; Integer getJvmHeapSizeMegabytes() ; CONFIGURATION withJvmHeapSizeMegabytes( Integer sizeMegabytes) ; Iterable< String > getJvmOtherOptions() ; CONFIGURATION withJvmOtherOptions( String... options ) ; Iterable< String > getProgramOtherOptions() ; CONFIGURATION withProgramOtherOptions( String... options ) ; Iterable< String > getProgramArguments() ; CONFIGURATION withProgramArguments( String... options ) ; } @SuppressWarnings( { "UnusedDeclaration" } ) public static class ConfigurationHelper { private ConfigurationHelper() { } public static Iterable< String > convert( final String... strings ) { return ImmutableList.of( strings ) ; } } }