/**
* Copyright (c) 2002-2015 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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.neo4j.wrapper;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
public abstract class ServerProcess
{
private static final Logger LOGGER = Logger.getLogger( ServerProcess.class.getName() );
/**
* The prefix of parameters that mark a directory whose *.jar entries must
* be appended to the server classpath. A runtime parameter.
*/
public static final String ClasspathEntryPrefix = "serverClasspath";
/**
* The runtime parameter that points to the working dir. Every other file is
* relative to that.
*/
public static final String WorkingDir = "workingDir";
/**
* The runtime parameter that holds the file name of the configuration file.
*/
public static final String ConfigFile = "configFile";
/**
* The prefix in the configuration file where additional arguments
* to the launched jvm are passed.
*/
public static final String ExtraArgsPrefix = "wrapper.java.additional";
/**
* The configuration file parameter where the -Xms setting for the
* launched jvm is passed.
*/
public static final String InitHeap = "wrapper.java.initmemory";
/**
* The configuration file parameter where the -Xmx setting for the
* launched jvm is passed.
*/
public static final String MaxHeap = "wrapper.java.maxmemory";
/**
* The InitHeap and MaxHeap settings are a number. This is their
* measurement unit.
*/
public static final String MemoryUnit = "m";
/**
* The runtime parameter that names the main class to run.
*/
public static final String MainClassPrefix = "serverMainClass";
/**
* The configuration file parameter prefix that names additional
* parameters to pass to the launched application.
*/
public static final String AppParamPrefix = "wrapper.app.parameter";
private File workingDir;
private File configFile;
public String classpath;
final List<String> extraArgs;
String mainClass;
final List<String> appArgs;
public ServerProcess()
{
extraArgs = new LinkedList<String>();
appArgs = new LinkedList<String>();
parseEnvironment();
parseConfig();
List<String> command = new LinkedList<String>();
command.add( "\"java\"" );
command.add( classpath );
command.addAll( extraArgs );
command.add( mainClass );
command.addAll( appArgs );
try
{
doStart( command, workingDir );
/*
* We have to grab and consume the input and error stream
* because otherwise the buffers might fill up and then
* it might get stuck. Just launch off two daemon
* threads.
*/
// InputStream outStr = process.getInputStream();
// InputStream errStr = process.getErrorStream();
// Thread out = new Thread( new StreamConsumer( outStr, System.out )
// );
// Thread err = new Thread( new StreamConsumer( errStr, System.err )
// );
// out.setDaemon( true );
// err.setDaemon( true );
// out.start();
// err.start();
// Wait ten seconds
Thread.sleep( 10_000 );
/*
* Get the exit value. If it returns something
* it means it has exited, which means the process
* failed for some reason. We forgive exit code of 0
* but the rest are reported with 128 added to differentiate
* from the launcer's exit codes.
* If it throws an exception, it means the process is still
* running, which is good (after 10 seconds). Catch it, swallow it.
*/
if ( isRunning() )
{
Runtime.getRuntime().halt( 3 );
}
}
catch ( Exception e )
{
LOGGER.throwing( this.getClass().toString(), "ServerProcess()", e );
e.printStackTrace();
Runtime.getRuntime().halt( 1 );
}
}
protected abstract void doStart( List<String> command, File workingDir ) throws IOException;
protected abstract boolean isRunning();
protected abstract void stop();
private void parseConfig()
{
FileReader fileReader = null;
try
{
fileReader = new FileReader( configFile );
BufferedReader in = new BufferedReader( fileReader );
String currentLine;
String paramName, value;
while ( ( currentLine = in.readLine() ) != null )
{
currentLine = currentLine.trim();
if ( currentLine.startsWith( "#" ) || currentLine.length() == 0 )
{// Skip comments and empty lines
continue;
}
int startFrom = currentLine.indexOf( "=" );
if ( startFrom > -1 )
{
value = currentLine.substring( startFrom + 1 );
paramName = currentLine.substring( 0, startFrom );
}
else
{
paramName = currentLine;
value = currentLine;
}
StringBuffer currentBuffer = new StringBuffer();
if ( paramName.startsWith( ExtraArgsPrefix ) )
{
if ( value.startsWith( "-D" ) )
{
int equalsIndex = value.indexOf( "=" );
currentBuffer.append( value.substring( 0, equalsIndex ) );
currentBuffer.append( "=" );
currentBuffer.append( "\"" );
currentBuffer.append( value.substring( equalsIndex + 1,
value.length() ) );
}
else
{
currentBuffer.append( "\"" );
currentBuffer.append( value );
}
currentBuffer.append( "\"" );
extraArgs.add( currentBuffer.toString() );
}
else if ( paramName.startsWith( AppParamPrefix ) )
{
currentBuffer.append( "\"" );
currentBuffer.append( value );
currentBuffer.append( "\"" );
appArgs.add( currentBuffer.toString() );
}
else if ( paramName.startsWith( InitHeap ) )
{
extraArgs.add( "-Xms" + value + MemoryUnit );
}
else if ( paramName.startsWith( MaxHeap ) )
{
extraArgs.add( "-Xmx" + value + MemoryUnit );
}
}
}
catch ( IOException e )
{
Runtime.getRuntime().halt( 2 );
}
finally
{
if ( fileReader != null )
{
try
{
fileReader.close();
}
catch ( IOException e )
{
e.printStackTrace();
}
}
}
}
private void parseEnvironment()
{
workingDir = new File( System.getProperty( WorkingDir ) );
configFile = new File( workingDir, System.getProperty( ConfigFile ) );
classpath = new ClasspathParser().parse( workingDir, System.getProperty( ClasspathEntryPrefix ) );
mainClass = System.getProperty( MainClassPrefix );
}
}