FELIX-1970: the stop script should always work even if the default user / password / host has been changed
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@900408 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/assembly/src/main/distribution/unix-shell/bin/karaf b/karaf/assembly/src/main/distribution/unix-shell/bin/karaf
index 86137e6..d0af57b 100755
--- a/karaf/assembly/src/main/distribution/unix-shell/bin/karaf
+++ b/karaf/assembly/src/main/distribution/unix-shell/bin/karaf
@@ -266,7 +266,12 @@
run() {
OPTS="-Dkaraf.startLocalConsole=true -Dkaraf.startRemoteShell=true"
+ MAIN=org.apache.felix.karaf.main.Bootstrap
case "$1" in
+ 'stop')
+ MAIN=org.apache.felix.karaf.main.Stop
+ shift
+ ;;
'console')
shift
;;
@@ -286,7 +291,7 @@
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
fi
cd $KARAF_BASE
- exec $JAVA $JAVA_OPTS -Dstorage.location="${KARAF_HOME}/instances" -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Djava.util.logging.config.file=$KARAF_BASE/etc/java.util.logging.properties $OPTS -classpath "$CLASSPATH" org.apache.felix.karaf.main.Bootstrap "$@"
+ exec $JAVA $JAVA_OPTS -Dstorage.location="${KARAF_HOME}/instances" -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Djava.util.logging.config.file=$KARAF_BASE/etc/java.util.logging.properties $OPTS -classpath "$CLASSPATH" $MAIN "$@"
}
main() {
diff --git a/karaf/assembly/src/main/distribution/unix-shell/bin/stop b/karaf/assembly/src/main/distribution/unix-shell/bin/stop
index 017e41d..dd6dfc2 100755
--- a/karaf/assembly/src/main/distribution/unix-shell/bin/stop
+++ b/karaf/assembly/src/main/distribution/unix-shell/bin/stop
@@ -21,20 +21,6 @@
DIRNAME=`dirname $0`
PROGNAME=`basename $0`
-#
-# Check/Set up some easily accessible MIN/MAX params for JVM mem usage
-#
-
-if [ "x$JAVA_MIN_MEM" = "x" ]; then
- JAVA_MIN_MEM=128M
- export JAVA_MIN_MEM
-fi
-
-if [ "x$JAVA_MAX_MEM" = "x" ]; then
- JAVA_MAX_MEM=512M
- export JAVA_MAX_MEM
-fi
-
warn() {
echo "${PROGNAME}: $*"
}
@@ -44,13 +30,6 @@
exit 1
}
-maybeSource() {
- file="$1"
- if [ -f "$file" ] ; then
- . $file
- fi
-}
-
detectOS() {
# OS specific support (must be 'true' or 'false').
cygwin=false;
@@ -79,34 +58,6 @@
fi
}
-unlimitFD() {
- # Use the maximum available, or set MAX_FD != -1 to use that
- if [ "x$MAX_FD" = "x" ]; then
- MAX_FD="maximum"
- fi
-
- # Increase the maximum file descriptors if we can
- if [ "$os400" = "false" ] && [ "$cygwin" = "false" ]; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ "$MAX_FD_LIMIT" != 'unlimited' ]; then
- if [ $? -eq 0 ]; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; then
- # use the system max
- MAX_FD="$MAX_FD_LIMIT"
- fi
-
- ulimit -n $MAX_FD > /dev/null
- # echo "ulimit -n" `ulimit -n`
- if [ $? -ne 0 ]; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query system maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
- fi
- fi
-}
-
locateHome() {
if [ "x$KARAF_HOME" != "x" ]; then
warn "Ignoring predefined value for KARAF_HOME"
@@ -131,137 +82,15 @@
fi
}
-setupNativePath() {
- # Support for loading native libraries
- LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:$KARAF_BASE/lib:$KARAF_HOME/lib"
-
- # For Cygwin, set PATH from LD_LIBRARY_PATH
- if $cygwin; then
- LD_LIBRARY_PATH=`cygpath --path --windows "$LD_LIBRARY_PATH"`
- PATH="$PATH;$LD_LIBRARY_PATH"
- export PATH
- fi
- export LD_LIBRARY_PATH
-}
-
-locateJava() {
- # Setup the Java Virtual Machine
- if $cygwin ; then
- [ -n "$JAVA" ] && JAVA=`cygpath --unix "$JAVA"`
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
- fi
-
- if [ "x$JAVA" = "x" ]; then
- if [ "x$JAVA_HOME" = "x" ] && [ "$darwin" = "true" ]; then
- JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home
- fi
- if [ "x$JAVA_HOME" != "x" ]; then
- if [ ! -d "$JAVA_HOME" ]; then
- die "JAVA_HOME is not valid: $JAVA_HOME"
- fi
- JAVA="$JAVA_HOME/bin/java"
- else
- warn "JAVA_HOME not set; results may vary"
- JAVA="java"
- fi
- fi
-}
-
-detectJVM() {
- #echo "`$JAVA -version`"
- # This service should call `java -version`,
- # read stdout, and look for hints
- if $JAVA -version 2>&1 | grep "^IBM" ; then
- JVM_VENDOR="IBM"
- # on OS/400, java -version does not contain IBM explicitly
- elif $os400; then
- JVM_VENDOR="IBM"
- else
- JVM_VENDOR="SUN"
- fi
- # echo "JVM vendor is $JVM_VENDOR"
-}
-
-setupDebugOptions() {
- if [ "x$JAVA_OPTS" = "x" ]; then
- JAVA_OPTS="$DEFAULT_JAVA_OPTS"
- fi
- export JAVA_OPTS
-
- # Set Debug options if enabled
- if [ "x$KARAF_DEBUG" != "x" ]; then
- # Use the defaults if JAVA_DEBUG_OPTS was not set
- if [ "x$JAVA_DEBUG_OPTS" = "x" ]; then
- JAVA_DEBUG_OPTS="$DEFAULT_JAVA_DEBUG_OPTS"
- fi
-
- JAVA_OPTS="$JAVA_DEBUG_OPTS $JAVA_OPTS"
- warn "Enabling Java debug options: $JAVA_DEBUG_OPTS"
- fi
-}
-
-setupDefaults() {
- DEFAULT_JAVA_OPTS="-Xms$JAVA_MIN_MEM -Xmx$JAVA_MAX_MEM "
-
- #Set the JVM_VENDOR specific JVM flags
- if [ "$JVM_VENDOR" = "SUN" ]; then
- DEFAULT_JAVA_OPTS="-server $DEFAULT_JAVA_OPTS -Dcom.sun.management.jmxremote"
- elif [ "$JVM_VENDOR" = "IBM" ]; then
- if $os400; then
- DEFAULT_JAVA_OPTS="$DEFAULT_JAVA_OPTS"
- elif $aix; then
- DEFAULT_JAVA_OPTS="-Xverify:none -Xlp $DEFAULT_JAVA_OPTS"
- else
- DEFAULT_JAVA_OPTS="-Xverify:none $DEFAULT_JAVA_OPTS"
- fi
- fi
-
- # Add the jars in the lib dir
- for file in $KARAF_HOME/lib/*.jar
- do
- if [ -z "$CLASSPATH" ]; then
- CLASSPATH="$file"
- else
- CLASSPATH="$CLASSPATH:$file"
- fi
- done
- DEFAULT_JAVA_DEBUG_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"
-
- ##
- ## TODO: Move to conf/profiler/yourkit.{sh|cmd}
- ##
- # Uncomment to enable YourKit profiling
- #DEFAULT_JAVA_DEBUG_OPTS="-Xrunyjpagent"
-}
-
init() {
# Determine if there is special OS handling we must perform
detectOS
- # Unlimit the number of file descriptors if possible
- unlimitFD
-
# Locate the Karaf home directory
locateHome
# Locate the Karaf base directory
locateBase
-
- # Setup the native library path
- setupNativePath
-
- # Locate the Java VM to execute
- locateJava
-
- # Determine the JVM vendor
- detectJVM
-
- # Setup default options
- setupDefaults
-
- # Install debug options
- setupDebugOptions
-
}
run() {
@@ -270,7 +99,11 @@
KARAF_BASE=`cygpath --path --windows "$KARAF_BASE"`
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
fi
- exec $JAVA $JAVA_OPTS -Dkaraf.home="$KARAF_HOME" -Dkaraf.base="$KARAF_BASE" -Djava.util.logging.config.file=$KARAF_BASE/etc/java.util.logging.properties -jar "$KARAF_HOME/lib/karaf-client.jar" osgi:shutdown "$@"
+ # Ensure the log directory exists -- we need to have a place to redirect stdout/stderr
+ if [ ! -d "$KARAF_HOME/data/log" ]; then
+ mkdir -p "$KARAF_HOME/data/log"
+ fi
+ exec "$KARAF_HOME"/bin/karaf stop "$@"
}
main() {
@@ -279,3 +112,4 @@
}
main "$@"
+
diff --git a/karaf/assembly/src/main/distribution/windows-text/bin/karaf.bat b/karaf/assembly/src/main/distribution/windows-text/bin/karaf.bat
index 5eb74ea..c8c3e7a 100755
--- a/karaf/assembly/src/main/distribution/windows-text/bin/karaf.bat
+++ b/karaf/assembly/src/main/distribution/windows-text/bin/karaf.bat
@@ -128,12 +128,19 @@
:RUN
SET OPTS=-Dkaraf.startLocalConsole=true -Dkaraf.startRemoteShell=true
+ SET MAIN=org.apache.felix.karaf.main.Bootstrap
SET SHIFT=false
+ if "%1" == "stop" goto :EXECUTE_STOP
if "%1" == "console" goto :EXECUTE_CONSOLE
if "%1" == "server" goto :EXECUTE_SERVER
if "%1" == "client" goto :EXECUTE_CLIENT
goto :EXECUTE
+:EXECUTE_STOP
+ SET MAIN=org.apache.felix.karaf.main.Stop
+ SET SHIFT=true
+ goto :EXECUTE
+
:EXECUTE_CONSOLE
SET SHIFT=true
goto :EXECUTE
diff --git a/karaf/assembly/src/main/distribution/windows-text/bin/stop.bat b/karaf/assembly/src/main/distribution/windows-text/bin/stop.bat
index 7db1ea6..3b875cd 100755
--- a/karaf/assembly/src/main/distribution/windows-text/bin/stop.bat
+++ b/karaf/assembly/src/main/distribution/windows-text/bin/stop.bat
@@ -16,9 +16,9 @@
rem See the License for the specific language governing permissions and
rem limitations under the License.
rem
-rem
+rem
rem $Id: karaf.bat 979 2005-11-30 22:50:55Z bsnyder $
-rem
+rem
if not "%ECHO%" == "" echo %ECHO%
@@ -58,77 +58,8 @@
set KARAF_BASE=%KARAF_HOME%
)
-set LOCAL_CLASSPATH=%CLASSPATH%
-set DEFAULT_JAVA_OPTS=-server -Xmx512M -Dderby.system.home="%KARAF_BASE%\data\derby" -Dderby.storage.fileSyncTransactionLog=true -Dcom.sun.management.jmxremote
-set CLASSPATH=%LOCAL_CLASSPATH%;%KARAF_BASE%\conf
-set DEFAULT_JAVA_DEBUG_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005
-
-if "%LOCAL_CLASSPATH%" == "" goto :KARAF_CLASSPATH_EMPTY
- set CLASSPATH=%LOCAL_CLASSPATH%;%KARAF_BASE%\conf
- goto :KARAF_CLASSPATH_END
-:KARAF_CLASSPATH_EMPTY
- set CLASSPATH=%KARAF_BASE%\conf
-:KARAF_CLASSPATH_END
-
-rem Setup Karaf Home
-if exist "%KARAF_HOME%\conf\karaf-rc.cmd" call %KARAF_HOME%\conf\karaf-rc.cmd
-if exist "%HOME%\karaf-rc.cmd" call %HOME%\karaf-rc.cmd
-
-rem Support for loading native libraries
-set PATH=%PATH%;%KARAF_BASE%\lib;%KARAF_HOME%\lib
-
-rem Setup the Java Virtual Machine
-if not "%JAVA%" == "" goto :Check_JAVA_END
- set JAVA=java
- if "%JAVA_HOME%" == "" call :warn JAVA_HOME not set; results may vary
- if not "%JAVA_HOME%" == "" set JAVA=%JAVA_HOME%\bin\java
- if not exist "%JAVA_HOME%" (
- call :warn JAVA_HOME is not valid: "%JAVA_HOME%"
- goto END
- )
-:Check_JAVA_END
-
-if "%JAVA_OPTS%" == "" set JAVA_OPTS=%DEFAULT_JAVA_OPTS%
-
-if "%KARAF_DEBUG%" == "" goto :KARAF_DEBUG_END
- rem Use the defaults if JAVA_DEBUG_OPTS was not set
- if "%JAVA_DEBUG_OPTS%" == "" set JAVA_DEBUG_OPTS=%DEFAULT_JAVA_DEBUG_OPTS%
-
- set "JAVA_OPTS=%JAVA_DEBUG_OPTS% %JAVA_OPTS%"
- call :warn Enabling Java debug options: %JAVA_DEBUG_OPTS%
-:KARAF_DEBUG_END
-
-if "%KARAF_PROFILER%" == "" goto :KARAF_PROFILER_END
- set KARAF_PROFILER_SCRIPT=%KARAF_HOME%\conf\profiler\%KARAF_PROFILER%.cmd
-
- if exist "%KARAF_PROFILER_SCRIPT%" goto :KARAF_PROFILER_END
- call :warn Missing configuration for profiler '%KARAF_PROFILER%': %KARAF_PROFILER_SCRIPT%
- goto END
-:KARAF_PROFILER_END
-
-rem Setup the classpath
-pushd "%KARAF_HOME%\lib"
-for %%G in (*.*) do call:APPEND_TO_CLASSPATH %%G
-popd
-goto CLASSPATH_END
-
-: APPEND_TO_CLASSPATH
-set filename=%~1
-set suffix=%filename:~-4%
-if %suffix% equ .jar set CLASSPATH=%CLASSPATH%;%KARAF_HOME%\lib\%filename%
-goto :EOF
-
-:CLASSPATH_END
-
-rem Execute the JVM or the load the profiler
-if "%KARAF_PROFILER%" == "" goto :RUN
- rem Execute the profiler if it has been configured
- call :warn Loading profiler script: %KARAF_PROFILER_SCRIPT%
- call %KARAF_PROFILER_SCRIPT%
-
-:RUN
- rem Execute the Java Virtual Machine
- "%JAVA%" %JAVA_OPTS% %OPTS% -classpath "%CLASSPATH%" -Dkaraf.home="%KARAF_HOME%" -Dkaraf.base="%KARAF_BASE%" -Djava.util.logging.config.file="%KARAF_BASE%\etc\java.util.logging.properties" -jar "%KARAF_HOME%\lib\karaf-client.jar" "osgi:shutdown" %ARGS%
+:EXECUTE
+ "%KARAF_HOME%\bin\karaf.bat" stop
rem # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -138,5 +69,4 @@
if not "%PAUSE%" == "" pause
-:END_NO_PAUSE
-
+:END_NO_PAUSE
\ No newline at end of file
diff --git a/karaf/assembly/src/main/filtered-resources/etc/config.properties b/karaf/assembly/src/main/filtered-resources/etc/config.properties
index 5cc8009..12c599f 100644
--- a/karaf/assembly/src/main/filtered-resources/etc/config.properties
+++ b/karaf/assembly/src/main/filtered-resources/etc/config.properties
@@ -51,6 +51,8 @@
org.osgi.framework.startlevel.beginning=100
karaf.startlevel.bundle=60
+karaf.shutdown.port.file=${karaf.base}/data/port
+
#
# FileMonitor properties
#
diff --git a/karaf/main/src/main/java/org/apache/felix/karaf/main/Main.java b/karaf/main/src/main/java/org/apache/felix/karaf/main/Main.java
index c983110..0646a15 100644
--- a/karaf/main/src/main/java/org/apache/felix/karaf/main/Main.java
+++ b/karaf/main/src/main/java/org/apache/felix/karaf/main/Main.java
@@ -18,18 +18,16 @@
*/
package org.apache.felix.karaf.main;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.BufferedReader;
+import java.io.*;
import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.net.InetAddress;
import java.net.MalformedURLException;
+import java.net.ServerSocket;
+import java.net.Socket;
import java.net.URL;
import java.net.URLClassLoader;
+import java.security.AccessControlException;
import java.security.Provider;
import java.security.Security;
import java.util.ArrayList;
@@ -38,11 +36,13 @@
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
+import java.util.Random;
import java.util.StringTokenizer;
+import java.util.logging.Level;
import java.util.logging.Logger;
-import java.util.concurrent.CountDownLatch;
import java.lang.reflect.Method;
-import java.lang.reflect.Constructor;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.apache.felix.karaf.main.Utils;
import org.osgi.framework.Bundle;
@@ -134,6 +134,18 @@
public static final String KARAF_FRAMEWORK = "karaf.framework";
+ public static final String KARAF_SHUTDOWN_PORT = "karaf.shutdown.port";
+
+ public static final String KARAF_SHUTDOWN_HOST = "karaf.shutdown.host";
+
+ public static final String KARAF_SHUTDOWN_PORT_FILE = "karaf.shutdown.port.file";
+
+ public static final String KARAF_SHUTDOWN_COMMAND = "karaf.shutdown.command";
+
+ public static final String KARAF_SHUTDOWN_PID_FILE = "karaf.shutdown.pid.file";
+
+ public static final String DEFAULT_SHUTDOWN_COMMAND = "SHUTDOWN";
+
public static final String PROPERTY_LOCK_CLASS_DEFAULT = SimpleFileLock.class.getName();
Logger LOG = Logger.getLogger(this.getClass().getName());
@@ -166,7 +178,7 @@
System.setProperty(PROP_KARAF_BASE, karafBase.getPath());
// Load system properties.
- loadSystemProperties();
+ loadSystemProperties(karafBase);
updateInstancePid();
@@ -654,7 +666,7 @@
* arbitrary URL.
* </p>
*/
- private void loadSystemProperties() {
+ protected static void loadSystemProperties(File karafBase) {
// The system properties file is either specified by a system
// property or it is in the same directory as the Felix JAR file.
// Try to load it from one of these places.
@@ -794,7 +806,7 @@
return configProps;
}
- private static Properties loadPropertiesFile(URL configPropURL) throws Exception {
+ protected static Properties loadPropertiesFile(URL configPropURL) throws Exception {
// Read the properties file.
Properties configProps = new Properties();
InputStream is = null;
@@ -823,7 +835,7 @@
return configProps;
}
- private static void copySystemProperties(Properties configProps) {
+ protected static void copySystemProperties(Properties configProps) {
for (Enumeration e = System.getProperties().propertyNames();
e.hasMoreElements();) {
String key = (String) e.nextElement();
@@ -1111,6 +1123,7 @@
if (lockLogged) {
LOG.info("Lock acquired.");
}
+ setupShutdown(props);
setStartLevel(defaultStartLevel);
for (;;) {
if (!lock.isAlive()) {
@@ -1150,4 +1163,120 @@
sl.setStartLevel(level);
}
+
+ private Random random = null;
+ private ServerSocket shutdownSocket;
+
+ protected void setupShutdown(Properties props) {
+ try {
+ String pidFile = props.getProperty(KARAF_SHUTDOWN_PID_FILE);
+ if (pidFile != null) {
+ RuntimeMXBean rtb = ManagementFactory.getRuntimeMXBean();
+ String processName = rtb.getName();
+ Pattern pattern = Pattern.compile("^([0-9]+)@.+$", Pattern.CASE_INSENSITIVE);
+ Matcher matcher = pattern.matcher(processName);
+ if (matcher.matches()) {
+ int pid = Integer.parseInt(matcher.group(1));
+ Writer w = new OutputStreamWriter(new FileOutputStream(pidFile));
+ w.write(Integer.toString(pid));
+ w.close();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ int port = Integer.parseInt(props.getProperty(KARAF_SHUTDOWN_PORT, "0"));
+ String host = props.getProperty(KARAF_SHUTDOWN_HOST, "localhost");
+ String portFile = props.getProperty(KARAF_SHUTDOWN_PORT_FILE);
+ final String shutdown = props.getProperty(KARAF_SHUTDOWN_COMMAND, DEFAULT_SHUTDOWN_COMMAND);
+ if (port >= 0) {
+ shutdownSocket = new ServerSocket(port, 1, InetAddress.getByName(host));
+ if (port == 0) {
+ port = shutdownSocket.getLocalPort();
+ }
+ if (portFile != null) {
+ Writer w = new OutputStreamWriter(new FileOutputStream(portFile));
+ w.write(Integer.toString(port));
+ w.close();
+ }
+ Thread thread = new Thread() {
+ public void run() {
+ try {
+ while (true) {
+ // Wait for the next connection
+ Socket socket = null;
+ InputStream stream = null;
+ try {
+ socket = shutdownSocket.accept();
+ socket.setSoTimeout(10 * 1000); // Ten seconds
+ stream = socket.getInputStream();
+ } catch (AccessControlException ace) {
+ LOG.log(Level.WARNING, "Karaf shutdown socket: security exception: "
+ + ace.getMessage(), ace);
+ continue;
+ } catch (IOException e) {
+ LOG.log(Level.SEVERE, "Karaf shutdown socket: accept: ", e);
+ System.exit(1);
+ }
+
+ // Read a set of characters from the socket
+ StringBuilder command = new StringBuilder();
+ int expected = 1024; // Cut off to avoid DoS attack
+ while (expected < shutdown.length()) {
+ if (random == null) {
+ random = new Random();
+ }
+ expected += (random.nextInt() % 1024);
+ }
+ while (expected > 0) {
+ int ch = -1;
+ try {
+ ch = stream.read();
+ } catch (IOException e) {
+ LOG.log(Level.WARNING, "Karaf shutdown socket: read: ", e);
+ ch = -1;
+ }
+ if (ch < 32) { // Control character or EOF terminates loop
+ break;
+ }
+ command.append((char) ch);
+ expected--;
+ }
+
+ // Close the socket now that we are done with it
+ try {
+ socket.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+
+ // Match against our command string
+ boolean match = command.toString().equals(shutdown);
+ if (match) {
+ framework.stop();
+ break;
+ } else {
+ LOG.log(Level.WARNING, "Karaf shutdown socket: Invalid command '" +
+ command.toString() + "' received");
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ shutdownSocket.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ };
+ thread.setDaemon(true);
+ thread.start();
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
}
diff --git a/karaf/main/src/main/java/org/apache/felix/karaf/main/Stop.java b/karaf/main/src/main/java/org/apache/felix/karaf/main/Stop.java
new file mode 100644
index 0000000..b3c9b2c
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/felix/karaf/main/Stop.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.karaf.main;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.net.Socket;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * Main class used to stop the root Karaf instance
+ */
+public class Stop {
+
+ public static void main(String[] args) throws Exception {
+ File karafHome = Utils.getKarafHome();
+ File karafBase = Utils.getKarafBase(karafHome);
+
+ System.setProperty(Main.PROP_KARAF_HOME, karafHome.getPath());
+ System.setProperty(Main.PROP_KARAF_BASE, karafBase.getPath());
+
+ // Load system properties.
+ Main.loadSystemProperties(karafBase);
+
+ File file = new File(new File(karafBase, "etc"), Main.CONFIG_PROPERTIES_FILE_NAME);
+ URL configPropURL = file.toURI().toURL();
+ Properties props = Main.loadPropertiesFile(configPropURL);
+ Main.copySystemProperties(props);
+
+ // Perform variable substitution for system properties.
+ for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
+ String name = (String) e.nextElement();
+ props.setProperty(name,
+ Main.substVars(props.getProperty(name), name, null, props));
+ }
+
+ int port = Integer.parseInt(props.getProperty(Main.KARAF_SHUTDOWN_PORT, "0"));
+ String host = props.getProperty(Main.KARAF_SHUTDOWN_HOST, "localhost");
+ String portFile = props.getProperty(Main.KARAF_SHUTDOWN_PORT_FILE);
+ String shutdown = props.getProperty(Main.KARAF_SHUTDOWN_COMMAND, Main.DEFAULT_SHUTDOWN_COMMAND);
+ if (port == 0 && portFile != null) {
+ BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(portFile)));
+ String portStr = r.readLine();
+ port = Integer.parseInt(portStr);
+ r.close();
+ }
+ if (port > 0) {
+ Socket s = new Socket(host, port);
+ s.getOutputStream().write(shutdown.getBytes());
+ s.close();
+ } else {
+ System.err.println("Unable to find port...");
+ }
+
+ }
+}