//
// Licensed 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.
//

=== Integration in the operating system

In the previous chapter, we saw the different scripts and commands to start, stop, restart Apache Karaf.

Instead of using these commands and scripts, you can integrate Apache Karaf directly in your operating system service control using:

* <<Service Wrapper>>
* <<Service Script Templates>>

The above methods allow you to directly integrate Apache Karaf:

* like a native Windows Service
* like a Unix daemon process

==== Service Wrapper

The "Service Wrapper" correctly handles "user log outs" under Windows, service dependencies, and the ability to run services which interact with the desktop.

It also includes advanced fault detection software which monitors an application.
The "Service Wrapper" is able to detect crashes, freezes, out of memory and other exception events, then automatically react by restarting Apache Karaf with a minimum of delay.
It guarantees the maximum possible uptime of Apache Karaf.

===== Supported platforms

* Windows 8, 7, 2008 R2, 2003, Vista (32 and 64 bits architecture)
* Linux RedHat Enterprise Linux, Debian, CentOS, Fedora, Ubuntu (32 and 64 bits architecture)
* FreeBSD 9.x, 8.x
* AIX 5.x, 6.x, 7.x (Power architecture)
* Solaris 8, 9, 10 (x86/Sparc, 32 and 64 bits architecture)
* HP-UX 10.x, 11.x (32 and 64 bits architecture)
* SGI Irix
* MacOS X

===== Installation

Apache Karaf Service Wrapper is an optional feature. You have to install the "Service Wrapper" installer first.

In the console:

----
karaf@root()> feature:install service-wrapper
----

Now, you have the `wrapper:install` command, to "register" Apache Karaf as service/daemon on your system:

----
karaf@root()> wrapper:install --help
DESCRIPTION
        wrapper:install

        Install the container as a system service in the OS.

SYNTAX
        wrapper:install [options]

OPTIONS
        -d, --display
                The display name of the service.
                (defaults to karaf)
        --help
                Display this help message
        -s, --start-type
                Mode in which the service is installed. AUTO_START or DEMAND_START (Default: AUTO_START)
                (defaults to AUTO_START)
        -n, --name
                The service name that will be used when installing the service. (Default: karaf)
                (defaults to karaf)
        -D, --description
                The description of the service.
                (defaults to )
----

The `wrapper:install` command detects the running Operating Service and provides the service/daemon ready to be integrated in your system.

For instance, on a Ubuntu/Debian Linux system:

----
karaf@root()> wrapper:install
Creating file: /opt/apache-karaf-4.0.0/bin/karaf-wrapper
Creating file: /opt/apache-karaf-4.0.0/bin/karaf-service
Creating file: /opt/apache-karaf-4.0.0/etc/karaf-wrapper.conf
Creating missing directory: /opt/apache-karaf-4.0.0/lib/wrapper
Creating file: /opt/apache-karaf-4.0.0/lib/wrapper/libwrapper.so
Creating file: /opt/apache-karaf-4.0.0/lib/wrapper/karaf-wrapper.jar
Creating file: /opt/apache-karaf-4.0.0/lib/wrapper/karaf-wrapper-main.jar

Setup complete.  You may wish to tweak the JVM properties in the wrapper configuration file:
        /opt/apache-karaf-4.0.0/etc/karaf-wrapper.conf
before installing and starting the service.


Ubuntu/Debian Linux system detected:
  To install the service:
    $ ln -s /opt/apache-karaf-4.0.0/bin/karaf-service /etc/init.d/

  To start the service when the machine is rebooted:
    $ update-rc.d karaf-service defaults

  To disable starting the service when the machine is rebooted:
    $ update-rc.d -f karaf-service remove

  To start the service:
    $ /etc/init.d/karaf-service start

  To stop the service:
    $ /etc/init.d/karaf-service stop

  To uninstall the service :
    $ rm /etc/init.d/karaf-service

----

[NOTE]
====
You can install the wrapper without starting Karaf using bin/shell wrapper:install command.
====

You can note that `wrapper:install` command detected the running operating system ("Ubuntu/Debian Linux system detected").

You have a complete explanation and list of system commands to perform to integrate Apache Karaf in your systemV:

----
ln -s /opt/apache-karaf-4.0.0/bin/karaf-service /etc/init.d/
update-rc.d karaf-service defaults
----

Karaf also supports the systemd service, so you can use systemctl instead of a SystemV based service:

----
systemctl enable /opt/apache-karaf-4.0.2/bin/karaf.service
----

This will enable Karaf at system boot.

===== Uninstall

The `wrapper:install` provides the system commands to perform to uninstall the service/daemon.

For instance, on Ubuntu/Debian, to uninstall the Apache Karaf service, you have to remove the `karaf-service` script from the runlevel scripts:

----
rm /etc/init.d/karaf-service
----

