Project

General

Profile

client.sh

Roger Borrello, 06/16/2026 07:21 PM

Download (10.4 KB)

 
1
#!/bin/bash
2

    
3
#set -x
4

    
5
# standard FWD interactive client startup script
6

    
7
# defaults
8
whole_path="$(cd "$(dirname "$0")"; pwd)/$(basename "$0")"
9
srcname=$(basename "$whole_path")
10
srcpath=$(dirname "$whole_path")
11
[ ! -f ${srcpath}/appname ] && echo "FATAL: No appname to source in $srcpath" && exit
12
[ -z "$appname" ] && . ${srcpath}/appname
13
suspend="n"
14
prog="java"
15
dump="-XX:+HeapDumpOnOutOfMemoryError"
16
#dump="-XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError='./stack_dump.sh %p'"
17
host="net:server:host=localhost"
18
batch_parms="client:mode:batch=true client:driver:background=true"
19
driver_type="gui"
20
instance=0
21
portbase=3333
22
secure=false
23
portstep=100
24
maxheap=""
25
# Set this to debug the ssl handshake and include in jvm parms
26
#ssl_debug="-Djavax.net.debug=ssl:handshake"
27

    
28
# Determine the configured JDK
29
#jver is 18 for java 1.8, 15 for java 1.5, 110 for java 11, 170 for java 17 etc.
30
jver=$(${prog} -version 2>&1 | awk -F '"' '/version/ {print $2}' | awk -F '.' '{sub("^$", "0", $2); print $1$2}')
31

    
32
# Ensure UTF-8 is set
33
ensure_utf8_lang()
34
{
35
   # Get the current LANG setting and encoding portion (after the dot '.')
36
   current_lang="${LANG}"
37
   encoding="${current_lang##*.}"
38

    
39
   shopt -s nocasematch
40
   # Check if the encoding is not UTF-8
41
   if [[ ! "$encoding" =~ ^utf-?8$ ]]; then
42
      # Warn the user
43
      echo "Warning: The current LANG setting (${current_lang}) is not using UTF-8 encoding."
44

    
45
      # Set LANG to LANGUAGE.UTF-8, or fallback to en_US.UTF-8 if LANGUAGE is not set
46
      [ -z "$LANGUAGE" ] && new_lang="en_US.UTF-8" || new_lang="${LANGUAGE}.UTF-8"
47

    
48
      # Apply the new LANG setting
49
      export LANG="$new_lang"
50

    
51
      # Inform the user
52
      echo "LANG has been updated to: ${LANG}"
53
   fi
54
   shopt -u nocasematch
55
}
56

    
57
# help text
58
show_usage()
59
{
60
   i=0;        usage[$i]="\nUsage: $0 [-d<port>] [-s] [-c<cfgfile>] [-i<instance>] [-m<path>] [-2] [-b] [-k<password>] [-t<password>] [-p<procedure>] [-x<heap>] [-o<cmd-line-option:params>] [--test] [--wb] [--swing] [--terminal] \n"
61
   i=$((i+1)); usage[$i]="Where:\n"
62
   i=$((i+1)); usage[$i]="d \t= enable JVM debug mode, use the specified TCP port"
63
   i=$((i+1)); usage[$i]="s \t= in JVM debug mode enable, suspend the JVM on startup (does not suspend by default)"
64
   i=$((i+1)); usage[$i]="h \t= hostname or IP address for the server (defaults to localhost)"
65
   i=$((i+1)); usage[$i]="i \t= server instance number (0..9, assigns the FWD server port, defaults to 0) to which to connect"
66
   i=$((i+1)); usage[$i]="m \t= Enable heap dump on OOME to given path"
67
   i=$((i+1)); usage[$i]="c \t= config file name (FWD bootstrap config file name, defaults to standard_client.xml)"
68
   i=$((i+1)); usage[$i]="2 \t= enable C2 HotSpot compiler (server compiler for the JVM)"
69
   i=$((i+1)); usage[$i]="b \t= run with client in batch mode (forces --terminal)"
70
   i=$((i+1)); usage[$i]="k \t= password for keystore"
71
   i=$((i+1)); usage[$i]="t \t= password for trust"
72
   i=$((i+1)); usage[$i]="p \t= procedure to run"
73
   i=$((i+1)); usage[$i]="x \t= set JVM max heap size to <heap> (must be an integer number of MB)"
74
   i=$((i+1)); usage[$i]="o \t= options (params) to pass to cmd-line-option:params. Make sure this is the last on the command line, and in \"\""
75
   i=$((i+1)); usage[$i]="--test \t\t= test mode (displays the command but doesn't execute)"
76
   i=$((i+1)); usage[$i]="--wb \t\t= enable widget browser for debug purposes"
77
   i=$((i+1)); usage[$i]="--swing \t= use Swing client"
78
   i=$((i+1)); usage[$i]="--terminal\t= use ChUI driver"
79
   i=$((i+1)); usage[$i]="--no-appcds\t= disable AppCDS: full classpath discovery, no shared archive (pre-AppCDS behavior)"
80

    
81
   for i in "${usage[@]}"; do
82
      echo -e $i
83
   done
84
}
85

    
86
# process options
87
while getopts "?d:sh:i:m:c:2bk:t:p:o:x:-:" opt; do
88
   case $opt in
