Skip to content

Commit a2b839e

Browse files
Treiblesschorlectrueden
authored andcommitted
Split OpInfo interface and implementation
1 parent 3a39fb6 commit a2b839e

6 files changed

Lines changed: 215 additions & 140 deletions

File tree

src/main/java/org/scijava/ops/OpService.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.scijava.ops.core.Op;
4444
import org.scijava.ops.matcher.MatchingResult;
4545
import org.scijava.ops.matcher.OpCandidate;
46+
import org.scijava.ops.matcher.OpClassInfo;
4647
import org.scijava.ops.matcher.OpInfo;
4748
import org.scijava.ops.matcher.OpRef;
4849
import org.scijava.ops.matcher.OpTypeMatchingService;
@@ -87,21 +88,31 @@ public class OpService extends AbstractService implements SciJavaService, OpEnvi
8788
private Map<String, String> opAliases = new HashMap<>();
8889

8990
public void initOpCache() {
90-
opCache = new PrefixTree<OpInfo>();
91-
for (final PluginInfo<Op> info : pluginService.getPluginsOfType(Op.class)) {
91+
opCache = new PrefixTree<>();
92+
93+
// Add regular Ops
94+
for (final PluginInfo<Op> pluginInfo : pluginService.getPluginsOfType(Op.class)) {
9295
try {
93-
final Class<? extends Op> opClass = info.loadClass();
94-
OpInfo opInfo = new OpInfo(opClass);
95-
String[] opNames = OpUtils.parseOpNames(info.getName());
96-
97-
addAliases(opNames);
98-
99-
opCache.add(new PrefixQuery(opNames[0]), opInfo);
96+
final Class<? extends Op> opClass = pluginInfo.loadClass();
97+
OpInfo opInfo = new OpClassInfo(opClass);
98+
addToCache(opInfo, pluginInfo.getName());
99+
100100
} catch (InstantiableException exc) {
101-
log.error("Can't load class from plugin info: " + info.toString(), exc);
101+
log.error("Can't load class from plugin info: " + pluginInfo.toString(), exc);
102102
}
103103
}
104104
}
105+
106+
private void addToCache(OpInfo opInfo, String opNames) {
107+
if (!opInfo.isValid()) {
108+
log.error("Skipping invalid Op " + opInfo.implementationName() + ":\n"
109+
+ opInfo.getValidityException().getMessage());
110+
return;
111+
}
112+
String[] parsedNames = OpUtils.parseOpNames(opNames);
113+
addAliases(parsedNames);
114+
opCache.add(new PrefixQuery(parsedNames[0]), opInfo);
115+
}
105116

106117
@Override
107118
public Iterable<OpInfo> infos() {

src/main/java/org/scijava/ops/OpUtils.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,7 @@ public static Type[] types(OpCandidate candidate) {
110110
}
111111

112112
public static double getPriority(final OpCandidate candidate) {
113-
// TODO: Think about what to do about non @Plugin-based ops...?
114-
// What if there is no annotation? How to discern a priority?
115-
return candidate.opInfo().getAnnotation().priority();
113+
return candidate.opInfo().priority();
116114
}
117115

118116
public static Type[] padArgs(final OpCandidate candidate) {
@@ -295,7 +293,7 @@ public static String opString(final OpInfo info, final Member<?> special) {
295293
final String outputString = paramString(outputs(info.struct()), null).trim();
296294
if (!outputString.isEmpty())
297295
sb.append("(" + outputString + ") =\n\t");
298-
sb.append(info.opClass().getName());
296+
sb.append(info.implementationName());
299297
sb.append("(" + paramString(inputs(info.struct()), special) + ")");
300298
return sb.toString();
301299
}
@@ -343,4 +341,26 @@ private static String paramString(final Iterable<Member<?>> items, final Member<
343341
}
344342
return sb.toString();
345343
}
344+
345+
public static String opString(final OpInfo info) {
346+
final StringBuilder sb = new StringBuilder();
347+
sb.append(info.implementationName() + "(\n\t Inputs:\n");
348+
for (final Member<?> arg : info.inputs()) {
349+
sb.append("\t\t");
350+
sb.append(arg.getType().getTypeName());
351+
sb.append(" ");
352+
sb.append(arg.getKey());
353+
sb.append("\n");
354+
}
355+
sb.append("\t Outputs:\n");
356+
for (final Member<?> arg : info.outputs()) {
357+
sb.append("\t\t");
358+
sb.append(arg.getType().getTypeName());
359+
sb.append(" ");
360+
sb.append(arg.getKey());
361+
sb.append("\n");
362+
}
363+
sb.append(")\n");
364+
return sb.toString();
365+
}
346366
}

src/main/java/org/scijava/ops/matcher/DefaultOpTypeMatchingService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public List<OpCandidate> findCandidates(final OpEnvironment ops, final List<OpRe
9292
final ArrayList<OpCandidate> candidates = new ArrayList<>();
9393
for (final OpRef ref : refs) {
9494
for (final OpInfo info : ops.infos(ref.getName())) {
95-
if (ref.typesMatch(info.opClass())) {
95+
if (ref.typesMatch(info.opType())) {
9696
candidates.add(new OpCandidate(ops, ref, info));
9797
}
9898
}

src/main/java/org/scijava/ops/matcher/OpCandidate.java

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -206,19 +206,7 @@ public StructInstance<?> createOp() {
206206
throw new IllegalArgumentException(
207207
"Status of candidate to create op " + "from indicates a problem: " + getStatus());
208208
}
209-
final Class<?> opClass = opInfo().opClass();
210-
final Object object;
211-
try {
212-
// TODO: Consider whether this is really the best way to
213-
// instantiate the op class here. No framework usage?
214-
// E.g., what about pluginService.createInstance?
215-
object = opClass.newInstance();
216-
} catch (final InstantiationException | IllegalAccessException e) {
217-
// TODO: Think about whether exception handling here should be
218-
// different.
219-
throw new IllegalStateException("Unable to instantiate op: '" + opClass.getName()
220-
+ "' Each op must have a no-args constructor.", e);
221-
}
222-
return struct().createInstance(object);
209+
210+
return opInfo().createOp();
223211
}
224212
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
* #%L
3+
* ImageJ software for multidimensional image processing and analysis.
4+
* %%
5+
* Copyright (C) 2014 - 2018 ImageJ developers.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
30+
package org.scijava.ops.matcher;
31+
32+
import java.lang.reflect.Type;
33+
import java.util.List;
34+
35+
import org.scijava.core.Priority;
36+
import org.scijava.ops.OpUtils;
37+
import org.scijava.ops.core.Op;
38+
import org.scijava.param.ParameterStructs;
39+
import org.scijava.param.ValidityException;
40+
import org.scijava.plugin.Plugin;
41+
import org.scijava.struct.Member;
42+
import org.scijava.struct.Struct;
43+
import org.scijava.struct.StructInstance;
44+
import org.scijava.util.Types;
45+
46+
/**
47+
* Metadata about an op implementation defined as a class.
48+
*
49+
* @author Curtis Rueden
50+
* @author David Kolb
51+
*/
52+
public class OpClassInfo implements OpInfo {
53+
54+
private final Class<? extends Op> opClass;
55+
private Struct struct;
56+
private ValidityException validityException;
57+
58+
public OpClassInfo(final Class<? extends Op> opClass) {
59+
this.opClass = opClass;
60+
try {
61+
struct = ParameterStructs.structOf(opClass);
62+
} catch (ValidityException e) {
63+
validityException = e;
64+
}
65+
}
66+
67+
// -- OpInfo methods --
68+
69+
@Override
70+
public Type opType() {
71+
// TODO: Check whether this is correct!
72+
return Types.parameterizeRaw(opClass);
73+
//return opClass;
74+
}
75+
76+
@Override
77+
public Struct struct() {
78+
return struct;
79+
}
80+
81+
@Override
82+
public List<Member<?>> inputs() {
83+
return OpUtils.inputs(struct());
84+
}
85+
86+
@Override
87+
public List<Member<?>> outputs() {
88+
return OpUtils.outputs(struct());
89+
}
90+
91+
@Override
92+
public double priority() {
93+
final Plugin opAnnotation = opClass.getAnnotation(Plugin.class);
94+
return opAnnotation == null ? Priority.NORMAL : opAnnotation.priority();
95+
}
96+
97+
@Override
98+
public String implementationName() {
99+
return opClass.getName();
100+
}
101+
102+
@Override
103+
public StructInstance<?> createOp() {
104+
final Object object;
105+
try {
106+
// TODO: Consider whether this is really the best way to
107+
// instantiate the op class here. No framework usage?
108+
// E.g., what about pluginService.createInstance?
109+
object = opClass.newInstance();
110+
} catch (final InstantiationException | IllegalAccessException e) {
111+
// TODO: Think about whether exception handling here should be
112+
// different.
113+
throw new IllegalStateException("Unable to instantiate op: '" + opClass.getName()
114+
+ "' Each op must have a no-args constructor.", e);
115+
}
116+
return struct().createInstance(object);
117+
}
118+
119+
@Override
120+
public ValidityException getValidityException() {
121+
return validityException;
122+
}
123+
124+
@Override
125+
public boolean isValid() {
126+
return validityException == null;
127+
}
128+
129+
// -- Object methods --
130+
131+
@Override
132+
public boolean equals(final Object o) {
133+
if (!(o instanceof OpClassInfo))
134+
return false;
135+
final OpInfo that = (OpInfo) o;
136+
return struct().equals(that.struct());
137+
}
138+
139+
@Override
140+
public int hashCode() {
141+
return struct().hashCode();
142+
}
143+
144+
@Override
145+
public String toString() {
146+
return OpUtils.opString(this);
147+
}
148+
}

0 commit comments

Comments
 (0)