3434import java .lang .reflect .TypeVariable ;
3535import java .util .ArrayList ;
3636import java .util .Arrays ;
37+ import java .util .Collections ;
38+ import java .util .Comparator ;
3739import java .util .EnumSet ;
3840import java .util .HashMap ;
3941import java .util .Iterator ;
4042import java .util .LinkedList ;
4143import java .util .List ;
4244import java .util .Map ;
4345import java .util .Map .Entry ;
46+ import java .util .function .Function ;
4447import java .util .stream .Collectors ;
4548
4649import org .scijava .InstantiableException ;
5558import org .scijava .ops .matcher .OpMatcher ;
5659import org .scijava .ops .matcher .OpMatchingException ;
5760import org .scijava .ops .matcher .OpRef ;
58- import org .scijava .ops .transform .DefaultOpTransformationMatcher ;
59- import org .scijava .ops .transform .OpTransformationCandidate ;
60- import org .scijava .ops .transform .OpTransformationException ;
61+ import org .scijava .ops .transform .AdaptedOp ;
6162import org .scijava .ops .transform .OpTransformationMatcher ;
6263import org .scijava .ops .transform .OpTransformer ;
64+ import org .scijava .ops .types .Any ;
6365import org .scijava .ops .types .Nil ;
6466import org .scijava .ops .types .TypeService ;
6567import org .scijava .ops .util .OpWrapper ;
@@ -211,12 +213,12 @@ private synchronized List<OpTransformer> getTransformerIndex() {
211213 return transformerIndex ;
212214 }
213215
214- private OpTransformationMatcher getTransformationMatcher () {
215- if (transformationMatcher == null ) {
216- transformationMatcher = new DefaultOpTransformationMatcher (getOpMatcher ());
217- }
218- return transformationMatcher ;
219- }
216+ // private OpTransformationMatcher getTransformationMatcher() {
217+ // if (transformationMatcher == null) {
218+ // transformationMatcher = new DefaultOpTransformationMatcher(getOpMatcher());
219+ // }
220+ // return transformationMatcher;
221+ // }
220222
221223 /**
222224 * Attempts to inject {@link OpDependency} annotated fields of the specified
@@ -264,49 +266,91 @@ public <T> T findOpInstance(final String opName, final Nil<T> specialType, final
264266 public Object findOpInstance (final String opName , final OpRef ref , boolean adaptable ) {
265267 Object op = null ;
266268 OpCandidate match = null ;
267- OpTransformationCandidate transformation = null ;
269+ AdaptedOp adaptation = null ;
268270 try {
269271 // Find single match which matches the specified types
270272 match = getOpMatcher ().findSingleMatch (this , ref );
271273 final List <Object > dependencies = resolveOpDependencies (match );
272274 op = match .createOp (dependencies );
273275 } catch (OpMatchingException e ) {
274276 log .debug ("No matching Op for request: " + ref + "\n " );
275- if (adaptable == false ) {
277+ if (adaptable == false ) {
276278 throw new IllegalArgumentException (opName + " cannot be adapted (adaptation is disabled)" );
277279 }
278- log .debug ("Attempting Op transformation..." );
279-
280- // If we can't find an op matching the original request, we try to find a
281- // transformation
282- transformation = getTransformationMatcher ().findTransformation (this , getTransformerIndex (), ref );
283- if (transformation == null ) {
284- log .debug ("No matching Op transformation found" );
285- throw new IllegalArgumentException (e );
286- }
287-
288- // If we found one, try to do transformation and return transformed op
289- log .debug ("Matching Op transformation found:\n " + transformation + "\n " );
280+ log .debug ("Attempting Op adaptation..." );
290281 try {
291- final List <Object > dependencies = resolveOpDependencies (transformation .getSourceOp ());
292- op = transformation .exceute (this , dependencies );
293- } catch (OpMatchingException | OpTransformationException e1 ) {
294- throw new IllegalArgumentException ("Execution of Op transformatioon failed:\n " + e1 );
282+ adaptation = adaptOp (ref );
283+ op = adaptation .op ();
284+ } catch (OpMatchingException e1 ) {
285+ log .debug ("No suitable Op adaptation found" );
286+ throw new IllegalArgumentException (e1 );
295287 }
288+
296289 }
297290 try {
298291 // Try to resolve annotated OpDependency fields
292+ // N.B. Adapted Op dependency fields are already matched.
299293 if (match != null )
300294 resolveOpDependencies (match );
301- else if (transformation != null )
302- resolveOpDependencies (transformation .getSourceOp ());
303295 } catch (OpMatchingException e ) {
304296 throw new IllegalArgumentException (e );
305297 }
306- Object wrappedOp = wrapOp (op , match , transformation );
298+ // TODO: THIS IS WRONG! We need the OpInfo of the output of the adaptation!
299+ // This gives the OpInfo of the original (unadapted) op!
300+ OpInfo adaptedInfo = adaptation == null ? null : adaptation .srcInfo ();
301+ Object wrappedOp = wrapOp (op , match , adaptedInfo );
307302 return wrappedOp ;
308303 }
309304
305+ private AdaptedOp adaptOp (OpRef ref ) throws OpMatchingException {
306+
307+ // TODO: support all types of ref
308+ // create an OpCandidate list of suitable adaptors
309+ Type adaptTo = ref .getTypes ()[0 ];
310+ Type adaptFrom = new Any ();
311+ Type refType = Types .parameterize (Function .class , new Type [] {adaptFrom , adaptTo });
312+ OpRef adaptorRef = new OpRef ("adapt" , new Type [] {refType }, adaptTo , new Type [] {adaptFrom });
313+ List <OpCandidate > adaptorCandidates = getOpMatcher ().findCandidates (this , adaptorRef );
314+ Comparator <OpCandidate > comp = (OpCandidate i1 ,
315+ OpCandidate i2 ) -> i1 .opInfo ().priority () < i2 .opInfo ().priority () ? -1
316+ : i1 .opInfo ().priority () == i2 .opInfo ().priority () ? 0 : 1 ;
317+ Collections .sort (adaptorCandidates , comp );
318+
319+ while (adaptorCandidates .size () > 0 ) {
320+ OpCandidate adaptor = adaptorCandidates .remove (0 );
321+ try {
322+ // resolve adaptor dependencies and get the adaptor (as a function) //TODO
323+ final List <Object > dependencies = resolveOpDependencies (adaptor );
324+ // adaptor.setStatus(StatusCode.MATCH);
325+ Object adaptorOp = adaptor .opInfo ().createOpInstance (dependencies ).object ();
326+
327+ // grab the first type parameter (from the OpCandidate?) and search for an Op
328+ // that will then be adapted (this will be the first (only) type in the args of
329+ // the adaptor)
330+ Type srcOpType = adaptor .opInfo ().inputs ().get (0 ).getType ();
331+ final OpRef srcOpRef ;
332+ srcOpRef = inferOpRef (srcOpType , ref .getName (), adaptor .typeVarAssigns ());
333+ // TODO: export this to another function (also done in findOpInstance).
334+ // We need this here because we need to grab the OpInfo.
335+ // TODO: is there a better way to do this?
336+ final OpCandidate srcCandidate = getOpMatcher ().findSingleMatch (this , srcOpRef );
337+ final List <Object > srcDependencies = resolveOpDependencies (srcCandidate );
338+ final Object fromOp = srcCandidate .opInfo ().createOpInstance (srcDependencies ).object ();
339+
340+ // get adapted Op by applying adaptor on unadapted Op, then return
341+ // TODO: can we make this safer?
342+ @ SuppressWarnings ("unchecked" )
343+ Object toOp = ((Function <Object , Object >) adaptorOp ).apply (fromOp );
344+ return new AdaptedOp (toOp , srcCandidate .opInfo (), adaptor .opInfo ());
345+ } catch (OpMatchingException e1 ) {
346+ continue ;
347+ }
348+
349+ }
350+ // no adaptors available.
351+ throw new OpMatchingException ("Op adaptation failed: no adaptable Ops of type " + ref .getName ());
352+ }
353+
310354 /**
311355 * Wraps the matched op into an {@link Op} that knows its generic typing and
312356 * {@link OpInfo}.
@@ -321,11 +365,11 @@ else if (transformation != null)
321365 * needed.
322366 * @return an {@link Op} wrapping of op.
323367 */
324- private Object wrapOp (Object op , OpCandidate match , OpTransformationCandidate transformation ) {
368+ private Object wrapOp (Object op , OpCandidate match , OpInfo adaptationSrcInfo ) {
325369 if (wrappers == null )
326370 initWrappers ();
327371
328- OpInfo opInfo = match == null ? transformation . getSourceOp (). opInfo () : match .opInfo ();
372+ OpInfo opInfo = match == null ? adaptationSrcInfo : match .opInfo ();
329373 // FIXME: this type is not necessarily Computer, Function, etc. but often
330374 // something more specific (like the class of an Op).
331375 Type type = opInfo .opType ();
0 commit comments