Home » Documentation » Apache Felix Subproject Documentation » Apache Felix Gogo

RFC 147 Overview

The RFC-147 draft is not yet publicly available. It used to be called RFC-132, which can be found in an early specification draft

This is an overview of its main features:

Standard way to implement and run commands for any OSGi 4.2 framework

Commands are registered via service attributes, you don't have to register a specific service. This allows commands to be registered by existing services, just by adding the new attributes:

{code:template=java} Dictionary dict = new Hashtable(); dict.put(CommandProcessor.COMMAND_SCOPE, "shell"); dict.put(CommandProcessor.COMMAND_FUNCTION, new String {"sleep", "grep"}); context.registerService(name, service, dict);

Scope is used to provide a namespace for commands. The commands above can be invoked as "shell:sleep" and "shell:grep". If the scope is omitted (e.g. "sleep" and "grep") then the first matching command is invoked.

Commands can have any signature - arguments are coerced to call the best matching method using reflection. A  argument is inserted if required:

public void sleep(long millis) throws InterruptedException{

public void sleep(String[] args) throws Exception;

public boolean grep(CommandSession session, String[] args) throws Exception;

The CommandSession interface provides methods for executing commands and getting and setting session variables:

{code:template=java} public interface org.apache.felix.service.command.CommandSession { Object execute(CharSequence commandline) throws Exception; Object get(String name); void put(String name, Object value); ... }

h2. Easy to use interactively - no unnecessary syntax.

// simple command

g! echo hello world
hello world

// session variables

g! msg = "hello world"
g! echo $msg
hello world

// execution quotes () - similar to bash backquotes

g! (bundle 1) location

h2. Provides lists, pipes and closures.

// lists - \[\]

g! list = [1 2 a b]

g! map = [Jan=1 Feb=2 Mar=3]
Jan                 1
Feb                 2
Mar                 3

// pipes

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)

// closures - {}

g! echo2 = { echo xxx $args yyy }
g! echo2 hello world
xxx hello world yyy

h2. Leverages existing Java capabilities, via reflection.

// exception handling - console shows summary, but full context available

g! start xxx
E: Cannot coerce start[xxx] to any of [(Bundle)]
g! $exception printstacktrace
java.lang.IllegalArgumentException: Cannot coerce start[xxx] to any of [(Bundle)]
        at org.apache.felix.gogo.runtime.shell.Reflective.method(Reflective.java:162)
        at org.apache.felix.gogo.runtime.shell.Command.execute(Command.java:40)
        at org.apache.felix.gogo.runtime.shell.Closure.execute(Closure.java:211)
        at org.apache.felix.gogo.runtime.shell.Closure.executeStatement(Closure.java:146)
        at org.apache.felix.gogo.runtime.shell.Pipe.run(Pipe.java:91)

// add all public methods on java.lang.System as commands:

g! addcommand system (loadClass java.lang.System)
g! system:getproperties
java.version        1.5.0_19
java.class.path     bin/felix.jar
user.language       en
sun.os.patch.level  unknown
os.version          10.6.2

h2. Easy to implement and test commands without needing OSGi.

Command implementations don't need to reference any OSGi interfaces. They can use System.in, System.out and System.err, just as you would in a trivial Java application. The ThreadIO service transparently manages the singleton System.out etc, so that each thread sees the appropriate stream:

{code:template=java}public void cat(String[] args) throws Exception {
    for (String arg : args)
        IOUtil.copy(arg, System.out);

Normal commands can provide control primitives.

{code:template=java}public void each(CommandSession session, Collection list, Function, closure) throws Exception { for (Object x : list) { closure.execute(session, null); } }

g! each [Jan Feb Mar] { echo $it | grep . }

The default *echo* command _returns_ a String and does not write to System.out. Also, by default, the console prints the results of each command, so *echo* appears to behave as you would expect.
However, the console does not see the *each* closure above, so the result of echo would not be seen. This is why it is piped into *grep*, as the _result_ of the command as well as its output is written to a pipeline.

Rev. 1712598 by cziegeler on Wed, 4 Nov 2015 17:48:20 +0000
Apache Felix, Felix, Apache, the Apache feather logo, and the Apache Felix project logo are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners.