在布建一個Web Application時,用.war來佈屬服務,算是最沒有效率的一種方式,因為,這樣無法把web container所需要的設定檔一起佈建出去,同時,也無法板本控製你的應用程式;本文接下來會敘述,如何用maven & jetty & debian來佈屬你的Web Application。

首先,先講講我的需求,我的需求如下
  • Web Application的版本必需能夠簡單被管理,要能簡單的就知道目前安裝的版本,並且輕鬆的昇級到新版
  • Web Application被佈建時,要連Web Container及設定擋包在一起
  • Debian Box開關機時,要能自動開關Web Container

這些需求,我是靠 unix-maven-plugin ,幫我把我的 web application 包成一個 .deb 來做到的,包成 .deb 的好處是,在 debian 上可以簡單的安裝,若是公司有架 debian package repository, 那麼,打個 apt-get install 就可以安裝或昇級到最新版,同時間,可以透過 debian 安裝的機制,來把些 script 掛入 rc.*

由於 unix-maven-plugin 已被原作者遺棄,所以需要從 github下載並安裝後人修改過的版本。

然後依附錄的方式,增修你的設定檔,需要增修的檔案有
  • pom.xml: 加入 unix-maven-plugin 及服務的名稱及PORT
  • src/main/unix/resources/default/${service.user} : 給 jetty 用的 default 設定值,在這邊你可以修改 JAVA_OPTIONS 及 NO_START
  • src/main/unix/resources/etc/jetty.conf
  • src/main/unix/resources/etc/start.conf
  • src/main/unix/resources/scripts/${service.user} : 給 debian 用的 init script
  • src/main/unix/resources/scripts/post-install post-remove pre-install pre-remove : debian 在安裝及昇級 .deb 時會跑的 script

將這些檔案設定好後,在 debian 的機器上打 mvn package deploy ,就可以自動生成 .deb 的檔案,並且上傳到你的 maven repository 上去,如果貴公司有架 debian package repository 的話,還可以加一段程式碼把 .deb 傳到 debian package repository 去。

接著,打 dpkg -i xxxx.deb 就可以把你的 web application 當成一個 debian service 安裝到你的 debain machine 上去。

查詢目前安裝的板本則是打 dpkg -l xxxx 即可

||/ Name           Version        Description
+++-==============-==============-============================================
ii backend 1.2.0-20120327.143115 backend


附錄



把底下的這段,加入你的 pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0</modelVersion>
com.locadz</groupId>
backend</artifactId>
war
backend
1.2.0-SNAPSHOT
backend

1.0-alpha-6.1
7.4.5.v20110725

Locadz Backend
/var/lib/bluetang/locadz-backend
locadz-backend
9080



debian-package


unix
linux





maven-resources-plugin</artifactId>
2.5


copy-resources

process-resources

copy-resources


${basedir}/target</outputDirectory>


src/main/unix
unix</targetPath>

