http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/render/RendererHints.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/render/RendererHints.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/render/RendererHints.java deleted file mode 100644 index 4ff47d1..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/config/render/RendererHints.java +++ /dev/null @@ -1,284 +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.core.config.render; - -import groovy.lang.Closure; - -import java.util.Set; - -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.render.RendererHints; -import org.apache.brooklyn.util.groovy.GroovyJavaMethods; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.annotations.Beta; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Function; -import com.google.common.base.Functions; -import com.google.common.base.Objects; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; -import com.google.common.base.Predicates; -import com.google.common.base.Strings; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Iterables; -import com.google.common.collect.LinkedHashMultimap; -import com.google.common.collect.Multimaps; -import com.google.common.collect.SetMultimap; -import com.google.common.collect.Sets; - -/** - * Registry of hints for displaying items such as sensors, e.g. in the web console. - */ -public class RendererHints { - - private static final Logger log = LoggerFactory.getLogger(RendererHints.class); - - private static SetMultimap<Object, Hint<?>> registry = Multimaps.synchronizedSetMultimap(LinkedHashMultimap.<Object, Hint<?>>create()); - - @VisibleForTesting - public static SetMultimap<Object, Hint<?>> getRegistry() { return registry; } - - /** - * Registers a {@link Hint} against the given element. - * <p> - * Returns the element, for convenience when used in a with block after defining the element. - */ - public static <T> AttributeSensor<T> register(AttributeSensor<T> element, Hint<? super T> hintForThatElement) { return _register(element, hintForThatElement); } - /** as {@link #register(AttributeSensor, Hint)} */ - public static <T> ConfigKey<T> register(ConfigKey<T> element, Hint<? super T> hintForThatElement) { return _register(element, hintForThatElement); } - /** as {@link #register(AttributeSensor, Hint)} */ - public static <T> Class<T> register(Class<T> element, Hint<? super T> hintForThatElement) { return _register(element, hintForThatElement); } - - private static <T> T _register(T element, Hint<?> hintForThatElement) { - if (element==null) { - // can happen if being done in a static initializer in an inner class - log.error("Invalid null target for renderer hint "+hintForThatElement, new Throwable("Trace for invalid null target for renderer hint")); - } - registry.put(element, hintForThatElement); - return element; - } - - /** Returns all registered hints against the given element */ - public static Set<Hint<?>> getHintsFor(AttributeSensor<?> element) { return _getHintsFor(element, null); } - /** as {@link #getHintsFor(AttributeSensor)} */ - public static Set<Hint<?>> getHintsFor(ConfigKey<?> element) { return _getHintsFor(element, null); } - /** as {@link #getHintsFor(AttributeSensor)} */ - public static Set<Hint<?>> getHintsFor(Class<?> element) { return _getHintsFor(element, null); } - - @Deprecated /** @deprecated since 0.7.0 only supported for certain types */ - public static Set<Hint<?>> getHintsFor(Object element) { return getHintsFor(element, null); } - - @Deprecated /** @deprecated since 0.7.0 only supported for certain types */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static Set<Hint<?>> getHintsFor(Object element, Class<? extends Hint> optionalHintSuperClass) { return (Set<Hint<?>>) _getHintsFor(element, optionalHintSuperClass); } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static <T extends Hint> Set<T> _getHintsFor(Object element, Class<T> optionalHintSuperClass) { - Set<Hint<?>> found = ImmutableSet.copyOf(registry.get(element)); - if (found.isEmpty() && element instanceof Class && !Object.class.equals(element)) { - // try superclasses of the element; this seems overkill for the main use case, Entity; - // (other classes registered are typically final) - found = (Set<Hint<?>>) _getHintsFor(((Class)element).getSuperclass(), optionalHintSuperClass); - if (found.isEmpty()) { - for (Class<?> parentInterface: ((Class)element).getInterfaces()) { - found = (Set<Hint<?>>) _getHintsFor(parentInterface, optionalHintSuperClass); - if (!found.isEmpty()) - break; - } - } - } - if (optionalHintSuperClass != null) { - return (Set<T>)Sets.filter(found, Predicates.instanceOf(optionalHintSuperClass)); - } else { - return (Set<T>)found; - } - } - - /** Applies the (first) display value hint registered against the given target to the given initialValue */ - public static Object applyDisplayValueHint(AttributeSensor<?> target, Object initialValue) { return applyDisplayValueHintUnchecked(target, initialValue); } - /** as {@link #applyDisplayValueHint(AttributeSensor, Object)} */ - public static Object applyDisplayValueHint(ConfigKey<?> target, Object initialValue) { return applyDisplayValueHintUnchecked(target, initialValue); } - /** as {@link #applyDisplayValueHint(AttributeSensor, Object)} */ - public static Object applyDisplayValueHint(Class<?> target, Object initialValue) { return applyDisplayValueHintUnchecked(target, initialValue); } - - /** as {@link #applyDisplayValueHint(AttributeSensor, Object)}, but without type checking; public for those few cases where we may have lost the type */ - @Beta - public static Object applyDisplayValueHintUnchecked(Object target, Object initialValue) { return _applyDisplayValueHint(target, initialValue, true); } - @SuppressWarnings("rawtypes") - private static Object _applyDisplayValueHint(Object target, Object initialValue, boolean includeClass) { - Iterable<RendererHints.DisplayValue> hints = RendererHints._getHintsFor(target, RendererHints.DisplayValue.class); - if (Iterables.size(hints) > 1) { - log.warn("Multiple display value hints set for {}; Only one will be applied, using first", target); - } - - Optional<RendererHints.DisplayValue> hint = Optional.fromNullable(Iterables.getFirst(hints, null)); - Object value = hint.isPresent() ? hint.get().getDisplayValue(initialValue) : initialValue; - if (includeClass && value!=null && !(value instanceof String) && !(value instanceof Number) && !(value.getClass().isPrimitive())) { - value = _applyDisplayValueHint(value.getClass(), value, false); - } - return value; - } - - - /** Parent marker class for hints. */ - public static abstract class Hint<T> { } - - public static interface NamedAction { - String getActionName(); - } - - /** - * This hint describes a named action possible on something, e.g. a sensor; - * currently used in web client to show actions on sensors - */ - public static class NamedActionWithUrl<T> extends Hint<T> implements NamedAction { - private final String actionName; - private final Function<T, String> postProcessing; - - public NamedActionWithUrl(String actionName) { - this(actionName, (Function<T, String>)null); - } - - @SuppressWarnings("unchecked") @Deprecated /** @deprecated since 0.7.0 use Function */ - public NamedActionWithUrl(String actionName, Closure<String> postProcessing) { - this.actionName = actionName; - this.postProcessing = (Function<T, String>) ((postProcessing == null) ? null : GroovyJavaMethods.functionFromClosure(postProcessing)); - } - - public NamedActionWithUrl(String actionName, Function<T, String> postProcessing) { - this.actionName = actionName; - this.postProcessing = postProcessing; - } - - /** @deprecated since 0.7.0 call {@link #getUrlFromValue(Object)}, parsing the sensor value yourself */ @Deprecated - public String getUrl(Entity e, AttributeSensor<T> s) { - return getUrlFromValue(e.getAttribute(s)); - } - - public String getActionName() { - return actionName; - } - - /** this is the method invoked by web console SensorSummary, at the moment */ - public String getUrlFromValue(T v) { - String v2; - if (postProcessing != null) { - v2 = postProcessing.apply(v); - } else { - v2 = (v==null ? null : v.toString()); - } - if (v2 == null) return v2; - return v2.toString(); - } - - @Override - public int hashCode() { - return Objects.hashCode(actionName, postProcessing); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof NamedActionWithUrl)) return false; - NamedActionWithUrl<?> o = (NamedActionWithUrl<?>) obj; - return Objects.equal(actionName, o.actionName) && Objects.equal(postProcessing, o.postProcessing); - } - } - - /** - * This hint describes a transformation used to generate a display value for config keys and sensors. - * <p> - * <em><strong>Warning</strong> This is currently a {@link Beta} implementation, and - * may be changed or removed if there is a suitable alternative mechanism to achieve - * this functionality.</em> - */ - @Beta - public static class DisplayValue<T> extends Hint<T> { - private final Function<Object, String> transform; - - @SuppressWarnings("unchecked") - protected DisplayValue(Function<?, String> transform) { - this.transform = (Function<Object, String>) Preconditions.checkNotNull(transform, "transform"); - } - - public String getDisplayValue(Object v) { - String dv = transform.apply(v); - return Strings.nullToEmpty(dv); - } - - @Override - public int hashCode() { - return Objects.hashCode(transform); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof DisplayValue)) return false; - return Objects.equal(transform, ((DisplayValue<?>)obj).transform); - } - } - - @Beta - public static <T> DisplayValue<T> displayValue(Function<T,String> transform) { - return new DisplayValue<T>(transform); - } - - @Beta - public static <T> NamedActionWithUrl<T> namedActionWithUrl(String actionName, Function<T,String> transform) { - return new NamedActionWithUrl<T>(actionName, transform); - } - - @Beta - public static <T> NamedActionWithUrl<T> namedActionWithUrl(String actionName) { - return new NamedActionWithUrl<T>(actionName); - } - - @Beta - public static <T> NamedActionWithUrl<T> namedActionWithUrl(Function<T,String> transform) { - return openWithUrl(transform); - } - - @Beta - public static <T> NamedActionWithUrl<T> namedActionWithUrl() { - return openWithUrl(); - } - - @Beta - public static <T> NamedActionWithUrl<T> openWithUrl() { - return openWithUrl((Function<T,String>) null); - } - - @Beta - public static <T> NamedActionWithUrl<T> openWithUrl(Function<T,String> transform) { - return new NamedActionWithUrl<T>("Open", transform); - } - - /** - * Forces the given sensor or config key's value to be censored. It will be - * presented as <code>********</code>. - */ - @Beta - public static <T> DisplayValue<T> censoredValue() { - return new DisplayValue<T>(Functions.constant("********")); - } - -}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AbstractEffector.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AbstractEffector.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AbstractEffector.java deleted file mode 100644 index 4acd0e0..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AbstractEffector.java +++ /dev/null @@ -1,90 +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.core.effector; - -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.api.effector.ParameterType; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.mgmt.Task; -import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory; -import org.apache.brooklyn.core.mgmt.internal.EffectorUtils; -import org.apache.brooklyn.util.core.config.ConfigBag; -import org.apache.brooklyn.util.core.task.DynamicSequentialTask; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.collect.ImmutableMap; - -/** - * The abstract {@link Effector} implementation. - * - * The concrete subclass (often anonymous) will supply the {@link #call(Entity, Map)} implementation, - * and the fields in the constructor. - */ -public abstract class AbstractEffector<T> extends EffectorBase<T> implements EffectorWithBody<T> { - - private static final long serialVersionUID = 1832435915652457843L; - - @SuppressWarnings("unused") - private static final Logger LOG = LoggerFactory.getLogger(AbstractEffector.class); - - public AbstractEffector(String name, Class<T> returnType, List<ParameterType<?>> parameters, String description) { - super(name, returnType, parameters, description); - } - - public abstract T call(Entity entity, @SuppressWarnings("rawtypes") Map parameters); - - /** Convenience for named-parameter syntax (needs map in first argument) */ - public T call(Entity entity) { return call(ImmutableMap.of(), entity); } - - /** Convenience for named-parameter syntax (needs map in first argument) */ - public T call(@SuppressWarnings("rawtypes") Map parameters, Entity entity) { return call(entity, parameters); } - - /** @deprecated since 0.7.0 use {@link #getFlagsForTaskInvocationAt(Entity, Effector, ConfigBag)} */ @Deprecated - protected final Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity) { - return getFlagsForTaskInvocationAt(entity, this, null); - } - /** subclasses may override to add additional flags, but they should include the flags returned here - * unless there is very good reason not to */ - protected Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity, Effector<T> effector, ConfigBag parameters) { - return EffectorUtils.getTaskFlagsForEffectorInvocation(entity, effector, parameters); - } - - /** not meant for overriding; subclasses should override the abstract {@link #call(Entity, Map)} method in this class */ - @Override - public final EffectorTaskFactory<T> getBody() { - return new EffectorTaskFactory<T>() { - @Override - public Task<T> newTask(final Entity entity, final Effector<T> effector, final ConfigBag parameters) { - return new DynamicSequentialTask<T>( - getFlagsForTaskInvocationAt(entity, AbstractEffector.this, parameters), - new Callable<T>() { - @Override public T call() { - return AbstractEffector.this.call(parameters.getAllConfig(), entity); - } - }); - } - }; - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddChildrenEffector.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddChildrenEffector.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddChildrenEffector.java deleted file mode 100644 index f2730ca..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddChildrenEffector.java +++ /dev/null @@ -1,117 +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.core.effector; - -import java.util.List; -import java.util.Map; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.effector.Effectors.EffectorBuilder; -import org.apache.brooklyn.core.mgmt.EntityManagementUtils; -import org.apache.brooklyn.core.mgmt.EntityManagementUtils.CreationResult; -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.gson.Gson; - -/** Entity initializer which defines an effector which adds a child blueprint to an entity. - * <p> - * One of the config keys {@link #BLUEPRINT_YAML} (containing a YAML blueprint (map or string)) - * or {@link #BLUEPRINT_TYPE} (containing a string referring to a catalog type) should be supplied, but not both. - * Parameters defined here are supplied as config during the entity creation. - * - * @since 0.7.0 */ -@Beta -public class AddChildrenEffector extends AddEffector { - - private static final Logger log = LoggerFactory.getLogger(AddChildrenEffector.class); - - public static final ConfigKey<Object> BLUEPRINT_YAML = ConfigKeys.newConfigKey(Object.class, "blueprint_yaml"); - public static final ConfigKey<String> BLUEPRINT_TYPE = ConfigKeys.newStringConfigKey("blueprint_type"); - public static final ConfigKey<Boolean> AUTO_START = ConfigKeys.newBooleanConfigKey("auto_start"); - - public AddChildrenEffector(ConfigBag params) { - super(newEffectorBuilder(params).build()); - } - - public AddChildrenEffector(Map<String,String> params) { - this(ConfigBag.newInstance(params)); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static EffectorBuilder<List<String>> newEffectorBuilder(ConfigBag params) { - EffectorBuilder<List<String>> eff = (EffectorBuilder) AddEffector.newEffectorBuilder(List.class, params); - eff.impl(new Body(eff.buildAbstract(), params)); - return eff; - } - - protected static class Body extends EffectorBody<List<String>> { - - private final Effector<?> effector; - private final String blueprintBase; - private final Boolean autostart; - - public Body(Effector<?> eff, ConfigBag params) { - this.effector = eff; - String newBlueprint = null; - Object yaml = params.get(BLUEPRINT_YAML); - if (yaml instanceof Map) { - newBlueprint = new Gson().toJson(yaml); - } else if (yaml instanceof String) { - newBlueprint = (String) yaml; - } else if (yaml!=null) { - throw new IllegalArgumentException(this+" requires map or string in "+BLUEPRINT_YAML+"; not "+yaml.getClass()+" ("+yaml+")"); - } - String blueprintType = params.get(BLUEPRINT_TYPE); - if (blueprintType!=null) { - if (newBlueprint!=null) { - throw new IllegalArgumentException(this+" cannot take both "+BLUEPRINT_TYPE+" and "+BLUEPRINT_YAML); - } - newBlueprint = "services: [ { type: "+blueprintType+" } ]"; - } - if (newBlueprint==null) { - throw new IllegalArgumentException(this+" requires either "+BLUEPRINT_TYPE+" or "+BLUEPRINT_YAML); - } - blueprintBase = newBlueprint; - autostart = params.get(AUTO_START); - } - - @Override - public List<String> call(ConfigBag params) { - params = getMergedParams(effector, params); - - String blueprint = blueprintBase; - if (!params.isEmpty()) { - blueprint = blueprint+"\n"+"brooklyn.config: "+ - new Gson().toJson(params.getAllConfig()); - } - - log.debug(this+" adding children to "+entity()+":\n"+blueprint); - CreationResult<List<Entity>, List<String>> result = EntityManagementUtils.addChildren(entity(), blueprint, autostart); - log.debug(this+" added children to "+entity()+": "+result.get()); - return result.task().getUnchecked(); - } - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java deleted file mode 100644 index 9590bcf..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddEffector.java +++ /dev/null @@ -1,116 +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.core.effector; - -import java.util.Collections; -import java.util.Map; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.api.effector.ParameterType; -import org.apache.brooklyn.api.entity.EntityInitializer; -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.config.MapConfigKey; -import org.apache.brooklyn.core.effector.Effectors.EffectorBuilder; -import org.apache.brooklyn.core.entity.EntityInternal; -import org.apache.brooklyn.util.core.config.ConfigBag; -import org.apache.brooklyn.util.text.Strings; - -import com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; - -/** - * Entity initializer which adds an effector to an entity. - * <p> - * This instance provides a {@link #newEffectorBuilder(Class, ConfigBag)} - * which returns an abstract (body-less) effector defining: - * <li> the name from {@link #EFFECTOR_NAME}; - * <li> the description from {@link #EFFECTOR_DESCRIPTION} - * <li> the parameters from {@link #EFFECTOR_PARAMETER_DEFS} - * <p> - * Callers should pass the effector to instantiate into the constructor. - * Often subclasses will supply a constructor which takes a ConfigBag of parameters, - * and a custom {@link #newEffectorBuilder(Class, ConfigBag)} which adds the body - * before passing to this class. - * <p> - * Note that the parameters passed to the call method in the body of the effector implementation - * are only those supplied by a user at runtime; in order to merge with default - * values, use {@link #getMergedParams(Effector, ConfigBag)}. - * - * @since 0.7.0 */ -@Beta -public class AddEffector implements EntityInitializer { - - public static final ConfigKey<String> EFFECTOR_NAME = ConfigKeys.newStringConfigKey("name"); - public static final ConfigKey<String> EFFECTOR_DESCRIPTION = ConfigKeys.newStringConfigKey("description"); - - public static final ConfigKey<Map<String,Object>> EFFECTOR_PARAMETER_DEFS = new MapConfigKey<Object>(Object.class, "parameters"); - - final Effector<?> effector; - - public AddEffector(Effector<?> effector) { - this.effector = Preconditions.checkNotNull(effector, "effector"); - } - - @Override - public void apply(EntityLocal entity) { - ((EntityInternal)entity).getMutableEntityType().addEffector(effector); - } - - public static <T> EffectorBuilder<T> newEffectorBuilder(Class<T> type, ConfigBag params) { - String name = Preconditions.checkNotNull(params.get(EFFECTOR_NAME), "name must be supplied when defining an effector: %s", params); - EffectorBuilder<T> eff = Effectors.effector(type, name); - eff.description(params.get(EFFECTOR_DESCRIPTION)); - - Map<String, Object> paramDefs = params.get(EFFECTOR_PARAMETER_DEFS); - if (paramDefs!=null) { - for (Map.Entry<String, Object> paramDef: paramDefs.entrySet()){ - if (paramDef!=null) { - String paramName = paramDef.getKey(); - Object value = paramDef.getValue(); - if (value==null) value = Collections.emptyMap(); - if (!(value instanceof Map)) { - if (value instanceof CharSequence && Strings.isBlank((CharSequence) value)) - value = Collections.emptyMap(); - } - if (!(value instanceof Map)) - throw new IllegalArgumentException("Illegal argument of type "+value.getClass()+" value '"+value+"' supplied as parameter definition " - + "'"+paramName); - eff.parameter(ConfigKeys.DynamicKeys.newNamedInstance(paramName, (Map<?, ?>) value)); - } - } - } - - return eff; - } - - /** returns a ConfigBag containing the merger of the supplied parameters with default values on the effector-defined parameters */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static ConfigBag getMergedParams(Effector<?> eff, ConfigBag params) { - ConfigBag result = ConfigBag.newInstanceCopying(params); - for (ParameterType<?> param: eff.getParameters()) { - ConfigKey key = Effectors.asConfigKey(param); - if (!result.containsKey(key)) - result.configure(key, params.get(key)); - } - return result; - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java deleted file mode 100644 index d35068f..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/AddSensor.java +++ /dev/null @@ -1,126 +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.core.effector; - -import java.util.Map; - -import org.apache.brooklyn.api.entity.EntityInitializer; -import org.apache.brooklyn.api.entity.EntityLocal; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.entity.EntityInternal; -import org.apache.brooklyn.core.sensor.Sensors; -import org.apache.brooklyn.util.core.config.ConfigBag; -import org.apache.brooklyn.util.guava.Maybe; -import org.apache.brooklyn.util.javalang.Boxing; -import org.apache.brooklyn.util.time.Duration; - -import com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; - -/** - * Creates a new {@link AttributeSensor} on an entity. - * <p> - * The configuration can include the sensor {@code name}, {@code period} and {@code targetType}. - * For the targetType, currently this only supports classes on the initial classpath, not those in - * OSGi bundles added at runtime. - * - * @since 0.7.0 - */ -@Beta -public class AddSensor<T> implements EntityInitializer { - - public static final ConfigKey<String> SENSOR_NAME = ConfigKeys.newStringConfigKey("name", "The name of the sensor to create"); - public static final ConfigKey<Duration> SENSOR_PERIOD = ConfigKeys.newConfigKey(Duration.class, "period", "Period, including units e.g. 1m or 5s or 200ms; default 5 minutes", Duration.FIVE_MINUTES); - public static final ConfigKey<String> SENSOR_TYPE = ConfigKeys.newStringConfigKey("targetType", "Target type for the value; default String", "java.lang.String"); - - protected final String name; - protected final Duration period; - protected final String type; - protected final AttributeSensor<T> sensor; - - public AddSensor(Map<String, String> params) { - this(ConfigBag.newInstance(params)); - } - - public AddSensor(final ConfigBag params) { - this.name = Preconditions.checkNotNull(params.get(SENSOR_NAME), "Name must be supplied when defining a sensor"); - this.period = params.get(SENSOR_PERIOD); - this.type = params.get(SENSOR_TYPE); - this.sensor = newSensor(); - } - - @Override - public void apply(EntityLocal entity) { - ((EntityInternal) entity).getMutableEntityType().addSensor(sensor); - } - - private AttributeSensor<T> newSensor() { - String className = getFullClassName(type); - Class<T> clazz = getType(className); - return Sensors.newSensor(clazz, name); - } - - @SuppressWarnings("unchecked") - protected Class<T> getType(String className) { - try { - // TODO use OSGi loader (low priority however); also ensure that allows primitives - Maybe<Class<?>> primitive = Boxing.getPrimitiveType(className); - if (primitive.isPresent()) return (Class<T>) primitive.get(); - return (Class<T>) Class.forName(className); - } catch (ClassNotFoundException e) { - if (!className.contains(".")) { - // could be assuming "java.lang" package; try again with that - try { - return (Class<T>) Class.forName("java.lang."+className); - } catch (ClassNotFoundException e2) { - throw new IllegalArgumentException("Invalid target type for sensor "+name+": " + className+" (also tried java.lang."+className+")"); - } - } else { - throw new IllegalArgumentException("Invalid target type for sensor "+name+": " + className); - } - } - } - - protected String getFullClassName(String className) { - if (className.equalsIgnoreCase("string")) { - return "java.lang.String"; - } else if (className.equalsIgnoreCase("int") || className.equalsIgnoreCase("integer")) { - return "java.lang.Integer"; - } else if (className.equalsIgnoreCase("long")) { - return "java.lang.Long"; - } else if (className.equalsIgnoreCase("float")) { - return "java.lang.Float"; - } else if (className.equalsIgnoreCase("double")) { - return "java.lang.Double"; - } else if (className.equalsIgnoreCase("bool") || className.equalsIgnoreCase("boolean")) { - return "java.lang.Boolean"; - } else if (className.equalsIgnoreCase("byte")) { - return "java.lang.Byte"; - } else if (className.equalsIgnoreCase("char") || className.equalsIgnoreCase("character")) { - return "java.lang.Character"; - } else if (className.equalsIgnoreCase("object")) { - return "java.lang.Object"; - } else { - return className; - } - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java deleted file mode 100644 index eb0417f..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/BasicParameterType.java +++ /dev/null @@ -1,116 +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.core.effector; - -import java.util.Collections; -import java.util.Map; - -import org.apache.brooklyn.api.effector.ParameterType; - -import com.google.common.base.Objects; - -public class BasicParameterType<T> implements ParameterType<T> { - private static final long serialVersionUID = -5521879180483663919L; - - private String name; - private Class<T> type; - private String description; - private Boolean hasDefaultValue = null; - private T defaultValue = null; - - public BasicParameterType() { - this(Collections.emptyMap()); - } - - @SuppressWarnings("unchecked") - public BasicParameterType(Map<?, ?> arguments) { - if (arguments.containsKey("name")) name = (String) arguments.get("name"); - if (arguments.containsKey("type")) type = (Class<T>) arguments.get("type"); - if (arguments.containsKey("description")) description = (String) arguments.get("description"); - if (arguments.containsKey("defaultValue")) defaultValue = (T) arguments.get("defaultValue"); - } - - public BasicParameterType(String name, Class<T> type) { - this(name, type, null, null, false); - } - - public BasicParameterType(String name, Class<T> type, String description) { - this(name, type, description, null, false); - } - - public BasicParameterType(String name, Class<T> type, String description, T defaultValue) { - this(name, type, description, defaultValue, true); - } - - public BasicParameterType(String name, Class<T> type, String description, T defaultValue, boolean hasDefaultValue) { - this.name = name; - this.type = type; - this.description = description; - this.defaultValue = defaultValue; - if (defaultValue!=null && !defaultValue.getClass().equals(Object.class)) { - // if default value is null (or is an Object, which is ambiguous on resolution to to rebind), - // don't bother to set this as it creates noise in the persistence files - this.hasDefaultValue = hasDefaultValue; - } - } - - @Override - public String getName() { return name; } - - @Override - public Class<T> getParameterClass() { return type; } - - @Override - public String getParameterClassName() { return type.getCanonicalName(); } - - @Override - public String getDescription() { return description; } - - @Override - public T getDefaultValue() { - return hasDefaultValue() ? defaultValue : null; - } - - public boolean hasDefaultValue() { - // a new Object() was previously used to indicate no default value, but that doesn't work well across serialization boundaries! - return hasDefaultValue!=null ? hasDefaultValue : defaultValue!=null && !defaultValue.getClass().equals(Object.class); - } - - @Override - public String toString() { - return Objects.toStringHelper(this).omitNullValues() - .add("name", name).add("description", description).add("type", getParameterClassName()) - .add("defaultValue", defaultValue) - .toString(); - } - - @Override - public int hashCode() { - return Objects.hashCode(name, description, type, defaultValue); - } - - @Override - public boolean equals(Object obj) { - return (obj instanceof ParameterType) && - Objects.equal(name, ((ParameterType<?>)obj).getName()) && - Objects.equal(description, ((ParameterType<?>)obj).getDescription()) && - Objects.equal(type, ((ParameterType<?>)obj).getParameterClass()) && - Objects.equal(defaultValue, ((ParameterType<?>)obj).getDefaultValue()); - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorAndBody.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorAndBody.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorAndBody.java deleted file mode 100644 index 49e85b8..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorAndBody.java +++ /dev/null @@ -1,60 +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.core.effector; - -import java.util.List; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.api.effector.ParameterType; -import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory; - -import com.google.common.annotations.Beta; -import com.google.common.base.Objects; - -@Beta // added in 0.6.0 -public class EffectorAndBody<T> extends EffectorBase<T> implements EffectorWithBody<T> { - - private static final long serialVersionUID = -6023389678748222968L; - private final EffectorTaskFactory<T> body; - - public EffectorAndBody(Effector<T> original, EffectorTaskFactory<T> body) { - this(original.getName(), original.getReturnType(), original.getParameters(), original.getDescription(), body); - } - - public EffectorAndBody(String name, Class<T> returnType, List<ParameterType<?>> parameters, String description, EffectorTaskFactory<T> body) { - super(name, returnType, parameters, description); - this.body = body; - } - - @Override - public EffectorTaskFactory<T> getBody() { - return body; - } - - @Override - public int hashCode() { - return Objects.hashCode(super.hashCode(), getBody()); - } - - @Override - public boolean equals(Object other) { - return super.equals(other) && Objects.equal(getBody(), ((EffectorAndBody<?>)other).getBody()); - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBase.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBase.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBase.java deleted file mode 100644 index 68132c4..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBase.java +++ /dev/null @@ -1,106 +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.core.effector; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.api.effector.ParameterType; -import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Joiner; -import com.google.common.base.Objects; - -/** concrete implementation of Effector interface, - * but not (at this level of the hirarchy) defining an implementation - * (see {@link EffectorTaskFactory} and {@link EffectorWithBody}) */ -public class EffectorBase<T> implements Effector<T> { - - @SuppressWarnings("unused") - private static final Logger log = LoggerFactory.getLogger(EffectorBase.class); - - private static final long serialVersionUID = -4153962199078384835L; - - private final String name; - private final Class<T> returnType; - private final List<ParameterType<?>> parameters; - private final String description; - - public EffectorBase(String name, Class<T> returnType, List<ParameterType<?>> parameters, String description) { - this.name = name; - this.returnType = returnType; - this.parameters = new ArrayList<ParameterType<?>>(parameters); - this.description = description; - } - - @Override - public String getName() { - return name; - } - - @Override - public Class<T> getReturnType() { - return returnType; - } - - @Override - public String getReturnTypeName() { - return returnType.getCanonicalName(); - } - - @Override - public List<ParameterType<?>> getParameters() { - return parameters; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public String toString() { - List<String> parameterNames = new ArrayList<String>(parameters.size()); - for (ParameterType<?> parameter: parameters) { - String parameterName = (parameter.getName() != null) ? parameter.getName() : "<unknown>"; - parameterNames.add(parameterName); - } - return name+"["+Joiner.on(",").join(parameterNames)+"]"; - } - - @Override - public int hashCode() { - return Objects.hashCode(name, returnType, parameters, description); - } - - @Override - public boolean equals(Object other) { - if (!(other instanceof EffectorBase)) return false; - if (!(other.getClass().equals(getClass()))) return false; - if (!Objects.equal(hashCode(), other.hashCode())) return false; - return Objects.equal(getName(), ((EffectorBase<?>)other).getName()) && - Objects.equal(getReturnType(), ((EffectorBase<?>)other).getReturnType()) && - Objects.equal(getParameters(), ((EffectorBase<?>)other).getParameters()) && - Objects.equal(getDescription(), ((EffectorBase<?>)other).getDescription()); - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBody.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBody.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBody.java deleted file mode 100644 index b1643ba..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorBody.java +++ /dev/null @@ -1,100 +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.core.effector; - -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.core.entity.EntityInternal; -import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; -import org.apache.brooklyn.util.core.config.ConfigBag; -import org.apache.brooklyn.util.core.flags.TypeCoercions; -import org.apache.brooklyn.util.core.task.DynamicSequentialTask; -import org.apache.brooklyn.util.core.task.DynamicTasks; -import org.apache.brooklyn.util.core.task.Tasks; - -import com.google.common.annotations.Beta; - -/** Typical implementations override {@link #main(ConfigBag)} to do the work of the effector - * <p> - * See also {@link EffectorTasks}: possibly this will be deleted in preference for an approach based on {@link EffectorTasks}. - * - * @since 0.6.0 - **/ -@Beta -public abstract class EffectorBody<T> { - /** Does the work of the effector, either in place, or (better) by building up - * subtasks, which can by added using {@link DynamicTasks} methods - * (and various convenience methods which do that automatically; see subclasses of EffectorBody - * for more info on usage; or see {@link DynamicSequentialTask} for details of the threading model - * by which added tasks are placed in a secondary thread) - * <p> - * The associated entity can be accessed through the {@link #entity()} method. - */ - public abstract T call(ConfigBag parameters); - - // NB: we could also support an 'init' method which is done at creation, - // as a place where implementers can describe the structure of the task before it executes - // (and init gets invoked in EffectorBodyTaskFactory.newTask _before_ the task is submitted and main is called) - - - // ---- convenience method(s) for implementers of main -- see subclasses and *Tasks statics for more - - protected EntityInternal entity() { - return (EntityInternal) BrooklynTaskTags.getTargetOrContextEntity(Tasks.current()); - } - - protected <V extends TaskAdaptable<?>> V queue(V task) { - return DynamicTasks.queue(task); - } - - protected <V extends TaskAdaptable<?>> void queue(V task1, V task2, V ...tasks) { - DynamicTasks.queue(task1); - DynamicTasks.queue(task2); - for (V task: tasks) - DynamicTasks.queue(task); - } - - protected <V extends TaskFactory<?>> void queue(V task1, V task2, V ...tasks) { - DynamicTasks.queue(task1.newTask()); - DynamicTasks.queue(task2.newTask()); - for (V task: tasks) - DynamicTasks.queue(task.newTask()); - } - - protected <U extends TaskAdaptable<?>> U queue(TaskFactory<U> task) { - return DynamicTasks.queue(task.newTask()); - } - - /** see {@link DynamicTasks#waitForLast()} */ - protected Task<?> waitForLast() { - return DynamicTasks.waitForLast(); - } - - /** Returns the result of the last task queued in this context, coerced to the given type */ - protected <V> V last(Class<V> type) { - Task<?> last = waitForLast(); - if (last==null) - throw new IllegalStateException("No last task available (in "+DynamicTasks.getTaskQueuingContext()+")"); - if (!Tasks.isQueuedOrSubmitted(last)) - throw new IllegalStateException("Last task "+last+" has not been queued or submitted; will not block on its result"); - - return TypeCoercions.coerce(last.getUnchecked(), type); - } -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java deleted file mode 100644 index 68d45a5..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorTasks.java +++ /dev/null @@ -1,234 +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.core.effector; - -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.api.effector.ParameterType; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.mgmt.Task; -import org.apache.brooklyn.api.mgmt.TaskAdaptable; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.location.Machines; -import org.apache.brooklyn.core.mgmt.BrooklynTaskTags; -import org.apache.brooklyn.core.mgmt.internal.EffectorUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.apache.brooklyn.location.ssh.SshMachineLocation; -import org.apache.brooklyn.api.location.MachineLocation; -import org.apache.brooklyn.util.core.config.ConfigBag; -import org.apache.brooklyn.util.core.task.DynamicSequentialTask; -import org.apache.brooklyn.util.core.task.DynamicTasks; -import org.apache.brooklyn.util.core.task.TaskBuilder; -import org.apache.brooklyn.util.core.task.Tasks; -import org.apache.brooklyn.util.javalang.Reflections; - -import com.google.common.annotations.Beta; -import com.google.common.base.Preconditions; - -/** - * Miscellaneous tasks which are useful in effectors. - * @since 0.6.0 - */ -@Beta -public class EffectorTasks { - - @SuppressWarnings("unused") - private static final Logger log = LoggerFactory.getLogger(EffectorTasks.class); - - public interface EffectorTaskFactory<T> { - public abstract TaskAdaptable<T> newTask(Entity entity, Effector<T> effector, ConfigBag parameters); - } - - /** wrapper for {@link EffectorBody} which simply runs that body on each invocation; - * the body must be thread safe and ideally stateless */ - public static class EffectorBodyTaskFactory<T> implements EffectorTaskFactory<T> { - private final EffectorBody<T> effectorBody; - public EffectorBodyTaskFactory(EffectorBody<T> effectorBody) { - this.effectorBody = effectorBody; - } - - @Override - public Task<T> newTask(final Entity entity, final org.apache.brooklyn.api.effector.Effector<T> effector, final ConfigBag parameters) { - final AtomicReference<DynamicSequentialTask<T>> dst = new AtomicReference<DynamicSequentialTask<T>>(); - - dst.set(new DynamicSequentialTask<T>( - getFlagsForTaskInvocationAt(entity, effector, parameters), - new Callable<T>() { - @Override - public T call() throws Exception { - try { - DynamicTasks.setTaskQueueingContext(dst.get()); - return effectorBody.call(parameters); - } finally { - DynamicTasks.removeTaskQueueingContext(); - } - } - }) { - @Override - public void handleException(Throwable throwable) throws Exception { - EffectorUtils.handleEffectorException(entity, effector, throwable); - } - }); - return dst.get(); - }; - - /** @deprecated since 0.7.0 use {@link #getFlagsForTaskInvocationAt(Entity, Effector, ConfigBag)} */ @Deprecated - protected final Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity, Effector<?> effector) { - return getFlagsForTaskInvocationAt(entity, effector, null); - } - /** subclasses may override to add additional flags, but they should include the flags returned here - * unless there is very good reason not to; default impl returns a MutableMap */ - protected Map<Object,Object> getFlagsForTaskInvocationAt(Entity entity, Effector<?> effector, ConfigBag parameters) { - return EffectorUtils.getTaskFlagsForEffectorInvocation(entity, effector, parameters); - } - } - - /** wrapper for {@link EffectorTaskFactory} which ensures effector task tags are applied to it if needed - * (wrapping in a task if needed); without this, {@link EffectorBody}-based effectors get it by - * virtue of the call to {@link #getFlagsForTaskInvocationAt(Entity,Effector,ConfigBag)} therein - * but {@link EffectorTaskFactory}-based effectors generate a task without the right tags - * to be able to tell using {@link BrooklynTaskTags} the effector-context of the task - * <p> - * this gets applied automatically so marked as package-private */ - static class EffectorMarkingTaskFactory<T> implements EffectorTaskFactory<T> { - private final EffectorTaskFactory<T> effectorTaskFactory; - public EffectorMarkingTaskFactory(EffectorTaskFactory<T> effectorTaskFactory) { - this.effectorTaskFactory = effectorTaskFactory; - } - - @Override - public Task<T> newTask(final Entity entity, final org.apache.brooklyn.api.effector.Effector<T> effector, final ConfigBag parameters) { - if (effectorTaskFactory instanceof EffectorBodyTaskFactory) - return effectorTaskFactory.newTask(entity, effector, parameters).asTask(); - // if we're in an effector context for this effector already, then also pass through - if (BrooklynTaskTags.isInEffectorTask(Tasks.current(), entity, effector, false)) - return effectorTaskFactory.newTask(entity, effector, parameters).asTask(); - // otherwise, create the task inside an appropriate effector body so tags, name, etc are set correctly - return new EffectorBodyTaskFactory<T>(new EffectorBody<T>() { - @Override - public T call(ConfigBag parameters) { - TaskAdaptable<T> t = DynamicTasks.queue(effectorTaskFactory.newTask(entity, effector, parameters)); - return t.asTask().getUnchecked(); - } - }).newTask(entity, effector, parameters); - } - } - - public static <T> ConfigKey<T> asConfigKey(ParameterType<T> t) { - return ConfigKeys.newConfigKey(t.getParameterClass(), t.getName()); - } - - public static <T> ParameterTask<T> parameter(ParameterType<T> t) { - return new ParameterTask<T>(asConfigKey(t)). - name("parameter "+t); - } - public static <T> ParameterTask<T> parameter(Class<T> type, String name) { - return new ParameterTask<T>(ConfigKeys.newConfigKey(type, name)). - name("parameter "+name+" ("+type+")"); - } - public static <T> ParameterTask<T> parameter(final ConfigKey<T> p) { - return new ParameterTask<T>(p); - } - public static class ParameterTask<T> implements EffectorTaskFactory<T> { - final ConfigKey<T> p; - private TaskBuilder<T> builder; - public ParameterTask(ConfigKey<T> p) { - this.p = p; - this.builder = Tasks.<T>builder().displayName("parameter "+p); - } - public ParameterTask<T> name(String taskName) { - builder.displayName(taskName); - return this; - } - @Override - public Task<T> newTask(Entity entity, Effector<T> effector, final ConfigBag parameters) { - return builder.body(new Callable<T>() { - @Override - public T call() throws Exception { - return parameters.get(p); - } - - }).build(); - } - - } - - public static <T> EffectorTaskFactory<T> of(final Task<T> task) { - return new EffectorTaskFactory<T>() { - @Override - public Task<T> newTask(Entity entity, Effector<T> effector, ConfigBag parameters) { - return task; - } - }; - } - - /** Finds the entity where this task is running - * @throws NullPointerException if there is none (no task, or no context entity for that task) */ - public static Entity findEntity() { - return Preconditions.checkNotNull(BrooklynTaskTags.getTargetOrContextEntity(Tasks.current()), - "This must be executed in a task whose execution context has a target or context entity " + - "(i.e. it must be run from within an effector)"); - } - - /** Finds the entity where this task is running, casted to the given Entity subtype - * @throws NullPointerException if there is none - * @throws IllegalArgumentException if it is not of the indicated type */ - public static <T extends Entity> T findEntity(Class<T> type) { - Entity t = findEntity(); - return Reflections.cast(t, type); - } - - /** Finds a unique {@link MachineLocation} attached to the entity - * where this task is running - * @throws NullPointerException if {@link #findEntity()} fails - * @throws IllegalStateException if call to {@link #getSshMachine(Entity)} fails */ - public static <T extends MachineLocation> T findMachine(Class<T> clazz) { - return getMachine(findEntity(), clazz); - } - - /** Finds a unique {@link MachineLocation} attached to the supplied entity - * @throws IllegalStateException if there is not a unique such {@link SshMachineLocation} */ - public static <T extends MachineLocation> T getMachine(Entity entity, Class<T> clazz) { - try { - return Machines.findUniqueMachineLocation(entity.getLocations(), clazz).get(); - } catch (Exception e) { - throw new IllegalStateException("Entity "+entity+" (in "+Tasks.current()+") requires a single " + clazz.getName() + ", but has "+entity.getLocations(), e); - } - } - - /** Finds a unique {@link SshMachineLocation} attached to the entity - * where this task is running - * @throws NullPointerException if {@link #findEntity()} fails - * @throws IllegalStateException if call to {@link #getSshMachine(Entity)} fails */ - public static SshMachineLocation findSshMachine() { - return getSshMachine(findEntity()); - } - - /** Finds a unique {@link SshMachineLocation} attached to the supplied entity - * @throws IllegalStateException if there is not a unique such {@link SshMachineLocation} */ - public static SshMachineLocation getSshMachine(Entity entity) { - return getMachine(entity, SshMachineLocation.class); - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorWithBody.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorWithBody.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorWithBody.java deleted file mode 100644 index 67dba14..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/EffectorWithBody.java +++ /dev/null @@ -1,32 +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.core.effector; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory; - -import com.google.common.annotations.Beta; - -@Beta // added in 0.6.0 -public interface EffectorWithBody<T> extends Effector<T> { - - /** returns the body of the effector, i.e. a factory which can generate tasks which can run */ - public EffectorTaskFactory<T> getBody(); - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java deleted file mode 100644 index 9b10d1d..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/Effectors.java +++ /dev/null @@ -1,214 +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.core.effector; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nullable; - -import org.apache.brooklyn.api.effector.Effector; -import org.apache.brooklyn.api.effector.ParameterType; -import org.apache.brooklyn.api.entity.Entity; -import org.apache.brooklyn.api.entity.EntityLocal; -import org.apache.brooklyn.api.mgmt.TaskAdaptable; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.effector.EffectorTasks.EffectorBodyTaskFactory; -import org.apache.brooklyn.core.effector.EffectorTasks.EffectorMarkingTaskFactory; -import org.apache.brooklyn.core.effector.EffectorTasks.EffectorTaskFactory; -import org.apache.brooklyn.core.entity.Entities; -import org.apache.brooklyn.core.entity.EntityInternal; -import org.apache.brooklyn.util.collections.MutableMap; -import org.apache.brooklyn.util.core.config.ConfigBag; -import org.apache.brooklyn.util.core.task.Tasks; -import org.apache.brooklyn.util.text.Strings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.base.Objects; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -public class Effectors { - - private static final Logger log = LoggerFactory.getLogger(Effectors.class); - - public static class EffectorBuilder<T> { - private Class<T> returnType; - private String effectorName; - private String description; - private Map<String,ParameterType<?>> parameters = new LinkedHashMap<String,ParameterType<?>>(); - private EffectorTaskFactory<T> impl; - - private EffectorBuilder(Class<T> returnType, String effectorName) { - this.returnType = returnType; - this.effectorName = effectorName; - } - public EffectorBuilder<T> description(String description) { - this.description = description; - return this; - } - public EffectorBuilder<T> parameter(Class<?> paramType, String paramName) { - return parameter(paramType, paramName, null, null); - } - public EffectorBuilder<T> parameter(Class<?> paramType, String paramName, String paramDescription) { - return parameter(paramType, paramName, paramDescription, null); - } - public <V> EffectorBuilder<T> parameter(Class<V> paramType, String paramName, String paramDescription, V defaultValue) { - return parameter(new BasicParameterType<V>(paramName, paramType, paramDescription, defaultValue)); - } - public <V> EffectorBuilder<T> parameter(ConfigKey<V> key) { - return parameter(asParameterType(key)); - } - public EffectorBuilder<T> parameter(ParameterType<?> p) { - // allow redeclaring, e.g. for the case where we are overriding an existing effector - parameters.put(p.getName(), p); - return this; - } - public EffectorBuilder<T> impl(EffectorTaskFactory<T> taskFactory) { - this.impl = new EffectorMarkingTaskFactory<T>(taskFactory); - return this; - } - public EffectorBuilder<T> impl(EffectorBody<T> effectorBody) { - this.impl = new EffectorBodyTaskFactory<T>(effectorBody); - return this; - } - /** returns the effector, with an implementation (required); @see {@link #buildAbstract()} */ - public Effector<T> build() { - Preconditions.checkNotNull(impl, "Cannot create effector %s with no impl (did you forget impl? or did you mean to buildAbstract?)", effectorName); - return new EffectorAndBody<T>(effectorName, returnType, ImmutableList.copyOf(parameters.values()), description, impl); - } - - /** returns an abstract effector, where the body will be defined later/elsewhere - * (impl must not be set) */ - public Effector<T> buildAbstract() { - Preconditions.checkArgument(impl==null, "Cannot create abstract effector {} as an impl is defined", effectorName); - return new EffectorBase<T>(effectorName, returnType, ImmutableList.copyOf(parameters.values()), description); - } - } - - /** creates a new effector builder with the given name and return type */ - public static <T> EffectorBuilder<T> effector(Class<T> returnType, String effectorName) { - return new EffectorBuilder<T>(returnType, effectorName); - } - - /** creates a new effector builder to _override_ the given effector */ - public static <T> EffectorBuilder<T> effector(Effector<T> base) { - EffectorBuilder<T> builder = new EffectorBuilder<T>(base.getReturnType(), base.getName()); - for (ParameterType<?> p: base.getParameters()) - builder.parameter(p); - builder.description(base.getDescription()); - if (base instanceof EffectorWithBody) - builder.impl(((EffectorWithBody<T>) base).getBody()); - return builder; - } - - /** as {@link #invocation(Entity, Effector, Map)} but convenience for passing a {@link ConfigBag} */ - public static <T> TaskAdaptable<T> invocation(Entity entity, Effector<T> eff, ConfigBag parameters) { - return invocation(entity, eff, parameters==null ? ImmutableMap.of() : parameters.getAllConfig()); - } - - /** returns an unsubmitted task which invokes the given effector; use {@link Entities#invokeEffector(EntityLocal, Entity, Effector, Map)} for a submitted variant */ - public static <T> TaskAdaptable<T> invocation(Entity entity, Effector<T> eff, @Nullable Map<?,?> parameters) { - @SuppressWarnings("unchecked") - Effector<T> eff2 = (Effector<T>) ((EntityInternal)entity).getEffector(eff.getName()); - if (log.isTraceEnabled()) { - Object eff1Body = (eff instanceof EffectorWithBody<?> ? ((EffectorWithBody<?>) eff).getBody() : "bodyless"); - String message = String.format("Invoking %s/%s on entity %s", eff, eff1Body, entity); - if (eff != eff2) { - Object eff2Body = (eff2 instanceof EffectorWithBody<?> ? ((EffectorWithBody<?>) eff2).getBody() : "bodyless"); - message += String.format(" (actually %s/%s)", eff2, eff2Body); - } - log.trace(message); - } - if (eff2 != null) { - if (eff2 != eff) { - if (eff2 instanceof EffectorWithBody) { - log.debug("Replacing invocation of {} on {} with {} which is the impl defined at that entity", new Object[] { eff, entity, eff2 }); - return ((EffectorWithBody<T>)eff2).getBody().newTask(entity, eff2, ConfigBag.newInstance().putAll(parameters)); - } else { - log.warn("Effector {} defined on {} has no body; invoking caller-supplied {} instead", new Object[] { eff2, entity, eff }); - } - } - } else { - log.debug("Effector {} does not exist on {}; attempting to invoke anyway", new Object[] { eff, entity }); - } - - if (eff instanceof EffectorWithBody) { - return ((EffectorWithBody<T>)eff).getBody().newTask(entity, eff, ConfigBag.newInstance().putAll(parameters)); - } - - throw new UnsupportedOperationException("No implementation registered for effector "+eff+" on "+entity); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public static <V> ParameterType<V> asParameterType(ConfigKey<V> key) { - return key.hasDefaultValue() - ? new BasicParameterType<V>(key.getName(), (Class)key.getType(), key.getDescription(), key.getDefaultValue()) - : new BasicParameterType<V>(key.getName(), (Class)key.getType(), key.getDescription()); - } - - public static <V> ConfigKey<V> asConfigKey(ParameterType<V> paramType) { - return ConfigKeys.newConfigKey(paramType.getParameterClass(), paramType.getName(), paramType.getDescription(), paramType.getDefaultValue()); - } - - /** convenience for {@link #invocationParallel(Effector, Map, Iterable)} */ - public static TaskAdaptable<List<?>> invocation(Effector<?> eff, Map<?,?> params, Iterable<? extends Entity> entities) { - return invocationParallel(eff, params, entities); - } - - /** returns an unsubmitted task which will invoke the given effector on the given entities in parallel; - * return type is Task<List<T>> (but haven't put in the blood sweat toil and tears to make the generics work) */ - public static TaskAdaptable<List<?>> invocationParallel(Effector<?> eff, Map<?,?> params, Iterable<? extends Entity> entities) { - List<TaskAdaptable<?>> tasks = new ArrayList<TaskAdaptable<?>>(); - for (Entity e: entities) tasks.add(invocation(e, eff, params)); - return Tasks.parallel("invoking "+eff+" on "+tasks.size()+" node"+(Strings.s(tasks.size())), tasks.toArray(new TaskAdaptable[tasks.size()])); - } - - /** as {@link #invocationParallel(Effector, Map, Iterable)} but executing sequentially */ - public static TaskAdaptable<List<?>> invocationSequential(Effector<?> eff, Map<?,?> params, Iterable<? extends Entity> entities) { - List<TaskAdaptable<?>> tasks = new ArrayList<TaskAdaptable<?>>(); - for (Entity e: entities) tasks.add(invocation(e, eff, params)); - return Tasks.sequential("invoking "+eff+" on "+tasks.size()+" node"+(Strings.s(tasks.size())), tasks.toArray(new TaskAdaptable[tasks.size()])); - } - - /** returns an unsubmitted task which will invoke the given effector on the given entities - * (this form of method is a convenience for {@link #invocation(Effector, Map, Iterable)}) */ - public static TaskAdaptable<List<?>> invocation(Effector<?> eff, MutableMap<?, ?> params, Entity ...entities) { - return invocation(eff, params, Arrays.asList(entities)); - } - - public static boolean sameSignature(Effector<?> e1, Effector<?> e2) { - return Objects.equal(e1.getName(), e2.getName()) && - Objects.equal(e1.getParameters(), e2.getParameters()) && - Objects.equal(e1.getReturnType(), e2.getReturnType()); - } - - // TODO sameSignatureAndBody - - public static boolean sameInstance(Effector<?> e1, Effector<?> e2) { - return e1 == e2; - } - -} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/ExplicitEffector.java ---------------------------------------------------------------------- diff --git a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/ExplicitEffector.java b/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/ExplicitEffector.java deleted file mode 100644 index 65c1f0c..0000000 --- a/brooklyn-server/core/src/main/java/org/apache/brooklyn/core/effector/ExplicitEffector.java +++ /dev/null @@ -1,74 +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.core.effector; - -import groovy.lang.Closure; - -import java.util.List; -import java.util.Map; - -import org.apache.brooklyn.api.effector.ParameterType; -import org.apache.brooklyn.api.entity.Entity; - -import com.google.common.base.Objects; -import com.google.common.collect.ImmutableList; - -public abstract class ExplicitEffector<I,T> extends AbstractEffector<T> { - public ExplicitEffector(String name, Class<T> type, String description) { - this(name, type, ImmutableList.<ParameterType<?>>of(), description); - } - public ExplicitEffector(String name, Class<T> type, List<ParameterType<?>> parameters, String description) { - super(name, type, parameters, description); - } - - public T call(Entity entity, Map parameters) { - return invokeEffector((I) entity, (Map<String,?>)parameters ); - } - - public abstract T invokeEffector(I trait, Map<String,?> parameters); - - /** convenience to create an effector supplying a closure; annotations are preferred, - * and subclass here would be failback, but this is offered as - * workaround for bug GROOVY-5122, as discussed in test class CanSayHi - */ - public static <I,T> ExplicitEffector<I,T> create(String name, Class<T> type, List<ParameterType<?>> parameters, String description, Closure body) { - return new ExplicitEffectorFromClosure<I,T>(name, type, parameters, description, body); - } - - private static class ExplicitEffectorFromClosure<I,T> extends ExplicitEffector<I,T> { - private static final long serialVersionUID = -5771188171702382236L; - final Closure<T> body; - public ExplicitEffectorFromClosure(String name, Class<T> type, List<ParameterType<?>> parameters, String description, Closure<T> body) { - super(name, type, parameters, description); - this.body = body; - } - public T invokeEffector(I trait, Map<String,?> parameters) { return body.call(trait, parameters); } - - @Override - public int hashCode() { - return Objects.hashCode(super.hashCode(), body); - } - - @Override - public boolean equals(Object other) { - return super.equals(other) && Objects.equal(body, ((ExplicitEffectorFromClosure<?,?>)other).body); - } - - } -}