89
      d  ) debug=true
90
           dport=$OPTARG ;;
91
      s  ) suspend="y" ;;
92
      h  ) host="net:server:host="$OPTARG ;;
93
      i  ) instance=$OPTARG ;;
94
      m  ) dump+=" -XX:HeapDumpPath=${OPTARG}" ;;
95
      c  ) cfg=$OPTARG ;;
96
      2  ) srvr="-server" ;;
97
      b  ) batch="${batch_parms}"
98
           use_terminal=true ;;
99
      k  ) kpasswd=$OPTARG ;;
100
      t  ) tpasswd=$OPTARG ;;
101
      p  ) procedure=$OPTARG ;;
102
      x  ) maxheap="-Xmx"${OPTARG}"m" ;;
103
      o  ) # Save the remaining command-line arguments into 'params'
104
           shift $((OPTIND - 2))  # Shift to the first argument after '-o'
105
           params=$*              # Capture all remaining text
106
           break                  # Exit the loop as we are done
107
           ;;
108
      -  ) case ${OPTARG} in
109
              test     ) test=true ;;
110
              wb       ) wb="-Dwidget.browser=true" ;;
111
              swing    ) use_swing=true ;;
112
              terminal ) use_terminal=true
113
                         driver_type="chui" ;;
114
              no-appcds ) no_appcds=true ;;
115
           esac ;;
116
      \? ) show_usage
117
           exit 1 ;;
118
   esac
119
done
120
shift $(($OPTIND - 1))
121

    
122
# Determine driver and token
123
if [ "$use_swing" == true ]; then
124
   client_driver_type="client:driver:type=${driver_type}_swing"
125
   if [ "$use_terminal" == true ]; then
126
      client_driver_type+=" client:chui:rows=24 client:chui:columns=80 client:chui:background=0x000000 client:chui:foreground=0xFFA500 client:chui:selection=0x0000FF client:chui:fontname=monospaced client:chui:fontsize=12"
127
   fi
128
else
129
   if [ "$use_terminal" == true ]; then
130
      client_driver_type="client:driver:type=${driver_type}_native"
131
   else
132
      client_driver_type="client:driver:type=${driver_type}_swing"
133
   fi
134
fi
135
token="client:project:token=${driver_type}"
136
if [ -n "$batch" ]; then
137
   secure=true
138
   unset client_driver_type
139
fi
140

    
141
# pass the remaining command line arguments directly to the java driver
142
# WARNING: any arguments with embedded spaces are not passed properly; for
143
#          example, if you pass this to the script:
144
#             client:cmd-line-option:parameter="\"\\\"some text here\\\"\""
145
#          you would expect the following to be passed to the java driver:
146
#             client:cmd-line-option:parameter="\"some text here\""
147
#          but that does not happen; when running the driver directly this would
148
#          work fine; via the script the result is that the driver sees add'l 
149
#          parameters, which will cause it to think it has add'l bootstrap config
150
#          files to load 
151
if [ -z "$params" ]; then
152
   remainder="$@"
153
fi
154

    
155
# final arg prep
156
sport=$(($portbase + $instance))
157
iport=$(($portbase + $instance + $portstep))
158
port="net:connection:secure=${secure} net:server:secure_port=$sport net:server:insecure_port=$iport"
159

    
160
# Prevent NIO sockets
161
nio="net:socket:nio=false"
162

    
163
if [ "$debug" == true ]; then
164
   [ -f "/.dockerenv" ] && daddress="0.0.0.0:${dport}" || daddress="${dport}"
165
   dtxt="-agentlib:jdwp=transport=dt_socket,server=y,suspend=${suspend},address=${daddress}"
166
fi
167

    
168
if [ -n "$cfg" ]; then
169
   # Path could be relative to the srcpath, so calculate it and test existence.
170
   p=$(cd $(dirname ${srcpath}/${cfg}) 2>/dev/null; echo $(pwd))
171
   f=$(basename $cfg)
172
   [ -f "${p}/${f}" ] && cfg="${p}/${f}"
