Project

General

Profile

deploy_appcds.sh

Roger Borrello, 06/17/2026 02:42 PM

Download (7.24 KB)

 
1
#!/bin/bash
2

    
3
# Default values
4
P2J_JAR="../lib/p2j.jar"
5
DIR_XML=""
6
APPCDS_DIR=""
7

    
8
show_usage()
9
{
10
   i=0;        usage[$i]="Usage: $(basename $0) [-f <directory.xml>] [-d <appcds_dir>] [path_to_p2j.jar]"
11
   i=$((i+1)); usage[$i]="Where:"
12
   i=$((i+1)); usage[$i]="path_to_p2j.jar \t= Path to p2j.jar (default=\"../lib/p2j.jar\")"
13
   i=$((i+1)); usage[$i]="-f | --file \t= Path to directory.xml (default=\"../server/directory.xml\")"
14
   i=$((i+1)); usage[$i]="-d | --dir \t= Path to output appcds folder (default=\"../appcds/client\")"
15
   i=$((i+1)); usage[$i]="-h | --help \t= Usage information"
16

    
17
   for i in "${usage[@]}"; do
18
      echo -e "$i"
19
   done
20
}
21

    
22
while [[ $# -gt 0 ]]; do
23
    case "$1" in
24
        -h|--help|-\?)
25
            show_usage
26
            exit 1
27
            ;;
28
        -f|--file)
29
            DIR_XML="$2"
30
            shift 2
31
            ;;
32
        -d|--dir)
33
            APPCDS_DIR="$2"
34
            shift 2
35
            ;;
36
        *)
37
            if [[ "$1" == -* ]]; then
38
                echo "Unknown option: $1"
39
                show_usage
40
                exit 1
41
            fi
42
            # Positional argument
43
            P2J_JAR="$1"
44
            shift
45
            ;;
46
    esac
