Parser Service

The Parser Service of the ProSyst Util Bundle maintains a common set of commands so that bundles in the OSGi framework can retrieve these commands and redirect them to miscellaneous clients. Adding pluggable commands to this common set provides capabilities for management and configuration of specific bundles.

Contents:


Parser Service Operation Model

Figure 1 clarifies the operation principles of the Parser Service.

Parser Service operation model
Figure 1: The Parser Service operation model.

The Parser Service manages an inventory of string commands, which a bundle developer can extend or map to a specific communication stream. The Parser Service has two usage aspects:

Command Syntax

The command syntax, adopted in the Parser Service, is as follows:

[<group_name>.]<command> [<param> [<param>]][&]

where:

Note: The Parser Service makes no difference between parameters and options. An option exists only as a term and is generally assumed as a parameter, which starts with "-" symbol. It is up to corresponding Pluggable Commands service to decide how to interpret a parameter.

Using the Parser Service

The Parser Service interface is com.prosyst.util.parser.ParserService.

Calling the Parser Service

You can call the Parser Service with the conventional techniques, defined by the OSGi Framework Specification.

  import org.osgi.framework.BundleContext; 
  import org.osgi.framework.BundleActivator;
  import org.osgi.framework.ServiceReference; 
  import com.prosyst.util.parser.ParserService;
        
  public class TestActivator implements BundleActivator {
     
    BundleContext bc;
    ServiceReference parserRef; 
    ParserService parser; 
      
public void start(BundleContext bc) {
// Retrieving the Parser Service parserRef = bc.getServiceReference(ParserService.class.getName()); parser = ((ParserService) bc.getService(parserRef)).getInstance(); . . . }

public void stop(BundleContext bc) {
bc.ungetService(parserRef);
}   }
Listing 1.1: Calling the Parser Service.

In order to release the runtime resources consumed by the Parser Service, when done using it call its release method before ungetting service reference from the framework.

Executing Commands through the Parser Service

In a Programming Way at Runtime

You can make the Parser Service load the execution of a command by calling its parseCommand method, which as input argument requires the command together with its options and parameters, all formatted as a single string. The Parser Service parses the input into command tokens for you.

Note: Do not place a new line symbol in the execution string.

Listing 1.2 uses the Parser Service from Listing 1.1 to invoke the cd info command (see "System Service Console Commands"), which result in switching to the info group.

  import org.osgi.framework.BundleContext; 
import org.osgi.framework.BundleActivator;
import org.osgi.framework.ServiceReference;
import com.prosyst.util.parser.ParserService;
. . . 
//The string of the command to add.
String command = "cd info";
  parser.parseCommand(command);
  . . .
Listing 1.2: Parsing commands through the Parser Service.

Through a Script at Startup

At registration, the Parser Service is capable of launching an install script with console commands to be executed, whose location is the value of the mbs.parser.startup system property. This startup file is treated in the same way as for the exec command - if the value of mbs.parser.startup is a valid URL, then the script is retrieved from there. Otherwise, it is searched for in the directory specified with the mbs.exec.base system property.

Mapping Execution Results to a Communication Stream

For a separate command output, you should use a separate instance of the Parser Service. The Parser Service is not available through a service factory and all its consumer receive the same service object. Changing the output from a bundle will result in changing the output in all other bundles using the Parser Service, which in some cases may cause troubles. That's why, a separate instance per output stream is a requirement.

To use another output stream, call the getInstance method to obtain a separate Parser Service instance.

To make a console client view the results from a command execution, you should specify the stream to which data should be redirected. Call the setOutputStream method of a separate Parser Service object with parameter the target output stream. Next, on calling the parseCommand method, the result will be provided over the output stream specific to the Parser Service instance.

Listing 1.3 redirects command results to the system output (for example the local console) identified by the System.out print stream.

    parser.setOutputStream(System.out);
Listing 1.3: Redirecting execution results.

Plugging Commands

As it was described above, to plug commands into the command inventory of the Parser Service you should develop a Pluggable Commands service and register it in the OSGi framework. The interface to implement is com.prosyst.util.pcommands.PluggableCommands.

Providing Information About Commands

You pass information about your commands in the getCommandInfo method. It should return an array of CommandInfo objects, each of them dedicated to a single command. You should pass the following command properties in the CommandInfo constructor:

Executing a Command

In the executeCommand method of PluggableCommands you should execute a command passed by the Parser Service. The arguments that this method receives are:

Organizing Commands in Groups

You should organize your commands in a group classifying the functions that they provide. Every group has a name and a help message describing its purpose. They are specified in the getGroupName and getHelpMessage methods of the Pluggable Commands service.

Note: You cannot insert commands in groups that are already defined by another entity.

Registering the Pluggable Commands as a Service

Finally, the Pluggable Commands service should be registered in the OSGi framework under the com.prosyst.util.pcommands.PluggableCommands interface name. The Pluggable Commands service should have the following registration properties:

If the registration properties are missing, the Parser Service will get the Pluggable Commands service right after it is registered. Otherwise, the Parser Service will hold only a reference to the service and will not get the service object until a command exported by the service is executed.

Using an Utility to Format the Command Output

The com.prosyst.util.pcommands.PCommandsUtils class contains methods for enhanced formatting of the printed command output.

An Example of Pluggable Commands

Listing 2.1 contains the TestCommands class, which implements a Pluggable Commands service. In the getGroupName method it adds a new command group, called "example". The getCommandInfo method introduces commands with the following properties:

When the client issues the "command" command, the executeCommand method prints the parameters received as well as a message when the command option is used.

import com.prosyst.util.pcommands.CommandInfo;
import com.prosyst.util.pcommands.PluggableCommands;
import java.io.PrintStream;
public class TestCommands implements PluggableCommands {
         
  private static String command = "command";
  private static String shortcut1 = "comm";
  private static String shortcut2 = "c"; 
         
  // Methods inherited from interface com.prosyst.util.pcommands.PluggableCommands
  // Executing a command on request
  public void executeCommand(String name, String[] params, PrintStream pStream) {
    String option = "";
    String result = "";
    if(name.equals(command) || name.equals(shortcut1) || name.equals(shortcut2)){
      for(int i=0; i < params.length; i ++) { 
        if(params[i].equals("-o")) {
          option = params[i]; 
        } else {
          result = result.concat(params[i]); 
        } 
      } 
      if(option != "") { 
        pStream.println("\tExample option used!");
      }
      pStream.println(result); 
    } else {
pStream.println("Unrecognized command: " + command);
}
}
    // Defining command properties     
public CommandInfo[] getCommandsInfo() { CommandInfo[] commands = new CommandInfo[1]; String[] names = {command, shortcut1, shortcut2}; String[] params = {"[-o]", "Command option", "parameter", "Command parameter"}; commands[0] = new CommandInfo(names, "Example command ", params);
return commands; }
  public String getGroupHelpMessage() {
    return "Just an example command group";
  }
  // Specifying the group's name
public String getGroupName() {
return "example"; } }
Listing 2.1: Defining new commands.

Listing 2.2 exemplifies how to register the commands above into the framework so that the Parser Service can receive a notification and insert them into its command inventory.

  import org.osgi.framework.BundleActivator;
  import org.osgi.framework.BundleContext;
  import org.osgi.framework.ServiceRegistration;
import TestCommands;
import java.util.Hashtable;

public class CommandsActivator implements BundleActivator {
ServiceRegistration sReg = null;
String servName = "com.prosyst.util.pcommands.PluggableCommands";

public void start(BundleContext bc) {
// Registering the collection of commands as a service
Hashtable regProps = new Hashtable();
regProps.put("group", "example"); regProps.put("description", "Just an example command group");
sReg = bc.registerService(servName, new TestCommands(), null);
if (sReg != null) {
System.out.println("Commands registered successfully!");
}
}

public void stop(BundleContext bc) {
sReg.unregister();
}
}
Listing 2.2: Announcing new commands set by registering it as a service in the framework.

System Properties

System Property Default Value Description
mbs.parser.startup - Specifies the URL of the Parser Service startup script.
mbs.parser.aliases.store false If true, command aliases will be persistently stored and will survive framework restarts. On updating the ProSyst Util Bundle, saved aliases will be lost.
mbs.parser.debug false If true, the exceptions thrown in the Parser Service will be printed to the standard output.
mbs.output.charscount 49 Specifies the character length of a line in a command output. The length is equal to the value of the property - 1.

References


Thread Pool Manager and Timer