9 min read

 

OSGi and Apache Felix 3.0 Beginner’s Guide

OSGi and Apache Felix 3.0 Beginner's Guide

Build your very own OSGi applications using the flexible and powerful Felix Framework

  • Build a completely operational real-life application composed of multiple bundles and a web front end using Felix
  • Get yourself acquainted with the OSGi concepts, in an easy-to-follow progressive manner
  • Learn everything needed about the Felix Framework and get familiar with Gogo, its command-line shell to start developing your OSGi applications
  • Simplify your OSGi development experience by learning about Felix iPOJO
  • A relentlessly practical beginner’s guide that will walk you through making real-life OSGi applications while showing you the development tools (Maven, Eclipse, and so on) that will make the journey more enjoyable

The Tiny Shell Language

The command syntax for the shell interface is based on the Tiny Shell Language (TSL) . It is simple enough to allow a lightweight implementation, yet provides features such as pipes, closures, variable setting and referencing, collection types such as lists and maps, and so on.

The TSL syntax allows the creation of scripts that can be executed by the shell runtime service. The introduction you will get here does not cover the complete syntax; instead, you will see the basic parts of it.

For a review of the proposal in its initial state, (http://www.osgi.org/download/osgi-4.2-early-draft.pdf). You may also refer to the RFC 147 Overview on the Felix documentation pages (http://felix.apache.org/site/rfc-147-overview.html) for potential differences with the initial draft .

Chained execution

A program is a set of chained execution blocks. Blocks are executed in parallel, and the output of a block is streamed as input to the next. Blocks are separated by the pipe character ( | ). Each block is made up of a sequence of statements, separated by a semicolon ( ; ).

For example, as we’ll see in the next section, the bundles command lists the currently installed bundles and the grep command takes a parameter that it uses to filter the input. The program below:

bundles | grep gogo


is made of two statement blocks, namely, bundles and grep gogo. The output of the bundles statement will be connected to the input of the grep gogo statement (here each the statement block contains one statement).

Running this program on your Felix installation, in the state it is now, will produce:

g! bundles | grep gogo
2|Active | 1|org.apache.felix.gogo.command (0.6.0)
3|Active | 1|org.apache.felix.gogo.runtime (0.6.0)
4|Active | 1|org.apache.felix.gogo.shell (0.6.0)
true


The grep statement has filtered the output of the bundles statement for lines containing the filter string gogo. In this case, the grep statement outputs the results of its execution to the shell which prints it.

Executing the statement grep gogo on its own, without a piped block that feeds it input, will connect its input to the user command line. In that case, use Ctrl-Z to terminate your input:

g! grep gogo
line 1
line 2 gogo
line 2 gogo
line 3
^Z
true


Notice that line 2 gogo is repeated right after you have entered it, showing that the grep statement is running in parallel. It receives the input and processes it right after you enter it.

Variable assignment and referencing

A session variable is assigned a value using the equal character ( = ) and referenced using its name preceded with a dollar character ( $ ). For example:

g! var1 = ‘this is a string’
this is a string
g! echo $var1
this is a string


The assignment operation returns the assigned value.

Value types

We’ve seen the string type previously, which is indicated by surrounding text with single quotes ( ‘ ).

A list is a sequence of terms separated by whitespace characters and is delimited by an opening and a closing square bracket.

For example:

g! days = [ mon tue wed thu fri sat sun ] mon
tue
wed
thu
fri
sat
sun


Here the variable, days, was created, assigned the list as a value, and stored in the session.

A map is a list of assignments, the value is assigned to the key using the equal character ( = ) . For example:

For example:

g! sounds = [ dog=bark cat=meow lion=roar ] dog bark
cat meow
lion roar


Here, the variable sounds is assigned a map with the preceding key value pairs.

Object properties and operations

The shell uses a mapping process that involves reflection to find the best operation to perform for a request. We’re not going to go into the details of how this happens; instead, we’ll give a few examples of the operations that can be performed. We’ll see a few others as we go along.

In the same session, days and sounds are defined previously to retrieve an entry in the $days list:

g! $days get 1
tue


To retrieve an entry in the sounds map

g! $sounds get dog
bark


An example we’ve seen earlier is the bundles command used when illustrating the piping. Bundles was mapped to the method getBundles() from the Gogo Runtime bundle BundleContext instance. Another property of this object that we’ll use in the next section is bundle &ltid> to get a bundle object instance using getBundle(long).

Execution quotes

Similar to the UNIX back-quote syntax, but providing one that’s simpler for a lightweight parser, the execution quotes are used to return the output of an executed program.

For example:

g!(bundle 1) location
file:/C:/felix/bundle/org.apache.felix.bundlerepository-1.6.2.jar


Here, (bundle 1) has returned the bundle with ID 1, which we’ve re-used to retrieve the property location making use of Gogo’s reflexion on beans (location is mapped to getLocation() on the Bundle object ).

Commands and scopes

The Gogo Runti me command processor is extensible and allows any bundle to register the commands it needs to expose to the user. Then, when the user types a command, the processor will attempt to find the method that’s best fit to be executed, based on the command name and passed arguments.

However, there are potential cases where two bundles would need to register the same command name. To avoid this clash, commands are registered with an opti onal scope. When there is no ambiguity as to which scope the command belongs to, the command can be used without a scope; otherwise, the scope must be included.

The scope of a command is specified by pre-pending it to the command, separated from the command with a colon ( : ). In the previous examples, we’ve used the grep command, which is in the gogo scope. In this case, grep and gogo:grep achieve the same result.

We will look closer at the command registration mechanism.

Let’s take a tour of some of the commands available in the Felix distribution.

At the time of writing of this article, the Gogo bundles are at version 0.6.0, which means that they are not yet finalized and may change by the time they are released with version 1.0.

felix scope commands

One of the many powerful features of Felix (and OSGi-compliant applications in general) is that many actions can be applied on bundles without needing to restart the framework. Bundles can be installed, updated, uninstalled, and so on while the remaining functionality of the framework is active.

The following are some of the available commands and a description of their usage. We will get to use many of those as we go along, so you need not worry much about learning them by heart. Just know they exist.

Listing installed bundles: lb

One of the most frequently used shell commands is the list bundles command (lb) , which gives a listing of the currently installed bundles, showing some informationon each of them.

Let’s check what’s running on our newly installed framework:

g! lb
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (3.0.1)
1|Active | 1|Apache Felix Bundle Repository (1.6.2)
2|Active | 1|Apache Felix Gogo Command (0.6.0)
3|Active | 1|Apache Felix Gogo Runtime (0.6.0)
4|Active | 1|Apache Felix Gogo Shell (0.6.0)


The listing provides the following useful information about each bundle:

  • Each bundle is given a unique id on install—this ID is used by commands such as update or uninstall to apply acti ons on that bundle
  • The bundle’s start level
  • The bundle’s name and version

This command also takes a parameter for filtering the bundles list. For example, to include only bundles that have ‘bundle’ in their name:

g! lb bundle
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (3.0.1)
1|Active | 1|Apache Felix Bundle Repository (1.6.2)


help

The help command provides hints on the usage of commands.

When called without any parameters, the help command gives a listing of the available commands:

g! help
felix:bundlelevel
felix:cd
felix:frameworklevel
felix:headers
felix:help
felix:inspect
felix:install
felix:lb
felix:log
felix:ls
felix:refresh
felix:resolve
felix:start
felix:stop
felix:uninstall
felix:update
felix:which
gogo:cat
gogo:each
gogo:echo
gogo:format
gogo:getopt
gogo:gosh
gogo:grep
gogo:not
gogo:set
gogo:sh
gogo:source
gogo:tac
gogo:telnetd
gogo:type
gogo:until
obr:deploy
obr:info
obr:javadoc
obr:list
obr:repos
obr:source


More help on the syntax of each command can be requested by typing help &ltcommand-name>.

For example, for more help on the repos command:

g! help repos

repos – manage repositories
scope: obr
parameters:
String ( add | list | refresh | remove )
String[] space-delimited list of repository URL


When the command is available with multiple signatures, a help block per signature is provided, for example:

g! help help

help – displays information about a specific command
scope: felix
parameters:
String target command

help – displays available commands
scope: felix


Here, the help command has 2 syntaxes: one that takes a parameter (the target command), and another that takes no parameters. We’ve used the first one to get help on help.

Some commands may have not registered help content with the shell service. Those will show minimal information using help &ltcommand>. In most cases, they expose a separate help listing—usually &ltcommand> -? or &ltcommand> — help.

install

The install command is used to instruct Felix to install an external bundle. The syntax is as follows:

g! help install

install – install bundle using URLs
scope: felix
parameters:
String[] target URLs


Each bundle is located using the URL and is downloaded to the local cache for installation.

Once a bundle is installed, it is given a unique id. This ID is used to refer to this bundle when using commands such as update or uninstall. For example:

g! install http://www.mysite.com/testbundle-1.0.0.jar
Bundle ID: 7


Here, the bundle I’ve just installed has the ID 7.

g! lb
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (3.0.1)
1|Active | 1|Apache Felix Bundle Repository (1.6.2)
2|Active | 1|Apache Felix Gogo Command (0.6.0)
3|Active | 1|Apache Felix Gogo Runtime (0.6.0)
4|Active | 1|Apache Felix Gogo Shell (0.6.0)
7|Installed | 1|Test Bundle (1.0.0)


In cases where many bundles are to be installed from the same base URL, you may want to set a session variable with the common base URL to simplify the task.

For example, instead of executing:

g! install http://site.com/bundle1.jar http://site.com/bundle2.jar


You would write:

g! b = http://site.com
g! install $b/bundle1.jar $b/bundle2.jar



Subscribe to the weekly Packt Hub newsletter

* indicates required

LEAVE A REPLY

Please enter your comment!
Please enter your name here