Differences between revisions 24 and 25
Revision 24 as of 2008-06-12 01:40:00
Size: 9984
Editor: KeiichiroOno
Comment:
Revision 25 as of 2008-06-12 19:09:53
Size: 10326
Editor: KeiichiroOno
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
[[TableOfContents]]
Line 8: Line 10:
 * Should be manageable by Undo manager (in application layer).  * Command history should be manageable by Undo manager (in application layer).
Line 10: Line 12:
 * Developers can chain commands to develop a workflow, like UNIX shell piping.
Line 16: Line 19:
Commands should be easily accessible from dynamic (scripting) languages, including Python, Ruby, and JavaScript. Commands should be easily accessible from dynamic (scripting) languages, including Python, Ruby, and JavaScript.  This will be implemented using scripting language engins running on JVM (Jruby, Rhino, and Jython). This enables users to write simple tasks as scripts.
Line 30: Line 33:
 * Each command will be represented as an OSGi service.
 * Users (developers) access commands through the OSGi service registory.
 * For easy access to commands, an utility class '''''CommandServiceManager''''' will be implemented.
 * Each command will be registered as an '''''OSGi service'''''.
 * Users (developers) access commands through the '''''OSGi ServiceTracker'''''.
 * For easy access to commands, an utility class '''''CommandServiceManager''''' will be implemented. This is a wrapper class for OSGi !ServiceTracker.

TableOfContents

Command Layer Definition

Command layer contains mechanism to make Cytoscape functions easily accessible from application layer. This layer should be separated from application layer and can be used in any mode: Desktop application, server version, and command line version.

Requirements

  • Command layer should be separated from application or UI.
  • Commands should be accessible from scripting (dynamic) languages.
  • Command history should be manageable by Undo manager (in application layer).
  • Extensible. Plugin writers and developers use Cytoscape as library can add their own commands.
  • Developers can chain commands to develop a workflow, like UNIX shell piping.

Command Usecases

(Not finished yet...)

Multiple Language Support

Commands should be easily accessible from dynamic (scripting) languages, including Python, Ruby, and JavaScript. This will be implemented using scripting language engins running on JVM (Jruby, Rhino, and Jython). This enables users to write simple tasks as scripts.

Functions Encapsulated as Command

In general, most of the classes in cytoscape.actions will be converted into Commands. In addition, some of the methods under the class cytoscape.Cytoscape will be encapsulated as command. Such as:

  • createNetwork()
  • createNewSession()
  • getNetwork()

Design

  • attachment:commandLayer1.png
  • Each command will be registered as an OSGi service.

  • Users (developers) access commands through the OSGi ServiceTracker.

  • For easy access to commands, an utility class CommandServiceManager will be implemented. This is a wrapper class for OSGi ServiceTracker.

How to Call Commands

   1 // Java
   2 Command c = CommandService.getCommand("command_name");
   3 Object result = c.execute( parameters );
   4 
   5 // Ruby
   6 c = CommandService.getCommand("command_name")
   7 result = c.execute( parameters )
   8 

We can implement similar functions Felix ShellService has:

   1 package org.apache.felix.shell;
   2 
   3 public interface ShellService
   4 {
   5     public String[] getCommands();
   6     public String getCommandUsage(String name);
   7     public String getCommandDescription(String name);
   8     public ServiceReference getCommandReference(String name);
   9     public void executeCommand(
  10         String commandLine, PrintStream out, PrintStream err)
  11         throws Exception;
  12 }
  13 

Like other layers, Command Layer will be distributed as a bundle. This bundle consists of the following:

  1. Command interface: All commands should implement this interface.
  2. Command implementations: Collection of actual implementations.
  3. Command Service Manager: (will be discussed in the next section)

When plugin developer wants to add a new command to the system, the plucin bundle will depends on this.

Command Service Manager

Command Service Manager is a simple utility class to make all commands easily accessible from all parts of Cytoscape. Essentially, this is a custom version of ServiceTracker class. Since all commands are registered as OSGi services, command users access commands through OSGi service mechanism. However, it is better to wrap this with a simple API to hide the detail of the OSGi service mechanism. The CommandServiceManager API will be something like the following:

   1 public class CommandServiceManager {
   2     public static Command getCommand(String command_name) {}
   3     public static List<String> getAvailableCommand() {}
   4 }
   5 

This class is only for accessing (using) commands. Developers should register command implementations like other OSGi services (can be done with Spring-DM).

Implementation

All commands should implement the following interface:

   1 public interface Command {
   2         
   3         public String getName();
   4         public String getDescription();
   5         
   6         public List<Object> execute(List<Object> args, List<Class<?>> argTypes) throws Exception;
   7 }
   8 
  • In most cases, command developer can extend this super class. Validation of the arguments (parameters) should be done by private method implemented by the command developer.

   1 public abstract class AbstractCommand {
   2 
   3         private String name;
   4         private String description;
   5 
   6         // Arguments will be stored in this data structure.     
   7         private Tunable arguments;
   8         
   9         public AbstractCommand(String name, String description) {
  10                 this.name = name;
  11                 this.description = description;
  12         }
  13 
  14         public String getDescription() {
  15                 return description;
  16         }
  17 
  18         public String getName() {
  19                 return name;
  20         }
  21 
  22         public List<Object> execute(List<Object> args, List<Class<?>> argTypes) throws Exception {
  23                 if(validate(args, argTypes) == false) {
  24                         throw new Exception();
  25                 }
  26                 
  27                 List<Object> result = new ArrayList<Object>();
  28                 
  29                 // Execute.  If necessary, put the result to the list.
  30                 
  31                 return result;
  32         }
  33         
  34         private Boolean validate(List<Object> args, List<Class<?>> argTypes) {
  35                 // Validate parameters
  36                 
  37                 // Then set parameters to Tunable.
  38                 return true;
  39         }
  40 }
  41 