**/*

true
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>



org.mortbay.jetty.toolchain</groupId>
unix-maven-plugin</artifactId>
${version.maven.unix.plugin}
true


package

package-deb-attached





true
yho@bluetangstudio.com
yho@bluetangstudio.com</contactEmail>


${service.user}
adm
</fileAttributes>

${service.user}
adm
</directoryAttributes>
</defaults>

bluetang

extra





org.eclipse.jetty:jetty-distribution:zip
${service.home}
/jetty-distribution-${version.jetty}(.*)
$1


*/contexts/**
*/contexts-available/**
*/webapps/**
*/javadoc/**
*/LICENSES/**
*/logs/**
**/win32/**




${project.build.directory}/${project.build.finalName}.${project.packaging}

${service.home}/webapps/ROOT.war</toFile>
</copyFile>

${basedir}/target/unix/resources/default/${service.user}
/etc/default</toDir>
</copyFile>

${basedir}/target/unix/resources/etc
/etc/bluetang/${service.user}
</copyDirectory>

${basedir}/target/unix/scripts/${service.user}
/etc/init.d</toDir>

0754
${service.user}
admin

</copyFile>
</assembly>
</configuration>
</plugin>
</plugins>
</build>

</profile>
</profiles>




org.eclipse.jetty</groupId>
jetty-distribution</artifactId>
${version.jetty}
zip



*</groupId>
*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</project>
</pre>
然後把下面這塊存成 src/main/unix/resources/default/${service.user}

# Defaults for jetty see /etc/${service.user}/jetty for more

# change to 0 to allow Jetty to start
NO_START=0

# change to 'no' or uncomment to use the default setting in /etc/default/rcS
VERBOSE=yes

# Run Jetty as this user ID (default: jetty)
# Set this to an empty string to prevent Jetty from starting automatically
JETTY_USER=${service.user}

# Listen to connections from this network host
# Use 0.0.0.0 as host to accept all connections.
# Uncomment to restrict access to localhost
#JETTY_HOST=$(uname -n)
JETTY_HOST=0.0.0.0

# The network port used by Jetty
JETTY_PORT=${service.port}

# Timeout in seconds for the shutdown of all webapps
#JETTY_SHUTDOWN=30

# Additional arguments to pass to Jetty
#JETTY_ARGS=

# Extra options to pass to the JVM
JAVA_OPTIONS="-Xmx256m -Djava.awt.headless=true -Duser.timezone=UTC"

# Home of Java installation.
#JAVA_HOME=

# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not
# defined in /etc/default/jetty). Should contain a list of space separated directories.
#JDK_DIRS="/usr/lib/jvm/default-java /usr/lib/jvm/java-6-sun"

# Java compiler to use for translating JavaServer Pages (JSPs). You can use all
# compilers that are accepted by Ant's build.compiler property.
#JSP_COMPILER=jikes

# Jetty uses a directory to store temporary files like unpacked webapps
JETTY_TMP=/var/cache/bluetang/jetty

# Jetty uses a config file to setup its boot classpath
JETTY_START_CONFIG=/etc/bluetang/${service.user}/start.config

# Default for number of days to keep old log files in /var/log/jetty/
#LOGFILE_DAYS=14


然後把下面這塊存成 src/main/unix/resources/ect/jetty.conf

# list of jetty configuration and property files
/var/lib/bluetang/${service.user}/etc/jetty-logging.xml


然後把下面這塊存成 src/main/unix/resources/etc/start.conf

# This file controls what file are to be put on classpath or command line.
#
# Format is as follows:
# Each line contains entry for one JAR file.
# Format of line:
#
# SUBJECT [ [!] CONDITION [AND|OR] ]*
#
# where SUBJECT:
# ends with ".class" is the Main class to run.
# ends with ".xml" is a configuration file for the command line
# ends with "/" is a directory from which to add all jar and zip files.
# ends with "/*" is a directory from which to add all unconsidered jar and zip files.
# ends with "/**" is a directory from which to recursively add all unconsidered jar and zip files.
# Containing = are used to assign system properties.
# all other subjects are treated as files to be added to the classpath.
#
# Subjects may include system properties with $(propertyname) syntax.
#
# Files starting with "/" are considered absolute, all others are relative to
# the home directory.
#
# CONDITION is one of:
# always
# never
# available classname # true if class on classpath
# property name # true of set
# java OPERATOR version # java version compared to literal
# nargs OPERATOR number # number of command line args compared to literal
# OPERATOR := one of "<",">","<=",">=","==","!="
#
# CONDITIONS can be combined with AND OR or !, with AND being the assume
# operator for a list of CONDITIONS.
# Classpath operations are evaluated on the fly, so once a class or jar is
# added to the classpath, subsequent available conditions will see that class.
#

$(jetty.class.path) always
$(jetty.lib)/** exists $(jetty.lib)

jetty.home=/var/lib/bluetang/${service.user} always

# The main class to run
org.mortbay.xml.XmlConfiguration.class

# The default configuration files
$(jetty.home)/etc/jetty.xml nargs == 0

/usr/share/java/servlet-api-2.5.jar
/usr/share/java/slf4j-api.jar

# Optional stuff for libjetty-extra-java
/usr/share/java/gnumail.jar
/usr/share/java/activation.jar
/usr/share/java/ant.jar

# Set the jetty classpath
/usr/share/jetty/lib/**

# Add a resources directory if it is there
$(jetty.home)/resources/




然後把下面這塊存成 src/main/unix/scripts/${service.user}

#!/bin/bash  
### BEGIN INIT INFO
# Provides: ${service.user}
# Required-Start:
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start daemon at boot time
# Description: Enable service provided by daemon.
### END INIT INFO
#
# Startup script for jetty under *nix systems (it works under NT/cygwin too).
#
# Configuration files
#
# /etc/default/${service.user}
# If it exists, this is read at the start of script. It may perform any
# sequence of shell commands, like setting relevant environment variables.
#
# /etc/bluetang/${service.user}/jetty.conf
# If found, and no configurations were given on the command line,
# the file will be used as this script's configuration.
# Each line in the file may contain:
# - A comment denoted by the pound (#) sign as first non-blank character.
# - The path to a regular file, which will be passed to jetty as a
# config.xml file.
# - The path to a directory. Each *.xml file in the directory will be
# passed to jetty as a config.xml file.
#
# The files will be checked for existence before being passed to jetty.
#
# $JETTY_HOME/etc/jetty.xml
# If found, used as this script's configuration file, but only if
# /etc/bluetang/${service.user}/jetty.conf was not present. See above.
#
# Configuration variables
#
# JAVA
# Command to invoke Java. If not set, java (from the PATH) will be used.
#
# JAVA_OPTIONS
# Extra options to pass to the JVM
#
# JETTY_HOME
# Where Jetty is installed. If not set, the script will try go
# guess it by first looking at the invocation path for the script,
# and then by looking in standard locations as $HOME/opt/jetty
# and /opt/jetty. The java system property "jetty.home" will be
# set to this value for use by configure.xml files, f.e.:
#
# /webapps/jetty.war</Arg>
#
# JETTY_PORT
# Override the default port for Jetty servers. If not set then the
# default value in the xml configuration file will be used. The java
# system property "jetty.port" will be set to this value for use in
# configure.xml files. For example, the following idiom is widely
# used in the demo config files to respect this property in Listener
# configuration elements:
#
# </Set>
#
# Note: that the config file could ignore this property simply by saying:
#
# 8080</Set>
#
# JETTY_RUN
# Where the jetty.pid file should be stored. It defaults to the
# first available of /var/run, /usr/var/run, and /tmp if not set.
#
# JETTY_PID
# The Jetty PID file, defaults to $JETTY_RUN/jetty.pid
#
# JETTY_ARGS
# The default arguments to pass to jetty.
#
# JETTY_USER
# if set, then used as a username to run the server as
#
JETTY_HOME=${service.home}
JETTY_USER=${service.user}
JETTY_PID=$JETTY_RUN/${service.user}.pid
usage()
{
echo "Usage: ${0##*/} [-d] {start|stop|run|restart|check|supervise} [ CONFIGS ... ] "
exit 1
}

