public WorkflowStepDefinition resolveStep()

in core/src/main/java/org/apache/brooklyn/core/workflow/WorkflowStepResolution.java [136:268]


    public WorkflowStepDefinition resolveStep(Object def) {
        if (def instanceof WorkflowStepDefinition) return (WorkflowStepDefinition) def;

        BrooklynClassLoadingContext loader = RegisteredTypes.getClassLoadingContextMaybe(brooklynObject()).or(() -> RegisteredTypes.getCurrentClassLoadingContextOrManagement(mgmt()));
        String shorthand = null;

        Map defM = null;

        if (def instanceof List) {
            // list treated as implicit subworkflow, eg step: [ "sleep 1" ] = step: { steps: [ "sleep 1" ] }
            def = MutableMap.of(SubWorkflowStep.SHORTHAND_TYPE_NAME_DEFAULT, def);
        }

        if (def instanceof String) {
            shorthand = (String) def;
            defM = MutableMap.of();
        } else if (def instanceof Map) {
            defM = MutableMap.copyOf((Map)def);
            if (!defM.containsKey("type")) {
                // if there isn't a type, pull out shorthand
                Object s = defM.remove("step");
                if (s == null) s = defM.remove("shorthand");
                if (s == null) s = defM.remove("s");

                if (s==null && defM.containsKey(WorkflowCommonConfig.STEPS.getName())) {
                    // if it has steps, but no step or s, assume it is a subworkflow
                    s = SubWorkflowStep.SHORTHAND_TYPE_NAME_DEFAULT;
                }

                if (s == null && defM.size()==1) {
                    // assume the colon caused it accidentally to be a map
                    s = Iterables.getOnlyElement(defM.keySet());
                    if (s instanceof String && ((String)s).contains(" ")) {
                        s = s + " : " + Iterables.getOnlyElement(defM.values());
                    } else {
                        s = null;
                    }
                }

                if (s==null) {
                    throw new IllegalArgumentException("Step definition must indicate a `type` or a `step` / `shorthand` / `s` (" + def + ")");
                }
                if (s instanceof Map && defM.size()==1) {
                    // allow shorthand to contain a nested map if the shorthand is the only thing in the map, eg { step: { step: "xxx" } }
                    return resolveStep(s);
                }
                if (!(s instanceof String)) {
                    throw new IllegalArgumentException("step shorthand must be a string");
                }
                shorthand = (String) s;
            }
        }

        String userSuppliedShorthand = shorthand;
        if (shorthand!=null) {
            shorthand = shorthand.trim();
            int wordBreak = shorthand.indexOf(" ");
            if (defM.containsKey("type")) throw new IllegalStateException("Must not supply 'type' when shorthand is used for step");
            if (wordBreak<0) {
                defM.put("type", shorthand);
                shorthand = null;
            } else {
                defM.put("type", shorthand.substring(0, wordBreak));
                shorthand = shorthand.substring(wordBreak + 1).trim();
            }
        }

        String typeBestGuess = defM != null ? ""+defM.get("type") : null;

        try {
            Object def0 = defM !=null ? defM : def;

            Callable<Object> converter = () -> {
                Object result = BeanWithTypeUtils.convert(mgmt(), def0, TypeToken.of(WorkflowStepDefinition.class), true, loader, true);
                if (!(result instanceof WorkflowStepDefinition)) {
                    // if it's unable to convert a complex type via the above, the original type may be returned,
                    // in particular by ObjectReferencingSerialization; so the conversion doesn't report failure,
                    // and the actual failure is masked by ObjectReferencingSerialization
                    if (!inCoercionErrorBlock) {
                        inCoercionErrorBlock = true;
                        try {
                            return TypeCoercions.tryCoerce(def0, WorkflowStepDefinition.class).get();
                        } finally {
                            inCoercionErrorBlock = false;
                        }
                    }
                    // prefer above to give a better error -- but need to prevent recursion (NBD not thread safe, just won't always get best error)
                    throw new IllegalArgumentException("Cannot convert "+def0+" to workflow step; either wrong step input or insufficient context");
                }

                return result;
            };
            Entity entity = entity();
            if (entity==null) {
                def = converter.call();
            } else {
                // run in a task context if we can, to facilitate conversion and type lookup; run in same thread, so we can do this at deploy time
                def = ((EntityInternal)entity).getExecutionContext().get(
                        Tasks.builder().displayName("convert steps").body(converter).tag(BrooklynTaskTags.TRANSIENT_TASK_TAG).build());
            }

            if (def instanceof WorkflowStepDefinition.WorkflowStepDefinitionWithSpecialDeserialization) {
                def = ((WorkflowStepDefinition.WorkflowStepDefinitionWithSpecialDeserialization)def).applySpecialDefinition(mgmt(), def0, typeBestGuess, (WorkflowStepDefinition.WorkflowStepDefinitionWithSpecialDeserialization) def);
            }
        } catch (Exception e) {
            throw Exceptions.propagateAnnotated("Unable to resolve step '"+def+"'", e);
        }

        if (def instanceof WorkflowStepDefinition) {
            WorkflowStepDefinition defW = (WorkflowStepDefinition) def;

            if (userSuppliedShorthand!=null) {
                defW.userSuppliedShorthand = userSuppliedShorthand;
            }
            if (typeBestGuess!=null) {
                defW.shorthandTypeName = typeBestGuess;
            }
            if (shorthand!=null) {
                defW.populateFromShorthand(shorthand);
            }

            List<Object> onError = WorkflowErrorHandling.wrappedInListIfNecessaryOrNullIfEmpty(defW.getOnError());
            if (onError!=null && !onError.isEmpty()) {
                defW.onError = resolveSubSteps("error handling", onError);
            }

            defW.validateStep(this);

            return defW;
        } else {
            throw new IllegalArgumentException("Unable to resolve step; unexpected object "+ def);
        }
    }