Open Questions

  • What's the best parameter set for execute() method? Array of String/Object?

  • Return data type. Is List of Objects too general? Do we need name-value pair (i.e., Map) instead of value only List?

Actual implementation of the Command looks like the following:

   1 public class ImportGraphFileCommand extends AbstractCommand {
   2     // Wrapping CytoscapeActions with Command
   3 }
   4 

Commands with Dependency Injection Framework

With DI container, the command layer will looks like the following:

One of the advantages to use DI container is simpler integration test code.

Example Command Implementation with Spring

   1 public abstract class AbstractCommand implements Command {
   2 
   3         protected String name;
   4         protected String description;
   5 
   6         public String getName() {
   7                 return name;
   8         }
   9 
  10         public String getDescription() {
  11                 return description;
  12         }
  13         
  14         public void setName(String name) {
  15                 this.name = name;
  16         }
  17         
  18         public void setDescription(String description) {
  19                 this.description = description;
  20         }
  21 
  22 }
  23 

        <context:annotation-config />
        
        <context:component-scan
                base-package="org.cytoscape.command.internal" />

        <!-- Inject command properties -->
        <bean id="importGraphFileCommand"
                class="org.cytoscape.command.internal.ImportGraphFileCommand">
                <property name="name" value="importGraphFileCommand" />
                <property name="description" value="Load network file." />
        </bean>
  • Commands will be created by Spring.

   1 @RunWith(SpringJUnit4ClassRunner.class)
   2 @ContextConfiguration(locations={"/META-INF/spring/bundle-context.xml"})
   3 public class ExampleBeanIntegrationTest extends
   4                 AbstractDependencyInjectionSpringContextTests {
   5         
   6         @Autowired
   7         private ImportGraphFileCommand command1;
   8 
   9         @Autowired
  10         private LayoutCommand command2;
  11 
  12         ...
  13 
  14         @Test
  15         public void testWorkflow() throws Exception {
  16                 List<Object> parameter = new ArrayList<Object>();
  17                 List<Class<?>> parameterType = new ArrayList<Class<?>>();
  18                 
  19                 parameter.add("testData/galFiltered.sif");
  20                 parameterType.add(String.class);
  21                 
  22                 List<Object> result = command1.execute(parameter, parameterType);
  23                 
  24                 //Do something with other commands
  25                 
  26         }
  27 }
  28 

Commad Implemented with Dynamic Languages

From Spring 2.5, it has a [http://static.springframework.org/spring/docs/2.5.x/reference/dynamic-language.html built-in support for dynamic languages]. By using this feature, developers can implement commands with other languages and make it available other developers.

require 'java'

class RubyCommand
        include org.cytoscape.command3.Command
        
        # Command detail
        
end
  • Spring configuration file

        <lang:jruby id="rubyService"
                script-interfaces="org.cytoscape.command3.Command"
                script-source="classpath:RubyCommand.rb">
                <lang:property name="name" value="Command implemented by ruby." />
        </lang:jruby>

Tunable

Tunable class was introduced in Cytoscape 2.5 and it is used to provide mechanism to store editable parameters. This can be re-implemented as an annotation.

Exporting OSGi Service by Spring-DM

If we use one command = one OSGi service style design, we can use [http://www.springframework.org/osgi Spring Dynamic Module] for managing service import/export.

<bean name="importGraphFileCommandService"
                class="org.cytoscape.command.impl.ImportGraphFileCommandService" />

<osgi:service auto-export="interfaces" ref="importGraphFileCommandService" />

And Command Manager will be a class to holds a OSGi Service Tracker:

   1 public final class CommandManager implements BundleActivator {
   2 
   3         private ServiceTracker commandServiceTracker;
   4 
   5         public Command getCommand(final String commandName){
   6             //returns the command using Service Tracker
   7         }
   8 
   9         public void start(BundleContext bundleContext) throws Exception {
  10                 commandServiceTracker = new ServiceTracker(bundleContext, Command.class
  11                                 .getName(), null) {
  12                         @Override
  13                         public Object addingService(ServiceReference serviceReference) {
  14                                 Command command = (Command) super.addingService(serviceReference);
  15                                 return command;
  16                         }
  17                 };
  18 
  19                 commandServiceTracker.open();
  20                 
  21         }
  22 
  23         public void stop(BundleContext bundleContext) throws Exception {
  24                 commandServiceTracker.close();
  25         }
  26 }
  27 

OSGi Service

Frameworks

Dynamic Language Support on JVM

Outdated_Cytoscape_3.0/CommandDiscussions (last edited 2011-02-24 15:33:09 by PietMolenaar)

Funding for Cytoscape is provided by a federal grant from the U.S. National Institute of General Medical Sciences (NIGMS) of the Na tional Institutes of Health (NIH) under award number GM070743-01. Corporate funding is provided through a contract from Unilever PLC.

MoinMoin Appliance - Powered by TurnKey Linux