ServerDriver.java
/*
** Module : ServerDriver.java
** Abstract : command line driver for the server
**
** Copyright (c) 2005-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- --JPRM-- ----------------------------------Description-----------------------------------
** 001 NVS 20050418 @20786 Repackaging net package. This file has been created as a
** generalized P2J server driver.
** 002 NVS 20050427 @20915 Introduced a way of passing application's arguments and options
** to the application and get its feedback on init() and arguments()
** calls. "false" returned from either will halt application execution.
** 003 NVS 20050830 @22423 Changed to bring the server to a production level.
** 004 GES 20060815 @28612 Refactored to remove duplicate code and share a common base class.
** Added kill and status modes.
** 005 GES 20060816 @28616 Cleaned up new modes/docs and added a wait mode.
** 006 GES 20061009 @30217 Minor fix to arguments processing.
** 007 GES 20061215 @31706 Changes in bootstrap config interface.
** 008 GES 20070111 @31781 Hard coded server class as StandardServer and removed some
** unnecessary code.
** 009 GES 20070112 @31813 Removed initial debug level (it wasn't being used downstream) and
** added application args.
** 010 EVL 20070609 @34005 Adding explicit import of the class com.goldencode.p2j.net.Queue
** to eliminate conflict with the same class from java.util package
** to be able to compile for Java 6.
** 011 ECF 20071101 @35891 Refactored to accommodate net package mods. Eliminated
** ServerBootstrap dependencies, integrated SessionManager.
** 012 GES 20080118 @36864 Output any abend info to STDERR not STDOUT. For servers, STDERR is
** the main log file and for clients STDOUT is interactive and can't
** be the destination. If STDERR on the client is redirected to file,
** then a record of any abend will be available.
** 013 GES 20110921 Minor javadoc fix.
** 014 GES 20111028 Added support for startup of a client session within the same
** process as the server.
** 015 GES 20111110 Single process mode now gets a unique initial context so client
** stuff is not shared to server threads. In addition, this makes it
** possible for multiple client sessions to co-exist in the same server
** session (with different initial contexts).
** 016 CA 20130705 Added appserver launching from server argument.
** 017 CA 20130822 Fixed the net protocol to support async requests.
** 018 CA 20140207 Added argument to reconfigure the private keys and certificates.
** Changed appserver launcher argument from "-p" to "-j".
** 019 CA 20140225 Fixed remote server connections when the key store is saved in the
** directory: we need to act as a server to initialize the transport
** security, then go back as a client when connecting to the remote
** server.
** 020 GES 20141228 Modified start() signature to match changes elsewhere.
** 021 EVL 20160225 Javadoc fixes to make compatible with Oracle Java 8 for Solaris 10.
** 022 GES 20170421 Removed references to application arguments (which is a feature that
** was removed from CommonDriver in H008. Changed default bootstrap
** name to server.xml.
** 023 ECF 20190451 Added -m{1|0} options for method execution tracing.
** 024 IAS 20200930 Added JMX instrumentation.
** IAS 20210827 Added BouncyCastle JCE/JSSE support
** GES 20210827 Added driver name initialization and diagnostics output.
** OM 20210923 Added -profile command line option for specifying the configuration profile.
** IAS 20220624 Added support for the Conscrypt JCE/JSSE provider
** CA 20230130 Added options to trim or restart the agents in an appserver.
** 025 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
** 026 GBB 20230517 Mark BootstrapConfig in configureLogging as server.
** 027 GBB 20230519 Resolve logger mode after server params are parsed and server mode is determined.
** 028 GBB 20230530 configureLogging to fallback to default configs on ConfigurationException.
** 029 GBB 20230825 SecurityManager context methods calls updated.
** A default exception handler registered.
** 030 HC 20240222 Enabled JMX on FWD Client.
** 031 GBB 20240709 Hard-coded config names replaced by ConfigItem constants.
** 032 GBB 20240729 Initialize CentralLogger after SecurityManager is created.
** 033 GBB 20240826 Removing SingleProcessClient.
** 034 VVT 20250303 A warning is logged if the default character set differs from the only supported
** UTF-8. See #7944.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero 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 Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.main;
import java.net.*;
import java.nio.charset.*;
import com.goldencode.p2j.aspects.ltw.*;
import com.goldencode.p2j.cfg.*;
import com.goldencode.p2j.directory.*;
import com.goldencode.p2j.jmx.*;
import com.goldencode.p2j.net.*;
import com.goldencode.p2j.security.*;
import com.goldencode.p2j.security.SecurityManager;
import com.goldencode.p2j.util.*;
import com.goldencode.p2j.util.logging.*;
/**
* General purpose command line driver to start a server process based on a
* bootstrap configuration file and/or command line parameters.
* <p>
* Configuration file can be plain (unencrypted) XML file or encrypted XML.
* If no password is given with the command line, the file is assumed to be
* plain XML.
* <p>
* This driver takes an optional name of a bootstrap configuration file, but
* if not specified, it will default to "standard_server.xml" in the current
* directory.
* <p>
* All entries in the bootstrap configuration can be overridden by a command
* line parameter using the "category:group:key=value" syntax (see below).
* <p>
* The bootstrap configuration can specify a custom class as the server
* process by using the "applications:class:server" key. If not specified
* in the configuration file or on the command line, its value will be
* defaulted to {@link StandardServer}.
* <p>
* The full syntax of the command line is:
* <p>
* <code>
* java ServerDriver [-?]
* [-k]
* [-s]
* [-c]
* [-w timeout]
* [-b batch-process]
* [-j appserver [restart|trim]]
* [<i>config</i>]
* [-p <i>config_file_password</i>]
* [-m{1|0}]
* [[[category:]group:]key=value]...
* </code>
* <p>
* Arguments can be specified in any order, except for the -? (help) which can only be
* specified as the first argument.
* <p>
* '-?' requests syntax help and exits.
* <p>
* '-b' will connect to the specified P2J server and attempt to start the specified batch process.
* <p>
* '-j' will connect to the specified P2J server and attempt to start the specified appserver.
* When <code>trim</code> is specified, then the appserver agents will be trimmed.
* When <code>restart</code> is specified, then the appserver agents will be restarted.
* <p>
* '-c' will reconfigure the certificates, keystores and truststores and save them in the
* directory.
* <p>
* '-k', '-s' and '-w' options all operate on a the specified server (which
* is referenced in the bootstrap configuration and/or the command line
* configuration overrides). These shift into a special "client" mode to
* connect (or attempt to connect) to the specified server. The '-k' will
* kill that server as long as the process' identity has "shutdown" rights
* on the P2J server. The '-s' queries the status of the server and the
* '-w' waits for the server to be in a <code>STATUS_RUNNING</code> state.
* The timeout for the '-w' option is in milliseconds and -1 means to wait
* indefinitely. All 3 of these special modes of the driver will always
* call <code>System.exit</code> with a process exit code that is one of the
* following (see the named class constants for the values and meanings):
* <p>
* <pre>
* STATUS_RUNNING
* STATUS_TIMEOUT
* STATUS_UNKNOWN
* STATUS_STOPPED
* </pre>
* <p>
* The exit code in each mode is the current state of the server at the
* <b>end</b> of the requested operation.
* <p>
* Password can be given with the command line or entered interactively.
* One special value can be used: "?" means interactive password input.
* <p>
* The '-m1' option starts method tracing data collection; 'm0' is used to stop it and to process
* the collected data. Method execution tracing introduces significant overhead to the operation
* of the server and therefore is intended to be a development-time feature only. It is enabled
* by adding {@code -javaagent:<path_to_jars>/aspectjweaver[version].jar} to the server's JVM
* command line options. Like the '-k', '-s', and '-w' options, the '-m1' and '-m0' options
* operate on the separate server process referenced in the bootstrap configuration and/or the
* command line configuration overrides.
* <p>
* Arguments in the form "category:group:key=value" are bootstrap
* configuration overrides. They may be used to add or change values of the
* configuration keys in the specified category and group. A short form of
* override (one that omits the category and group) is allowed after a long
* form override and refers to the most recently specified category and
* group.
*/
public class ServerDriver
extends CommonDriver
{
/** Status flag indicates a working/running server. */
public static final int STATUS_RUNNING = 0;
/**
* Status flag indicates a server which is accepting connections but not
* responding to transaction requests.
*/
public static final int STATUS_TIMEOUT = 1;
/**
* Status flag indicates a server which is accepting connections but some
* failure occurred during the transaction request that was used to check
* the server's status.
*/
public static final int STATUS_UNKNOWN = 2;
/** Status flag indicates a server that is not currently running. */
public static final int STATUS_STOPPED = 3;
/** Mode flag to start the server (the default). */
private static final int MODE_START = 0;
/** Mode flag to stop the server. */
private static final int MODE_STOP = 1;
/** Mode flag to check if the server is running. */
private static final int MODE_STATUS = 2;
/** Mode flag to wait for the server to be running. */
private static final int MODE_WAIT = 3;
/** Mode flag to start an appserver. */
private static final int MODE_START_APPSERVER = 4;
/** Mode flag to reconfigure the server's security data. */
private static final int MODE_RECONFIGURE = 5;
/** Mode flag to start a batch process. */
private static final int MODE_START_BATCH_PROCESS = 6;
/** Mode flag to start collecting method trace data. */
private static final int MODE_START_METHOD_TRACE = 7;
/** Mode flag to stop collecting method trace data. */
private static final int MODE_STOP_METHOD_TRACE = 8;
/** Logger. Should be instantiated after setting the logger to server mode. */
private static CentralLogger LOG;
/** Mode flag to restart the agents in an appserver. */
private static final int MODE_RESTART_APPSERVER = 9;
/** Mode flag to trim the agents in an appserver. */
private static final int MODE_TRIM_APPSERVER = 10;
/** Flag that allows overriding the default application. */
private int mode = MODE_START;
/** Maximum milliseconds to wait in <code>MODE_WAIT</code> or -1 for an infinite wait. */
private int timeout = 0;
/** The name of the remote appserver to start. */
private String appServer;
/** The name of the remote batch process to start. */
private String batchProcess;
/** The optional configuration profile. */
private String cfgProfile = null;
{
// initialize our protected members
driverName = "ServerDriver";
defCfg = "server.xml";
helptxt = new String[]
{
"------------------------------- P2J Server Driver -------------------------------",
"",
"Syntax:",
" java ServerDriver -?",
" [-c]",
" [-k]",
" [-s]",
" [-w timeout]",
" [-b batch-process]",
" [-j <appserver> [trim|restart]]",
" [-profile profile-name]",
" [config]",
" [-p config_file_password]",
" [parameter_overrides]",
"",
"Where:",
"",
"-? = displays this help screen",
"-c = reconfigure the directory's truststore, certificates and",
" keystores for the defined servers and processes",
"-k = kill the server specified by this config",
"-s = check the status of the server specified by this config",
"-w = wait for the status of the server specified by this",
" config to be STATUS_RUNNING or for the given timeout,",
" whichever comes first",
"-b <batch-process> = start the specified batch process, in the context of the",
" remote P2J server",
"-profile profile-name = The optional configuration profile name",
"-j <appserver> = start the specified appserver, in the context of the",
" remote P2J server. Optionally, 'trim' or 'restart' commands can be",
" set to either trim or restart the agents in the specified appserver",
"timeout = milliseconds to wait with -1 meaning an indefinite wait",
"config = a relative or absolute filename of a valid bootstrap",
" configuration file for this server",
"config_file_password = the password to use to decrypt the config file or '?' to",
" force an interactive password prompt",
"parameter_overrides = configuration values that add to or replace values that",
" can be specified in the bootstrap configuration;",
" the override must take one of three forms:",
" category:group:key=value",
" group:key=value",
" key=value",
" (the shorter forms will use the most recently specified",
" category and/or group as needed)",
"",
"All arguments can be specified in any order except '-?' which must always",
"appear first.",
"",
"Exit codes for '-k', '-s' and '-w' options:",
" " + STATUS_RUNNING + " = STATUS_RUNNING",
" " + STATUS_TIMEOUT + " = STATUS_TIMEOUT",
" " + STATUS_UNKNOWN + " = STATUS_UNKNOWN",
" " + STATUS_STOPPED + " = STATUS_STOPPED",
"Normally success would mean that '-k' would return a",
"STATUS_STOPPED and a '-s' or '-w' would return a STATUS_RUNNING."
};
}
/**
* Process arguments for any data or options that are specific to the
* subclass. This method is called in a loop from
* {@link CommonDriver#process} and should call the superclass version if
* the current parameter is not processed.
*
* @param args
* The command line arguments.
* @param current
* The current element being processed.
*
* @return The number of array elements that have been processed by
* this method and which MUST be skipped (no processing in
* the base class).
*/
protected int processArguments(String[] args, int current)
{
int skip = 0;
// kill option
if (args[current].equals("-k"))
{
mode = MODE_STOP;
skip = 1;
}
// reconfiguration option
if (args[current].equals("-c"))
{
mode = MODE_RECONFIGURE;
skip = 1;
}
// status check option
if (args[current].equals("-s"))
{
mode = MODE_STATUS;
skip = 1;
}
// start method trace option
if (args[current].equals("-m1"))
{
mode = MODE_START_METHOD_TRACE;
skip = 1;
}
// stop method trace option
if (args[current].equals("-m0"))
{
mode = MODE_STOP_METHOD_TRACE;
skip = 1;
}
// wait option
if (args[current].equals("-w"))
{
testFollowing(args, current, 1, true, "timeout");
timeout = Integer.parseInt(args[current + 1]);
mode = MODE_WAIT;
skip = 2;
}
// batch process startup
if (args[current].equals("-b"))
{
mode = MODE_START_BATCH_PROCESS;
batchProcess = args[current + 1];
skip = 2;
}
// appserver startup
if (args[current].equals("-j"))
{
mode = MODE_START_APPSERVER;
appServer = args[current + 1];
skip = 2;
if (current + 2 <= args.length - 1)
{
String nxt = args[current + 2];
if (nxt.equals("restart"))
{
mode = MODE_RESTART_APPSERVER;
skip = 3;
}
else if (nxt.equals("trim"))
{
mode = MODE_TRIM_APPSERVER;
skip = 3;
}
}
}
CentralLogger.setMode(mode == MODE_START ? CentralLogger.Mode.SERVER : CentralLogger.Mode.DEFAULT);
// -profile profile-name
if (args[current].equals("-profile"))
{
cfgProfile = args[current + 1];
skip = 2;
}
if (skip == 0)
{
skip = super.processArguments(args, current);
}
return skip;
}
/**
* Allows a subclass to check if the given configuration matches any
* required values. Edits may be made if needed.
*
* @param bc
* The configuration to be checked.
*/
protected void checkConfig(BootstrapConfig bc)
throws ConfigurationException
{
// MODE_START is the server, other modes act like a client node
bc.setServer((mode == MODE_START));
}
/**
* Runs the primary application using the preprocessed configuration and
* target object.
*
* @param bc
* The configuration to use.
*/
protected void start(BootstrapConfig bc)
throws Exception
{
SecureSocketsRegistrar.register(bc, false);
switch (mode)
{
case MODE_RECONFIGURE:
// the server must not be running
int status = statusWorker(bc);
if (status != STATUS_STOPPED)
{
LOG.severe("Make sure the server is not running!");
return;
}
// we can put it in server mode now
bc.setServer(true);
// reconfigure
SSLCertGenUtil gen = new SSLCertGenUtil(bc);
gen.generate();
// don't fallback to server mode
break;
case MODE_START:
StandardServer srv = new StandardServer();
srv.bootstrap(bc, this::printDriverDetails, cfgProfile);
break;
case MODE_STOP:
stop(bc);
break;
case MODE_STATUS:
status(bc);
break;
case MODE_START_METHOD_TRACE:
enableMethodTracing(bc, true);
break;
case MODE_STOP_METHOD_TRACE:
enableMethodTracing(bc, false);
break;
case MODE_WAIT:
wait(bc, timeout);
break;
case MODE_START_APPSERVER:
launchAppServer(bc, appServer);
break;
case MODE_RESTART_APPSERVER:
restartAppServer(bc, appServer);
break;
case MODE_TRIM_APPSERVER:
trimAppServer(bc, appServer);
break;
case MODE_START_BATCH_PROCESS:
launchBatchProcess(bc, batchProcess);
break;
default:
syntax("Unknown mode " + mode, -100);
}
}
/**
* Make a connection to the specified server and then shut that server
* down. This method will report on the that state by exiting with a
* predefined exit code in <code>System.exit</code>.
* <p>
* <b>This method never returns.</b>
*
* @param bc
* The configuration to use.
*/
protected void stop(BootstrapConfig bc)
{
int result = STATUS_STOPPED;
try
{
Session session = connect(bc);
RoutingKey key = RoutingKey.getSpecial(RoutingKey.SHUTDOWN_PACKAGE);
if (session != null)
{
Message msg = new Message(MessageTypes.REQUEST_SYNCH,
key,
new Object[] {});
Message reply = (Message) session.transact(msg, 60000);
if (reply != null && reply.getType() == MessageTypes.REPLY_EXCEPTION_SYNC)
{
// shutdown failed
result = STATUS_RUNNING;
}
else
{
// null reply or a non-exception means it stopped properly there is no really good way to
// detect a timeout, so ignore that case
}
}
}
catch (Exception e)
{
LOG.severe("Exception while stopping the remote server:", e);
result = STATUS_UNKNOWN;
}
finally
{
System.exit(result);
}
}
/**
* Check on the state of the specified server and report that state by
* exiting with a predefined exit code in <code>System.exit</code>.
* <p>
* <b>This method never returns.</b>
*
* @param bc
* The configuration to use.
*/
protected void status(BootstrapConfig bc)
{
System.exit(statusWorker(bc));
}
/**
* Wait until the specified server is in a running state or the specified
* timeout elapsed, whichever comes first. This method reports the
* resulting state by exiting with a predefined exit code in
* <code>System.exit</code>.
* <p>
* This method uses polling to detect the <code>STATUS_RUNNING</code>
* state! It will also exit in the case where the status of the server
* is <code>STATUS_UNKNOWN</code> or in a timeout case. As long as the
* timeout has not occurred and the state is <code>STATUS_STOPPED</code>,
* this method will wait.
* <p>
* <b>This method never returns.</b>
*
* @param bc
* The configuration to use.
* @param timeout
* Number of milliseconds to wait or -1 for an infinite wait.
*/
protected void wait(BootstrapConfig bc, int timeout)
{
int result = STATUS_STOPPED;
long waited = 0;
long start = System.currentTimeMillis();
while (timeout == -1 || waited < timeout)
{
result = statusWorker(bc);
if (result != STATUS_STOPPED)
{
// done
break;
}
// setup for possible timeout return on next loop condition test
result = STATUS_TIMEOUT;
try
{
// wait
Thread.sleep(500);
}
catch (InterruptedException ie)
{
// best efforts only
}
// calc total time waited
waited = System.currentTimeMillis() - start;
}
System.exit(result);
}
/**
* Connect to the remote P2J server and send the command to start the appserver.
*
* @param config
* The P2J server configuration.
* @param appServer
* The appserver name.
*/
private void launchAppServer(BootstrapConfig config, String appServer)
{
Session session = null;
try
{
session = connect(config);
AppServer launcher = (AppServer) RemoteObject.obtainNetworkInstance(AppServer.class, session);
launcher.launch(appServer);
}
finally
{
if (session != null)
{
session.terminate();
}
}
}
/**
* Connect to the remote P2J server and send the command to restart all agents in the appserver.
*
* @param config
* The P2J server configuration.
* @param appServer
* The appserver name.
*/
private void restartAppServer(BootstrapConfig config, String appServer)
{
Session session = null;
try
{
session = connect(config);
AppServer launcher = (AppServer) RemoteObject.obtainNetworkInstance(AppServer.class, session);
launcher.restart(appServer);
}
finally
{
if (session != null)
{
session.terminate();
}
}
}
/**
* Connect to the remote P2J server and send the command to trim the agents in the appserver.
*
* @param config
* The P2J server configuration.
* @param appServer
* The appserver name.
*/
private void trimAppServer(BootstrapConfig config, String appServer)
{
Session session = null;
try
{
session = connect(config);
AppServer launcher = (AppServer) RemoteObject.obtainNetworkInstance(AppServer.class, session);
launcher.trim(appServer);
}
finally
{
if (session != null)
{
session.terminate();
}
}
}
/**
* Start or stop data collection for method execution tracing running in the separate server
* process defined by the given bootstrap configuration.
*
* @param config
* The configuration used to connect to the tracing server.
* @param enable
* {@code true} to start data collection; {@code false} to stop it and process the
* collected data.
*/
protected void enableMethodTracing(BootstrapConfig config, boolean enable)
{
Session session = null;
try
{
session = connect(config);
MethodTraceController controller = (MethodTraceController)
RemoteObject.obtainNetworkInstance(MethodTraceController.class, session);
controller.enableTracing(enable);
}
finally
{
if (session != null)
{
session.terminate();
}
}
}
/**
* Connect to the remote P2J server and send the command to start the batch process.
*
* @param config
* The P2J server configuration.
* @param batchProcess
* The batch process name.
*/
private void launchBatchProcess(BootstrapConfig config, String batchProcess)
{
Session session = null;
try
{
session = connect(config);
BatchProcess launcher = (BatchProcess) RemoteObject.obtainNetworkInstance(BatchProcess.class,
session);
launcher.launch(batchProcess);
}
finally
{
if (session != null)
{
session.terminate();
}
}
}
/**
* Check on the state of the specified server and return that state.
*
* @param bc
* The configuration to use.
*
* @return The state of the server.
*/
private int statusWorker(BootstrapConfig bc)
{
int result = STATUS_STOPPED;
try
{
Session session = connect(bc);
if (session != null)
{
byte[] data = new byte[] { 0 };
try
{
// try an echo
Object reply = session.echo(data, 10000, null);
result = (reply == null) ? STATUS_TIMEOUT : STATUS_RUNNING;
}
catch (Exception e)
{
result = STATUS_UNKNOWN;
}
}
}
catch (Exception e)
{
// default return
}
return result;
}
/**
* Connect to the specified server on the <code>localhost</code>.
*
* @param bc
* The configuration to use.
*
* @return The established connection.
*/
private Session connect(BootstrapConfig bc)
{
Session session = null;
// force config to certain known values
// allow the node address to be dynamically assigned
bc.setConfigItem("net", "server", "nodeaddress", null);
// reduce the dispatcher threads to a minimum to make this faster
bc.setConfigItem("net", "dispatcher", "threads", "2");
String host = bc.getString(ConfigItem.SERVER_HOST, null);
// default to localhost if no target host is specified
if (host == null)
{
bc.setConfigItem(ConfigItem.SERVER_HOST, "localhost");
}
try
{
if (bc.getString("security", "keystore", "filename", null) == null)
{
// if no keystore is specified, then we need to initialize as "server" and load it
// from the directory.
bc.setServer(true);
bc.setConfigItem("directory", "xml", "must_exist", "true");
DirectoryService ds = DirectoryService.createInstance(bc);
if (!ds.bind())
{
LOG.warning("Could not bind directory!");
}
SecurityManager sm = SecurityManager.createInstance(bc);
if (bc.getString("security", "truststore", "alias", null) == null)
{
// explictly set the trust alias as the server's alias
String alias = sm.getServerAlias();
bc.setConfigItem("security", "truststore", "alias", alias);
}
// force loading of the transport security
sm.contextSm.getSecureSocketContext();
// go back in non-server mode
bc.setServer(false);
}
else if (SecurityManager.getInstance() == null)
{
SecurityManager.createInstance(bc);
}
SessionManager sessMgr = SessionManagerFactory.createLeafNode(bc);
session = sessMgr.connectDirect(bc, null, null);
}
catch (ConnectException exc)
{
// nothing to do; the server is not running --> just allow null to
// be returned below
}
catch (Exception exc)
{
LOG.severe("Error connecting to server", exc);
}
return session;
}
/**
* The command line entry point.
*
* @param args
* The array of command-line parameters.
*/
public static void main(String[] args)
{
CentralLogger.setMode(CentralLogger.Mode.SERVER_BASE);
LOG = CentralLogger.get(ServerDriver.class);
setDefaultExceptionHandler(LOG);
final Charset charset = Charset.defaultCharset();
if (!StandardCharsets.UTF_8.equals(charset))
{
LOG.warning("The default character set is " + charset
+ ", but currently only UTF-8 is supported.");
}
ServerDriver server = new ServerDriver();
FwdServerJMX.init();
server.process(args);
}
}