/*
* 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.objs;
import static org.apache.brooklyn.util.groovy.GroovyJavaMethods.elvis;
import java.util.Collections;
import java.util.Map;
import org.apache.brooklyn.api.entity.EntityLocal;
import org.apache.brooklyn.api.mgmt.ExecutionContext;
import org.apache.brooklyn.config.ConfigKey;
import org.apache.brooklyn.core.config.ConfigKeys;
import org.apache.brooklyn.core.config.Sanitizer;
import org.apache.brooklyn.core.config.StructuredConfigKey;
import org.apache.brooklyn.core.config.internal.AbstractConfigMapImpl;
import org.apache.brooklyn.core.entity.EntityInternal;
import org.apache.brooklyn.util.core.flags.TypeCoercions;
import org.apache.brooklyn.util.core.internal.ConfigKeySelfExtracting;
import org.apache.brooklyn.util.guava.Maybe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.Maps;
public class AdjunctConfigMap extends AbstractConfigMapImpl {
private static final Logger LOG = LoggerFactory.getLogger(AdjunctConfigMap.class);
/** policy against which config resolution / task execution will occur */
private final AbstractEntityAdjunct adjunct;
/*
* TODO An alternative implementation approach would be to have:
* setParent(Entity o, Map<ConfigKey,Object> inheritedConfig=[:])
* The idea is that the parent could in theory decide explicitly what in its config
* would be shared.
* I (Aled) am undecided as to whether that would be better...
*
* (Alex) i lean toward the config key getting to make the decision
*/
public AdjunctConfigMap(AbstractEntityAdjunct adjunct) {
this.adjunct = Preconditions.checkNotNull(adjunct, "AbstractEntityAdjunct must be specified");
}
@SuppressWarnings("unchecked")
@Override
public <T> T getConfig(ConfigKey<T> key, T defaultValue) {
// FIXME What about inherited task in config?!
// alex says: think that should work, no?
// FIXME What if someone calls getConfig on a task, before setting parent app?
// alex says: not supported (throw exception, or return the task)
// In case this entity class has overridden the given key (e.g. to set default), then retrieve this entity's key
// TODO If ask for a config value that's not in our configKeys, should we really continue with rest of method and return key.getDefaultValue?
// e.g. SshBasedJavaAppSetup calls setAttribute(JMX_USER), which calls getConfig(JMX_USER)
// but that example doesn't have a default...
ConfigKey<T> ownKey = adjunct!=null ? (ConfigKey<T>)elvis(adjunct.getAdjunctType().getConfigKey(key.getName()), key) : key;
// Don't use groovy truth: if the set value is e.g. 0, then would ignore set value and return default!
if (ownKey instanceof ConfigKeySelfExtracting) {
if (((ConfigKeySelfExtracting<T>)ownKey).isSet(ownConfig)) {
// FIXME Should we support config from futures? How to get execution context before setEntity?
EntityLocal entity = adjunct.entity;
ExecutionContext exec = (entity != null) ? ((EntityInternal)entity).getExecutionContext() : null;
return ((ConfigKeySelfExtracting<T>)ownKey).extractValue(ownConfig, exec);
}
} else {
LOG.warn("Config key {} of {} is not a ConfigKeySelfExtracting; cannot retrieve value; returning default", ownKey, this);
}
return TypeCoercions.coerce((defaultValue != null) ? defaultValue : ownKey.getDefaultValue(), key.getTypeToken());
}
@Override
public Maybe<Object> getConfigRaw(ConfigKey<?> key, boolean includeInherited) {
if (ownConfig.containsKey(key)) return Maybe.of(ownConfig.get(key));
return Maybe.absent();
}
/** returns the config of this policy */
@Override
public Map<ConfigKey<?>,Object> getAllConfig() {
// Don't use ImmutableMap because valide for values to be null
return Collections.unmodifiableMap(Maps.newLinkedHashMap(ownConfig));
}
public Object setConfig(ConfigKey<?> key, Object v) {
Object val = coerceConfigVal(key, v);
if (key instanceof StructuredConfigKey) {
return ((StructuredConfigKey)key).applyValueToMap(val, ownConfig);
} else {
return ownConfig.put(key, val);
}
}
public void addToLocalBag(Map<String, ?> vals) {
for (Map.Entry<String, ?> entry : vals.entrySet()) {
setConfig(ConfigKeys.newConfigKey(Object.class, entry.getKey()), entry.getValue());
}
}
public void removeFromLocalBag(String key) {
ownConfig.remove(key);
}
@Override
public AdjunctConfigMap submap(Predicate<ConfigKey<?>> filter) {
AdjunctConfigMap m = new AdjunctConfigMap(adjunct);
for (Map.Entry<ConfigKey<?>,Object> entry: ownConfig.entrySet())
if (filter.apply(entry.getKey()))
m.ownConfig.put(entry.getKey(), entry.getValue());
return m;
}
@Override
public String toString() {
return super.toString()+"[own="+Sanitizer.sanitize(ownConfig)+"]";
}
}