blob: 947d7180dc4aa590ebccffa48ada31f82c254fca [file] [log] [blame]
//
// 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.
//
=== 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))"
}
----