Difference between revisions of "Analysis method development"
Tagir Valeev (Talk | contribs) (Preliminary description of analysis) |
Tagir Valeev (Talk | contribs) (→Implementing parameters) |
||
(7 intermediate revisions by one user not shown) | |||
Line 13: | Line 13: | ||
If your analysis has not very much code, you may consider putting parameters class and its bean info as nested static classes into analysis class in the following manner: | If your analysis has not very much code, you may consider putting parameters class and its bean info as nested static classes into analysis class in the following manner: | ||
− | public class ProcessDataAnalysis extends AnalysisMethodSupport<ProcessDataAnalysis.ProcessDataParameters> | + | public class ProcessDataAnalysis extends {{Class|ru.biosoft.analysis.AnalysisMethodSupport}}<ProcessDataAnalysis.ProcessDataParameters> |
{ | { | ||
... | ... | ||
− | public static class ProcessDataParameters extends AbstractAnalysisParameters | + | public static class ProcessDataParameters extends {{Class|ru.biosoft.analysis.AbstractAnalysisParameters}} |
{ | { | ||
... | ... | ||
} | } | ||
− | public static class ProcessDataParametersBeanInfo extends BeanInfoEx2 | + | public static class ProcessDataParametersBeanInfo extends {{Class|ru.biosoft.util.bean.BeanInfoEx2}} |
{ | { | ||
... | ... | ||
Line 33: | Line 33: | ||
Parameters class must have default constructor and getter and setter methods for all parameters used in analysis method. Setters must call {{Method|com.beanexplorer.beans.Option.firePropertyChange}} superclass method. Getters can be annotated using {{Annotation|ru.biosoft.util.bean.PropertyName}} and {{Annotation|ru.biosoft.util.bean.PropertyDescription}} annotations. Usual implementation look like this: | Parameters class must have default constructor and getter and setter methods for all parameters used in analysis method. Setters must call {{Method|com.beanexplorer.beans.Option.firePropertyChange}} superclass method. Getters can be annotated using {{Annotation|ru.biosoft.util.bean.PropertyName}} and {{Annotation|ru.biosoft.util.bean.PropertyDescription}} annotations. Usual implementation look like this: | ||
− | public class ProcessDataParameters extends AbstractAnalysisParameters | + | public class ProcessDataParameters extends {{Class|ru.biosoft.analysis.AbstractAnalysisParameters}} |
{ | { | ||
private DataElementPath inputPath, outputPath; | private DataElementPath inputPath, outputPath; | ||
Line 98: | Line 98: | ||
=== Writing bean info class for parameters === | === Writing bean info class for parameters === | ||
− | + | Bean info class must have the same name as parameters class with <code>BeanInfo</code> suffix. It must have default constructor which calls superclass constructor passing parameters class name: | |
− | === | + | public class ProcessDataParametersBeanInfo extends {{Class|ru.biosoft.util.bean.BeanInfoEx2}} |
+ | { | ||
+ | public ProcessDataParametersBeanInfo() | ||
+ | { | ||
+ | super(ProcessDataParameters.class); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | To register parameters override {{Method|com.beanexplorer.beans.BeanInfoEx.initProperties()}} superclass method. For each parameter you should create {{Class|java.beans.PropertyDescriptor}} and add it via {{Method|ru.biosoft.util.bean.BeanInfoEx2.add(PropertyDescriptor)}} superclass method. There are also some helper methods defined in {{Class|ru.biosoft.util.bean.BeanInfoEx2}} which make things easier: | ||
+ | * <code>add(String name)</code> - create {{Class|java.beans.PropertyDescriptor}} with default getter/setter names and add it. | ||
+ | * <code>add(String name, Class<?> editor)</code> - the same as above, but also sets custom property editor class. | ||
+ | * <code>addHidden(String name, String hiddenMethodName)</code> - create conditionally hidden option. The hiddenMethodName is name of parameters class method which takes no parameters and returns boolean value (true if parameter must be hidden) | ||
+ | * <code>addHidden(String name, Class<?> editor, String hiddenMethodName)</code> - the same as above, but also sets custom property editor class. | ||
+ | and so on. | ||
+ | |||
+ | Parameters will appear in the form in the registration order. By convention first should be input repository elements, then other parameters and finally output repository elements. If parameter X depends on parameter Y, then X must be registered after Y. | ||
+ | |||
+ | === Registering complex parameters === | ||
+ | For simple data types like primitives or {{Class|java.lang.String}} calling <code>add(parameterName)</code> is enough to register the parameter. In case of more complex parameters special editor must be set as well as some additional {{Class|java.beans.PropertyDescriptor}} parameters. Usually this can be done using special convenience methods. | ||
+ | |||
+ | * Repository elements should be registered via static methods defined in {{Class|ru.biosoft.access.repository.DataElementPathEditor}}: | ||
+ | ** Use {{Method|ru.biosoft.access.repository.DataElementPathEditor.registerInput}} methods to register input element (user will be forced to select existing element of given type). | ||
+ | ** Use {{Method|ru.biosoft.access.repository.DataElementPathEditor.registerInputMulti}} methods to register set of input elements (user will be able to select several elemens using Ctrl or Shift buttons). | ||
+ | ** Use {{Method|ru.biosoft.access.repository.DataElementPathEditor.registerOutput}} methods to register output element (user will be asked for confirmation to overwrite an existing item). | ||
+ | * {{Type link|table|Table}} column name selector should be registered via static methods defined in {{Class|ru.biosoft.table.columnbeans.ColumnNameSelector}}: | ||
+ | ** Use {{Method|ru.biosoft.table.columnbeans.ColumnNameSelector.registerSelector}} methods to allow selection of any column. | ||
+ | ** Use {{Method|ru.biosoft.table.columnbeans.ColumnNameSelector.registerNumericSelector}} methods to allow selection of numerical column only. | ||
+ | *: <b>Note</b>: column name must be defined as {{Class|java.lang.String}} in parameters class and its default value must be either {{Constant|ru.biosoft.table.columnbeans.ColumnNameSelector.NONE_COLUMN}} or any existing column (not null). | ||
+ | * Set of {{Type link|table}} column names should be registered via static methods defined in {{Class|ru.biosoft.table.columnbeans.ColumnNamesSelector}}: | ||
+ | ** Use {{Method|ru.biosoft.table.columnbeans.ColumnNameSelector.registerSelector}} methods to allow selection of any columns. | ||
+ | ** Use {{Method|ru.biosoft.table.columnbeans.ColumnNameSelector.registerNumericSelector}} methods to allow selection of numerical columns only. | ||
+ | *: <b>Note</b>: column names must be defined as {{Class|java.lang.String[]}} in parameters class. | ||
+ | * Selector for predefined species can be registered using {{Method|ru.biosoft.workbench.editors.DataElementComboBoxSelector.registerSelector}} method with {{Constant|biouml.standard.type.Species.SPECIES_PATH}} as collectionPath parameter. | ||
+ | * Selector for [[reference type]] should be registered via {{Method|ru.biosoft.workbench.editors.ReferenceTypeSelector.registerSelector}} methods. | ||
+ | * For {{Class|java.awt.Color}} parameter type set {{Class|com.beanexplorer.editors.ColorEditor}} property editor class. | ||
+ | |||
+ | === Creating custom parameter editor === | ||
{{Stub}} | {{Stub}} | ||
== Implementing analysis == | == Implementing analysis == | ||
− | {{ | + | If your analysis extends {{Class|ru.biosoft.analysis.AnalysisMethodSupport}} abstract class, then it's necessary to create constructor and override {{Method|ru.biosoft.analysis.AnalysisMethodSupport.justAnalyzeAndPut}} method where actual analysis must be performed. Normally constructor looks like this: |
+ | public ProcessData(DataCollection<?> origin, String name) | ||
+ | { | ||
+ | super(origin, name, new ProcessDataParameters()); | ||
+ | } | ||
+ | Adding any other initialization code is not recommended. It's better to initialize analysis inside {{Method|ru.biosoft.analysis.AnalysisMethodSupport.justAnalyzeAndPut}} method. | ||
+ | |||
+ | Analysis parameters are accessible in {{Field|ru.biosoft.analysis.AnalysisMethodSupport.parameters}} field. | ||
+ | |||
+ | === justAnalyzeAndPut implementation === | ||
+ | The <code>justAnalyzeAndPut</code> method is called at most once per analysis class object. If user launches the same analysis several times, new objects will be created. | ||
+ | |||
+ | The return value of this method can be either resulting element or Java array of resulting elements. System will try to store analysis parameters in these elements info and open them automatically. Return null if your analysis don't create any result (but throw an exception if your analysis should be considered as failed). | ||
+ | |||
+ | === Parameters validation === | ||
+ | Analysis parameters are validated before <code>justAnalyzeAndPut</code> is called. | ||
+ | |||
+ | By default only repository paths are validated. The following validations are performed: | ||
+ | * Input elements must exist, must have the requested element type and [[reference type]] (if it was constrained). | ||
+ | * Parent collection for output element must exist. If it doesn't exist, validator will try to create this collection. | ||
+ | * Parent collection for output element must be writable. | ||
+ | * It must be possible to save the requested output element type to the parent collection. | ||
+ | * Output path cannot be the same as any of input paths. | ||
+ | |||
+ | To add your own validation code, override {{Method|ru.biosoft.analysis.AnalysisMethodSupport.validateParameters()}} method. There are some handy check* methods in {{Class|ru.biosoft.analysis.AnalysisMethodSupport}} class which will make basic validations easy. | ||
+ | |||
+ | Please remember that even if user interface doesn't allow to enter invalid value (for example, restricting choise with drop-down list), parameters can be filled in the various ways: | ||
+ | * Using [[workflow]] mechanism; | ||
+ | * Executing analysis from JavaScript console; | ||
+ | * Executing analysis via BioUML API (using [[BioUML web client]] or [[rbiouml]] R package). | ||
+ | Thus you may still encounter values which might be impossible to enter using UI controls. | ||
+ | |||
=== Logging === | === Logging === | ||
− | To log messages during analysis execution, use {{Field|ru.biosoft.analysis.AnalysisMethodSupport.log}} logger instance. This instance is connected with analysis or [[workflow]] log. In case of unrecoverable error, it's better to throw [[BioUML exception]] out of <code>justAnalyzeAndPut</code> method than to log it by yourself. | + | To log messages during analysis execution, use {{Field|ru.biosoft.analysis.AnalysisMethodSupport.log}} logger instance. This instance is connected with analysis or [[workflow]] log. In case of unrecoverable error, it's better to throw [[BioUML exceptions|BioUML exception]] out of <code>justAnalyzeAndPut</code> method than to log it by yourself. |
=== Progress bar === | === Progress bar === | ||
+ | {{Stub}} | ||
=== Parallelization === | === Parallelization === | ||
+ | {{Stub}} | ||
[[Category:Development]] | [[Category:Development]] |
Latest revision as of 14:06, 13 September 2013
BioUML analysis method is a function which takes some user-defined parameters, processes them somehow (probably using repository elements and databases) and produces some results, storing them in the repository. This page describes implementation details on how to create your own analysis method.
If you want to create your analysis method in new plugin, please read plugin development page first.
Contents |
[edit] Classes
To create analysis method, you should create at least three classes:
- Analysis class: class implementing
AnalysisMethod
interface. It's strongly recommended to extendAnalysisMethodSupport
class parameterizing it via parameters class. - Parameters class: bean class for analysis parameters, which must implement
AnalysisParameters
interface. It's strongly recommended to extendAbstractAnalysisParameters
class. - Bean info for parameters class: class implementing
BeanInfo
interface which describes parameters class. Must have the same name as parameters class withBeanInfo
suffix. It's strongly recommended to extendBeanInfoEx2
class.
The following naming conventions are used. Consider, you want to create some analysis to "process data". Then analysis class should be named as ProcessData
or ProcessDataAnalysis
, parameters class should be named as ProcessDataParameters
and bean info for parameters class should be named as ProcessDataParametersBeanInfo
.
If your analysis has not very much code, you may consider putting parameters class and its bean info as nested static classes into analysis class in the following manner:
public class ProcessDataAnalysis extendsAnalysisMethodSupport
<ProcessDataAnalysis.ProcessDataParameters> { ... public static class ProcessDataParameters extendsAbstractAnalysisParameters
{ ... } public static class ProcessDataParametersBeanInfo extendsBeanInfoEx2
{ ... } }
[edit] Extension
To make your analysis available in the tree, you must register it as extension for ru.biosoft.analysis.method extension point. Consider also creating method description HTML file and JavaScript host object (or use existing one).
[edit] Implementing parameters
Parameters class must have default constructor and getter and setter methods for all parameters used in analysis method. Setters must call Option.firePropertyChange
superclass method. Getters can be annotated using @PropertyName
and @PropertyDescription
annotations. Usual implementation look like this:
public class ProcessDataParameters extends AbstractAnalysisParameters
{
private DataElementPath inputPath, outputPath;
private String myStringParameter;
private boolean myBooleanParameter;
@PropertyName("Input table")
@PropertyDescription("Table to process")
public DataElementPath getInputPath()
{
return inputPath;
}
public void setInputPath(DataElementPath inputPath)
{
Object oldValue = this.inputPath;
this.inputPath = inputPath;
firePropertyChange("inputPath", oldValue, this.inputPath);
}
@PropertyName("String parameter")
@PropertyDescription("String which will be used during processing")
public String getMyStringParameter()
{
return myStringParameter;
}
public void setMyStringParameter(String myStringParameter)
{
Object oldValue = this.myStringParameter;
this.myStringParameter = myStringParameter;
firePropertyChange("myStringParameter", oldValue, myStringParameter);
}
@PropertyName("Verbose output")
@PropertyDescription("Whether to print additional messages during processing")
public boolean isMyBooleanParameter()
{
return myBooleanParameter;
}
public void setMyBooleanParameter(boolean myBooleanParameter)
{
Object oldValue = this.myBooleanParameter;
this.myBooleanParameter = myBooleanParameter;
firePropertyChange("myBooleanParameter", oldValue, myBooleanParameter);
}
}
[edit] Parameter types
Many parameter types are supported, including (but not limited to) the following:
- Primitive types (boolean, short, int, long, float, double);
-
String
for textual parameters; -
DataElementPath
for paths to the repository elements (both for inputs and outputs); -
DataElementPathSet
for sets of input repository elements; -
Species
for selection of species from preinstalled list; -
BasicGenomeSelector
andGenomeSelector
for convenient selection of the genome (either in preinstalled database or user-uploaded); -
Color
for color selection; - Java arrays of any supported types (array elements can be added or deleted by user).
You may use your own bean as complex parameter type, but the following requirements should be met:
- Your bean should extend
Option
class. - Your bean should be serializable via
TextUtil.fromString
/TextUtil.toString
methods. See text serialization for details.
[edit] Writing bean info class for parameters
Bean info class must have the same name as parameters class with BeanInfo
suffix. It must have default constructor which calls superclass constructor passing parameters class name:
public class ProcessDataParametersBeanInfo extends BeanInfoEx2
{
public ProcessDataParametersBeanInfo()
{
super(ProcessDataParameters.class);
}
}
To register parameters override BeanInfoEx.initProperties()
superclass method. For each parameter you should create PropertyDescriptor
and add it via BeanInfoEx2.add(PropertyDescriptor)
superclass method. There are also some helper methods defined in BeanInfoEx2
which make things easier:
-
add(String name)
- createPropertyDescriptor
with default getter/setter names and add it. -
add(String name, Class<?> editor)
- the same as above, but also sets custom property editor class. -
addHidden(String name, String hiddenMethodName)
- create conditionally hidden option. The hiddenMethodName is name of parameters class method which takes no parameters and returns boolean value (true if parameter must be hidden) -
addHidden(String name, Class<?> editor, String hiddenMethodName)
- the same as above, but also sets custom property editor class.
and so on.
Parameters will appear in the form in the registration order. By convention first should be input repository elements, then other parameters and finally output repository elements. If parameter X depends on parameter Y, then X must be registered after Y.
[edit] Registering complex parameters
For simple data types like primitives or String
calling add(parameterName)
is enough to register the parameter. In case of more complex parameters special editor must be set as well as some additional PropertyDescriptor
parameters. Usually this can be done using special convenience methods.
- Repository elements should be registered via static methods defined in
DataElementPathEditor
:- Use
DataElementPathEditor.registerInput
methods to register input element (user will be forced to select existing element of given type). - Use
DataElementPathEditor.registerInputMulti
methods to register set of input elements (user will be able to select several elemens using Ctrl or Shift buttons). - Use
DataElementPathEditor.registerOutput
methods to register output element (user will be asked for confirmation to overwrite an existing item).
- Use
- Table column name selector should be registered via static methods defined in
ColumnNameSelector
:- Use
ColumnNameSelector.registerSelector
methods to allow selection of any column. - Use
ColumnNameSelector.registerNumericSelector
methods to allow selection of numerical column only.
- Note: column name must be defined as
String
in parameters class and its default value must be eitherNONE_COLUMN
or any existing column (not null).
- Use
- Set of table column names should be registered via static methods defined in
ColumnNamesSelector
:- Use
ColumnNameSelector.registerSelector
methods to allow selection of any columns. - Use
ColumnNameSelector.registerNumericSelector
methods to allow selection of numerical columns only.
- Note: column names must be defined as
String[]
in parameters class.
- Use
- Selector for predefined species can be registered using
DataElementComboBoxSelector.registerSelector
method withSPECIES_PATH
as collectionPath parameter. - Selector for reference type should be registered via
ReferenceTypeSelector.registerSelector
methods. - For
Color
parameter type setColorEditor
property editor class.
[edit] Creating custom parameter editor
This page or section is a stub. Please add more information here! |
[edit] Implementing analysis
If your analysis extends AnalysisMethodSupport
abstract class, then it's necessary to create constructor and override AnalysisMethodSupport.justAnalyzeAndPut
method where actual analysis must be performed. Normally constructor looks like this:
public ProcessData(DataCollection<?> origin, String name) { super(origin, name, new ProcessDataParameters()); }
Adding any other initialization code is not recommended. It's better to initialize analysis inside AnalysisMethodSupport.justAnalyzeAndPut
method.
Analysis parameters are accessible in AnalysisMethodSupport.parameters
field.
[edit] justAnalyzeAndPut implementation
The justAnalyzeAndPut
method is called at most once per analysis class object. If user launches the same analysis several times, new objects will be created.
The return value of this method can be either resulting element or Java array of resulting elements. System will try to store analysis parameters in these elements info and open them automatically. Return null if your analysis don't create any result (but throw an exception if your analysis should be considered as failed).
[edit] Parameters validation
Analysis parameters are validated before justAnalyzeAndPut
is called.
By default only repository paths are validated. The following validations are performed:
- Input elements must exist, must have the requested element type and reference type (if it was constrained).
- Parent collection for output element must exist. If it doesn't exist, validator will try to create this collection.
- Parent collection for output element must be writable.
- It must be possible to save the requested output element type to the parent collection.
- Output path cannot be the same as any of input paths.
To add your own validation code, override AnalysisMethodSupport.validateParameters()
method. There are some handy check* methods in AnalysisMethodSupport
class which will make basic validations easy.
Please remember that even if user interface doesn't allow to enter invalid value (for example, restricting choise with drop-down list), parameters can be filled in the various ways:
- Using workflow mechanism;
- Executing analysis from JavaScript console;
- Executing analysis via BioUML API (using BioUML web client or rbiouml R package).
Thus you may still encounter values which might be impossible to enter using UI controls.
[edit] Logging
To log messages during analysis execution, use AnalysisMethodSupport.log
logger instance. This instance is connected with analysis or workflow log. In case of unrecoverable error, it's better to throw BioUML exception out of justAnalyzeAndPut
method than to log it by yourself.
[edit] Progress bar
This page or section is a stub. Please add more information here! |
[edit] Parallelization
This page or section is a stub. Please add more information here! |