[ $# -gt 0 ] || usage


##################################################
# Some utility functions
##################################################
findDirectory()
{
local L OP=$1
shift
for L in "$@"; do
[ "$OP" "$L" ] || continue
printf %s "$L"
break
done
}

running()
{
local PID=$(cat "$1" 2>/dev/null) || return 1
kill -0 "$PID" 2>/dev/null
}

readConfig()
{
(( DEBUG )) && echo "Reading $1.."
source "$1"
}



##################################################
# Get the action & configs
##################################################
CONFIGS=()
NO_START=0
DEBUG=0

while [[ $1 = -* ]]; do
case $1 in
-d) DEBUG=1 ;;
esac
shift
done
ACTION=$1
shift

##################################################
# See if there's a default configuration file
##################################################
if [ -f /etc/default/${service.user} ] ; then
. /etc/default/${service.user}
fi


##################################################
# Set tmp if not already set.
##################################################
TMPDIR=${TMPDIR:-/tmp}

##################################################
# Jetty's hallmark
##################################################
JETTY_INSTALL_TRACE_FILE="etc/jetty.xml"


##################################################
# Try to determine JETTY_HOME if not set
##################################################
if [ -z "$JETTY_HOME" ]
then
JETTY_SH=$0
case "$JETTY_SH" in
/*) ;;
./*) ;;
*) JETTY_SH=./$JETTY_SH ;;
esac
JETTY_HOME=${JETTY_SH%/*/*}