173
   token=""
174
   host=""
175
fi
176

    
177
# Server with store   
178
if [ -n "$tpasswd" ]; then
179
   tpasswd="ssl-socket:truststore:password=${tpasswd}"
180
fi   
181
# Connect with trust
182
if [ -n "$kpasswd" ]; then
183
   kpasswd="ssl-socket:keystore:password=${kpasswd}"
184
fi
185

    
186
# Pass in: client:cmd-line-option:startup-procedure=<file.p>
187
if [ -n "$procedure" ]; then
188
   procedure="client:cmd-line-option:startup-procedure=${procedure}"
189
fi
190

    
191
# Pass in options (params): client:cmd-line-option:parameter=<params>
192
if [ -n "$params" ]; then
193
   params="'client:cmd-line-option:parameter=${params}'"
194
fi
195

    
196
# getcp.sh and getspi.sh are helpers for setting up the classpath and spi for the given application. 
197
# This allows more flexibility in where the FWD configuration is placed. It can be one directory up,
198
# and then in lib, or in /opt/fwd/lib, or specified by FWD_LIB exported or up to the build directory,
199
# then down to lib. If the helper isn't found, we can only fall back to the original method.
200
helper=$(cd ${srcpath}/..; echo $(pwd))
201
export PATH=$helper:$PATH
202
if [ ".$(which getcp.sh)." == ".." ]; then
203
   lpath="-Djava.library.path=../lib/"
204
   cpath="-classpath ../lib/p2j.jar:"
205

    
206
   for each in ../lib/*.jar
207
   do
208
      cpath=$cpath:$each
209
   done
210
else
211
   # --appcds tells getcp.sh to prefer the curated client classpath published by
212
   # deploy_appcds.sh (appcds/client/<type>.cpath), matching the AppCDS archive.
213
   # It falls back to the normal FWD library discovery when no curated file
214
   # exists, so this is safe on deployments without AppCDS. With --no-appcds we
215
   # omit the flag so getcp.sh does full FWD library discovery (pre-AppCDS behavior).
216
   appcds_flag="--appcds"
217
   [ "$no_appcds" == true ] && appcds_flag=""
218
   cpath=$(getcp.sh $appname $srcpath $appcds_flag)
219
   lpath="-Djava.library.path="$(getspi.sh "$cpath" "p2j.jar")
220
   cpath="-classpath $cpath"
221
fi
222

    
223
# Enable AppCDS for the client when a curated archive is present. This is the
224
# complement to the curated classpath above: -XX:SharedArchiveFile points the JVM
225
# at the pre-parsed class archive built by deploy_appcds.sh, while the classpath
226
# (from getcp.sh --appcds) determines which jars are actually loaded. They are
227
# independent JVM inputs -- the archive only accelerates classes that are also on
228
# the classpath, and -Xshare:auto silently ignores the archive if the runtime
229
# classpath does not match the one it was dumped against. This mirrors the
230
# webClient jvmArgs in directory.xml and the cdsparams assembled in server.sh.
231
appcds_type="default"
232
cdsparams=""
233
if [ "$no_appcds" != true ]; then
234
   for cand in "/opt/${appname}/appcds/client/${appcds_type}.jsa" \
235
               "${srcpath}/../appcds/client/${appcds_type}.jsa"; do
236
      if [ -f "$cand" ]; then
237
         [ "$debug" == true ] && p="-Xshare:on -Xlog:class+path=info" || p="-Xshare:auto"
238
         cdsparams="${p} -XX:SharedArchiveFile=$cand"
239
         break
240
      fi
241
   done
242
fi
243

    
244
# Ensure UTF-8 encoding
245
original_lang="${LANG}"
246
ensure_utf8_lang
247

    
248
# run the FWD client
249
java_args="$srvr $maxheap $dump $wb $dtxt $lpath $cpath $cdsparams"
250

    
251
# Compatibility with Java 25
252
if [ $jver -ge 240 ]; then
253
   java_args+=" --enable-native-access=ALL-UNNAMED" 
254
fi
255

    
256
client_driver_args="$kpasswd $tpasswd $token $host $nio $port $client_driver_type $cfg $batch $procedure $params $remainder"
257
cmd="$prog $java_args com.goldencode.p2j.main.ClientDriver $client_driver_args"
258
if [ "$test" == "true" ]; then
259
   echo $cmd
260
else
261
   eval $cmd
262
fi
263

    
264
# Restore the original LANG setting, if sourced ad set
265
[ "${BASH_SOURCE[0]}" != "${0}" ] && [ ."$original_lang". != ".." ] && export LANG="$original_lang"
266