Skip to content

Commit 48c5b38

Browse files
authored
Merge pull request #18 from scijava/input-providers
Add input provider plugins
2 parents 14d5b22 + c503a13 commit 48c5b38

File tree

9 files changed

+247
-20
lines changed

9 files changed

+247
-20
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</parent>
1111

1212
<artifactId>batch-processor</artifactId>
13-
<version>0.1.4-SNAPSHOT</version>
13+
<version>0.2.0-SNAPSHOT</version>
1414

1515
<name>Batch Processor</name>
1616
<description>A Batch Processor for SciJava Modules and Scripts</description>

src/main/java/org/scijava/batch/BatchModuleSearchActionFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ public class BatchModuleSearchActionFactory implements SearchActionFactory {
2222
@Override
2323
public boolean supports(final SearchResult result) {
2424
return (result instanceof ModuleSearchResult)
25-
&& batchService.supports(((ModuleSearchResult) result).info());
25+
&& batchService.supportsModule(((ModuleSearchResult) result).info());
2626
}
2727

2828
@Override
2929
public SearchAction create(final SearchResult result) {
30-
return new DefaultSearchAction("Batch", true, () -> {
30+
return new DefaultSearchAction("Batch", () -> {
3131
batchService.run(((ModuleSearchResult) result).info());
3232
});
3333
}

src/main/java/org/scijava/batch/BatchService.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,34 @@
44
import java.util.stream.Collectors;
55
import java.util.stream.StreamSupport;
66

7+
import org.scijava.batch.input.BatchInput;
8+
import org.scijava.batch.input.BatchInputProvider;
9+
import org.scijava.module.Module;
710
import org.scijava.module.ModuleInfo;
811
import org.scijava.module.ModuleItem;
12+
import org.scijava.plugin.HandlerService;
913
import org.scijava.service.SciJavaService;
1014

11-
public interface BatchService extends SciJavaService {
15+
public interface BatchService extends HandlerService<BatchInput, BatchInputProvider<?>>, SciJavaService {
1216
/**
1317
* Returns true if {@code moduleInfo} has at least one input item whose type
1418
* is supported by this service
1519
*/
16-
default public boolean supports(ModuleInfo moduleInfo) {
20+
default public boolean supportsModule(ModuleInfo moduleInfo) {
1721
for (ModuleItem<?> input : moduleInfo.inputs()) {
18-
if (supports(input.getType()))
22+
if (supportsItem(input))
1923
return true;
2024
}
2125
return false;
2226
}
27+
28+
//default public getHandler(ModuleItem)
2329

2430
/**
2531
* Returns true if {@code type} can be populated with batch inputs provided
2632
* by this service
2733
*/
28-
public boolean supports(Class<?> type);
34+
public boolean supportsItem(ModuleItem<?> moduleItem);
2935

3036
/**
3137
* Run the module described by {@link ModuleInfo} in batch.
@@ -38,7 +44,14 @@ default public boolean supports(ModuleInfo moduleInfo) {
3844
*/
3945
default public List<ModuleItem<?>> batchableInputs(ModuleInfo moduleInfo) {
4046
return StreamSupport.stream(moduleInfo.inputs().spliterator(), false)
41-
.filter(item -> supports(item.getType()))
47+
.filter(item -> supportsItem(item))
4248
.collect(Collectors.toList());
4349
}
50+
51+
/**
52+
* Fill a provided ModuleItem with a given input object
53+
* @param <I>
54+
*/
55+
public <I> void fillInput(Module module, ModuleItem<?> moduleItem, I inputObject);
56+
4457
}

src/main/java/org/scijava/batch/FileBatchService.java

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,48 @@
44
import java.util.HashMap;
55

66
import org.scijava.Priority;
7+
import org.scijava.batch.input.BatchInput;
8+
import org.scijava.batch.input.BatchInputProvider;
79
import org.scijava.command.CommandService;
810
import org.scijava.log.LogService;
11+
import org.scijava.module.Module;
912
import org.scijava.module.ModuleInfo;
13+
import org.scijava.module.ModuleItem;
14+
import org.scijava.plugin.AbstractHandlerService;
1015
import org.scijava.plugin.Parameter;
1116
import org.scijava.plugin.Plugin;
12-
import org.scijava.service.AbstractService;
1317
import org.scijava.service.Service;
1418

1519
@Plugin(type = Service.class, priority = Priority.LOW)
16-
public final class FileBatchService extends AbstractService implements
17-
BatchService {
20+
public final class FileBatchService extends AbstractHandlerService<BatchInput, BatchInputProvider<?>> implements BatchService {
1821

1922
@Parameter
2023
private LogService log;
21-
24+
2225
@Parameter
2326
private CommandService commandService;
2427

2528
/**
2629
* Returns true if {@code type} is a {@link File}.
2730
*/
2831
@Override
29-
public boolean supports(Class<?> type) {
30-
return type.isAssignableFrom(File.class);
32+
public boolean supportsItem(ModuleItem<?> moduleItem) {
33+
BatchInputProvider<?> handler = getHandler(new BatchInput(File.class, moduleItem));
34+
if (handler == null) {
35+
return false;
36+
}
37+
return handler.canProvide(moduleItem);
38+
}
39+
40+
@SuppressWarnings("unchecked")
41+
@Override
42+
public <I> void fillInput(Module module, ModuleItem<?> moduleItem, I inputObject) {
43+
BatchInputProvider<File> handler = (BatchInputProvider<File>) getHandler(new BatchInput(File.class, moduleItem));
44+
if (handler == null) {
45+
log.error("No handler found for input: " + moduleItem.getName());
46+
return;
47+
}
48+
handler.populateInput(module, moduleItem, (File) inputObject);
3149
}
3250

3351
@Override
@@ -37,10 +55,30 @@ public void run(ModuleInfo moduleInfo) {
3755
log.error("No compatible inputs (of type File) found.");
3856
return;
3957
}
58+
59+
// 1) get input ModuleItems
60+
// 2) choose ModuleItem
61+
// 3) get suitable BatchInputProvider
62+
// 4) get Iterator for ModuleItem
63+
64+
//for (getHandler(new BatchInput(File.class, moduleItem)).iterate(fileList)) {
65+
//}
66+
4067
// Call ModuleBatchProcessor with input moduleInfo
4168
HashMap<String, Object> inputMap = new HashMap<>();
4269
inputMap.put("moduleInfo", moduleInfo);
4370
commandService.run(ModuleBatchProcessor.class, true, inputMap);
4471
}
4572

73+
@SuppressWarnings({ "unchecked", "rawtypes" })
74+
@Override
75+
public Class<BatchInputProvider<?>> getPluginType() {
76+
return (Class) BatchInputProvider.class;
77+
}
78+
79+
@Override
80+
public Class<BatchInput> getType() {
81+
return BatchInput.class;
82+
}
83+
4684
}

src/main/java/org/scijava/batch/ModuleBatchProcessor.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
import org.scijava.widget.FileWidget;
2828

2929
@Plugin(type = Command.class, label = "Choose batch processing parameters", initializer = "initInputChoice")
30-
public class ModuleBatchProcessor extends DynamicCommand {
30+
public class ModuleBatchProcessor<T> extends DynamicCommand {
3131
@Parameter
3232
private ModuleService moduleService;
3333

@@ -66,6 +66,8 @@ protected void initInputChoice() {
6666
} else if (compatibleInputs.size() > 1) {
6767
choiceInput.setChoices(compatibleInputs.stream()
6868
.map(ModuleItem::getName).collect(Collectors.toList()));
69+
} else {
70+
log.error("No compatible inputs found. Unable to initialize input choice.");
6971
}
7072
}
7173

@@ -74,7 +76,7 @@ protected void initInputChoice() {
7476
@Override
7577
public void run() {
7678
// mark inputChoice as resolved, then harvest script parameters (i.e. run)
77-
ModuleItem<File> fileInput = moduleInfo.getInput(inputChoice, File.class);
79+
ModuleItem<?> inputModuleItem = moduleInfo.getInput(inputChoice);
7880
// TODO check if conversion needed?
7981
Module scriptModule = moduleService.createModule(moduleInfo);
8082
scriptModule.resolveInput(inputChoice);
@@ -89,8 +91,8 @@ public void run() {
8991
scriptModule.resolveOutput(outputKey);
9092
}
9193

92-
for (File file: inputFileList) {
93-
if(!processFile(scriptModule, fileInput, file)) {
94+
for (File file : inputFileList) {
95+
if(!processFile(scriptModule, inputModuleItem, file)) {
9496
log.warn("Terminating batch process.");
9597
break; // end for loop
9698
}
@@ -105,8 +107,9 @@ public void run() {
105107
// -- Helper methods --
106108

107109
@SuppressWarnings("unchecked")
108-
private boolean processFile(Module module, ModuleItem<File> fileInput, File file) {
109-
fileInput.setValue(module, file);
110+
private boolean processFile(Module module, ModuleItem<?> inputModuleItem, File file) {
111+
batchService.fillInput(module, inputModuleItem, file);
112+
//fileInput.setValue(module, file);
110113
outputTable.appendRow(file.getName());
111114

112115
Future<Module> instance = moduleService.run(module, true);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.scijava.batch.input;
2+
3+
import java.lang.reflect.Type;
4+
5+
import org.scijava.module.ModuleItem;
6+
7+
/**
8+
* Currency for use with {@link BatchInputProvider} methods
9+
*
10+
*
11+
*
12+
* @author Jan Eglinger
13+
*
14+
*/
15+
public class BatchInput {
16+
private final Type srcType;
17+
private final ModuleItem<?> destItem;
18+
19+
public BatchInput(final Class<?> srcClass, final ModuleItem<?> destItem) {
20+
this.srcType = srcClass;
21+
this.destItem = destItem;
22+
}
23+
24+
public BatchInput(final Type srcType, final ModuleItem<?> destItem) {
25+
this.srcType = srcType;
26+
this.destItem = destItem;
27+
}
28+
29+
public Type sourceType() {
30+
return srcType;
31+
}
32+
33+
public ModuleItem<?> moduleItem() {
34+
return destItem;
35+
}
36+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
package org.scijava.batch.input;
3+
4+
import org.scijava.module.Module;
5+
import org.scijava.module.ModuleItem;
6+
import org.scijava.plugin.HandlerPlugin;
7+
8+
public interface BatchInputProvider<I> extends HandlerPlugin<BatchInput> {
9+
10+
@Override
11+
default public Class<BatchInput> getType() {
12+
return BatchInput.class;
13+
}
14+
15+
/**
16+
* Check if a given {@code ModuleItem} can be populated by this input provider.
17+
* Implementations should make sure to not only match the type of objects, but
18+
* also respect possible widget style settings, such as files, directories,
19+
* image files only, etc.
20+
*
21+
* @param moduleItem
22+
* the input item that needs to be populated
23+
* @return true if this input provider can provide suitable objects
24+
*/
25+
public boolean canProvide(ModuleItem<?> moduleItem);
26+
27+
public void populateInput(Module module, ModuleItem<?> moduleItem, I inputObject);
28+
29+
public String getTargetWidgetStyle(ModuleItem<?> moduleItem);
30+
31+
// public Iterable<O> iterate(Collection<I> fileList);
32+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
2+
package org.scijava.batch.input;
3+
4+
import java.io.File;
5+
import java.util.ArrayList;
6+
import java.util.Arrays;
7+
8+
import org.scijava.module.Module;
9+
import org.scijava.module.ModuleItem;
10+
import org.scijava.plugin.AbstractHandlerPlugin;
11+
import org.scijava.plugin.Plugin;
12+
import org.scijava.widget.FileListWidget;
13+
import org.scijava.widget.FileWidget;
14+
15+
@Plugin(type = BatchInputProvider.class)
16+
public class FileBatchInputProvider extends AbstractHandlerPlugin<BatchInput> implements
17+
BatchInputProvider<File>
18+
{
19+
@Override
20+
public boolean supports(BatchInput input) {
21+
return canProvide(input.moduleItem());
22+
}
23+
24+
@Override
25+
public boolean canProvide(ModuleItem<?> item) {
26+
// we can't provide inputs for saving files
27+
return item.getType() == File.class && !hasStyle(item, FileWidget.SAVE_STYLE);
28+
}
29+
30+
@SuppressWarnings("unchecked")
31+
@Override
32+
public void populateInput(Module module, ModuleItem<?> moduleItem, File inputObject) {
33+
((ModuleItem<File>)moduleItem).setValue(module, inputObject);
34+
}
35+
36+
@Override
37+
public String getTargetWidgetStyle(ModuleItem<?> item) {
38+
ArrayList<String> targetStyles = new ArrayList<>();
39+
40+
if (hasStyle(item, FileWidget.DIRECTORY_STYLE)) {
41+
targetStyles.add(FileListWidget.DIRECTORIES_ONLY);
42+
} else {
43+
targetStyles.add(FileListWidget.FILES_ONLY);
44+
}
45+
46+
// extensions?
47+
String widgetStyle = item.getWidgetStyle();
48+
if (widgetStyle != null) {
49+
String[] styles = widgetStyle.trim().split("\\s*,\\s*");
50+
for (String s : styles) {
51+
if (s.startsWith("extensions")) { // TODO: use new constant from FileListWidget
52+
targetStyles.add(s);
53+
}
54+
}
55+
}
56+
return String.join(",", targetStyles);
57+
}
58+
59+
private boolean hasStyle(ModuleItem<?> item, String style) {
60+
String widgetStyle = item.getWidgetStyle();
61+
if (widgetStyle == null) return false;
62+
return Arrays.asList(widgetStyle.trim().split("\\s*,\\s*"))
63+
.contains(style);
64+
}
65+
}

0 commit comments

Comments
 (0)