Running the Server¶
Overview¶
The FWD Application Server is a Java process whose command line driver program is the class com.goldencode.p2j.main.ServerDriver
. This class can be run directly to launch the server as long as it is given the proper arguments.
It is very common to script the startup of the server to make it easier to launch and for users to handle a range of different use cases with an easier syntax. To this end, this chapter documents scripts called server.sh
(Linux/UNIX) and server.cmd
(Windows) which automate the startup of the server.
Details are provided for both the ServerDriver
and the server.sh
/server.cmd
scripts.
ServerDriver¶
Command Line Syntax¶
The main class from which the server starts is com.goldencode.p2j.main.ServerDriver
.
The syntax of a command for starting the server would be:
java [jvm_options] com.goldencode.p2j.main.ServerDriver [arguments ...]
jvm_options
- These are command line options given to the JVM to customize the JVM's runtime features. The classpath and the custom class loader are both required. See JVM Options for these and some other common options.
arguments
- These are the configuration and other options passed to the ServerDriver
itself. They are used to identify the server being started and to provide enough configuration for the server to properly function. See Arguments for more details.
Arguments¶
The following documents the possible arguments:
Argument | Purpose |
---|---|
-? | Displays command line syntax help. |
-c | Uses a cryptography utility to reconfigure the directory's truststore, certificates and keystores for the all servers and processes defined in the directory. |
-k | Stop the identified server. For this to work, the credentials used to connect to the server must be for an account that has been assigned "shutdown" rights. |
-s | Check the status of the identified server. |
-w timeout | Wait for the identified server's status to be STATUS_RUNNING or for the timeout (in milliseconds), whichever comes first. As timeout of -1 means an indefinite wait. |
-b batch-process | Connect to the identified server and instruct it to launch the specified batch process. |
-j <appserver> | Connect to the identified server and instruct it to launch the specified appserver agent. |
config_file | A relative or absolute filename of a valid bootstrap configuration file for this server. This can be specified 0, 1 or 2 times. |
-p config_file_password | The password to use to decrypt the bootstrap configuration 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 or key=value . The shorter forms will default to the most recently specified category and/or group. A common use is to specify the secure and insecure port numbers for the server. |
TODO: Clarify the meaning of the batch-process
and appserver
parameter values. Are these FWD account names or something else?
TODO: Provide details on how the command options above identify the server to be processed.
All arguments can be specified in any order except '-?' which must always appear first.
Common Arguments¶
Bootstrap Configuration File¶
The server's bootstrap configuration file name is passed as an optional application argument on the java command line. The 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. If the bootstrap file is not specified as argument, it will default to standard_server.xml
file, located in the current directory of the server process.
The most common contents of this file are the details on how to find the directory file (the main configuration file for the FWD server).
The server's bootstrap file can specify the secure and insecure port numbers and/or these can be set as arguments of ServerDriver
inside the java command line.
Directory¶
The primary configuration file for the FWD server is called the directory. The directory source is usually specified inside the bootstrap file, but can also be overridden in the same way the secure and insecure ports are overridden, via i.e. a directory:xml:filename=directory.xml
argument.
Server Port Numbers¶
The secure and insecure port numbers can be specified either inside the bootstrap configuration file or as arguments in the java command. When specified on the command line it would look something like this: net:connection:secure=true net:server:port=3333 net:server:insecure_port=3334
.
On systems where multiple application server instances will be started, it is useful to hide port calculations in a script. One construct that is useful is to provide each application server process with an “instance number”. The startup script can then determine the value for the secure port which would be defined by either a -i<instance_num>
parameter or the -p<port>
parameter. The -i
might calculate the secure port as 3333 + <instance_number>
, while -p
might calculate the secure port as equal to <port>
. Once the secure port is known the insecure port will be calculated by adding or subtracting some number to the secure port. It is also useful to have a "production mode" (perhaps using a -z
option). In production mode, a different set of calculations might be made to get the port numbers. Also useful in these scripts is code to calculate the host. By default the host would default to localhost
, but that can be overridden with an option (like -h<host>
). With these options properly specified, a startup script can ensure that the command line is modified as needed for connectivity.
Return Code¶
Exit codes for '-k', '-s' and '-w' options:
Exit Code | Symbolic Name | Notes |
---|---|---|
0 | STATUS_RUNNING | Successful return code from -s or -w. |
1 | STATUS_TIMEOUT | |
2 | STATUS_UNKNOWN | |
3 | STATUS_STOPPED | Successful return code from -k. |
JVM Options¶
Classpath¶
The CLASSPATH environment variable or java command line parameter -classpath
(specified as a JVM parameter which means it is positioned before the com.goldencode.p2j.main.ServerDriver
argument) must list the following (full or relative paths to these jar files):
p2jadmin.jar
p2j.jar
(this must appear AFTER the p2jadmin.jar)- each converted application jar file (created using the FWD conversion process)
- any other customer-specific application jar (used to add custom code that can be processed in the FWD server)
- dependent jars which are required by the customer-specific application jars
Specifying the Custom Class-Loader¶
FWD uses a custom class-loader implemented by the com.goldencode.p2j.classloader.MultiClassLoader
class. This class-loader has two purposes:
- It allows hot-replacement of customer-specific application jars without restarting the server, using the Admin Console.
- It provides a dedicated class-loader implemented by
com.goldencode.compile.InMemoryClassLoader
, required by the FWD implementation of legacy code which relies on runtime conversion of 4GL code. At this time, this is only used by the dynamic database support.
This custom class-loader is mandatory for FWD and needs to be provided via the -Djava.system.class.loader=com.goldencode.p2j.classloader.MultiClassLoader
JVM option. The classloader allows full integration of a running FWD server with a profiling tools like JVisualVM or JConsole.
Heapsize¶
The JVM heap size should be specified on the java command line (as a JVM parameter which means it is positioned before the com.goldencode.p2j.main.ServerDriver
argument). For a server with hundreds of users, this might be set to: -Xmx24576m
JMX¶
If jconsole (or another JMX management console) is to be used to monitor and/or control the JVM of the FWD application server, then the appropriate options should be specified on the java command line (as a JVM parameter which means it is positioned before the com.goldencode.p2j.main.ServerDriver
argument). For example:
-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.port=5000
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
Heap Dump¶
In case the JVM runs out of memory the -XX:+HeapDumpOnOutOfMemoryError
option can be added.
This will create a heap dump automatically whenever the java process runs out of memory, even if the process may continue to run after the heap dump was generated. Usually, one heap dump file is enough to analyze the problem.
Profiling¶
The simplest report to generate is a text profile. To generate a text profile, the application will be run with the -
@Xrunhprof@ option.
Xrunhprof usage:
java -Xrunhprof:help Hprof usage: -Xrunhprof[:help]|[<option>=<value>, ...]
Option Name and Value | Description | Default |
---|---|---|
heap=dump|sites|all |
heap profiling |
all |
cpu=samples|times|old |
CPU usage |
off |
monitor=y|n |
monitor contention |
n |
format=a|b |
ascii or binary output |
a |
file=<file> |
write data to file |
java.hprof(.txt for ascii) |
net=<host>:<port> |
send data over a socket |
write to file |
depth=<size> |
stack trace depth |
4 |
cutoff=<value> |
output cutoff point |
0.0001 |
lineno=y|n |
line number in traces |
y |
thread=y|n |
thread in traces? |
n |
doe=y|n |
dump on exit? |
y |
This will output to the file gc.log in binary output with heap option on dump and dump on exit.
Example¶
The following example comes from the Hotel GUI sample project:
java -Xmx4768m -server -classpath :../lib/hotel.jar:../lib/p2jadmin.jar:../lib/p2j.jar: -Djava.system.class.loader=com.goldencode.p2j.classloader.MultiClassLoader com.goldencode.p2j.main.ServerDriver server.xml net:connection:secure=true net:server:secure_port=3333 net:server:insecure_port=3433
Linux/UNIX (server.sh)¶
Sample Script¶
This script can be used as-is so long as the installation matches the requirements in Application Server Installation. It is also OK to modify the script as needed for a specific installation.
#!/bin/bash # standard P2J server startup script # defaults cpath="" for f in ../lib/*.jar do cpath=$cpath:$f done debug=0 suspend="n" hprof="" prog="java" srvr="-server" heap=4768 outlog="stdout.log" errlog="server.log" cfg="server.xml" port="" portbase=3333 portstep=100 mode="" statcode="n" instance=0 batch="" test=0 usage[0]="\nUsage: $0 [-dyptksw1] [-bprocess] [-zcp] [-hheap] [-llog] [-ccfg] [-iinst]\n" usage[1]="Where:\n" usage[2]="d \t= enable JVM debug mode (debugger port will be set as 2080 + instance #)" usage[3]="y \t= in JVM debug mode enable, suspend the JVM on startup (does not suspend by default)" usage[4]="p \t= enable JVM hprof (profiling output to gc.log)" usage[5]="t \t= test mode (displays the command but doesn't execute)" usage[6]="k \t= kill mode (shuts down the specified/default instance)" usage[7]="s \t= status mode (displays the status of the specified/default instance)" usage[8]="w \t= wait mode (does not return until the specified/default instance is STATUS_RUNNING)" usage[9]="1 \t= enable C1 HotSpot compiler (client compiler for the JVM)" usage[10]="cp \t= override the classpath which would otherwise be set to $cpath" usage[11]="heap \t= set JVM max heap size (must be an integer number of MB)" usage[12]="log \t= log file name (all STDERR is redirected to this file, defaults to ./server.log)" usage[13]="cfg \t= config file name (P2J bootstrap config file name, defaults to server.xml)" usage[14]="inst \t= server instance number (0..9, assigns the P2J server port, defaults to 0)" usage[15]="process \t= launch a program associated with a process account\n"; # process options while getopts ":dyptksw1z:h:l:c:i:b:" opt; do case $opt in d ) debug=1 ;; y ) suspend="y" ;; p ) hprof="-Xrunhprof:heap=dump,doe=y,format=b,file=gc.log" ;; t ) test=1 ;; k ) mode="-k"; statcode="y" ;; s ) mode="-s"; statcode="y" ;; w ) mode="-w -1"; statcode="y" ;; b ) batch="-b $OPTARG" ;; 1 ) srvr="" ;; z ) cpath=$OPTARG ;; h ) heap=$OPTARG ;; l ) log=$OPTARG ;; c ) cfg=$OPTARG ;; i ) instance=$OPTARG ;; \? ) for i in "${usage[@]}"; do echo -e $i done exit 1 ;; esac done shift $(($OPTIND - 1)) # final arg prep cpath="-classpath $cpath" dport=$((2080 + $instance)) sport=$(($portbase + $instance)) iport="net:server:insecure_port="$(($portbase + $instance + $portstep)) port="net:connection:secure=true net:server:secure_port=$sport $iport" if [ $debug -eq 1 ]; then dtxt="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=$dport,server=y,suspend=$suspend" else dtxt="" fi maxheap="-Xmx"$heap"m" # run the P2J server if [ $test -eq 1 ] ; then echo $prog $hprof $maxheap $srvr $dtxt $cpath -Djava.system.class.loader=com.goldencode.p2j.classloader.MultiClassLoader com.goldencode.p2j.main.ServerDriver $mode $batch $cfg $port "$@" else eval $prog $hprof $maxheap $srvr $dtxt $cpath -Djava.system.class.loader=com.goldencode.p2j.classloader.MultiClassLoader com.goldencode.p2j.main.ServerDriver $mode $batch $cfg $port "$@" 1>$outlog 2>$errlog fi rc=$? if [ $statcode = "y" ]; then case $rc in 0 ) status="STATUS_RUNNING" ;; 1 ) status="STATUS_TIMEOUT" ;; 2 ) status="STATUS_UNKNOWN" ;; 3 ) status="STATUS_STOPPED" ;; esac echo "Result =" $status fi
Usage¶
.\server.sh [-dyptksw1] [-bprocess] [-zcp] [-hheap] [-llog] [-ccfg] [-iinst]
Where:
Parameter | Usage |
---|---|
-b<process> | Launch a program associated with the given process account name. |
-c<cfg> | The bootstrap configuration file name for the server (defaults to server.xml ). |
-d | Enable JVM debug mode (debugger port will be set as 2080 + instance number) |
-h<heap> | Set the JVM max heap size (must be an integer in MB). |
-k | Stop the specified server (the default instance if not specified). |
-i<inst> | Server instance number (0..9). This assigns the FWD server's secure and insecure ports. The instance number defaults to 0. secure_port = 3333 + instance_number insecure_port = 3333 + instance_number + 100 |
-l<log> | Specify a log filename for all STDERR output (defaults to ./server.log ). |
-p | Enable profiling (JVM hprof output will be written to gc.log ). |
-s | Check the status of the specified server (the default instance if not specified). |
-t | Test mode (displays the command but doesn't execute). |
-w | Wait for the specified server (the default instance if not specified) to be started (until it returns STATUS_RUNNING). |
-y | In JVM debug mode enable, suspend the JVM on startup (does not suspend by default). |
-z<cp> | Override the calculated classpath with the given value. |
-1 | Enable C1 HotSpot compiler (client compiler for the JVM). By default the "server" compiler is used. |
Startup Command JVM Options Explained¶
TODO: this doesn't match the generic script shown above. Some of these options should be added to that script and these two sections can be made to match.
The java command used by server.sh to start the server looks like:
"$prog $hprof $maxheap $srvr $dtxt $classloader $manageddir $assert $cpath $oome $jmx \ com.goldencode.p2j.main.ServerDriver $mode $cfg $port $@ \ 1>$outlog 2>$errlog"
$prog = ”java”
$hprof = enable JVM hprof -text profiling, when present (profiling output to gc.log)
$maxheap = the maximum heap size option
$srvr = ”-server”
$dtxt = additional options for debug mode
$classloader = ”-Djava.system.class.loader=com.goldencode.p2j.classloader.MultiClassLoader'”
$manageddir = ”-Dmanaged.libs.dir=../../customer_libs/managed"
$assert = set to "-enableassertions" when the option is specified
$cpath = ”-classpath”
$oome = "-XX:+HeapDumpOnOutOfMemoryError" when heapdumpoutofmemory is not disabled
$jmx = The jmx parameters in case jmx is set.
Windows (server.cmd)¶
Sample Script¶
This sample server.cmd
script can be used as-is so long as the installation matches the requirements in Application Server Installation. It is also OK to modify the script as needed for a specific installation.
:: standard P2J server startup script @echo off setlocal enableextensions enabledelayedexpansion :: defaults set cpath=. for %%f in (..\lib\*.jar) do call :add_jar %%f set debug=0 set suspend=n set test=n set hprof= set prog=java set srvr=-server :: this option to be adjusted according particular application requirements set heap=8192 set outlog=stdout.log set errlog=server.log set cfg=server.xml set port= set portbase=3333 set portstep=100 set mode= set statcode=n set instance=0 set batch= set usage[0]=Usage: %0 [-dyptksw1] [-bprocess] [-z cp] [-h heap] [-l log] [-c cfg] [-i inst] set usage[1]=Where: set usage[2]=-d = enable JVM debug mode (debugger port will be set as 2080 + instance #) set usage[3]=-y = in JVM debug mode enable, suspend the JVM on startup (does not suspend by default) set usage[4]=-p = enable JVM hprof (profiling output to gc.log) set usage[5]=-t = test mode (displays the command but doesn't execute) set usage[6]=-k = kill mode (shuts down the specified/default instance) set usage[7]=-s = status mode (displays the status of the specified/default instance) set usage[8]=-w = wait mode (does not return until the specified/default instance is STATUS_RUNNING) set usage[9]=-1 = enable C1 HotSpot compiler (client compiler for the JVM) set usage[10]=-z = override the classpath which would otherwise be set to %cpath% set usage[11]=-h = set JVM max heap size (must be an integer number of MB) set usage[12]=-l = log file name (all STDERR is redirected to this file, defaults to ./server.log) set usage[13]=-c = config file name (P2J bootstrap config file name, defaults to server.xml) set usage[14]=-i = server instance number (0..9, assigns the P2J server port, defaults to 0) set usage[15]=-b = launch a program associated with a process account set argCount=0 for %%x in (%*) do ( set /A argCount=!argCount!+1 set "argVec[!argCount!]=%%~x" ) set srvr=-server set /a i=1 :while1 set carg=!argVec[%i%]! if "%carg%" equ "-d" ( set debug=1 ) else if "%carg%" equ "-y" ( set suspend=y ) else if "%carg%" equ "-p" ( set hprof=-Xrunhprof:heap=dump,doe=y,format=b,file=gc.log ) else if "%carg%" equ "-t" ( set prog=echo %prog% set test=y ) else if "%carg%" equ "-k" ( set mode=-k set statcode=y ) else if "%carg%" equ "-s" ( set mode=-s set statcode=y ) else if "%carg%" equ "-w" ( set mode=-w -1 set statcode=y ) else if "%carg%" equ "-b" ( set /A "i=i+1" call :setvar batch !i! set batch=-b !batch! ) else if "%carg%" equ "-1" ( set srvr= ) else if "%carg%" equ "-z" ( set /A "i=i+1" call :setvar cpath !i! ) else if "%carg%" equ "-h" ( set /A "i=i+1" call :setvar heap !i! ) else if "%carg%" equ "-l" ( set /A "i=i+1" call :setvar log !i! ) else if "%carg%" equ "-c" ( set /A "i=i+1" call :setvar cfg !i! ) else if "%carg%" equ "-i" ( set /A "i=i+1" call :setvar instance !i! ) else if "%carg%" equ "help" ( for /L %%a in (0,1,14) do call echo.%%usage[%%a]%% ) set /a i=%i%+1 if %i% leq %argCount% ( goto :while1 ) :: final arg prep set cpath=-classpath %cpath% set /A dport=(2080 + %instance%) set /A sport=(%portbase% + %instance%) set /A iport=(%portbase% + %instance% + %portstep%) set iport=net:server:insecure_port=%iport% set port=net:connection:secure=true net:server:secure_port=%sport% %iport% if %debug% equ 1 ( set dtxt=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=%dport%,server=y,suspend=%suspend% ) else ( set dtxt= ) set maxheap=-Xmx%heap%m :: prepare command line to run the server set serverCmd=%prog% %maxheap% %srvr% %dtxt% %cpath% -Djava.system.class.loader=com.goldencode.p2j.classloader.MultiClassLoader com.goldencode.p2j.main.ServerDriver %mode% %batch% %cfg% %port% :: long lines protection if "%test%" equ "y" ( set serverCmd="%serverCmd% ) else ( set serverCmd="%serverCmd% 1>%outlog% 2>%errlog%" ) :: clean up environment variables no longer needed, this is mandatory for web client to operate :: normally, otherwise some unexpected errors will occur like The parameter is incorrect with :: CreateProcessWithLogonW. set usage[0]= set usage[1]= set usage[2]= set usage[3]= set usage[4]= set usage[5]= set usage[6]= set usage[7]= set usage[8]= set usage[9]= set usage[10]= set usage[11]= set usage[12]= set usage[13]= set usage[14]= set dport= set sport= set iport= set portbase= set portstep= set instance= set i= set argCount= set carg= set debug= set dport= set heap= set suspend= set prog= set maxheap= set srvr= set dtxt= set cpath= set mode= set cfg= set port= set outlog= set errlog= :: run the P2J server CMD.EXE /C %serverCmd% set rc=%errorlevel% if "%statcode%" equ "y" ( switch %rc% case 0 set status=STATUS_RUNNING case 1 set status=STATUS_TIMEOUT case 2 set status=STATUS_UNKNOWN case 3 set status=STATUS_STOPPED endswitch echo Result = %status% fi endlocal goto:eof :add_jar set cpath=%cpath%;%1 goto:eof :setvar set k=%2 set %1=!argVec[%k%]! goto:eof :getPID [RtnVar] :: :: Store the Process ID (PID) of the currently running script in environment variable RtnVar. :: If called without any argument, then simply write the PID to stdout. :: setlocal disableDelayedExpansion :getLock set "lock=%temp%\%~nx0.%time::=.%.lock" set "uid=%lock:\=:b%" set "uid=%uid:,=:c%" set "uid=%uid:'=:q%" set "uid=%uid:_=:u%" setlocal enableDelayedExpansion set "uid=!uid:%%=:p!" endlocal & set "uid=%uid%" 2>nul ( 9>"%lock%" ( for /f "skip=1" %%A in ( 'wmic process where "name='cmd.exe' and CommandLine like '%%<%uid%>%%'" get ParentProcessID' ) do for %%B in (%%A) do set "PID=%%B" (call ) ))||goto :getLock del "%lock%" 2>nul endlocal & if "%~1" equ "" (echo(%PID%) else set "%~1=%PID%" exit /b
Usage¶
Configuration¶
Due to plenty of Windows OS versions existed in a market there are some version specific additional steps to take into account. For the versions mentioned below assume all of them are 64-bit. Also there are some general hints common to all OS to get the best trouble free results.
Common rules¶
- When installing Java only
JDK
is enough and the best way. Disable separateJRE
install, it is included inJDK
by default. - Set up system wide environment variable
JAVA_HOME
, modifyPATH
to include%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin\server
. - The Apache
ANT
build tool is an optional install to properly distribute the libraries to thedeploy/lib
directory. Includebin
directory fromANT
into systemPATH
. No need to installmingw64
and recompile native parts of the FWD to provide compatibility with specific version of the Windows. It is possible to use precompiled binaries forFWD
.
Client type operating systems (Windows 7, Windows 10, Windows 11)¶
- All current system updates should be installed before using
FWD
server. If the Windows 7 OS was installed in 2022 it can be problematic due to official support ended. But this is mandatory. As of April 2022 it is possible to find standalone service packs on the Web. - Even if the user is administrator the default opening command prompt has not enough rights to do administrative tasks. This affects the ability to start FWD server and is a known feature of the non-server types of the Windows OS. To properly start the server as application from shell session it must be explicitly run as Administrator mode.
Running as a Service¶
It might be useful to run application as service. Several considerations to take into account:
- To be able to start server as a user other than the currently logged on Windows GUI session the server starter should be administrator (or otherwise have sufficient permissions).
- When using
nssm
as service control program to set up the server theserver.cmd
fromdeploy/server
directory. The service owner must be the same account that is defined indirectory.xml
assystemUser
. - Any file system resources to be used during application server run must be accessible for service owner user. This is important.
- The
systemPassword
in directory is a mandatory option when trying to run the server with a user that is not the same as the one logged in to Windows. The password can be plain (theenabled
option inspawn.ini
set to0
) or encrypted (theenabled
option inspawn.ini
is set to1
). - All files/directories entries in
directory.xml
must be valid (present in the local file system). - Using network drive is not recommended. It can be problematic depending on the Windows version.
- If there is a problem with the server startup, configure "terminate on crash" in
nssm
. This will result in aserver.log
for the failure instead of an infinite restarting loop. - The user that owns the service process itself must not match any of the user that is planned to work via the spawner. This means you must take great care with the userids configured in the directory for web clients, appserver agents and batch processes. For example, if you have
fwd
andfwdprocess
used to launch processes during the FWD server startup, the service owner MUST BE different. Otherwise you will have no ability to start application servers or web client for the user matching the service owner. Create a user dedicated for launching the service.
© 2004-2022 Golden Code Development Corporation. ALL RIGHTS RESERVED.