modules/ROOT/pages/subprojects/apache-felix-gogo/rfc-147-overview.adoc (126 lines of code) (raw):

= 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 http://www.osgi.org/download/osgi-4.2-early-draft.pdf[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: [source,java] Dictionary<String, Object> dict = new Hashtable<String, Object>(); 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 `CommandSession` argument is inserted if required: [source,java] ---- public void sleep(long millis) throws InterruptedException{ Thread.sleep(millis); } 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: [source,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); ... } === Easy to use interactively - no unnecessary syntax * basic commands [source,sh] g! echo hello world hello world * session variables [source,sh] g! msg = "hello world" g! echo $msg hello world * execution quotes `()` - similar to bash backquotes [source,sh] g! (bundle 1) location file:/Users/derek/Downloads/felix-framework-3.0.0/bundle/org.apache.felix.bundlerepository-1.6.2.jar === Lists, maps, pipes and closures * lists - `[]` [source,sh] g! list = [1 2 a b] 1 2 a b * maps - `[]` [source,sh] g! map = [Jan=1 Feb=2 Mar=3] Jan 1 Feb 2 Mar 3 * pipes - `|` [source,sh] 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 - `{}` [source,sh] g! echo2 = { echo xxx $args yyy } g! echo2 hello world xxx hello world yyy === Leverages existing Java capabilities, via reflection * exception handling - console shows summary, but full context available [source,sh] 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: [source,sh] g! addcommand system (loadClass java.lang.System) g! system:getproperties sun.io.unicode.encodingUnicodeLittle java.version 1.5.0_19 java.class.path bin/felix.jar java.awt.graphicsenvapple.awt.CGraphicsEnvironment user.language en sun.os.patch.level unknown os.version 10.6.2 [snip] === 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: [source,java] public void cat(String[] args) throws Exception { for (String arg : args) { IOUtil.copy(arg, System.out); } } === Normal commands can provide control primitives [source,java] public void each(CommandSession session, Collection<Object> list, Function closure) throws Exception { for (Object x : list) { closure.execute(session, null); } } then [source,sh] g! each [Jan Feb Mar] { echo $it | grep . } Jan Feb Mar NOTE: 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.