if [ ! -f "${JETTY_SH%/*/*}/$JETTY_INSTALL_TRACE_FILE" ]
then
JETTY_HOME=
fi
fi



##################################################
# if no JETTY_HOME, search likely locations.
##################################################
if [ -z "$JETTY_HOME" ] ; then
STANDARD_LOCATIONS=(
"/usr/share"
"/usr/share/java"
"${HOME}"
"${HOME}/src"
"${HOME}/opt"
"/opt"
"/java"
"/usr/local"
"/usr/local/share"
"/usr/local/share/java"
"/home"
)
JETTY_DIR_NAMES=(
"jetty-7"
"jetty7"
"jetty-7.*"
"jetty"
"Jetty-7"
"Jetty7"
"Jetty-7.*"
"Jetty"
)

for L in "${STANDARD_LOCATIONS[@]}"
do
for N in "${JETTY_DIR_NAMES[@]}"
do
POSSIBLE_JETTY_HOME=("$L/"$N)
if [ ! -d "$POSSIBLE_JETTY_HOME" ]
then
# Not a directory. skip.
unset POSSIBLE_JETTY_HOME
elif [ ! -f "$POSSIBLE_JETTY_HOME/$JETTY_INSTALL_TRACE_FILE" ]
then
# Trace file not found. skip.
unset POSSIBLE_JETTY_HOME
else
# Good hit, Use it
JETTY_HOME=$POSSIBLE_JETTY_HOME
# Break out of JETTY_DIR_NAMES loop
break
fi
done
if [ -n "$POSSIBLE_JETTY_HOME" ]
then
# We have found our JETTY_HOME
# Break out of STANDARD_LOCATIONS loop
break
fi
done
fi


##################################################
# No JETTY_HOME yet? We're out of luck!
##################################################
if [ -z "$JETTY_HOME" ]; then
echo "** ERROR: JETTY_HOME not set, you need to set it or install in a standard location"
exit 1
fi

cd "$JETTY_HOME"
JETTY_HOME=$PWD


#####################################################
# Check that jetty is where we think it is
#####################################################
if [ ! -r "$JETTY_HOME/$JETTY_INSTALL_TRACE_FILE" ]
then
echo "** ERROR: Oops! Jetty doesn't appear to be installed in $JETTY_HOME"
echo "** ERROR: $JETTY_HOME/$JETTY_INSTALL_TRACE_FILE is not readable!"
exit 1
fi

##################################################
# Try to find this script's configuration file,
# but only if no configurations were given on the
# command line.
##################################################
if [ -z "$JETTY_CONF" ]
then
if [ -f /etc/bluetang/${service.user}/jetty.conf ]
then
JETTY_CONF=/etc/bluetang/${service.user}/jetty.conf
elif [ -f "${JETTY_HOME}/etc/jetty.conf" ]
then
JETTY_CONF="${JETTY_HOME}/etc/jetty.conf"
fi
fi

##################################################
# Get the list of config.xml files from jetty.conf
##################################################
if [ -z "$CONFIGS" ] && [ -f "$JETTY_CONF" ] && [ -r "$JETTY_CONF" ]
then
while read -r CONF
do
if expr "$CONF" : '#' >/dev/null ; then
continue
fi

if [ -d "$CONF" ]
then
# assume it's a directory with configure.xml files
# for example: /etc/jetty.d/
# sort the files before adding them to the list of CONFIGS
for file in "$CONF/"*.xml
do
if [ -r "$FILE" ] && [ -f "$FILE" ]
then
CONFIGS+=("$FILE")
else
echo "** WARNING: Cannot read '$FILE' specified in '$JETTY_CONF'"
fi
done
else
# assume it's a command line parameter (let start.jar deal with its validity)
CONFIGS+=("$CONF")
fi
done < "$JETTY_CONF"
fi

#####################################################
# Find a location for the pid file
#####################################################
if [ -z "$JETTY_RUN" ]
then
JETTY_RUN=$(findDirectory -w /var/run /usr/var/run /tmp)
fi

#####################################################
# Find a PID for the pid file
#####################################################
if [ -z "$JETTY_PID" ]
then
JETTY_PID="$JETTY_RUN/jetty.pid"
fi

##################################################
# Setup JAVA if unset
##################################################
if [ -z "$JAVA" ]
then
JAVA=$(which java)
fi

if [ -z "$JAVA" ]
then
echo "Cannot find a Java JDK. Please set either set JAVA or put java (>=1.5) in your PATH." 2>&2
exit 1
fi

#####################################################
# See if JETTY_PORT is defined
#####################################################
if [ "$JETTY_PORT" ]
then
JAVA_OPTIONS+=("-Djetty.port=$JETTY_PORT")
fi

#####################################################
# See if JETTY_LOGS is defined
#####################################################
if [ "$JETTY_LOGS" ]
then
JAVA_OPTIONS+=("-Djetty.logs=$JETTY_LOGS")
fi

#####################################################
# Are we running on Windows? Could be, with Cygwin/NT.
#####################################################
case "`uname`" in
CYGWIN*) PATH_SEPARATOR=";";;
*) PATH_SEPARATOR=":";;
esac


#####################################################
# Add jetty properties to Java VM options.
#####################################################
JAVA_OPTIONS+=("-Djetty.home=$JETTY_HOME" "-Djava.io.tmpdir=$TMPDIR")

[ -f "$JETTY_HOME/etc/start.config" ] && JAVA_OPTIONS=("-DSTART=$JETTY_HOME/etc/start.config" "${JAVA_OPTIONS[@]}")

#####################################################
# This is how the Jetty server will be started
#####################################################

JETTY_START=$JETTY_HOME/start.jar
[ ! -f "$JETTY_START" ] && JETTY_START=$JETTY_HOME/lib/start.jar

START_INI=$(dirname $JETTY_START)/start.ini
[ -r "$START_INI" ] || START_INI=""

RUN_ARGS=(${JAVA_OPTIONS[@]} -jar "$JETTY_START" $JETTY_ARGS "${CONFIGS[@]}")
RUN_CMD=("$JAVA" ${RUN_ARGS[@]})

#####################################################
# Comment these out after you're happy with what
# the script is doing.
#####################################################
if (( DEBUG ))
then
echo "JETTY_HOME = $JETTY_HOME"
echo "JETTY_CONF = $JETTY_CONF"
echo "JETTY_RUN = $JETTY_RUN"
echo "JETTY_PID = $JETTY_PID"
echo "JETTY_ARGS = $JETTY_ARGS"
echo "CONFIGS = ${CONFIGS[*]}"
echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}"
echo "JAVA = $JAVA"
echo "RUN_CMD = ${RUN_CMD}"
fi

##################################################
# Do the action
##################################################
case "$ACTION" in
start)
echo -n "Starting ${service.name}: "

if (( NO_START )); then
echo "Not starting ${service.user} - NO_START=1";
exit
fi


