Chapter 3. Felix Gogo

A request for comments (RFC 147) by Peter Kriens, an attachment to the OSGi 4.2 specifications document early draft, describes a proposed interface for the processing and launching of commands for the OSGi framework. It defines the blueprint for a shell service and its language.

The goal behind such an endeavor is to attempt to standardize the way humans and external systems interact with an OSGi framework using a text command-based interface. For example, such an interface would be used for launching, configuring, and controlling the framework using a local or remote console or scripting without locking an enterprise platform to a specific OSGi framework implementation.

Felix Gogo, a sub-project of Apache Felix, is an implementation of this early draft specification. The Gogo shell is included with the Felix Framework Distribution since version 3.0.

It is worth noting that this specification is not yet part of the official OSGi specifications, and therefore, may change in the future.

In this chapter, you will:

  • Learn about the Tiny Shell Language and its syntax
  • Cover some of the commands provided by Gogo

So let's start with a quick overview of the language.

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, please refer to the OSGi 4.2 early draft appendix (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.

Note

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:

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

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:

! $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 <id> 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 Runtime 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 optional 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 in Chapter 8, Adding a Command-Line Interface, when we define our own for the Bookshelf case study.

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

Note

At the time of writing of this book, 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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.48.161