protected Object doTaskBody()

in core/src/main/java/org/apache/brooklyn/core/workflow/steps/appmodel/SetSensorWorkflowStep.java [83:207]


    protected Object doTaskBody(WorkflowStepInstanceExecutionContext context) {
        EntityValueToSet sensor = context.getInput(SENSOR);
        if (sensor==null) throw new IllegalArgumentException("Sensor name is required");

        String sensorNameFull = context.resolve(WorkflowExpressionResolution.WorkflowExpressionStage.STEP_INPUT, sensor.name, String.class);
        if (Strings.isBlank(sensorNameFull)) throw new IllegalArgumentException("Sensor name is required");

        List<Object> sensorNameIndexes = MutableList.of();
        String sensorNameBase = extractSensorNameBaseAndPopulateIndices(sensorNameFull, sensorNameIndexes);

        TypeToken<?> type = context.lookupType(sensor.type, () -> TypeToken.of(Object.class));
        final Entity entity = sensor.entity!=null ? sensor.entity : context.getEntity();
        AttributeSensor<Object> sensorBase = (AttributeSensor<Object>) Sensors.newSensor(type, sensorNameBase);
        AtomicReference<Object> resolvedValue = new AtomicReference<>();
        Object oldValue;

        Runnable resolve = () -> {
//        // might need to be careful if defined type is different or more generic than type specified here;
//        // but that should be fine as XML persistence preserves types
//        Sensor<?> sd = entity.getEntityType().getSensor(sensorName);
//        if (!type.isSupertypeOf(sd.getTypeToken())) {
//            ...
//        }

            resolvedValue.set(context.getInput(VALUE.getName(), type));
        };

        DslPredicates.DslPredicate require = context.getInput(REQUIRE);
        if (require==null && sensorNameIndexes.isEmpty()) {
            resolve.run();
            oldValue = entity.sensors().set(sensorBase, resolvedValue.get());
        } else {
            oldValue = entity.sensors().modify(sensorBase, oldBase -> {
                if (require!=null) {
                    Object old = oldBase;
                    MutableList<Object> indexes = MutableList.copyOf(sensorNameIndexes);
                    while (!indexes.isEmpty()) {
                        Object i = indexes.remove(0);
                        if (old == null) break;
                        if (old instanceof Map) old = ((Map) old).get(i);
                        else if (old instanceof Iterable && i instanceof Integer) {
                            int ii = (Integer)i;
                            int size = Iterables.size((Iterable) old);
                            if (ii==-1) ii = size-1;
                            old = (ii<0 || ii>=size) ? null : Iterables.get((Iterable) old, ii);
                        } else {
                            throw new IllegalArgumentException("Cannot find argument '" + i + "' in " + old);
                        }
                    }

                    if (old == null && !((AbstractEntity.BasicSensorSupport) entity.sensors()).contains(sensorBase.getName())) {
                        DslPredicates.DslEntityPredicateDefault requireTweaked = new DslPredicates.DslEntityPredicateDefault();
                        requireTweaked.sensor = sensorNameFull;
                        requireTweaked.check = WrappedValue.of(require);
                        if (!requireTweaked.apply(entity)) {
                            throw new SensorRequirementFailedAbsent("Sensor " + sensorNameFull + " unset or unavailable when there is a non-absent requirement");
                        }
                    } else {
                        if (!require.apply(old)) {
                            throw new SensorRequirementFailed("Sensor " + sensorNameFull + " value does not match requirement", old);
                        }
                    }
                }

                resolve.run();

                // now set
                Object result;

                if (!sensorNameIndexes.isEmpty()) {
                    result = oldBase;

                    // ensure mutable
                    result = makeMutable(result, sensorNameIndexes);

                    Object target = result;
                    MutableList<Object> indexes = MutableList.copyOf(sensorNameIndexes);
                    while (!indexes.isEmpty()) {
                        Object i = indexes.remove(0);
                        boolean isLast = indexes.isEmpty();
                        Object nextTarget;

                        if (target instanceof Map) {
                            nextTarget = ((Map) target).get(i);
                            if (nextTarget==null || isLast || !(nextTarget instanceof MutableMap)) {
                                // ensure mutable
                                nextTarget = isLast ? resolvedValue.get() : makeMutable(nextTarget, indexes);
                                ((Map) target).put(i, nextTarget);
                            }

                        } else if (target instanceof Iterable && i instanceof Integer) {
                            int ii = (Integer)i;
                            int size = Iterables.size((Iterable) target);
                            if (ii==-1) ii = size-1;
                            boolean outOfBounds = ii < 0 || ii >= size;
                            nextTarget = outOfBounds ? null : Iterables.get((Iterable) target, ii);

                            if (nextTarget==null || isLast || (!(nextTarget instanceof MutableMap) && !(nextTarget instanceof MutableSet) && !(nextTarget instanceof MutableList))) {
                                nextTarget = isLast ? resolvedValue.get() : makeMutable(nextTarget, indexes);
                                if (outOfBounds) {
                                    ((Collection) target).add(nextTarget);
                                } else {
                                    if (!(target instanceof List)) throw new IllegalStateException("Cannot set numerical position index in a non-list collection (and was not otherwise known as mutable; e.g. use MutableSet): "+target);
                                    ((List) target).set(ii, nextTarget);
                                }
                            }

                        } else {
                            throw new IllegalArgumentException("Cannot find argument '" + i + "' in " + target);
                        }
                        target = nextTarget;
                    }
                } else {
                    result = resolvedValue.get();
                }

                return Maybe.of(result);
            });
        }

        context.noteOtherMetadata("Value set", resolvedValue.get());
        if (oldValue!=null) context.noteOtherMetadata("Previous value", oldValue);

        return context.getPreviousStepOutput();
    }