Scripting
In the console section of the users guide, we introduced the scripting support.
Assignation
You already know the first usage of scripting: execution of command.
karaf@root()> echo hello world hello world
You can also assign value to session variables:
karaf@root()> msg = "hello world" hello world
Once you have assigned a value to a variable, you can display this value using the "resolved" variable name:
karaf@root()> echo $msg hello world
The () are execution quotes (like the backquotes when you use bash on Unix).
karaf@root()> ($.context bundle 1) location mvn:org.apache.karaf.jaas/org.apache.karaf.jaas.modules/3.0.1-SNAPSHOT
The $.context
access the context variables in the current session.
We access to the bundle
variable (an array containing all bundles), and we want to display the bundle location for
the bundle at the index 1 in the bundle array.
List, maps, pipes and closures
Using [], you can define array variable:
karaf@root()> list = [1 2 a b] 1 2 a b
You can also create a map if you put variables assignation in the array:
karaf@root()> map = [Jan=1 Feb=2 Mar=3] Jan 1 Feb 2 Mar 3
Using the | character, you can pipe output from a command as an input to another one.
For instance, you can access to the bundles context variables and send it as input to the grep command:
karaf@root()> ($.context bundles) | grep -i felix 0|Active | 0|org.apache.felix.framework (4.2.1) 21|Active | 11|org.apache.felix.fileinstall (3.2.6) 43|Active | 10|org.apache.felix.configadmin (1.6.0) 51|Active | 30|org.apache.felix.gogo.runtime (0.10.0)
You can assign name to script execution. It’s what we use for alias:
karaf@root()> echo2 = { echo xxx $args yyy } echo xxx $args yyy karaf@root()> echo2 hello world xxx hello world yyy
Startup
The etc/shell.init.script
file is executed at startup in each shell session, allowing the definition of additional
variables or aliases or even complex functions. It’s like the bashrc or profile on Unix.
Constants and variables
Apache Karaf console provides a set of implicit constants and variables that you can use in your script.
-
$.context
to access a bundle context -
$.variables
to access the list of defined variables -
$.commands
to access the list of defined commands
The variables starting with a # that are defined as Function (such as closures) will be executed automatically:
karaf@root> \#inc = { var = "${var}i" ; $var } var = "${var}i" ; $var karaf@root> echo $inc i karaf@root> echo $inc ii karaf@root>
Built-in variables and commands
Apache Karaf console provides built-in variable very useful for scripting:
-
$args
retrieves the list of script parameters, given to the closure being executed -
$1 .. $999
retrieves the nth argument of the closure -
$it
(same as$1
) is used in a loop to access the current iterator value
Apache Karaf console provides commands for scripting:
-
shell:if
-
shell:new
-
shell:each
-
…
Leveraging existing Java capabilities (via reflection)
Apache Karaf console supports loading and execution of Java classes.
The $karaf.lastException
implicit variable contains the latest Exception thrown.
karaf@root()> ($.context bundle) loadClass foo Error executing command: foo not found by org.apache.karaf.shell.console [17] karaf@root()> $karaf.lastException printStackTrace java.lang.ClassNotFoundException: foo not found by org.apache.karaf.shell.console [17] at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1460) at org.apache.felix.framework.BundleWiringImpl.access$400(BundleWiringImpl.java:72) at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:1843) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) at org.apache.felix.framework.Felix.loadBundleClass(Felix.java:1723) at org.apache.felix.framework.BundleImpl.loadClass(BundleImpl.java:926) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.felix.gogo.runtime.Reflective.invoke(Reflective.java:137) at org.apache.felix.gogo.runtime.Closure.executeMethod(Closure.java:527) at org.apache.felix.gogo.runtime.Closure.executeStatement(Closure.java:403) at org.apache.felix.gogo.runtime.Pipe.run(Pipe.java:108) at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:183) at org.apache.felix.gogo.runtime.Closure.execute(Closure.java:120) at org.apache.felix.gogo.runtime.CommandSessionImpl.execute(CommandSessionImpl.java:89) at org.apache.karaf.shell.console.jline.Console.run(Console.java:166) at java.lang.Thread.run(Thread.java:680)
It’s possible to create objects to create commands "on the fly":
karaf@root()> addcommand system (($.context bundle) loadClass java.lang.System) karaf@root()> system:getproperty karaf.name root
It means that you can create object using the new
directive, and call methods on the objects:
karaf@root> map = (new java.util.HashMap) karaf@root> $map put 0 0 karaf@root> $map 0 0
Examples
The following examples show some scripts defined in etc/shell.init.script
.
The first example show a script to add a value into a configuration list:
# # Add a value at the end of a property in the given OSGi configuration # # For example: # > config-add-to-list org.ops4j.pax.url.mvn org.ops4j.pax.url.mvn.repositories http://scala-tools.org/repo-releases # config-add-to-list = { config:edit $1 ; a = (config:property-list | grep --color never $2 | tac) ; b = (echo $a | grep --color never "\b$3\b" | tac) ; if { ($b trim) isEmpty } { if { $a isEmpty } { config:property-set $2 $3 } { config:property-append $2 ", $3" } ; config:update } { config:cancel } }
This second example shows a script to wait for an OSGi service, up to a given timeout, and combine this script in other scripts:
# # Wait for the given OSGi service to be available # wait-for-service-timeout = { _filter = $.context createFilter $1 ; _tracker = shell:new org.osgi.util.tracker.ServiceTracker $.context $_filter null ; $_tracker open ; _service = $_tracker waitForService $2 ; $_tracker close } # # Wait for the given OSGi service to be available with a timeout of 10 seconds # wait-for-service = { wait-for-service-timeout $1 10000 } # # Wait for the given command to be available with a timeout of 10 seconds # For example: # > wait-for-command dev watch # wait-for-command = { wait-for-service "(&(objectClass=org.apache.felix.service.command.Function)(osgi.command.scope=$1)(osgi.command.function=$2))" }