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);
}
}