/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.brooklyn.enricher.stock; import static com.google.common.base.Preconditions.checkArgument; import org.apache.brooklyn.api.sensor.SensorEvent; import org.apache.brooklyn.config.ConfigKey; import org.apache.brooklyn.core.config.ConfigKeys; import org.apache.brooklyn.util.collections.MutableSet; import org.apache.brooklyn.util.core.task.Tasks; import org.apache.brooklyn.util.core.task.ValueResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Function; import com.google.common.reflect.TypeToken; //@Catalog(name="Transformer", description="Transforms attributes of an entity; see Enrichers.builder().transforming(...)") @SuppressWarnings("serial") public class Transformer<T,U> extends AbstractTransformer<T,U> { @SuppressWarnings("unused") private static final Logger LOG = LoggerFactory.getLogger(Transformer.class); // exactly one of these should be supplied to set a value public static ConfigKey<?> TARGET_VALUE = ConfigKeys.newConfigKey(Object.class, "enricher.targetValue"); public static ConfigKey<Function<?, ?>> TRANSFORMATION_FROM_VALUE = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation"); public static ConfigKey<Function<?, ?>> TRANSFORMATION_FROM_EVENT = ConfigKeys.newConfigKey(new TypeToken<Function<?, ?>>() {}, "enricher.transformation.fromevent"); public Transformer() { } /** returns a function for transformation, for immediate use only (not for caching, as it may change) */ @Override @SuppressWarnings("unchecked") protected Function<SensorEvent<T>, U> getTransformation() { MutableSet<Object> suppliers = MutableSet.of(); suppliers.addIfNotNull(config().getRaw(TARGET_VALUE).orNull()); suppliers.addIfNotNull(config().getRaw(TRANSFORMATION_FROM_EVENT).orNull()); suppliers.addIfNotNull(config().getRaw(TRANSFORMATION_FROM_VALUE).orNull()); checkArgument(suppliers.size()==1, "Must set exactly one of: %s, %s, %s", TARGET_VALUE.getName(), TRANSFORMATION_FROM_VALUE.getName(), TRANSFORMATION_FROM_EVENT.getName()); Function<?, ?> fromEvent = config().get(TRANSFORMATION_FROM_EVENT); if (fromEvent != null) { return (Function<SensorEvent<T>, U>) fromEvent; } final Function<T, U> fromValueFn = (Function<T, U>) config().get(TRANSFORMATION_FROM_VALUE); if (fromValueFn != null) { // named class not necessary as result should not be serialized return new Function<SensorEvent<T>, U>() { @Override public U apply(SensorEvent<T> input) { return fromValueFn.apply(input.getValue()); } @Override public String toString() { return ""+fromValueFn; } }; } // from target value // named class not necessary as result should not be serialized final Object targetValueRaw = config().getRaw(TARGET_VALUE).orNull(); return new Function<SensorEvent<T>, U>() { @Override public U apply(SensorEvent<T> input) { // evaluate immediately, or return null // PRETTY_QUICK/200ms seems a reasonable compromise for tasks which require BG evaluation // but which are non-blocking // TODO better would be to have a mode in which tasks are not permitted to block on // external events; they can submit tasks and block on them (or even better, have a callback architecture); // however that is a non-trivial refactoring return (U) Tasks.resolving(targetValueRaw).as(targetSensor.getType()) .context(entity) .description("Computing sensor "+targetSensor+" from "+targetValueRaw) .timeout(ValueResolver.PRETTY_QUICK_WAIT) .getMaybe().orNull(); } public String toString() { return ""+targetValueRaw; } }; } }