if type start-stop-daemon > /dev/null 2>&1
then
unset CH_USER
if [ -n "$JETTY_USER" ]
then
CH_USER="-c$JETTY_USER"
fi
if start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon
then
sleep 1
if running "$JETTY_PID"
then
echo "OK"
else
echo "FAILED"
fi
fi

else

if [ -f "$JETTY_PID" ]
then
if running $JETTY_PID
then
echo "Already Running!"
exit 1
else
# dead pid file - remove
rm -f "$JETTY_PID"
fi
fi

if [ "$JETTY_USER" ]
then
touch "$JETTY_PID"
chown "$JETTY_USER" "$JETTY_PID"
# FIXME: Broken solution: wordsplitting, pathname expansion, arbitrary command execution, etc.
su - "$JETTY_USER" -c "
${RUN_CMD[*]} --daemon &
disown \$!
echo \$! > '$JETTY_PID'"
else
"${RUN_CMD[@]}" &
disown $!
echo $! > "$JETTY_PID"
fi

echo "STARTED ${service.name} `date`"
fi

;;

stop)
echo -n "Stopping ${service.name}: "
if type start-stop-daemon > /dev/null 2>&1; then
start-stop-daemon -K -p"$JETTY_PID" -d"$JETTY_HOME" -a "$JAVA" -s HUP

TIMEOUT=30
while running "$JETTY_PID"; do
if (( TIMEOUT-- == 0 )); then
start-stop-daemon -K -p"$JETTY_PID" -d"$JETTY_HOME" -a "$JAVA" -s KILL
fi

sleep 1
done

rm -f "$JETTY_PID"
echo OK
else
PID=$(cat "$JETTY_PID" 2>/dev/null)
kill "$PID" 2>/dev/null

TIMEOUT=30
while running $JETTY_PID; do
if (( TIMEOUT-- == 0 )); then
kill -KILL "$PID" 2>/dev/null
fi

sleep 1
done

rm -f "$JETTY_PID"
echo OK
fi

;;

restart)
JETTY_SH=$0
if [ ! -f $JETTY_SH ]; then
if [ ! -f $JETTY_HOME/bin/jetty.sh ]; then
echo "$JETTY_HOME/bin/jetty.sh does not exist."
exit 1
fi
JETTY_SH=$JETTY_HOME/bin/jetty.sh
fi

"$JETTY_SH" stop "$@"
"$JETTY_SH" start "$@"

;;

supervise)
#
# Under control of daemontools supervise monitor which
# handles restarts and shutdowns via the svc program.
#
exec "${RUN_CMD[@]}"

;;

run|demo)
echo "Running Jetty: "

if [ -f "$JETTY_PID" ]
then
if running "$JETTY_PID"
then
echo "Already Running!"
exit 1
else
# dead pid file - remove
rm -f "$JETTY_PID"
fi
fi

exec "${RUN_CMD[@]}"

;;

check)
echo "Checking arguments to Jetty: "
echo "JETTY_HOME = $JETTY_HOME"
echo "JETTY_CONF = $JETTY_CONF"
echo "JETTY_RUN = $JETTY_RUN"
echo "JETTY_PID = $JETTY_PID"
echo "JETTY_PORT = $JETTY_PORT"
echo "JETTY_LOGS = $JETTY_LOGS"
echo "START_INI = $START_INI"
echo "CONFIGS = ${CONFIGS[*]}"
echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}"
echo "JAVA = $JAVA"
echo "CLASSPATH = $CLASSPATH"
echo "RUN_CMD = ${RUN_CMD[*]}"
echo

if [ -f "$JETTY_RUN/jetty.pid" ]
then
echo "Jetty running pid=$(< "$JETTY_RUN/jetty.pid")"
exit 0
fi
exit 1

;;

*)
usage

;;
esac

exit 0

</pre>然後把下面這塊存成 src/main/unix/scripts/post-install,並修改 USER=locadz-backend 這一行成跟你 ${service.user} 一樣的值
#!/bin/sh
set -e