47
done
48

    
49
# Resolve DEPLOY_HOME relative to this script
50
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
51
DEPLOY_HOME="$(cd "$SCRIPT_DIR/.." && pwd)"
52

    
53
# Ensure P2J_JAR is an absolute path if it exists
54
if [[ "$P2J_JAR" != /* ]]; then
55
    P2J_JAR="$PWD/$P2J_JAR"
56
fi
57

    
58
DIR_XML="${DIR_XML:-$DEPLOY_HOME/server/directory.xml}"
59
if [[ "$DIR_XML" != /* ]]; then
60
    DIR_XML="$PWD/$DIR_XML"
61
fi
62

    
63
APPCDS_DIR="${APPCDS_DIR:-$DEPLOY_HOME/appcds/client}"
64
if [[ "$APPCDS_DIR" != /* ]]; then
65
    APPCDS_DIR="$PWD/$APPCDS_DIR"
66
fi
67

    
68
if [ ! -f "$DIR_XML" ]; then
69
    echo "Error: $DIR_XML not found."
70
    exit 1
71
fi
72

    
73
TMP_PROPS=$(mktemp)
74
java -cp "$P2J_JAR" com.goldencode.util.JvmArgsExtractor -f "$DIR_XML" -o "$TMP_PROPS"
75

    
76
if [ $? -ne 0 ]; then
77
    echo "Error: Failed to extract JVM args."
78
    rm -f "$TMP_PROPS"
79
    exit 1
80
fi
81

    
82
# Read properties into dynamically named variables
83
while IFS='=' read -r key value; do
84
    if [[ $key == \#* ]] || [ -z "$key" ]; then
85
        continue
86
    fi
87
    key=$(echo "$key" | xargs)
88
    value="${value//\\:/:}"
89
    value="${value//\\=/=}"
90
    
91
    var_name="${key//./_}"
92
    var_name="${var_name//-/_}"
93
    declare "$var_name=$value"
94
done < "$TMP_PROPS"
95

    
96
rm -f "$TMP_PROPS"
97

    
98
# Remove existing appcds directory to prevent Java from reusing a stale .jsa archive.
99
# The JVM does not overwrite an existing SharedArchiveFile in-place; removing the
100
# directory guarantees a clean dump on every run.
101
if [ -d "$APPCDS_DIR" ]; then
102
    rm -rf "$APPCDS_DIR"
103
fi
104
mkdir -p "$APPCDS_DIR"
105

    
106
if [ -z "$appcds_clients" ]; then
107
    echo "No clients found for AppCDS."
108
    exit 0
109
fi
110

    
111
IFS=',' read -ra clients <<< "$appcds_clients"
112
for client_type in "${clients[@]}"; do
113
    client_type=$(echo "$client_type" | xargs)
114
    if [ -z "$client_type" ]; then
115
        continue
116
    fi
117
    
118
    echo "Processing client: $client_type"
119
    
120
    cp_var="appcds_classpath_$client_type"
121
    args_var="appcds_jvmargs_$client_type"
122
    
123
    client_cp="${!cp_var}"
124
    client_args="${!args_var}"
125

    
126
    # Directory holding p2j.jar (and its manifest-referenced jars). Used only when
127
    # INCLUDE_STATIC=true, to give LstExporter an explicit classpath to analyze --
128
    # the manifest expansion is not visible via java.class.path.
129
    appcds_lib_dir="$(cd "$(dirname "${client_cp%%:*}")" 2>/dev/null && pwd)"
130

    
131
    echo "JVM classpath for $client_type: $client_cp"
132
    echo "JVM args for $client_type: $client_args"
133
    
134
    base_lst=$(mktemp)
135
    runtime_lst=$(mktemp)
136

    
137
    # 1. (Optional) LstExporter static reachability. OFF by default: walking the whole
138
    #    classpath yields ~18k classes / ~140MB .jsa, while a real client loads ~2k --
139
    #    the bloat balloons per-client memory with no benefit. Enable INCLUDE_STATIC=true
140
    #    for broader coverage. It needs an EXPLICIT classpath (the lib dir's jars),
141
    #    because under -cp p2j.jar the manifest-referenced jars are invisible to it.
142
    if [ "${INCLUDE_STATIC:-false}" = "true" ]; then
143
        static_cp="$client_cp"
144
        for j in "$appcds_lib_dir"/*.jar; do
145
            [ "$j" = "${client_cp%%:*}" ] || static_cp="$static_cp:$j"
146
        done
147
        cd "$DEPLOY_HOME/client" || exit 1
148
        java -cp "$static_cp" com.goldencode.util.LstExporter \
149
            "com.goldencode.p2j.main.ClientDriver" \
150
            "com.goldencode.p2j.ui.client" \
151
            "-com.goldencode.p2j.persist" \
152
            "-com.goldencode.p2j.main.StandardServer" \
153
            "!com.goldencode.p2j.util" \
154
            "-o" "$base_lst"
155
        if [ $? -ne 0 ]; then
156
            echo "Error: LstExporter failed for $client_type"
157
            rm -f "$base_lst" "$runtime_lst"
158
            exit 1
159
        fi
160
    fi
161

    
162
    # 2. ClientDriver to dump the runtime (actually-loaded) class list.
163
    cd /tmp || exit 1
164
    java -cp "$client_cp" \
165
        -Djava.library.path="$DEPLOY_HOME/lib" \
166
        -XX:DumpLoadedClassList="$runtime_lst" \
167
        com.goldencode.p2j.main.ClientDriver
168
        
169
    # 3. Assemble the class list. Default = runtime-loaded set only (lean archive that
170
    #    matches what the client actually uses). Prepend the static set only when
171
    #    INCLUDE_STATIC produced one.
172
    final_lst="$APPCDS_DIR/${client_type}.lst"
173
    if [ -s "$base_lst" ]; then
174
        sed -i '1i# base_lst (static)' "$base_lst"
175
        sed -i '1i# runtime_lst' "$runtime_lst"
176
        cat "$base_lst" "$runtime_lst" > "$final_lst"
177
    else
178
        cp "$runtime_lst" "$final_lst"
179
    fi
180

    
181
    # LstExporter copies SPI provider entries from META-INF/services/* verbatim, and
182
    # those files may carry inline comments that are legal per the ServiceLoader spec
183
    # (e.g. ecj's javax.tools.JavaCompiler lists
184
    #   org.eclipse.jdt...EclipseCompiler #Eclipse compiler).
185
    # The -Xshare:dump class-list parser rejects a class name followed by such a
186
    # trailing comment, so strip any inline "#..." while leaving full-line comments
187
    # (lines that begin with #) intact.
188
    sed -i 's/\([^[:space:]]\)[[:space:]]*#.*$/\1/' "$final_lst"
189
    
190
    # 4. Build JSA archive
191
    cd "$DEPLOY_HOME/client" || exit 1
192
    
193
    # We must split client_args on spaces properly without quotes
194
    # so that -Xmx512m -Dfoo=bar are treated as separate args
195
    java -cp "$client_cp" \
196
        -Djava.library.path="$DEPLOY_HOME/lib" \
197
        -Xshare:dump \
198
        -XX:SharedClassListFile="$APPCDS_DIR/${client_type}.lst" \
199
        -XX:SharedArchiveFile="$APPCDS_DIR/${client_type}.jsa" \
200
        $client_args \
201
        com.goldencode.p2j.main.ClientDriver
202
        
203
    if [ $? -ne 0 ]; then
204
        echo "Error: JSA archive generation failed for $client_type"
205
        rm -f "$base_lst" "$runtime_lst"
206
        exit 1
207
    fi
208

    
209
    # Record the exact classpath the archive was dumped against, alongside the
210
    # .jsa/.lst. The client runtime (getcp.sh --appcds) reads this file so its
211
    # classpath matches the archive. AppCDS requires the dumped classpath to be
212
    # a prefix of the runtime classpath, so these must stay in lock-step. The
213
    # client never has access to directory.xml, which is why this is published
214
    # here at prepare time instead.
215
    echo "$client_cp" > "$APPCDS_DIR/${client_type}.cpath"
216

    
217
    rm -f "$base_lst" "$runtime_lst"
218
done
219

    
220
echo "AppCDS deployment completed successfully."