If you preferred the systemd service instead of systemV:

----
systemctl disable karaf
----

You can remove the "Wrapper Service" installer after that:

----
karaf@root()> feature:uninstall service-wrapper
----

===== Note for MacOS users

On MacOS you can install the service for a user or for the system.

If you want to add `bin/org.apache.karaf.KARAF` as user service move this file into `~/Library/LaunchAgents/`:

----
mv bin/org.apache.karaf.KARAF.plist ~/Library/LaunchAgents/
----

If you want to add org.apache.karaf.KARAF as system service move this into /Library/LaunchDaemons:

----
sudo mv bin/org.apache.karaf.KARAF.plist /Library/LaunchDaemons/
----

Change owner and rights:

----
sudo chown root:wheel /Library/LaunchDaemons/org.apache.karaf.KARAF.plist
sudo chmod u=rw,g=r,o=r /Library/LaunchDaemons/org.apache.karaf.KARAF.plist
----

You can test your service:

----
launchctl load ~/Library/LaunchAgents/org.apache.karaf.KARAF.plist
launchctl start org.apache.karaf.KARAF
launchctl stop org.apache.karaf.KARAF
----

Finally, after restart your session or system you can use launchctl command to start and stop your service.

If you want to remove the service call:

----
launchctl remove org.apache.karaf.KARAF
----

===== Configuration

When using scripts in the Apache Karaf `bin` folder, you can using `bin/setenv` Unix script (`bin\setenv.bat` on Windows) as described in the [Start, stop, restart, connect|start-stop] section of the documentation.

[NOTE]
====
The `bin/setenv` Unix script (`bin\setenv.bat` on Windows) is not used by the Apache Karaf Service Wrapper.
====

To configure Apache Karaf started by the Service Wrapper, you have to tune the `etc/karaf-wrapper.conf` file. If you provided the `name` option to the `wrapper:install` command, the file is `etc/karaf-yourname.conf`.

In this file, you can configure the different environment variables used by Apache Karaf. The Service Wrapper installer automatically populates these variables for you during the installation (using `wrapper:install` command).
For instance:

* `set.default.JAVA_HOME` is the `JAVA_HOME` used to start Apache Karaf (populated during Service Wrapper installation).
* `set.default.KARAF_HOME` is the location of your Apache Karaf installation (populated during Service Wrapper installation).
* `set.default.KARAF_BASE` is the location of your Apache Karaf installation (populated during Service Wrapper installation).
* `set.default.KARAF_DATA` is the location of the Apache Karaf data folder (populated during Service Wrapper installation).
* `set.default.KARAF_ETC` is the location of the Apache Karaf etc folder (populated during Service Wrapper installation).
* `wrapper.java.additional` is used to pass additional arguments to the Java command, indexed by the argument number. The next index to use is 11.
* `wrapper.java.initmemory` is the initial JVM memory size (the `-Xms`). It's not set by default (JVM default).
* `wrapper.java.maxmemory` is the maximum JVM memory size (the `-Xmx`). It's set to 512M by default.
* `wrapper.logfile` is the location of the Service Wrapper log file. It's set to `%KARAF_DATA%/log/wrapper.log` by default.
* `wrapper.logfile.loglevel` is the Service Wrapper log level. It's set to `INFO` by default.
* `wrapper.logfile.maxsize` is the Service Wrapper log file maximum size (before rotation). It's set to `10m` (10MB) by default.
* `wrapper.logfile.maxfiles` is the number of Service Wrapper log files created (and rotated). It's set to `5` by default.
* `wrapper.syslog.loglevel` is the integration with Unix syslog daemon. By default, it's set to `none` meaning disabled.
* `wrapper.ntservice.name` is Windows service specific and defines the Windows service name. It's set to the `name` option of the `wrapper:install` command, or `karaf` by default.
* `wrapper.ntservice.displayname` is Windows service specific and defines the Windows service display name. It's set to the `display` option of the `wrapper:install` command, or `karaf` by default.
* `wrapper.ntservice.description` is Windows service specific and defines the Windows service description. It's set to the `description` option of the `wrapper:install` command, or empty by default.
* `wrapper.ntservice.starttype` is Windows service specific and defines if the Windows service is started automatically with the service, or just on demand. It's set to `AUTO_START` by default, and could be switched to `DEMAND_START`.

This is a example of the generated `etc/karaf-wrapper.conf` file:

----
# ------------------------------------------------------------------------
# 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.
# ------------------------------------------------------------------------

#********************************************************************
# Wrapper Properties
#********************************************************************
set.default.JAVA_HOME=/opt/jdk/1.7.0_21
set.default.KARAF_HOME=/opt/apache-karaf-4.0.0
set.default.KARAF_BASE=/opt/apache-karaf-4.0.0
set.default.KARAF_DATA=/opt/apache-karaf-4.0.0/data
set.default.KARAF_ETC=/opt/apache-karaf-4.0.0/etc

