General Introduction
A non-functional requirement: There should be a single wrapper object that encapsulates all notion of a connection the remote framework. This wrapper object might have methods that return session or factory objects, or it might be an adapter for session and factory methods, but client code should not have to pass around sessions and factories separately, or to write their own wrappers/adapters. In the following, I've called that wrapper "factory", but this is just for convenience. If a different name is preferred in order to avoid confusion with the Factory pattern, that's fine with me. In my code, I've been calling the object that interacts with the database a "connection".
Note that some of these things are going to look and feel a bit redundant, or at least reflexive. I think it's particularly important to be able to have some sort of symmetry of calls. For example, earlier today, i was looking at something and realized that i wanted to find all of the executions for a given chain. Given a dataset, it's currently easy to find all of the executions for all chains, and then to filter out executions for the given chain. However, if all i have handy is a pointer to the chain, it's harder to get the executions. Ideally, i'd be able to ask both the dataset and the chain for executions.
Some of the other suggestions below involve finding sets of items with or without constraints - ie., find all of the chain executions in a dataset, or find all of the chain executions in a dataset _for a given chain_. I'd like to suggest that the API provide dedicated calls for the more important constraints, along with a _well_documented_ vocabulary for setting arbitrary constraints - something like the hash that we can use now on factory.findObjects(), but perhaps a bit cleaner.
I've left out some of the obvious calls like getID() (that's the only one that I can think of). Also, I have intentionally omitted calls that probably shouldn't be exposed to clients, like location and execution instructions for modules.
Finally, all clases for core database objects - Project, Dataset, Chain, etc. - should be extensible through subclassing. This might mean that java's dynamic proxy mechanism might be inappropriate for these objects, as it's not clear how to subclass objects returned by dynamic proxies. !!! Specific Details
- Retrieve lists from the database
- Retrieve sizes of those lists, without getting the whole list.
- All modules
public List factory.getModules();
- Modules by category (i.e, given a ModuleCategory? or text name)
public List factory.getModules(ModuleCategory? modCat); public List factory.getModules(String name);
- Uncategorized Module
public List factory.getUncategorizedModules()
- All chains
public List factory.getChains();
- # of chains
public int factory.getChainCount();
- All Projects
public List factory.getProjects();
- # of projects
public int factory.getProjectCount();
- All projects for the current user
public List factory.getProjectsForCurrentUser();
- Projects for a given user
public List factory.getProjects(String userName);
- counts
public int factory.getProjectCountForCurrentUser() public int factory.getProjectCount(String userName)
- Retrieve by ID
- Module
public Module fatory.getModule(int id);
- Chain
public Chain factory.getChain(int id);
- Project
public Project factory.getProject(int id);
- Dataset
public Dataset factory.getDataset(int id);
- Chain Executions
public ChainExecution? factory.getChainExecution(int id);
- Module Executions
public ModuleExecution? factory.getModuleExecution(int id);
- Database contents statistics:
- Number of Modules
public int factory.getModuleCount();
- Number of Chains
public int factory.getChainCount();
- Number of Projects
public int factory.getProjectCount();
- Number of Datasets
public int factory.getDatasetCount();
- number of datasets in a project
- public int project.getDatasetCount();
- number of images in a dataset
public int dataset.getImageCount()
- From a semantic type
- Name
public String type.getName();
- Description
public String type.getDescription();
- Elements
public List type.getElements(); public Iterator type.iterateElements();
- Granularity
public int type.getGranularity()
- From a semantic element
- semantic type
public SemanticType? element.getSemanticType();
- name
public String element.getName();
(currently, this is getElementName(), which seems unnecessarily verbose);
- description
public String element.getDescription()
(currently getElementDescription()).
- From a Formal Parameter
- Name
public String parameter.getName()
(again, getParameterName() is too verbose)
- Description
public String parameter.getDescription()
(not getParameterDescription())
- Semantic Type
public SemanticType? parameter.getSemanticType()
- Arity
public boolean parameter.isList();
- Optional (true/false)
public boolean parameter.isOptional()
- From a formal input
- UserDefined??
public boolean input.isUserDefined()
- From a formal output
m - Feature Tag public String getFeatureTag()
- From a Module
- Name
public String module.getName();
- Description
public String module.getDescription();
- Category
public ModuleCategory? getCategory();
- Iterator
public String getDefaultIterator();
- New Feature Tag
public String getNewFeatureTag();
public List module.getInputs(); public Iterator module.iterateInputs();
public List module.getOutputs(); public Iterator module.iterateOutputs();
- Executions
public List module.getExecutions(); public Iterator module.iterateExecutions();
- From a Chain
- Name
public String chain.getName();
- Owner
public Experimenter chain.getOwner(); Note: currently, getOwner() is defined as returning an Attribute. As we move towards clases for each of the semantic types, we should avoid explicit use of the "attribute" class, even if the classes for the semantic types are simply wrappers.
- Description
public String chain.getDescription()
- Locked (true/false)
public boolean chain.isLocked()
- Nodes
public List chain.getNodes() public Iterator chain.iterateNodes()
- Links
public List chain.getLinks() public Iteator chain.iterateLinks()
- List of all executions
public List chain.getExecutions(); public int chain.getExecutionCount();
- List of executions for a given dataset
public List chain.getExecutions(Dataset d) public int chain.getExecutionCount(Dataset d)
- Chain Node
- Chain
public Chain node.getChain();
- Module
public Module node.getModule();
- iterator tag
public String node.getIteratorTag();
- New Feature tag
public String getNewFeatureTag();
- Input Links
public List getInputLinks() public Iterator iterateInputLinks();
- Output Links
public List getOutputLinks() public Iterator iterateOutputLinks();
- Chain Link
- chain
public Chain link.getChain();
- From node
public Node link.getFromNode();
public FomalOutput?? link.getFromOutput()
- to Node
public Node link.getToNode()
public FomalOutput?? link.getToOutput()
- From a project
- Name
public String project.getName()
- Description
public String project.getDescription();
- Owner
public Experimenter project.getOwner() (see above comment on - chain owner)
- All datasets
public List getDatasets(); public Iterator getDatasets(); public int getDatasetCount()
- From a dataset
- Name
public String dataset.getName();
- Description
public String dataset.getDescription();
- Locked status
public boolean dataset.isLocked();
- Owner
public Experimenter dataset.getOwner()
- projects
public List dataset.getProjects(); public Iterator dataset.iterateProjects(); public int getProjectCount();
- Images
public List dataset.getImages() public Iterator dataset.iterateImages() public int getImageCount()
- All Chain executions
public List dataset.getChainExecutions(); public Iterator dataset.iterateChainExecutions(); public int dataset.getChainExecutions();
- Chains with executions in that set?
public List dataset.executedChains(); public Iterator dataset.iterateExecutedChains(); public int dataset.executedChainCount();
- list of all executions for a given chain
public List dataset.getChainExecutions(Chain chain) public Iterator dataset.iterateChainExecutions(Chain chain) public int dataset.getChainExecutionCount(Chain chain)
- From an Image
- Name
public String image.getName()
- Description
public String image.getDescription();
- created
public String image.getCreated()
- inserted
public String image.getInserted();
- Experimenter
public Experimenter image.getOwner() (to be consistent with other calls that get the experimenter)
- Group
public Group image.getGroup(); (again, this is an attribute currently, but should be a semantic type)
Datasets
public List image.getDatasets() public Iterator image.iterateDatasets(); public int image.getDatasetCount();
Features
public List image.getFeatures() public Iterator image.iterateFeatures(); public int getFeatureCount()
Retrieve an arbitrary slice
public ImageIcon?? image.getPlane(int z, int c, int t);
Retrieve Some sort of thumbnail, preferably in JPEG
public ImageIcon?? getThumbnail();
other calls found in ImagePixels?? might also be useful.
- Time
public String execution.getTimestamp();
- Chain
public Chain execution.getChain();
- Dataset
public Dataset execution.getDataset();
- Dataset
public Experimenter execution.getOwner();
- Nodes
public List getNodes() public Iterator iterateNodes()
- Chain Execution
public ChainExecution?? node.getChainExecution();
- chain node
public Chain.Node getChainNode();
- module execution
public ModuleExecution?? getModuleExecution();
Execution Results
A sketch for getting analysis results:
Each result of an analysis is from a formal output. Thus, each result will be an instance of a semantic type, or of some generic class (in the worst case, "Attribute") if the given semantic type does not have a java class defined.
We'd also like to tie any given result back to the image that produced it. This will require going back through to the features and to the image id.
So, the basic call will return all of the results for a chain execution, module, formal output, and image
public List execution.getResults(Module mod, FormalOutput?? out, Image img); public Iterator execution.iterateResults(Module mod, FormalOutput?? out, Image img); The result of this call will be a list of items of the SemanticType? corresponding to the FormalOutput??.
If we only have the module and formal output, we might get a list of ImageResults??, each of which is an <image,list of results> pair, where the <list of results> is a list of semantic types, as above: public List execution.getResults(Module mod,FormalOutput?? out); public Iterator execution.iterateResults(Module mod,FormalOutput?? out);
If we just have the module, we'll still get a list of ImageResults??. However, the contents will be a bit different. In the previous case, the items in the list all had the same semantic type. In this case, the lit can contain elements of different semantic types, corresponding to the different outputs of a module. Since a given module can only have one output of a given semantic type, there's no ambiguity:
public List execution.getResults(Module mod); public Iterator execution.iterateResults(Module mod);
Finally, if we want all of the results from an execution, we'll get a list of ExecutionResults?, each of which is a <module,ImageResult?> pair. This will let us find all of the results from each module.
public List execution.getResults(); public Iterator execution.iterateResults();
This raises the question of what the semantic type outputs will look like. This will be addressed in a different document
Data Transfer Objects - DTOs
DTOs aggregate data for the convenience of various client applications. ImageResultse? and ExecutionResults? described above are just two examples.
Other examples that may be of use are given below. These examples are intentionally not prioritized.
These examples often specify lists as return values. Where possible, these elements should be sorted in the most obvious manner - usually by ID.
- Analysis Chain Nodes with lists of successors and predecessors: this would be useful for automated layout of analysis chains
- List/Collection of datasets with image counts for each dataset.
- Populated list/collection of modules, with each module including populated lists of formal inputs and outputs, and retrievable by Id.
- List/collection of "top-level" Module Categories - those that do not have any parent
- List/collection of uncategorized modules
- A Tree structure of modules by category, with uncategorized modules in their own top-level subtree.
- List/collections of chains, populated with executions.
- Chains with executions addressable by dataset - ie., a structure that would let me find all of the executions of a given chain for a specified dataset.
- Chain Executions populated with executions results, as described above.
NOTE: These DTOs clearly raise questions of granularity. Should every call for a list of chains return a list of executions addressible by dataset, with each execution containing fully populated results? Some more experience with system overhead may be needed to answer these questions?
- For a given Formal Input(output), a list of matching formal outputs(inputs) ie. formal outputs(inputs) of the same semantic type.
- For a given semantic type, a list/collection of elements, each populated.
