← Revision 21 as of 2008-06-09 19:04:08
Size: 7704
Comment:
|
← Revision 22 as of 2008-06-09 19:18:21 →
Size: 8243
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 194: | Line 194: |
private ImportGraphFileCommand command; | private ImportGraphFileCommand command1; |
Line 198: | Line 198: |
... |
|
Line 207: | Line 209: |
List<Object> result = command.execute(parameter, parameterType); | List<Object> result = command1.execute(parameter, parameterType); |
Line 214: | Line 216: |
==== Method Injection / Aspect Oriented Programming for Command ==== Usually commands have parameters and we should implement a mechanism to set those parameters. We can separate this function as an aspect and call it automatically every time user call ''execute()'' method. This can be implemented using intercepter model. ===== 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. |
(This page is under construction)
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.
- Should be manageable by Undo manager (in application layer).
- Extensible. Plugin writers and developers use Cytoscape as library can add their own commands.
Command Usecases
From Plugins or Other Pre-Compiled Programs
From Interactive Shells
From Scripting Languages
Multiple Language Support
Commands should be easily accessible from dynamic (scripting) languages, including Python, Ruby, and JavaScript.
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 represented as an OSGi service.
- Command executes the function through the OSGi service registory.
For easy access to commands, an utility class CommandService will be used.
1 // Java
2 CommandService.getCommand("command_name").execute();
3
4 // Ruby
5 CommandService.getCommand("command_name").execute
6
We can use similar design to Felix ShellService:
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
Implementation
All commands should implement the following interface:
- All command developer should implement this 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
Method Injection / Aspect Oriented Programming for Command
Usually commands have parameters and we should implement a mechanism to set those parameters. We can separate this function as an aspect and call it automatically every time user call execute() method. This can be implemented using intercepter model.
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
References and External Links
OSGi Service
[http://neilbartlett.name/downloads/preview_intro_services.pdf Introduction to Services]
[http://www.knopflerfish.org/osgi_service_tutorial.html OSGi Service Tutorial]
[http://felix.apache.org/site/apache-felix-shell-service.html Felix ShellService]
Dynamic Language Support on JVM
[http://jruby.codehaus.org/ JRuby]
[http://www.mozilla.org/rhino/ Rhino (JavaScript)]