http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeSensorAndConfigKey.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeSensorAndConfigKey.java deleted file mode 100644 index b777352..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/core/AttributeSensorAndConfigKey.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.sensor.core; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntityLocal; -import org.apache.brooklyn.api.mgmt.ManagementContext; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.BasicConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.entity.AbstractEntity; -import org.apache.brooklyn.core.entity.BrooklynConfigKeys; -import org.apache.brooklyn.sensor.feed.ConfigToAttributes; -import org.apache.brooklyn.util.core.flags.TypeCoercions; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.reflect.TypeToken; - -/** -* A {@link Sensor} describing an attribute that can be configured with inputs that are used to derive the final value. -* <p> -* The {@link ConfigKey} will have the same name and description as the sensor but not necessarily the same type. -* Conversion to set the sensor value from the config key must be supplied in a subclass. -* <p> -* {@link ConfigToAttributes#apply(EntityLocal, AttributeSensorAndConfigKey)} is useful to set the attribute from the sensor. -*/ -public abstract class AttributeSensorAndConfigKey<ConfigType,SensorType> extends BasicAttributeSensor<SensorType> - implements ConfigKey.HasConfigKey<ConfigType> { - private static final long serialVersionUID = -3103809215973264600L; - private static final Logger log = LoggerFactory.getLogger(AttributeSensorAndConfigKey.class); - - private ConfigKey<ConfigType> configKey; - - public AttributeSensorAndConfigKey(Class<ConfigType> configType, Class<SensorType> sensorType, String name) { - this(configType, sensorType, name, name, null); - } - - public AttributeSensorAndConfigKey(Class<ConfigType> configType, Class<SensorType> sensorType, String name, String description) { - this(TypeToken.of(configType), TypeToken.of(sensorType), name, description, null); - } - - public AttributeSensorAndConfigKey(Class<ConfigType> configType, Class<SensorType> sensorType, String name, String description, Object defaultValue) { - this(TypeToken.of(configType), TypeToken.of(sensorType), name, description, defaultValue); - } - - public AttributeSensorAndConfigKey(TypeToken<ConfigType> configType, TypeToken<SensorType> sensorType, String name) { - this(configType, sensorType, name, null); - } - - public AttributeSensorAndConfigKey(TypeToken<ConfigType> configType, TypeToken<SensorType> sensorType, String name, String description) { - this(configType, sensorType, name, description, null); - } - - public AttributeSensorAndConfigKey(TypeToken<ConfigType> configType, TypeToken<SensorType> sensorType, String name, String description, Object defaultValue) { - super(sensorType, name, description); - ConfigType defaultValueTyped; - try { - defaultValueTyped = TypeCoercions.coerce(defaultValue, configType); - } catch (Exception e) { - log.warn("Invalid default value '"+defaultValue+"' for "+name+" (rethrowing: "+e, e); - throw Exceptions.propagate(e); - } - configKey = new BasicConfigKey<ConfigType>(configType, name, description, defaultValueTyped); - } - - public AttributeSensorAndConfigKey(AttributeSensorAndConfigKey<ConfigType,SensorType> orig, ConfigType defaultValue) { - super(orig.getTypeToken(), orig.getName(), orig.getDescription()); - configKey = ConfigKeys.newConfigKeyWithDefault(orig.configKey, - TypeCoercions.coerce(defaultValue, orig.configKey.getTypeToken())); - } - - public ConfigKey<ConfigType> getConfigKey() { return configKey; } - - /** returns the sensor value for this attribute on the given entity, if present, - * otherwise works out what the sensor value should be based on the config key's value - * <p> - * calls to this may allocate resources (e.g. ports) so should be called only once and - * then (if non-null) assigned as the sensor's value - * <p> - * <b>(for this reason this method should generally not be invoked by callers except in tests and by the framework, - * and similarly should not be overridden; implement {@link #convertConfigToSensor(Object, Entity)} instead for single-execution calls. - * the framework calls this from {@link AbstractEntity#setAttribute(AttributeSensorAndConfigKey)} - * typically via {@link ConfigToAttributes#apply(EntityLocal)} e.g. from SoftwareProcessImpl.preStart().) - * </b> - */ - public SensorType getAsSensorValue(Entity e) { - SensorType sensorValue = e.getAttribute(this); - if (sensorValue!=null) return sensorValue; - - ConfigType v = ((EntityLocal)e).getConfig(this); - try { - return convertConfigToSensor(v, e); - } catch (Throwable t) { - throw new IllegalArgumentException("Cannot convert config value "+v+" for sensor "+this+": "+t, t); - } - } - - /** - * @see {@link #getAsSensorValue(Entity)} - * - * Differs in that the config value is converted based on just the management context, rather - * than for a specific entity. For example, useful if using {@link BrooklynConfigKeys} in BrooklynWebServer. - * </b> - */ - public SensorType getAsSensorValue(ManagementContext managementContext) { - ConfigType v = managementContext.getConfig().getConfig(this); - try { - return convertConfigToSensor(v, managementContext); - } catch (Throwable t) { - throw new IllegalArgumentException("Cannot convert config value "+v+" for sensor "+this+": "+t, t); - } - } - - /** converts the given ConfigType value to the corresponding SensorType value, - * with respect to the given entity - * <p> - * this is invoked after checks whether the entity already has a value for the sensor, - * and the entity-specific config value is passed for convenience if set, - * otherwise the config key default value is passed for convenience - * <p> - * this message should be allowed to return null if the conversion cannot be completed at this time */ - protected abstract SensorType convertConfigToSensor(ConfigType value, Entity entity); - - /** - * @see {@link #convertConfigToSensor(Object, Entity)} - */ - protected abstract SensorType convertConfigToSensor(ConfigType value, ManagementContext entity); -}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensor.java deleted file mode 100644 index fa50cec..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensor.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.sensor.core; - -import static com.google.common.base.Preconditions.checkNotNull; - -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.Sensor; - -import com.google.common.reflect.TypeToken; - -/** - * A {@link Sensor} describing an attribute change. - */ -public class BasicAttributeSensor<T> extends BasicSensor<T> implements AttributeSensor<T> { - private static final long serialVersionUID = -2493209215974820300L; - - private final SensorPersistenceMode persistence; - - public BasicAttributeSensor(Class<T> type, String name) { - this(type, name, name); - } - - public BasicAttributeSensor(Class<T> type, String name, String description) { - this(TypeToken.of(type), name, description); - } - - public BasicAttributeSensor(TypeToken<T> typeToken, String name) { - this(typeToken, name, name); - } - - public BasicAttributeSensor(TypeToken<T> typeToken, String name, String description) { - this(typeToken, name, description, SensorPersistenceMode.REQUIRED); - } - - public BasicAttributeSensor(TypeToken<T> typeToken, String name, String description, SensorPersistenceMode persistence) { - super(typeToken, name, description); - this.persistence = checkNotNull(persistence, "persistence"); - } - - @Override - public SensorPersistenceMode getPersistenceMode() { - // persistence could be null if deserializing state written by an old version; in which case default to 'required' - return (persistence != null) ? persistence : SensorPersistenceMode.REQUIRED; - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensorAndConfigKey.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensorAndConfigKey.java deleted file mode 100644 index 5f473a8..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicAttributeSensorAndConfigKey.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.sensor.core; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.mgmt.ManagementContext; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.config.ConfigKey; - -import com.google.common.reflect.TypeToken; - -/** - * A {@link Sensor} describing an attribute that can be configured with a default value. - * - * The {@link ConfigKey} has the same type, name and description as the sensor, - * and is typically used to populate the sensor's value at runtime. - */ -public class BasicAttributeSensorAndConfigKey<T> extends AttributeSensorAndConfigKey<T,T> { - - private static final long serialVersionUID = -2204916730008559688L; - - public BasicAttributeSensorAndConfigKey(Class<T> type, String name) { - this(type, name, name, null); - } - public BasicAttributeSensorAndConfigKey(Class<T> type, String name, String description) { - this(type, name, description, null); - } - public BasicAttributeSensorAndConfigKey(Class<T> type, String name, String description, T defaultValue) { - super(type, type, name, description, defaultValue); - } - - public BasicAttributeSensorAndConfigKey(TypeToken<T> type, String name) { - super(type, type, name); - } - - public BasicAttributeSensorAndConfigKey(TypeToken<T> type, String name, String description) { - super(type, type, name, description); - } - - public BasicAttributeSensorAndConfigKey(TypeToken<T> type, String name, String description, Object defaultValue) { - super(type, type, name, description, defaultValue); - } - - public BasicAttributeSensorAndConfigKey(AttributeSensorAndConfigKey<T,T> orig, T defaultValue) { - super(orig, defaultValue); - } - - @Override - protected T convertConfigToSensor(T value, Entity entity) { return value; } - - @Override - protected T convertConfigToSensor(T value, ManagementContext managementContext) { return value; } - - public static class StringAttributeSensorAndConfigKey extends BasicAttributeSensorAndConfigKey<String> { - - private static final long serialVersionUID = 810512615528081865L; - - public StringAttributeSensorAndConfigKey(AttributeSensorAndConfigKey<String,String> orig, String defaultValue) { - super(orig, defaultValue); - } - - public StringAttributeSensorAndConfigKey(String name, String description, String defaultValue) { - super(String.class, name, description, defaultValue); - } - - public StringAttributeSensorAndConfigKey(String name, String description) { - super(String.class, name, description); - } - - public StringAttributeSensorAndConfigKey(String name) { - super(String.class, name); - } - - } - - public static class IntegerAttributeSensorAndConfigKey extends BasicAttributeSensorAndConfigKey<Integer> { - - private static final long serialVersionUID = 7159564523829723929L; - - public IntegerAttributeSensorAndConfigKey(AttributeSensorAndConfigKey<Integer,Integer> orig, Integer defaultValue) { - super(orig, defaultValue); - } - - public IntegerAttributeSensorAndConfigKey(String name, String description, Integer defaultValue) { - super(Integer.class, name, description, defaultValue); - } - - public IntegerAttributeSensorAndConfigKey(String name, String description) { - super(Integer.class, name, description); - } - - public IntegerAttributeSensorAndConfigKey(String name) { - super(Integer.class, name); - } - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/BasicNotificationSensor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicNotificationSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/BasicNotificationSensor.java deleted file mode 100644 index 627e3c8..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicNotificationSensor.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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.sensor.core; - -import org.apache.brooklyn.api.sensor.Sensor; - -/** - * A {@link Sensor} used to notify subscribers about events. - */ -public class BasicNotificationSensor<T> extends BasicSensor<T> { - private static final long serialVersionUID = -7670909215973264600L; - - public BasicNotificationSensor(Class<T> type, String name) { - this(type, name, name); - } - - public BasicNotificationSensor(Class<T> type, String name, String description) { - super(type, name, description); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensor.java deleted file mode 100644 index 439fbb2..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensor.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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.sensor.core; - -import static com.google.common.base.Preconditions.checkNotNull; - -import java.util.List; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.api.sensor.SensorEvent; -import org.apache.brooklyn.util.guava.TypeTokens; - -import com.google.common.base.Objects; -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableList; -import com.google.common.reflect.TypeToken; - -/** - * Parent for all {@link Sensor}s. - */ -public class BasicSensor<T> implements Sensor<T> { - private static final long serialVersionUID = -3762018534086101323L; - - private static final Splitter dots = Splitter.on('.'); - - private TypeToken<T> typeToken; - private Class<? super T> type; - private String name; - private String description; - private transient List<String> nameParts; - - // FIXME In groovy, fields were `public final` with a default constructor; do we need the gson? - public BasicSensor() { /* for gson */ } - - /** name is typically a dot-separated identifier; description is optional */ - public BasicSensor(Class<T> type, String name) { - this(type, name, name); - } - - public BasicSensor(Class<T> type, String name, String description) { - this(TypeToken.of(type), name, description); - } - - public BasicSensor(TypeToken<T> typeToken, String name, String description) { - this.typeToken = TypeTokens.getTypeTokenIfNotRaw(checkNotNull(typeToken, "typeToken")); - this.type = TypeTokens.getRawTypeIfRaw(typeToken); - this.name = checkNotNull(name, "name"); - this.description = description; - } - - /** @see Sensor#getTypeToken() */ - public TypeToken<T> getTypeToken() { return TypeTokens.getTypeToken(typeToken, type); } - - /** @see Sensor#getType() */ - public Class<? super T> getType() { return TypeTokens.getRawType(typeToken, type); } - - /** @see Sensor#getTypeName() */ - public String getTypeName() { - return getType().getName(); - } - - /** @see Sensor#getName() */ - public String getName() { return name; } - - /** @see Sensor#getNameParts() */ - public synchronized List<String> getNameParts() { - if (nameParts==null) nameParts = ImmutableList.copyOf(dots.split(name)); - return nameParts; - } - - /** @see Sensor#getDescription() */ - public String getDescription() { return description; } - - /** @see Sensor#newEvent(Entity, Object) */ - public SensorEvent<T> newEvent(Entity producer, T value) { - return new BasicSensorEvent<T>(this, producer, value); - } - - @Override - public int hashCode() { - return Objects.hashCode(getTypeName(), name, description); - } - - @Override - public boolean equals(Object other) { - if (this==other) return true; - if (!(other instanceof BasicSensor)) return false; - BasicSensor<?> o = (BasicSensor<?>) other; - - return Objects.equal(getTypeName(), o.getTypeName()) && Objects.equal(name, o.name) && Objects.equal(description, o.description); - } - - @Override - public String toString() { - return String.format("Sensor: %s (%s)", name, getTypeName()); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensorEvent.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensorEvent.java b/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensorEvent.java deleted file mode 100644 index fb0f7a9..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/core/BasicSensorEvent.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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.sensor.core; - -import java.util.ConcurrentModificationException; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.api.sensor.SensorEvent; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Objects; - -/** - * A {@link SensorEvent} containing data from a {@link Sensor} generated by an {@link Entity}. - */ -public class BasicSensorEvent<T> implements SensorEvent<T> { - - private static final Logger log = LoggerFactory.getLogger(BasicSensorEvent.class); - - private final Sensor<T> sensor; - private final Entity source; - private final T value; - private final long timestamp; - - public T getValue() { return value; } - - public Sensor<T> getSensor() { return sensor; } - - public Entity getSource() { return source; } - - public long getTimestamp() { return timestamp; } - - /** arguments should not be null (except in certain limited testing situations) */ - public BasicSensorEvent(Sensor<T> sensor, Entity source, T value) { - this(sensor, source, value, System.currentTimeMillis()); - } - - public BasicSensorEvent(Sensor<T> sensor, Entity source, T value, long timestamp) { - this.sensor = sensor; - this.source = source; - this.value = value; - this.timestamp = timestamp; - } - - public static <T> SensorEvent<T> of(Sensor<T> sensor, Entity source, T value, long timestamp) { - return new BasicSensorEvent<T>(sensor, source, value, timestamp); - } - - @SuppressWarnings("unchecked") - public static <T> SensorEvent<T> ofUnchecked(Sensor<T> sensor, Entity source, Object value, long timestamp) { - return new BasicSensorEvent<T>(sensor, source, (T)value, timestamp); - } - - public static <T> SensorEvent<T> of(Sensor<T> sensor, Entity source, T value) { - return new BasicSensorEvent<T>(sensor, source, value); - } - - @SuppressWarnings("unchecked") - public static <T> SensorEvent<T> ofUnchecked(Sensor<T> sensor, Entity source, Object value) { - return new BasicSensorEvent<T>(sensor, source, (T)value); - } - - @Override - public int hashCode() { - return Objects.hashCode(sensor, source, value); - } - - /** - * Any SensorEvents are equal if their sensor, source and value are equal. - * Ignore timestamp for ease of use in unit tests. - */ - @Override - public boolean equals(Object o) { - if (!(o instanceof SensorEvent)) return false; - SensorEvent<?> other = (SensorEvent<?>) o; - return Objects.equal(sensor, other.getSensor()) && Objects.equal(source, other.getSource()) && - Objects.equal(value, other.getValue()); - } - - @Override - public String toString() { - try { - return source+"."+sensor+"="+value+" @ "+timestamp; - } catch (ConcurrentModificationException e) { - // TODO occasional CME observed on shutdown, wrt map, e.g. in UrlMappingTest - // transformations should set a copy of the map; see e.g. in ServiceStateLogic.updateMapSensor - String result = getClass()+":"+source+"."+sensor+"@"+timestamp; - log.warn("Error creating string for " + result + " (ignoring): " + e); - if (log.isDebugEnabled()) - log.debug("Trace for error creating string for " + result + " (ignoring): " + e, e); - return result; - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/DependentConfiguration.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/DependentConfiguration.java b/core/src/main/java/org/apache/brooklyn/sensor/core/DependentConfiguration.java deleted file mode 100644 index 9327b19..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/core/DependentConfiguration.java +++ /dev/null @@ -1,823 +0,0 @@ -/* - * 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.sensor.core; - -import static com.google.common.base.Preconditions.checkNotNull; -import groovy.lang.Closure; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; - -import javax.annotation.Nullable; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntityLocal; -import org.apache.brooklyn.api.mgmt.ExecutionContext; -import org.apache.brooklyn.api.mgmt.SubscriptionHandle; -import org.apache.brooklyn.api.mgmt.Task; -import org.apache.brooklyn.api.mgmt.TaskAdaptable; -import org.apache.brooklyn.api.mgmt.TaskFactory; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.SensorEvent; -import org.apache.brooklyn.api.sensor.SensorEventListener; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.entity.Attributes; -import org.apache.brooklyn.core.entity.Entities; -import org.apache.brooklyn.core.entity.EntityInternal; -import org.apache.brooklyn.core.entity.lifecycle.Lifecycle; -import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; -import org.apache.brooklyn.util.collections.CollectionFunctionals; -import org.apache.brooklyn.util.collections.MutableList; -import org.apache.brooklyn.util.collections.MutableMap; -import org.apache.brooklyn.util.core.task.BasicExecutionContext; -import org.apache.brooklyn.util.core.task.BasicTask; -import org.apache.brooklyn.util.core.task.DeferredSupplier; -import org.apache.brooklyn.util.core.task.DynamicTasks; -import org.apache.brooklyn.util.core.task.ParallelTask; -import org.apache.brooklyn.util.core.task.TaskInternal; -import org.apache.brooklyn.util.core.task.Tasks; -import org.apache.brooklyn.util.core.task.ValueResolver; -import org.apache.brooklyn.util.exceptions.CompoundRuntimeException; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.apache.brooklyn.util.exceptions.NotManagedException; -import org.apache.brooklyn.util.exceptions.RuntimeTimeoutException; -import org.apache.brooklyn.util.groovy.GroovyJavaMethods; -import org.apache.brooklyn.util.guava.Functionals; -import org.apache.brooklyn.util.guava.Maybe; -import org.apache.brooklyn.util.text.Strings; -import org.apache.brooklyn.util.time.CountdownTimer; -import org.apache.brooklyn.util.time.Duration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.annotations.Beta; -import com.google.common.base.Function; -import com.google.common.base.Functions; -import com.google.common.base.Predicate; -import com.google.common.base.Predicates; -import com.google.common.base.Throwables; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; - -/** Conveniences for making tasks which run in entity {@link ExecutionContext}s, subscribing to attributes from other entities, possibly transforming those; - * these {@link Task} instances are typically passed in {@link EntityLocal#setConfig(ConfigKey, Object)}. - * <p> - * If using a lot it may be useful to: - * <pre> - * {@code - * import static brooklyn.event.basic.DependentConfiguration.*; - * } - * </pre> - */ -public class DependentConfiguration { - - private static final Logger LOG = LoggerFactory.getLogger(DependentConfiguration.class); - - //not instantiable, only a static helper - private DependentConfiguration() {} - - /** - * Default readiness is Groovy truth. - * - * @see #attributeWhenReady(Entity, AttributeSensor, Predicate) - */ - public static <T> Task<T> attributeWhenReady(Entity source, AttributeSensor<T> sensor) { - return attributeWhenReady(source, sensor, GroovyJavaMethods.truthPredicate()); - } - - public static <T> Task<T> attributeWhenReady(Entity source, AttributeSensor<T> sensor, Closure<Boolean> ready) { - Predicate<Object> readyPredicate = (ready != null) ? GroovyJavaMethods.<Object>predicateFromClosure(ready) : GroovyJavaMethods.truthPredicate(); - return attributeWhenReady(source, sensor, readyPredicate); - } - - /** returns an unsubmitted {@link Task} which blocks until the given sensor on the given source entity gives a value that satisfies ready, then returns that value; - * particular useful in Entity configuration where config will block until Tasks have a value - */ - public static <T> Task<T> attributeWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready) { - Builder<T, T> builder = builder().attributeWhenReady(source, sensor); - if (ready != null) builder.readiness(ready); - return builder.build(); - - } - - public static <T,V> Task<V> attributePostProcessedWhenReady(Entity source, AttributeSensor<T> sensor, Closure<Boolean> ready, Closure<V> postProcess) { - Predicate<? super T> readyPredicate = (ready != null) ? GroovyJavaMethods.predicateFromClosure(ready) : GroovyJavaMethods.truthPredicate(); - Function<? super T, V> postProcessFunction = GroovyJavaMethods.<T,V>functionFromClosure(postProcess); - return attributePostProcessedWhenReady(source, sensor, readyPredicate, postProcessFunction); - } - - public static <T,V> Task<V> attributePostProcessedWhenReady(Entity source, AttributeSensor<T> sensor, Closure<V> postProcess) { - return attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), GroovyJavaMethods.<T,V>functionFromClosure(postProcess)); - } - - public static <T> Task<T> valueWhenAttributeReady(Entity source, AttributeSensor<T> sensor, T value) { - return DependentConfiguration.<T,T>attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), Functions.constant(value)); - } - - public static <T,V> Task<V> valueWhenAttributeReady(Entity source, AttributeSensor<T> sensor, Function<? super T,V> valueProvider) { - return attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), valueProvider); - } - - public static <T,V> Task<V> valueWhenAttributeReady(Entity source, AttributeSensor<T> sensor, Closure<V> valueProvider) { - return attributePostProcessedWhenReady(source, sensor, GroovyJavaMethods.truthPredicate(), valueProvider); - } - - public static <T,V> Task<V> attributePostProcessedWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready, final Closure<V> postProcess) { - return attributePostProcessedWhenReady(source, sensor, ready, GroovyJavaMethods.<T,V>functionFromClosure(postProcess)); - } - - @SuppressWarnings("unchecked") - public static <T,V> Task<V> attributePostProcessedWhenReady(final Entity source, final AttributeSensor<T> sensor, final Predicate<? super T> ready, final Function<? super T,V> postProcess) { - Builder<T,T> builder1 = DependentConfiguration.builder().attributeWhenReady(source, sensor); - // messy generics here to support null postProcess; would be nice to disallow that here - Builder<T,V> builder; - if (postProcess != null) { - builder = builder1.postProcess(postProcess); - } else { - builder = (Builder<T,V>)builder1; - } - if (ready != null) builder.readiness(ready); - - return builder.build(); - } - - public static <T> T waitInTaskForAttributeReady(Entity source, AttributeSensor<T> sensor, Predicate<? super T> ready) { - return waitInTaskForAttributeReady(source, sensor, ready, ImmutableList.<AttributeAndSensorCondition<?>>of()); - } - - public static <T> T waitInTaskForAttributeReady(final Entity source, final AttributeSensor<T> sensor, Predicate<? super T> ready, List<AttributeAndSensorCondition<?>> abortConditions) { - String blockingDetails = "Waiting for ready from "+source+" "+sensor+" (subscription)"; - return waitInTaskForAttributeReady(source, sensor, ready, abortConditions, blockingDetails); - } - - // TODO would be nice to have an easy semantics for whenServiceUp (cf DynamicWebAppClusterImpl.whenServiceUp) - - public static <T> T waitInTaskForAttributeReady(final Entity source, final AttributeSensor<T> sensor, Predicate<? super T> ready, List<AttributeAndSensorCondition<?>> abortConditions, String blockingDetails) { - return new WaitInTaskForAttributeReady<T,T>(source, sensor, ready, abortConditions, blockingDetails).call(); - } - - protected static class WaitInTaskForAttributeReady<T,V> implements Callable<V> { - - /* This is a change since before Oct 2014. Previously it would continue to poll, - * (maybe finding a different error) if the target entity becomes unmanaged. - * Now it actively checks unmanaged by default, and still throws although it might - * now find a different problem. */ - private final static boolean DEFAULT_IGNORE_UNMANAGED = false; - - protected final Entity source; - protected final AttributeSensor<T> sensor; - protected final Predicate<? super T> ready; - protected final List<AttributeAndSensorCondition<?>> abortSensorConditions; - protected final String blockingDetails; - protected final Function<? super T,? extends V> postProcess; - protected final Duration timeout; - protected final Maybe<V> onTimeout; - protected final boolean ignoreUnmanaged; - protected final Maybe<V> onUnmanaged; - // TODO onError Continue / Throw / Return(V) - - protected WaitInTaskForAttributeReady(Builder<T, V> builder) { - this.source = builder.source; - this.sensor = builder.sensor; - this.ready = builder.readiness; - this.abortSensorConditions = builder.abortSensorConditions; - this.blockingDetails = builder.blockingDetails; - this.postProcess = builder.postProcess; - this.timeout = builder.timeout; - this.onTimeout = builder.onTimeout; - this.ignoreUnmanaged = builder.ignoreUnmanaged; - this.onUnmanaged = builder.onUnmanaged; - } - - private WaitInTaskForAttributeReady(Entity source, AttributeSensor<T> sensor, Predicate<? super T> ready, - List<AttributeAndSensorCondition<?>> abortConditions, String blockingDetails) { - this.source = source; - this.sensor = sensor; - this.ready = ready; - this.abortSensorConditions = abortConditions; - this.blockingDetails = blockingDetails; - - this.timeout = Duration.PRACTICALLY_FOREVER; - this.onTimeout = Maybe.absent(); - this.ignoreUnmanaged = DEFAULT_IGNORE_UNMANAGED; - this.onUnmanaged = Maybe.absent(); - this.postProcess = null; - } - - @SuppressWarnings("unchecked") - protected V postProcess(T value) { - if (this.postProcess!=null) return postProcess.apply(value); - // if no post-processing assume the types are correct - return (V) value; - } - - protected boolean ready(T value) { - if (ready!=null) return ready.apply(value); - return GroovyJavaMethods.truth(value); - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - @Override - public V call() { - T value = source.getAttribute(sensor); - - // return immediately if either the ready predicate or the abort conditions hold - if (ready(value)) return postProcess(value); - - final List<Exception> abortionExceptions = Lists.newCopyOnWriteArrayList(); - long start = System.currentTimeMillis(); - - for (AttributeAndSensorCondition abortCondition : abortSensorConditions) { - Object abortValue = abortCondition.source.getAttribute(abortCondition.sensor); - if (abortCondition.predicate.apply(abortValue)) { - abortionExceptions.add(new Exception("Abort due to "+abortCondition.source+" -> "+abortCondition.sensor)); - } - } - if (abortionExceptions.size() > 0) { - throw new CompoundRuntimeException("Aborted waiting for ready from "+source+" "+sensor, abortionExceptions); - } - - TaskInternal<?> current = (TaskInternal<?>) Tasks.current(); - if (current == null) throw new IllegalStateException("Should only be invoked in a running task"); - Entity entity = BrooklynTaskTags.getTargetOrContextEntity(current); - if (entity == null) throw new IllegalStateException("Should only be invoked in a running task with an entity tag; "+ - current+" has no entity tag ("+current.getStatusDetail(false)+")"); - - final LinkedList<T> publishedValues = new LinkedList<T>(); - final Semaphore semaphore = new Semaphore(0); // could use Exchanger - SubscriptionHandle subscription = null; - List<SubscriptionHandle> abortSubscriptions = Lists.newArrayList(); - - try { - subscription = ((EntityInternal)entity).getSubscriptionContext().subscribe(source, sensor, new SensorEventListener<T>() { - @Override public void onEvent(SensorEvent<T> event) { - synchronized (publishedValues) { publishedValues.add(event.getValue()); } - semaphore.release(); - }}); - for (final AttributeAndSensorCondition abortCondition : abortSensorConditions) { - abortSubscriptions.add(((EntityInternal)entity).getSubscriptionContext().subscribe(abortCondition.source, abortCondition.sensor, new SensorEventListener<Object>() { - @Override public void onEvent(SensorEvent<Object> event) { - if (abortCondition.predicate.apply(event.getValue())) { - abortionExceptions.add(new Exception("Abort due to "+abortCondition.source+" -> "+abortCondition.sensor)); - semaphore.release(); - } - }})); - Object abortValue = abortCondition.source.getAttribute(abortCondition.sensor); - if (abortCondition.predicate.apply(abortValue)) { - abortionExceptions.add(new Exception("Abort due to "+abortCondition.source+" -> "+abortCondition.sensor)); - } - } - if (abortionExceptions.size() > 0) { - throw new CompoundRuntimeException("Aborted waiting for ready from "+source+" "+sensor, abortionExceptions); - } - - CountdownTimer timer = timeout!=null ? timeout.countdownTimer() : null; - Duration maxPeriod = ValueResolver.PRETTY_QUICK_WAIT; - Duration nextPeriod = ValueResolver.REAL_QUICK_PERIOD; - while (true) { - // check the source on initial run (could be done outside the loop) - // and also (optionally) on each iteration in case it is more recent - value = source.getAttribute(sensor); - if (ready(value)) break; - - if (timer!=null) { - if (timer.getDurationRemaining().isShorterThan(nextPeriod)) { - nextPeriod = timer.getDurationRemaining(); - } - if (timer.isExpired()) { - if (onTimeout.isPresent()) return onTimeout.get(); - throw new RuntimeTimeoutException("Unsatisfied after "+Duration.sinceUtc(start)); - } - } - - String prevBlockingDetails = current.setBlockingDetails(blockingDetails); - try { - if (semaphore.tryAcquire(nextPeriod.toMilliseconds(), TimeUnit.MILLISECONDS)) { - // immediately release so we are available for the next check - semaphore.release(); - // if other permits have been made available (e.g. multiple notifications) drain them all as no point running multiple times - semaphore.drainPermits(); - } - } finally { - current.setBlockingDetails(prevBlockingDetails); - } - - // check any subscribed values which have come in first - while (true) { - synchronized (publishedValues) { - if (publishedValues.isEmpty()) break; - value = publishedValues.pop(); - } - if (ready(value)) break; - } - - // if unmanaged then ignore the other abort conditions - if (!ignoreUnmanaged && Entities.isNoLongerManaged(entity)) { - if (onUnmanaged.isPresent()) return onUnmanaged.get(); - throw new NotManagedException(entity); - } - - if (abortionExceptions.size() > 0) { - throw new CompoundRuntimeException("Aborted waiting for ready from "+source+" "+sensor, abortionExceptions); - } - - nextPeriod = nextPeriod.times(2).upperBound(maxPeriod); - } - if (LOG.isDebugEnabled()) LOG.debug("Attribute-ready for {} in entity {}", sensor, source); - return postProcess(value); - } catch (InterruptedException e) { - throw Exceptions.propagate(e); - } finally { - if (subscription != null) { - ((EntityInternal)entity).getSubscriptionContext().unsubscribe(subscription); - } - for (SubscriptionHandle handle : abortSubscriptions) { - ((EntityInternal)entity).getSubscriptionContext().unsubscribe(handle); - } - } - } - } - - /** - * Returns a {@link Task} which blocks until the given job returns, then returns the value of that job. - * - * @deprecated since 0.7; code will be moved into test utilities - */ - @Deprecated - public static <T> Task<T> whenDone(Callable<T> job) { - return new BasicTask<T>(MutableMap.of("tag", "whenDone", "displayName", "waiting for job"), job); - } - - /** - * Returns a {@link Task} which waits for the result of first parameter, then applies the function in the second - * parameter to it, returning that result. - * - * Particular useful in Entity configuration where config will block until Tasks have completed, - * allowing for example an {@link #attributeWhenReady(Entity, AttributeSensor, Predicate)} expression to be - * passed in the first argument then transformed by the function in the second argument to generate - * the value that is used for the configuration - */ - public static <U,T> Task<T> transform(final Task<U> task, final Function<U,T> transformer) { - return transform(MutableMap.of("displayName", "transforming "+task), task, transformer); - } - - /** @see #transform(Task, Function) */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static <U,T> Task<T> transform(Task<U> task, Closure transformer) { - return transform(task, GroovyJavaMethods.functionFromClosure(transformer)); - } - - /** @see #transform(Task, Function) */ - @SuppressWarnings({ "rawtypes" }) - public static <U,T> Task<T> transform(final Map flags, final TaskAdaptable<U> task, final Function<U,T> transformer) { - return new BasicTask<T>(flags, new Callable<T>() { - public T call() throws Exception { - if (!task.asTask().isSubmitted()) { - BasicExecutionContext.getCurrentExecutionContext().submit(task); - } - return transformer.apply(task.asTask().get()); - }}); - } - - /** Returns a task which waits for multiple other tasks (submitting if necessary) - * and performs arbitrary computation over the List of results. - * @see #transform(Task, Function) but note argument order is reversed (counterintuitive) to allow for varargs */ - public static <U,T> Task<T> transformMultiple(Function<List<U>,T> transformer, @SuppressWarnings("unchecked") TaskAdaptable<U> ...tasks) { - return transformMultiple(MutableMap.of("displayName", "transforming multiple"), transformer, tasks); - } - - /** @see #transformMultiple(Function, TaskAdaptable...) */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static <U,T> Task<T> transformMultiple(Closure transformer, TaskAdaptable<U> ...tasks) { - return transformMultiple(GroovyJavaMethods.functionFromClosure(transformer), tasks); - } - - /** @see #transformMultiple(Function, TaskAdaptable...) */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static <U,T> Task<T> transformMultiple(Map flags, Closure transformer, TaskAdaptable<U> ...tasks) { - return transformMultiple(flags, GroovyJavaMethods.functionFromClosure(transformer), tasks); - } - - /** @see #transformMultiple(Function, TaskAdaptable...) */ - @SuppressWarnings({ "rawtypes" }) - public static <U,T> Task<T> transformMultiple(Map flags, final Function<List<U>,T> transformer, @SuppressWarnings("unchecked") TaskAdaptable<U> ...tasks) { - return transformMultiple(flags, transformer, Arrays.asList(tasks)); - } - @SuppressWarnings({ "rawtypes" }) - public static <U,T> Task<T> transformMultiple(Map flags, final Function<List<U>,T> transformer, Collection<? extends TaskAdaptable<U>> tasks) { - if (tasks.size()==1) { - return transform(flags, Iterables.getOnlyElement(tasks), new Function<U,T>() { - @Override - @Nullable - public T apply(@Nullable U input) { - return transformer.apply(ImmutableList.of(input)); - } - }); - } - return transform(flags, new ParallelTask<U>(tasks), transformer); - } - - - /** Method which returns a Future containing a string formatted using String.format, - * where the arguments can be normal objects or tasks; - * tasks will be waited on (submitted if necessary) and their results substituted in the call - * to String.format. - * <p> - * Example: - * <pre> - * {@code - * setConfig(URL, DependentConfiguration.formatString("%s:%s", - * DependentConfiguration.attributeWhenReady(target, Target.HOSTNAME), - * DependentConfiguration.attributeWhenReady(target, Target.PORT) ) ); - * } - * </pre> - */ - @SuppressWarnings("unchecked") - public static Task<String> formatString(final String spec, final Object ...args) { - List<TaskAdaptable<Object>> taskArgs = Lists.newArrayList(); - for (Object arg: args) { - if (arg instanceof TaskAdaptable) taskArgs.add((TaskAdaptable<Object>)arg); - else if (arg instanceof TaskFactory) taskArgs.add( ((TaskFactory<TaskAdaptable<Object>>)arg).newTask() ); - } - - return transformMultiple( - MutableMap.<String,String>of("displayName", "formatting '"+spec+"' with "+taskArgs.size()+" task"+(taskArgs.size()!=1?"s":"")), - new Function<List<Object>, String>() { - @Override public String apply(List<Object> input) { - Iterator<?> tri = input.iterator(); - Object[] vv = new Object[args.length]; - int i=0; - for (Object arg : args) { - if (arg instanceof TaskAdaptable || arg instanceof TaskFactory) vv[i] = tri.next(); - else if (arg instanceof DeferredSupplier) vv[i] = ((DeferredSupplier<?>) arg).get(); - else vv[i] = arg; - i++; - } - return String.format(spec, vv); - }}, - taskArgs); - } - - /** returns a task for parallel execution returning a list of values for the given sensor for the given entity list, - * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */ - public static <T> Task<List<T>> listAttributesWhenReady(AttributeSensor<T> sensor, Iterable<Entity> entities) { - return listAttributesWhenReady(sensor, entities, GroovyJavaMethods.truthPredicate()); - } - - public static <T> Task<List<T>> listAttributesWhenReady(AttributeSensor<T> sensor, Iterable<Entity> entities, Closure<Boolean> readiness) { - Predicate<Object> readinessPredicate = (readiness != null) ? GroovyJavaMethods.<Object>predicateFromClosure(readiness) : GroovyJavaMethods.truthPredicate(); - return listAttributesWhenReady(sensor, entities, readinessPredicate); - } - - /** returns a task for parallel execution returning a list of values of the given sensor list on the given entity, - * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */ - public static <T> Task<List<T>> listAttributesWhenReady(final AttributeSensor<T> sensor, Iterable<Entity> entities, Predicate<? super T> readiness) { - if (readiness == null) readiness = GroovyJavaMethods.truthPredicate(); - return builder().attributeWhenReadyFromMultiple(entities, sensor, readiness).build(); - } - - /** @see #waitForTask(Task, Entity, String) */ - public static <T> T waitForTask(Task<T> t, Entity context) throws InterruptedException { - return waitForTask(t, context, null); - } - - /** blocks until the given task completes, submitting if necessary, returning the result of that task; - * optional contextMessage is available in status if this is running in a task - */ - @SuppressWarnings("unchecked") - public static <T> T waitForTask(Task<T> t, Entity context, String contextMessage) throws InterruptedException { - try { - return (T) Tasks.resolveValue(t, Object.class, ((EntityInternal)context).getExecutionContext(), contextMessage); - } catch (ExecutionException e) { - throw Throwables.propagate(e); - } - } - - public static class AttributeAndSensorCondition<T> { - protected final Entity source; - protected final AttributeSensor<T> sensor; - protected final Predicate<? super T> predicate; - - public AttributeAndSensorCondition(Entity source, AttributeSensor<T> sensor, Predicate<? super T> predicate) { - this.source = checkNotNull(source, "source"); - this.sensor = checkNotNull(sensor, "sensor"); - this.predicate = checkNotNull(predicate, "predicate"); - } - } - - public static ProtoBuilder builder() { - return new ProtoBuilder(); - } - - /** - * Builder for producing variants of attributeWhenReady. - */ - @Beta - public static class ProtoBuilder { - /** - * Will wait for the attribute on the given entity. - * If that entity reports {@link Lifecycle#ON_FIRE} for its {@link Attributes#SERVICE_STATE} then it will abort. - */ - public <T2> Builder<T2,T2> attributeWhenReady(Entity source, AttributeSensor<T2> sensor) { - return new Builder<T2,T2>(source, sensor).abortIfOnFire(); - } - - /** - * Will wait for the attribute on the given entity, not aborting when it goes {@link Lifecycle#ON_FIRE}. - */ - public <T2> Builder<T2,T2> attributeWhenReadyAllowingOnFire(Entity source, AttributeSensor<T2> sensor) { - return new Builder<T2,T2>(source, sensor); - } - - /** Constructs a builder for task for parallel execution returning a list of values of the given sensor list on the given entity, - * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */ - @Beta - public <T> MultiBuilder<T, T, List<T>> attributeWhenReadyFromMultiple(Iterable<? extends Entity> sources, AttributeSensor<T> sensor) { - return attributeWhenReadyFromMultiple(sources, sensor, GroovyJavaMethods.truthPredicate()); - } - /** As {@link #attributeWhenReadyFromMultiple(Iterable, AttributeSensor)} with an explicit readiness test. */ - @Beta - public <T> MultiBuilder<T, T, List<T>> attributeWhenReadyFromMultiple(Iterable<? extends Entity> sources, AttributeSensor<T> sensor, Predicate<? super T> readiness) { - return new MultiBuilder<T, T, List<T>>(sources, sensor, readiness); - } - } - - /** - * Builder for producing variants of attributeWhenReady. - */ - public static class Builder<T,V> { - protected Entity source; - protected AttributeSensor<T> sensor; - protected Predicate<? super T> readiness; - protected Function<? super T, ? extends V> postProcess; - protected List<AttributeAndSensorCondition<?>> abortSensorConditions = Lists.newArrayList(); - protected String blockingDetails; - protected Duration timeout; - protected Maybe<V> onTimeout; - protected boolean ignoreUnmanaged = WaitInTaskForAttributeReady.DEFAULT_IGNORE_UNMANAGED; - protected Maybe<V> onUnmanaged; - - protected Builder(Entity source, AttributeSensor<T> sensor) { - this.source = source; - this.sensor = sensor; - } - - /** - * Will wait for the attribute on the given entity. - * If that entity report {@link Lifecycle#ON_FIRE} for its {@link Attributes#SERVICE_STATE_ACTUAL} then it will abort. - * @deprecated since 0.7.0 use {@link DependentConfiguration#builder()} then {@link ProtoBuilder#attributeWhenReady(Entity, AttributeSensor)} then {@link #abortIfOnFire()} - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public <T2> Builder<T2,T2> attributeWhenReady(Entity source, AttributeSensor<T2> sensor) { - this.source = checkNotNull(source, "source"); - this.sensor = (AttributeSensor) checkNotNull(sensor, "sensor"); - abortIfOnFire(); - return (Builder<T2, T2>) this; - } - public Builder<T,V> readiness(Closure<Boolean> val) { - this.readiness = GroovyJavaMethods.predicateFromClosure(checkNotNull(val, "val")); - return this; - } - public Builder<T,V> readiness(Predicate<? super T> val) { - this.readiness = checkNotNull(val, "ready"); - return this; - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - public <V2> Builder<T,V2> postProcess(Closure<V2> val) { - this.postProcess = (Function) GroovyJavaMethods.<T,V2>functionFromClosure(checkNotNull(val, "postProcess")); - return (Builder<T,V2>) this; - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - public <V2> Builder<T,V2> postProcess(final Function<? super T, V2> val) { - this.postProcess = (Function) checkNotNull(val, "postProcess"); - return (Builder<T,V2>) this; - } - public <T2> Builder<T,V> abortIf(Entity source, AttributeSensor<T2> sensor) { - return abortIf(source, sensor, GroovyJavaMethods.truthPredicate()); - } - public <T2> Builder<T,V> abortIf(Entity source, AttributeSensor<T2> sensor, Predicate<? super T2> predicate) { - abortSensorConditions.add(new AttributeAndSensorCondition<T2>(source, sensor, predicate)); - return this; - } - public Builder<T,V> abortIfOnFire() { - abortIf(source, Attributes.SERVICE_STATE_ACTUAL, Predicates.equalTo(Lifecycle.ON_FIRE)); - return this; - } - public Builder<T,V> blockingDetails(String val) { - blockingDetails = val; - return this; - } - /** specifies an optional timeout; by default it waits forever, or until unmanaged or other abort condition */ - public Builder<T,V> timeout(Duration val) { - timeout = val; - return this; - } - public Builder<T,V> onTimeoutReturn(V val) { - onTimeout = Maybe.of(val); - return this; - } - public Builder<T,V> onTimeoutThrow() { - onTimeout = Maybe.<V>absent(); - return this; - } - public Builder<T,V> onUnmanagedReturn(V val) { - onUnmanaged = Maybe.of(val); - return this; - } - public Builder<T,V> onUnmanagedThrow() { - onUnmanaged = Maybe.<V>absent(); - return this; - } - /** @since 0.7.0 included in case old behaviour of not checking whether the entity is managed is required - * (I can't see why it is; polling will likely give errors, once it is unmanaged this will never completed, - * and before management the current code will continue, so long as there are no other errors) */ @Deprecated - public Builder<T,V> onUnmanagedContinue() { - ignoreUnmanaged = true; - return this; - } - /** take advantage of the fact that this builder can build multiple times, allowing subclasses - * to change the source along the way */ - protected Builder<T,V> source(Entity source) { - this.source = source; - return this; - } - /** as {@link #source(Entity)} */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - protected Builder<T,V> sensor(AttributeSensor<? extends T> sensor) { - this.sensor = (AttributeSensor) sensor; - return this; - } - public Task<V> build() { - validate(); - - return Tasks.<V>builder().dynamic(false) - .name("waiting on "+sensor.getName()) - .description("Waiting on sensor "+sensor.getName()+" from "+source) - .tag("attributeWhenReady") - .body(new WaitInTaskForAttributeReady<T,V>(this)) - .build(); - } - - public V runNow() { - validate(); - return new WaitInTaskForAttributeReady<T,V>(this).call(); - } - @SuppressWarnings({ "unchecked", "rawtypes" }) - private void validate() { - checkNotNull(source, "Entity source"); - checkNotNull(sensor, "Sensor"); - if (readiness == null) readiness = GroovyJavaMethods.truthPredicate(); - if (postProcess == null) postProcess = (Function) Functions.identity(); - } - } - - /** - * Builder for producing variants of attributeWhenReady. - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - @Beta - public static class MultiBuilder<T, V, V2> { - protected final String name; - protected final String descriptionBase; - protected final Builder<T,V> builder; - // if desired, the use of this multiSource could allow different conditions; - // but probably an easier API just for the caller to build the parallel task - protected final List<AttributeAndSensorCondition<?>> multiSource = Lists.newArrayList(); - protected Function<? super List<V>, V2> postProcessFromMultiple; - - /** returns a task for parallel execution returning a list of values of the given sensor list on the given entity, - * optionally when the values satisfy a given readiness predicate (defaulting to groovy truth if not supplied) */ - @Beta - protected MultiBuilder(Iterable<? extends Entity> sources, AttributeSensor<T> sensor) { - this(sources, sensor, GroovyJavaMethods.truthPredicate()); - } - @Beta - protected MultiBuilder(Iterable<? extends Entity> sources, AttributeSensor<T> sensor, Predicate<? super T> readiness) { - builder = new Builder<T,V>(null, sensor); - builder.readiness(readiness); - - for (Entity s : checkNotNull(sources, "sources")) { - multiSource.add(new AttributeAndSensorCondition<T>(s, sensor, readiness)); - } - this.name = "waiting on "+sensor.getName(); - this.descriptionBase = "waiting on "+sensor.getName()+" "+readiness - +" from "+Iterables.size(sources)+" entit"+Strings.ies(sources); - } - - /** Apply post-processing to the entire list of results */ - public <V2b> MultiBuilder<T, V, V2b> postProcessFromMultiple(final Function<? super List<V>, V2b> val) { - this.postProcessFromMultiple = (Function) checkNotNull(val, "postProcessFromMulitple"); - return (MultiBuilder<T,V, V2b>) this; - } - /** Apply post-processing to the entire list of results - * See {@link CollectionFunctionals#all(Predicate)} and {@link CollectionFunctionals#quorum(org.apache.brooklyn.util.collections.QuorumCheck, Predicate) - * which allow useful arguments. */ - public MultiBuilder<T, V, Boolean> postProcessFromMultiple(final Predicate<? super List<V>> val) { - return postProcessFromMultiple(Functions.forPredicate(val)); - } - - public <V1> MultiBuilder<T, V1, V2> postProcess(Closure<V1> val) { - builder.postProcess(val); - return (MultiBuilder<T, V1, V2>) this; - } - public <V1> MultiBuilder<T, V1, V2> postProcess(final Function<? super T, V1> val) { - builder.postProcess(val); - return (MultiBuilder<T, V1, V2>) this; - } - public <T2> MultiBuilder<T, V, V2> abortIf(Entity source, AttributeSensor<T2> sensor) { - builder.abortIf(source, sensor); - return this; - } - public <T2> MultiBuilder<T, V, V2> abortIf(Entity source, AttributeSensor<T2> sensor, Predicate<? super T2> predicate) { - builder.abortIf(source, sensor, predicate); - return this; - } - public MultiBuilder<T, V, V2> abortIfOnFire() { - builder.abortIfOnFire(); - return this; - } - public MultiBuilder<T, V, V2> blockingDetails(String val) { - builder.blockingDetails(val); - return this; - } - public MultiBuilder<T, V, V2> timeout(Duration val) { - builder.timeout(val); - return this; - } - public MultiBuilder<T, V, V2> onTimeoutReturn(V val) { - builder.onTimeoutReturn(val); - return this; - } - public MultiBuilder<T, V, V2> onTimeoutThrow() { - builder.onTimeoutThrow(); - return this; - } - public MultiBuilder<T, V, V2> onUnmanagedReturn(V val) { - builder.onUnmanagedReturn(val); - return this; - } - public MultiBuilder<T, V, V2> onUnmanagedThrow() { - builder.onUnmanagedThrow(); - return this; - } - - public Task<V2> build() { - List<Task<V>> tasks = MutableList.of(); - for (AttributeAndSensorCondition<?> source: multiSource) { - builder.source(source.source); - builder.sensor((AttributeSensor)source.sensor); - builder.readiness((Predicate)source.predicate); - tasks.add(builder.build()); - } - final Task<List<V>> parallelTask = Tasks.<List<V>>builder().parallel(true).addAll(tasks) - .name(name) - .description(descriptionBase+ - (builder.timeout!=null ? ", timeout "+builder.timeout : "")) - .build(); - - if (postProcessFromMultiple == null) { - // V2 should be the right type in normal operations - return (Task<V2>) parallelTask; - } else { - return Tasks.<V2>builder().name(name).description(descriptionBase) - .tag("attributeWhenReady") - .body(new Callable<V2>() { - @Override public V2 call() throws Exception { - List<V> prePostProgress = DynamicTasks.queue(parallelTask).get(); - return DynamicTasks.queue( - Tasks.<V2>builder().name("post-processing").description("Applying "+postProcessFromMultiple) - .body(Functionals.callable(postProcessFromMultiple, prePostProgress)) - .build()).get(); - } - }) - .build(); - } - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java b/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java deleted file mode 100644 index 6b9c780..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/core/HttpRequestSensor.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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.sensor.core; - -import java.net.URI; - -import net.minidev.json.JSONObject; - -import org.apache.brooklyn.api.entity.EntityLocal; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.effector.AddSensor; -import org.apache.brooklyn.sensor.feed.http.HttpFeed; -import org.apache.brooklyn.sensor.feed.http.HttpPollConfig; -import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions; -import org.apache.brooklyn.util.core.config.ConfigBag; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.annotations.Beta; -import com.google.common.base.Functions; -import com.google.common.base.Supplier; - -/** - * Configurable {@link org.apache.brooklyn.api.entity.EntityInitializer} which adds an HTTP sensor feed to retrieve the - * {@link JSONObject} from a JSON response in order to populate the sensor with the data at the {@code jsonPath}. - * - * @see SshCommandSensor - * @see JmxAttributeSensor - */ -@Beta -public final class HttpRequestSensor<T> extends AddSensor<T> { - - private static final Logger LOG = LoggerFactory.getLogger(HttpRequestSensor.class); - - public static final ConfigKey<String> SENSOR_URI = ConfigKeys.newStringConfigKey("uri", "HTTP URI to poll for JSON"); - public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath", "JSON path to select in HTTP response; default $", "$"); - public static final ConfigKey<String> USERNAME = ConfigKeys.newStringConfigKey("username", "Username for HTTP request, if required"); - public static final ConfigKey<String> PASSWORD = ConfigKeys.newStringConfigKey("password", "Password for HTTP request, if required"); - - protected final Supplier<URI> uri; - protected final String jsonPath; - protected final String username; - protected final String password; - - public HttpRequestSensor(final ConfigBag params) { - super(params); - - uri = new Supplier<URI>() { - @Override - public URI get() { - return URI.create(params.get(SENSOR_URI)); - } - }; - jsonPath = params.get(JSON_PATH); - username = params.get(USERNAME); - password = params.get(PASSWORD); - } - - @Override - public void apply(final EntityLocal entity) { - super.apply(entity); - - if (LOG.isDebugEnabled()) { - LOG.debug("Adding HTTP JSON sensor {} to {}", name, entity); - } - - HttpPollConfig<T> pollConfig = new HttpPollConfig<T>(sensor) - .checkSuccess(HttpValueFunctions.responseCodeEquals(200)) - .onFailureOrException(Functions.constant((T) null)) - .onSuccess(HttpValueFunctions.<T>jsonContentsFromPath(jsonPath)) - .period(period); - - HttpFeed.builder().entity(entity) - .baseUri(uri) - .credentialsIfNotNull(username, password) - .poll(pollConfig) - .build(); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/2a78e273/core/src/main/java/org/apache/brooklyn/sensor/core/PortAttributeSensorAndConfigKey.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/brooklyn/sensor/core/PortAttributeSensorAndConfigKey.java b/core/src/main/java/org/apache/brooklyn/sensor/core/PortAttributeSensorAndConfigKey.java deleted file mode 100644 index e269966..0000000 --- a/core/src/main/java/org/apache/brooklyn/sensor/core/PortAttributeSensorAndConfigKey.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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.sensor.core; - -import java.util.Collection; -import java.util.Iterator; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.location.Location; -import org.apache.brooklyn.api.location.MachineProvisioningLocation; -import org.apache.brooklyn.api.location.PortRange; -import org.apache.brooklyn.api.location.PortSupplier; -import org.apache.brooklyn.api.mgmt.ManagementContext; -import org.apache.brooklyn.api.sensor.Sensor; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.entity.BrooklynConfigKeys; -import org.apache.brooklyn.core.internal.BrooklynInitialization; -import org.apache.brooklyn.core.location.Locations; -import org.apache.brooklyn.util.core.flags.TypeCoercions; -import org.apache.brooklyn.util.guava.Maybe; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Optional; -import com.google.common.base.Predicates; -import com.google.common.collect.Iterables; - -/** - * A {@link Sensor} describing a port on a system, - * with a {@link ConfigKey} which can be configured with a port range - * (either a number e.g. 80, or a string e.g. "80" or "8080-8089" or even "80, 8080-8089, 8800+", or a list of these). - * <p> - * To convert at runtime a single port is chosen, respecting the entity. - */ -public class PortAttributeSensorAndConfigKey extends AttributeSensorAndConfigKey<PortRange,Integer> { - - private static final long serialVersionUID = 4680651022807491321L; - - public static final Logger LOG = LoggerFactory.getLogger(PortAttributeSensorAndConfigKey.class); - - static { BrooklynInitialization.initAll(); } - - public PortAttributeSensorAndConfigKey(String name) { - this(name, name, null); - } - public PortAttributeSensorAndConfigKey(String name, String description) { - this(name, description, null); - } - public PortAttributeSensorAndConfigKey(String name, String description, Object defaultValue) { - super(PortRange.class, Integer.class, name, description, defaultValue); - } - public PortAttributeSensorAndConfigKey(PortAttributeSensorAndConfigKey orig, Object defaultValue) { - super(orig, TypeCoercions.coerce(defaultValue, PortRange.class)); - } - @Override - protected Integer convertConfigToSensor(PortRange value, Entity entity) { - if (value==null) return null; - Collection<? extends Location> locations = entity.getLocations(); - if (!locations.isEmpty()) { - Maybe<? extends Location> lo = Locations.findUniqueMachineLocation(locations); - if (!lo.isPresent()) { - // Try a unique location which isn't a machine provisioner - Iterator<? extends Location> li = Iterables.filter(locations, - Predicates.not(Predicates.instanceOf(MachineProvisioningLocation.class))).iterator(); - if (li.hasNext()) lo = Maybe.of(li.next()); - if (li.hasNext()) lo = Maybe.absent(); - } - // Fall back to selecting the single location - if (!lo.isPresent() && locations.size() == 1) { - lo = Maybe.of(locations.iterator().next()); - } - if (LOG.isTraceEnabled()) { - LOG.trace("Convert config to sensor for {} found locations: {}. Selected: {}", new Object[] {entity, locations, lo}); - } - if (lo.isPresent()) { - Location l = lo.get(); - Optional<Boolean> locationRunning = Optional.fromNullable(l.getConfig(BrooklynConfigKeys.SKIP_ENTITY_START_IF_RUNNING)); - Optional<Boolean> entityRunning = Optional.fromNullable(entity.getConfig(BrooklynConfigKeys.SKIP_ENTITY_START_IF_RUNNING)); - Optional<Boolean> locationInstalled = Optional.fromNullable(l.getConfig(BrooklynConfigKeys.SKIP_ENTITY_INSTALLATION)); - Optional<Boolean> entityInstalled = Optional.fromNullable(entity.getConfig(BrooklynConfigKeys.SKIP_ENTITY_INSTALLATION)); - Optional<Boolean> entityStarted = Optional.fromNullable(entity.getConfig(BrooklynConfigKeys.SKIP_ENTITY_START)); - boolean skipCheck = locationRunning.or(entityRunning).or(locationInstalled).or(entityInstalled).or(entityStarted).or(false); - if (l instanceof PortSupplier) { - int p = ((PortSupplier) l).obtainPort(value); - if (p != -1) { - LOG.debug("{}: choosing port {} for {}", new Object[] { entity, p, getName() }); - return p; - } - // If we are not skipping install or already started, fail now - if (!skipCheck) { - int rangeSize = Iterables.size(value); - if (rangeSize == 0) { - LOG.warn("{}: no port available for {} (empty range {})", new Object[] { entity, getName(), value }); - } else if (rangeSize == 1) { - Integer pp = value.iterator().next(); - if (pp > 1024) { - LOG.warn("{}: port {} not available for {}", new Object[] { entity, pp, getName() }); - } else { - LOG.warn("{}: port {} not available for {} (root may be required?)", new Object[] { entity, pp, getName() }); - } - } else { - LOG.warn("{}: no port available for {} (tried range {})", new Object[] { entity, getName(), value }); - } - return null; // Definitively, no ports available - } - } - // Ports may be available, we just can't tell from the location - Integer v = (value.isEmpty() ? null : value.iterator().next()); - LOG.debug("{}: choosing port {} (unconfirmed) for {}", new Object[] { entity, v, getName() }); - return v; - } else { - LOG.warn("{}: ports not applicable, or not yet applicable, because has multiple locations {}; ignoring ", new Object[] { entity, locations, getName() }); - } - } else { - LOG.warn("{}: ports not applicable, or not yet applicable, bacause has no locations; ignoring {}", entity, getName()); - } - return null; - } - - @Override - protected Integer convertConfigToSensor(PortRange value, ManagementContext managementContext) { - LOG.warn("ports not applicable, because given managementContext rather than entity; ignoring {}", getName()); - return null; - } -}