# Java Application
wrapper.working.dir=%KARAF_BASE%
wrapper.java.command=%JAVA_HOME%/bin/java
wrapper.java.mainclass=org.apache.karaf.wrapper.internal.Main
wrapper.java.classpath.1=%KARAF_HOME%/lib/karaf-wrapper.jar
wrapper.java.classpath.2=%KARAF_HOME%/lib/karaf.jar
wrapper.java.classpath.3=%KARAF_HOME%/lib/karaf-jaas-boot.jar
wrapper.java.classpath.4=%KARAF_HOME%/lib/karaf-wrapper-main.jar
wrapper.java.classpath.5=%KARAF_HOME%/lib/karaf-org.osgi.core.jar
wrapper.java.library.path.1=%KARAF_HOME%/lib/

# Application Parameters.  Add parameters as needed starting from 1
#wrapper.app.parameter.1=

# JVM Parameters
# note that n is the parameter number starting from 1.
wrapper.java.additional.1=-Dkaraf.home=%KARAF_HOME%
wrapper.java.additional.2=-Dkaraf.base=%KARAF_BASE%
wrapper.java.additional.3=-Dkaraf.data=%KARAF_DATA%
wrapper.java.additional.4=-Dkaraf.etc=%KARAF_ETC%
wrapper.java.additional.5=-Dkaraf.startLocalConsole=false
wrapper.java.additional.6=-Dkaraf.startRemoteShell=true
wrapper.java.additional.7=-Djava.io.tmpdir=%KARAF_DATA%/tmp
# Uncomment if you need libraries on Java 8
#wrapper.java.additional.9=-Djava.endorsed.dirs=%JAVA_HOME%/jre/lib/endorsed:%JAVA_HOME%/lib/endorsed:%KARAF_HOME%/lib/endorsed
#wrapper.java.additional.10=-Djava.ext.dirs=%JAVA_HOME%/jre/lib/ext:%JAVA_HOME%/lib/ext:%KARAF_HOME%/lib/ext

# Uncomment to enable jmx
#wrapper.java.additional.n=-Dcom.sun.management.jmxremote.port=1616
#wrapper.java.additional.n=-Dcom.sun.management.jmxremote.authenticate=false
#wrapper.java.additional.n=-Dcom.sun.management.jmxremote.ssl=false

# Uncomment to enable YourKit profiling
#wrapper.java.additional.n=-Xrunyjpagent

# Uncomment to enable remote debugging
#wrapper.java.additional.n=-Xdebug -Xnoagent -Djava.compiler=NONE
#wrapper.java.additional.n=-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005

# Initial Java Heap Size (in MB)
#wrapper.java.initmemory=3

# Maximum Java Heap Size (in MB)
wrapper.java.maxmemory=512


#********************************************************************
# Wrapper Logging Properties
#********************************************************************
# Format of output for the console.  (See docs for formats)
wrapper.console.format=PM

# Log Level for console output.  (See docs for log levels)
wrapper.console.loglevel=INFO

# Log file to use for wrapper output logging.
wrapper.logfile=%KARAF_DATA%/log/wrapper.log

# Format of output for the log file.  (See docs for formats)
wrapper.logfile.format=LPTM

# Log Level for log file output.  (See docs for log levels)
wrapper.logfile.loglevel=INFO

# Maximum size that the log file will be allowed to grow to before
#  the log is rolled. Size is specified in bytes.  The default value
#  of 0, disables log rolling.  May abbreviate with the 'k' (kb) or
#  'm' (mb) suffix.  For example: 10m = 10 megabytes.
wrapper.logfile.maxsize=10m

# Maximum number of rolled log files which will be allowed before old
#  files are deleted.  The default value of 0 implies no limit.
wrapper.logfile.maxfiles=5

# Log Level for sys/event log output.  (See docs for log levels)
wrapper.syslog.loglevel=NONE

#********************************************************************
# Wrapper Windows Properties
#********************************************************************
# Title to use when running as a console
wrapper.console.title=karaf

#********************************************************************
# Wrapper Windows NT/2000/XP Service Properties
#********************************************************************
# WARNING - Do not modify any of these properties when an application
#  using this configuration file has been installed as a service.
#  Please uninstall the service before modifying this section.  The
#  service can then be reinstalled.

# Name of the service
wrapper.ntservice.name=karaf

# Display name of the service
wrapper.ntservice.displayname=karaf

# Description of the service
wrapper.ntservice.description=

# Service dependencies.  Add dependencies as needed starting from 1
wrapper.ntservice.dependency.1=

# Mode in which the service is installed.  AUTO_START or DEMAND_START
wrapper.ntservice.starttype=AUTO_START

