Project

General

Profile

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
  1. When installing Java only JDK is enough and the best way. Disable separate JRE install, it is included in JDK by default.
  2. Set up system wide environment variable JAVA_HOME, modify PATH to include %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin\server.
  3. The Apache ANT build tool is an optional install to properly distribute the libraries to the deploy/lib directory. Include bin directory from ANT into system PATH. No need to install mingw64 and recompile native parts of the FWD to provide compatibility with specific version of the Windows. It is possible to use precompiled binaries for FWD.
Client type operating systems (Windows 7, Windows 10, Windows 11)
  1. 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.
  2. 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:

  1. 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).
  2. When using nssm as service control program to set up the server the server.cmd from deploy/server directory. The service owner must be the same account that is defined in directory.xml as systemUser.
  3. Any file system resources to be used during application server run must be accessible for service owner user. This is important.
  4. 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 (the enabled option in spawn.ini set to 0) or encrypted (the enabled option in spawn.ini is set to 1).
  5. All files/directories entries in directory.xml must be valid (present in the local file system).
  6. Using network drive is not recommended. It can be problematic depending on the Windows version.
  7. If there is a problem with the server startup, configure "terminate on crash" in nssm. This will result in a server.log for the failure instead of an infinite restarting loop.
  8. 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 and fwdprocess 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.