USER=locadz-backend

case "$1" in
configure)
if ! id $USER > /dev/null 2>&1 ; then
adduser --system --home /var/lib/bluetang/$USER --no-create-home \
--group --disabled-password --shell /bin/false \
$USER
fi

if [ ! -e /var/log/bluetang ]
then
mkdir -p /var/log/bluetang
fi
if [ ! -e /var/log/bluetang/$USER/ ]
then
ln -s /var/lib/bluetang/$USER/logs /var/log/bluetang/$USER
fi
if [ ! -e /var/cache/bluetang/$USER ]
then
mkdir -p /var/cache/bluetang/$USER
fi


chown -R $USER:adm /var/cache/bluetang/$USER /var/log/bluetang/$USER /var/lib/bluetang/$USER
chmod 0744 /etc/init.d/$USER
update-rc.d $USER defaults

;;

abort-upgrade|abort-remove|abort-deconfigure)
;;

*)
echo "$0 called with unknown argument \`$1'" >&2
exit 1
;;
esac

然後把下面這塊存成 src/main/unix/scripts/post-remove,並修改 USER=locadz-backend 這一行成跟你 ${service.user} 一樣的值
#!/bin/sh
set -e

USER=locadz-backend

#DEBHELPER#

# Remove cached files
rm -rf /var/cache/blutang/$USER/*

case "$1" in
remove)
# Remove ROOT webapp if not modified
RWLOC="/var/lib/bluetang/$USER/webapps/root"
RWFILES="$RWLOC/index.html $RWLOC/jetty_banner.gif"
if [ "`(cat $RWFILES | md5sum -) 2>/dev/null | cut -d ' ' -f 1`" \
= "12471c4b3020defb7ebd30ef84c0f9dd" ] ; then
rm $RWFILES
rmdir --ignore-fail-on-non-empty \
/var/lib/bluetang/$USER/webapps/root \
/var/lib/bluetang/$USER/webapps \
/var/lib/bluetang/$USER || true
fi
if [ -d "/var/cache/bluetang/$USER" ] ; then
rm -rf /var/cache/bluetang/$USER
fi
;;

purge)
# Remove user/group and log files (don't remove everything under
# /var/lib/jetty because there might be user-installed webapps)
deluser jetty || true
rm -rf /var/log/bluetang/$USER
if [ -d "/var/lib/bluetang/$USER" ] ; then
rmdir --ignore-fail-on-non-empty /var/lib/bluetang/$USER || true
fi
rmdir --ignore-fail-on-non-empty /etc/bluetang/$USER/contexts /etc/bluetang/$USER || true
;;

remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
# Nothing to do here
;;

*)
echo "$0 called with unknown argument \`$1'" >&2
exit 1
;;
esac
然後把下面這塊存成 src/main/unix/scripts/pre-install,並修改 USER=locadz-backend 這一行成跟你 ${service.user} 一樣的值
#!/bin/sh
#
# This is the preinst script for the Blue Tang Servers
#
# Written by Yung-Lin Ho yho@bluetangstudio.com

set -e
USER=locadz-backend
SCRIPT=/etc/init.d/$USER


case "$1" in
upgrade|remove|purge)
$SCRIPT stop
;;
install|failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "preinst called with unknown argument \`$1'" >&2
;;
esac

exit 0
下面這塊存成 src/main/unix/scripts/pre-remove,並修改 USER=locadz-backend 這一行成跟你 ${service.user} 一樣的值
#!/bin/sh
#
# This is the prerm script for the Blue Tang Servers
#
# Written by Yung-Lin Ho yho@bluetangstudio.com

set -e
USER=locadz-backend
SCRIPT=/etc/init.d/$USER

case "$1" in
upgrade)
;;
remove|purge)
$SCRIPT stop
;;
failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
;;
esac

exit 0
</div>