# Allow the service to interact with the desktop.
wrapper.ntservice.interactive=false
----

==== Service Script Templates

By using the "Service Script Templates", you can run Apache Karaf with the help of operating system specific init scripts.

[NOTE]
====
As opposed to the Service Wrapper, the templates targeting Unix systems do not rely on 3rd party binaries
====

You can find these templates under the bin/contrib directory.

{nbsp} +

===== Unix

The karaf-service.sh utility helps you to generate ready to use scripts by automatically identifying the operating system, the default init system and the template to use.

[NOTE]
====
You may still need to customize the generated files to adapt them to your environment.
====

The utility karaf-service.sh can be configured by defining environment variables or by passing command line options:

,===
Command line option, Environment variable, Description
-k, KARAF_SERVICE_PATH       , Karaf installation path (mandatory)
-d, KARAF_SERVICE_DATA       , Karaf data path (default to ${KARAF_SERVICE_PATH}/data)
-c, KARAF_SERVICE_CONF       , Karaf configuration file (default to ${KARAF_SERVICE_PATH/etc/${KARAF_SERVICE_NAME}.conf
-t, KARAF_SERVICE_ETC        , Karaf etc path (default to ${KARAF_SERVICE_PATH/etc}
-p, KARAF_SERVICE_PIDFILE    , Karaf pid path (default to ${KARAF_SERVICE_DATA}/${KARAF_SERVICE_NAME}.pid)
-n, KARAF_SERVICE_NAME       , Karaf service name (default karaf)
-e, KARAF_ENV                , Karaf environment variable (can be repeated)
-u, KARAF_SERVICE_USER       , Karaf user
-g, KARAF_SERVICE_GROUP      , Karaf group (default ${KARAF_SERVICE_USER)
-l, KARAF_SERVICE_LOG        , Karaf console log (default to ${KARAF_SERVICE_DATA}/log/${KARAF_SERVICE_NAME}-console.log)
-f, KARAF_SERVICE_TEMPLATE   , Template file to use
-x, KARAF_SERVICE_EXECUTABLE , Karaf executable name (defaul karaf, should support daemon and stop commands)
,===

{nbsp} +

===== Systemd

When karaf-service.sh detects Systemd, it generates three files:

- a systemd unit file to manage the root Apache Karaf container
- a systemd environment file with variables used by the root Apache Karaf container
- a systemd template unit file to manage Apache Karaf child containers

.Example
....
$ ./karaf-service.sh -k /opt/karaf-4 -n karaf-4
Writing service file "/opt/karaf-4/bin/contrib/karaf-4.service"
Writing service configuration file ""/opt/karaf-4/etc/karaf-4.conf"
Writing service file "/opt/karaf-4/bin/contrib/karaf-4@.service"

$ cp /opt/karaf-4/bin/contrib/karaf-4.service /etc/systemd/system
$ cp /opt/karaf-4/bin/contrib/karaf-4@.service /etc/systemd/system

$ systemctl enable karaf-4.service
....

{nbsp} +

===== SysV

When karaf-service.sh detects a SysV system, it generates two files:

- an init script to manage the root Apache Karaf container
- an environment file with variables used by the root Apache Karaf container

.Example
....
$ ./karaf-service.sh -k /opt/karaf-4 -n karaf-4
Writing service file "/opt/karaf-4/bin/contrib/karaf-4"
Writing service configuration file "/opt/karaf-4/etc/karaf-4.conf"

$ ln -s /opt/karaf-4/bin/contrib/karaf-4 /etc/init.d/
$ chkconfig karaf-4 on
....

[NOTE]
====
To enable service startup upon boot, please consult your operating system init guide
====

{nbsp} +

===== Solaris SMF

When karaf-service.sh detects a Solaris system, it generates a single file:

.Example
....
$ ./karaf-service.sh -k /opt/karaf-4 -n karaf-4 -u lburgazz -g lburgazz
Writing service file "/opt/karaf-4/bin/contrib/karaf-4.xml"

$ svccfg validate /opt/karaf-4/bin/contrib/karaf-4.xml
$ svccfg import /opt/karaf-4/bin/contrib/karaf-4.xml
....

[NOTE]
====
The generated SMF descriptor is defined as transient so the start method is executed once
====

{nbsp} +

===== Windows

Installation of Apache Karaf as windows service is supported through https://github.com/kohsuke/winsw[winsw].

Steps:

- Rename karaf-service-win.exe to the service name i.e karaf-4.exe
- Rename karaf-service-win.xml to match the service name i.e. karaf-4.xml
- Customize the service descriptor to fit your needs
- Use the service executable to install/star/stop the service

.Example
....
C:\opt\apache-karaf-4\bin\contrib> karaf-4.exe install
C:\opt\apache-karaf-4\bin\contrib> karaf-4.exe start
....
