Java Code Examples for org.apache.brooklyn.util.collections.MutableMap#copyOf()
The following examples show how to use
org.apache.brooklyn.util.collections.MutableMap#copyOf() .
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: EmbeddedFelixFramework.java From brooklyn-server with Apache License 2.0 | 6 votes |
public static Framework newFrameworkStarted(String felixCacheDir, boolean clean, Map<?,?> extraStartupConfig) { Map<Object,Object> cfg = MutableMap.copyOf(extraStartupConfig); if (clean) cfg.put(Constants.FRAMEWORK_STORAGE_CLEAN, "onFirstInit"); if (felixCacheDir!=null) cfg.put(Constants.FRAMEWORK_STORAGE, felixCacheDir); cfg.put(Constants.FRAMEWORK_BSNVERSION, Constants.FRAMEWORK_BSNVERSION_MULTIPLE); FrameworkFactory factory = newFrameworkFactory(); Stopwatch timer = Stopwatch.createStarted(); Framework framework = factory.newFramework(cfg); try { framework.init(); installBootBundles(framework); framework.start(); } catch (Exception e) { // framework bundle start exceptions are not interesting to caller... throw Exceptions.propagate(e); } LOG.debug("System bundles are: "+SYSTEM_BUNDLES); LOG.debug("OSGi framework started in " + Duration.of(timer)); return framework; }
Example 2
Source File: SshCommandSensor.java From brooklyn-server with Apache License 2.0 | 6 votes |
@Override public Map<String, String> get() { if (entity == null) return ImmutableMap.of(); // See BROOKLYN-568 Map<String, Object> env = MutableMap.copyOf(entity.getConfig(BrooklynConfigKeys.SHELL_ENVIRONMENT)); // Add the shell environment entries from our configuration if (rawSensorShellEnv != null) { env.putAll(TypeCoercions.coerce(rawSensorShellEnv, new TypeToken<Map<String,Object>>() {})); } // Try to resolve the configuration in the env Map try { env = (Map<String, Object>) Tasks.resolveDeepValue(env, Object.class, ((EntityInternal) entity).getExecutionContext()); } catch (InterruptedException | ExecutionException e) { Exceptions.propagateIfFatal(e); } // Convert the environment into strings with the serializer ShellEnvironmentSerializer serializer = new ShellEnvironmentSerializer(((EntityInternal) entity).getManagementContext()); return serializer.serialize(env); }
Example 3
Source File: CassandraDatacenterImpl.java From brooklyn-library with Apache License 2.0 | 5 votes |
@Override protected Entity createNode(@Nullable Location loc, Map<?,?> flags) { Map<Object, Object> allflags = MutableMap.copyOf(flags); if (flags.containsKey("token") || flags.containsKey("cassandra.token")) { // TODO Delete in future version; was deprecated in 0.7.0; deleted config key in 0.9.0 log.warn("Cassandra token no longer supported - use 'tokens' in "+CassandraDatacenterImpl.this); } if (flags.containsKey(CassandraNode.TOKENS) || flags.containsKey("tokens") || flags.containsKey("cassandra.tokens")) { // leave token config as-is } else if (!useVnodes()) { BigInteger token = getTokenGenerator().newToken(); if (token != null) { allflags.put(CassandraNode.TOKENS, ImmutableSet.of(token)); } } if ((flags.containsKey(CassandraNode.NUM_TOKENS_PER_NODE) || flags.containsKey("numTokensPerNode"))) { // leave num_tokens as-is } else if (useVnodes()) { Integer numTokensPerNode = getConfig(NUM_TOKENS_PER_NODE); allflags.put(CassandraNode.NUM_TOKENS_PER_NODE, numTokensPerNode); } else { allflags.put(CassandraNode.NUM_TOKENS_PER_NODE, 1); } return super.createNode(loc, allflags); }
Example 4
Source File: DynamicWebAppClusterImpl.java From brooklyn-library with Apache License 2.0 | 5 votes |
static void addToWarsByContext(Entity entity, String url, String targetName) { targetName = FILENAME_TO_WEB_CONTEXT_MAPPER.convertDeploymentTargetNameToContext(targetName); // TODO a better way to do atomic updates, see comment above synchronized (entity) { Map<String,String> newWarsMap = MutableMap.copyOf(entity.getConfig(WARS_BY_CONTEXT)); newWarsMap.put(targetName, url); entity.config().set(WARS_BY_CONTEXT, newWarsMap); } }
Example 5
Source File: Artifact.java From brooklyn-server with Apache License 2.0 | 5 votes |
@SuppressWarnings("unchecked") public static Artifact of(Map<String, Object> artifact) { Map<String,Object> fields = MutableMap.copyOf(artifact); Artifact result = new Artifact(); result.name = (String) fields.remove("name"); result.description = (String) fields.remove("description"); result.artifactType = (String) Yamls.removeMultinameAttribute(fields, "artifactType", "type"); result.content = ArtifactContent.of( fields.remove("content") ); result.requirements = new ArrayList<ArtifactRequirement>(); Object reqs = fields.remove("requirements"); if (reqs instanceof Iterable) { for (Object req: (Iterable<Object>)reqs) { if (req instanceof Map) { result.requirements.add(ArtifactRequirement.of((Map<String,Object>) req)); } else { throw new IllegalArgumentException("requirement should be a map, not "+req.getClass()); } } } else if (reqs!=null) { // TODO "map" short form throw new IllegalArgumentException("artifacts body should be iterable, not "+reqs.getClass()); } result.customAttributes = fields; return result; }
Example 6
Source File: BrooklynDslCommon.java From brooklyn-server with Apache License 2.0 | 5 votes |
public DslObject( Class<?> type, String factoryMethodName, List<Object> factoryMethodArgs, Map<String, Object> fields, Map<String, Object> config) { this.typeName = null; this.type = checkNotNull(type, "type"); this.constructorArgs = ImmutableList.of(); this.factoryMethodName = factoryMethodName; this.factoryMethodArgs = checkNotNull(factoryMethodArgs, "factoryMethodArgs"); this.fields = MutableMap.copyOf(fields); this.config = MutableMap.copyOf(config); }
Example 7
Source File: RiakNodeSshDriver.java From brooklyn-library with Apache License 2.0 | 5 votes |
@Override public Map<String, String> getShellEnvironment() { MutableMap<String, String> result = MutableMap.copyOf(super.getShellEnvironment()); // how to change epmd port, according to // http://serverfault.com/questions/582787/how-to-change-listening-interface-of-rabbitmqs-epmd-port-4369 if (getEntity().getEpmdListenerPort() != null) { result.put("ERL_EPMD_PORT", Integer.toString(getEntity().getEpmdListenerPort())); } result.put("WAIT_FOR_ERLANG", "60"); return result; }
Example 8
Source File: InboundPortsUtils.java From brooklyn-server with Apache License 2.0 | 5 votes |
/** * Returns the required open inbound ports for an Entity. * If {@code portsAutoInfer} is {@code true} then * return the first value for each {@link org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey} * config key {@link PortRange} plus any ports defined with a config key matching the provided regex. * This method also accepts an extra set of config keys in addition to those that are defined in the EntityType of the entity itself. * * @param entity the Entity * @param extraConfigKeys extra set of config key to inspect for inbound ports * @param portsAutoInfer if {@code true} then return the first value for each {@link org.apache.brooklyn.core.sensor.PortAttributeSensorAndConfigKey} * config key {@link PortRange} plus any ports defined with a config keys matching the provided regex * @param portRegex the regex to match config keys that define inbound ports * @return a collection of port numbers */ public static Collection<Integer> getRequiredOpenPorts(Entity entity, Set<ConfigKey<?>> extraConfigKeys, Boolean portsAutoInfer, String portRegex) { Set<Integer> ports = MutableSet.of(); /* TODO: This won't work if there's a port collision, which will cause the corresponding port attribute to be incremented until a free port is found. In that case the entity will use the free port, but the firewall will open the initial port instead. Mostly a problem for SameServerEntity, localhost location. */ if (portsAutoInfer == null || portsAutoInfer.booleanValue()) { // auto-infer defaults to true if not specified Set<ConfigKey<?>> configKeys = Sets.newHashSet(extraConfigKeys); configKeys.addAll(entity.getEntityType().getConfigKeys()); // Also add dynamically added config keys Map<ConfigKey<?>, ?> configuredConfigKeys = MutableMap.copyOf(((EntityInternal) entity).config().getBag().getAllConfigAsConfigKeyMap()); configKeys.addAll(configuredConfigKeys.keySet()); if (portRegex == null) { portRegex = ".*\\.port"; // defaults to legacy regex if not specified } Pattern portsPattern = Pattern.compile(portRegex); for (ConfigKey<?> k : configKeys) { if (isAssignableFromPortConfigKey(configuredConfigKeys, k) || (portsPattern.matcher(k.getName()).matches())) { Object value = entity.config().get(k); Maybe<PortRange> maybePortRange = TypeCoercions.tryCoerce(value, new TypeToken<PortRange>() { }); if (maybePortRange.isPresentAndNonNull()) { PortRange p = maybePortRange.get(); if (p != null && !p.isEmpty()) ports.add(p.iterator().next()); } } } } log.debug("getRequiredOpenPorts detected default {} for {}", ports, entity); return ports; }
Example 9
Source File: ArtifactRequirement.java From brooklyn-server with Apache License 2.0 | 5 votes |
public static ArtifactRequirement of(Map<String, Object> req) { Map<String,Object> attrs = MutableMap.copyOf(req); ArtifactRequirement result = new ArtifactRequirement(); result.name = (String) attrs.remove("name"); result.description = (String) attrs.remove("description"); result.requirementType = (String) Yamls.removeMultinameAttribute(attrs, "requirementType", "type"); // TODO fulfillment result.customAttributes = attrs; return result; }
Example 10
Source File: SoftlayerObtainPrivateLiveTest.java From brooklyn-library with Apache License 2.0 | 5 votes |
private Collection<String> getLocationConfig() { Map<String, Object> config = MutableMap.copyOf(((ConfigurationSupportInternal)loc.config()).getBag().getAllConfig()); config.putAll(customizeSharedLocation()); return MutableList.<String>of() .appendAll(createLocationConfig(NAMED_LOCATION_PREFIX + TEST_LOCATION, (String)config.get("spec.original"), config)) .appendAll(createLocationConfig(NAMED_LOCATION_PREFIX + TEST_LOCATION_PUBLIC, "named:" + TEST_LOCATION, customizePublicLocation())) .appendAll(createLocationConfig(NAMED_LOCATION_PREFIX + TEST_LOCATION_PRIVATE, "named:" + TEST_LOCATION, customizePrivateLocation())); }
Example 11
Source File: TaskBuilder.java From brooklyn-server with Apache License 2.0 | 5 votes |
@SuppressWarnings({ "unchecked", "rawtypes" }) public Task<T> build() { MutableMap<String, Object> taskFlags = MutableMap.copyOf(flags); if (displayName!=null) taskFlags.put("displayName", displayName); if (description!=null) taskFlags.put("description", description); if (!tags.isEmpty()) taskFlags.put("tags", tags); if (Boolean.FALSE.equals(dynamic) && children.isEmpty()) { if (swallowChildrenFailures!=null) throw new IllegalArgumentException("Cannot set swallowChildrenFailures for non-dynamic task: "+this); return new BasicTask<T>(taskFlags, body); } // prefer dynamic set unless (a) user has said not dynamic, or (b) it's parallel (since there is no dynamic parallel yet) // dynamic has better cancel (will interrupt the thread) and callers can submit tasks flexibly; // however dynamic uses an extra thread and task and is noisy for contexts which don't need it if (Boolean.TRUE.equals(dynamic) || (dynamic==null && !parallel)) { if (parallel) throw new UnsupportedOperationException("No implementation of parallel dynamic aggregate task available"); DynamicSequentialTask<T> result = new DynamicSequentialTask<T>(taskFlags, body); if (swallowChildrenFailures!=null && swallowChildrenFailures.booleanValue()) result.swallowChildrenFailures(); for (TaskAdaptable t: children) result.queue(t.asTask()); return result; } // T must be of type List<V> for these to be valid if (body != null) { throw new UnsupportedOperationException("No implementation of non-dynamic task with both body and children"); } if (swallowChildrenFailures!=null) { throw new IllegalArgumentException("Cannot set swallowChildrenFailures for non-dynamic task: "+this); } if (parallel) return new ParallelTask(taskFlags, children); else return new SequentialTask(taskFlags, children); }
Example 12
Source File: ApplicationFacade.java From SeaCloudsPlatform with Apache License 2.0 | 5 votes |
public ApplicationFacade(Map<String, Object> adp, DamGeneratorConfigBag configBag) { this.adp = adp; this.template = MutableMap.copyOf(adp); this.topologyTemplate = new TopologyTemplateFacade(adp); this.configBag = configBag; init(); }
Example 13
Source File: Service.java From brooklyn-server with Apache License 2.0 | 5 votes |
@SuppressWarnings("unchecked") public static Service of(Map<String, Object> service) { Map<String,Object> fields = MutableMap.copyOf(service); Service result = new Service(); result.name = (String) fields.remove("name"); result.description = (String) fields.remove("description"); // FIXME _type needed in lots of places result.serviceType = (String) Yamls.removeMultinameAttribute(fields, "service_type", "serviceType", "type"); result.characteristics = new ArrayList<ServiceCharacteristic>(); Object chars = fields.remove("characteristics"); if (chars instanceof Iterable) { for (Object req: (Iterable<Object>)chars) { if (req instanceof Map) { result.characteristics.add(ServiceCharacteristic.of((Map<String,Object>) req)); } else { throw new IllegalArgumentException("characteristics should be a map, not "+req.getClass()); } } } else if (chars!=null) { // TODO "map" short form throw new IllegalArgumentException("services body should be iterable, not "+chars.getClass()); } result.customAttributes = fields; return result; }
Example 14
Source File: EntityDynamicType.java From brooklyn-server with Apache License 2.0 | 5 votes |
public void clearConfigKeys() { Map<String, FieldAndValue<ConfigKey<?>>> oldKeys = MutableMap.copyOf(configKeys); configKeys.clear(); invalidateSnapshot(); for (FieldAndValue<ConfigKey<?>> k: oldKeys.values()) { instance.sensors().emit(AbstractEntity.CONFIG_KEY_REMOVED, k.value); } }
Example 15
Source File: DeploymentPlan.java From brooklyn-server with Apache License 2.0 | 4 votes |
@SuppressWarnings("unchecked") public static DeploymentPlan of(Map<String,Object> root, String optionalSourceCode) { Map<String,Object> attrs = MutableMap.copyOf(root); DeploymentPlan result = new DeploymentPlan(); result.name = (String) attrs.remove("name"); result.description = (String) attrs.remove("description"); result.origin = (String) attrs.remove("origin"); result.sourceCode = optionalSourceCode; // TODO version result.services = new ArrayList<Service>(); Object services = attrs.remove("services"); if (services instanceof Iterable) { for (Object service: (Iterable<Object>)services) { if (service instanceof Map) { result.services.add(Service.of((Map<String,Object>) service)); } else { throw new UserFacingException("Services list should have a map for each entry, not "+JavaClassNames.superSimpleClassName(service)); } } } else if (services!=null) { // TODO "map" short form throw new UserFacingException("Services block should be a list, not "+JavaClassNames.superSimpleClassName(services)); } result.artifacts = new ArrayList<Artifact>(); Object artifacts = attrs.remove("artifacts"); if (artifacts instanceof Iterable) { for (Object artifact: (Iterable<Object>)artifacts) { if (artifact instanceof Map) { result.artifacts.add(Artifact.of((Map<String,Object>) artifact)); } else { throw new UserFacingException("Artifacts list should contain map items, not "+JavaClassNames.superSimpleClassName(artifact)); } } } else if (artifacts!=null) { // TODO "map" short form throw new UserFacingException("Artifacts block should contain a list, not "+JavaClassNames.superSimpleClassName(artifacts)); } result.customAttributes = attrs; return result; }
Example 16
Source File: DockerJcloudsLocation.java From brooklyn-server with Apache License 2.0 | 4 votes |
@Override public Template buildTemplate(ComputeService computeService, ConfigBag config, Collection<JcloudsLocationCustomizer> customizers) { String loginUser = config.get(JcloudsLocation.LOGIN_USER); String loginPassword = config.get(JcloudsLocation.LOGIN_USER_PASSWORD); String loginKeyFile = config.get(JcloudsLocation.LOGIN_USER_PRIVATE_KEY_FILE); String loginKeyData = config.get(JcloudsLocation.LOGIN_USER_PRIVATE_KEY_DATA); Template template = super.buildTemplate(computeService, config, customizers); DockerTemplateOptions templateOptions = (DockerTemplateOptions) template.getOptions(); Image image = template.getImage(); List<String> env = MutableList.copyOf(templateOptions.getEnv()); // Inject login credentials, if required Boolean injectLoginCredentials = config.get(INJECT_LOGIN_CREDENTIAL); if (injectLoginCredentials == null) { String imageDescription = image.getDescription(); for (String regex : IMAGE_DESCRIPTION_REGEXES_REQUIRING_INJECTED_LOGIN_CREDS) { if (imageDescription != null && imageDescription.matches(regex)) { injectLoginCredentials = true; break; } } } if (Strings.isBlank(loginUser) && Strings.isBlank(loginPassword) && Strings.isBlank(loginKeyFile) && Strings.isBlank(loginKeyData)) { if (Boolean.TRUE.equals(injectLoginCredentials)) { loginUser = "root"; loginPassword = Identifiers.makeRandomPassword(12); templateOptions.overrideLoginUser(loginUser); templateOptions.overrideLoginPassword(loginPassword); env.add("BROOKLYN_ROOT_PASSWORD=" + loginPassword); } } Entity context = validateCallerContext(config); Map<String, Object> containerEnv = MutableMap.copyOf(context.config().get(DockerContainer.CONTAINER_ENVIRONMENT)); for (Map.Entry<String, String> entry : Maps.transformValues(containerEnv, Functions.toStringFunction()).entrySet()) { env.add(String.format("%s=%s", entry.getKey(), entry.getValue())); } templateOptions.env(env); return template; }
Example 17
Source File: ByonLocationResolver.java From brooklyn-server with Apache License 2.0 | 4 votes |
protected LocationSpec<? extends MachineLocation> parseMachine(Map<String, ?> vals, Class<? extends MachineLocation> locationClass, Map<String, ?> defaults, String specForErrMsg) { Map<String, Object> valSanitized = Sanitizer.sanitize(vals); Map<String, Object> machineConfig = MutableMap.copyOf(vals); String osFamily = (String) machineConfig.remove(OS_FAMILY.getName()); String ssh = (String) machineConfig.remove("ssh"); String winrm = (String) machineConfig.remove("winrm"); Map<Integer, String> tcpPortMappings = (Map<Integer, String>) machineConfig.get("tcpPortMappings"); checkArgument(ssh != null ^ winrm != null, "Must specify exactly one of 'ssh' or 'winrm' for machine: %s", valSanitized); UserAndHostAndPort userAndHostAndPort; String host; int port; if (ssh != null) { userAndHostAndPort = parseUserAndHostAndPort(ssh, 22); } else { // TODO set to null and rely on the MachineLocation. If not then make a dependency to WinRmMachineLocation and use its config key name. userAndHostAndPort = parseUserAndHostAndPort(winrm, vals.get("winrm.useHttps") != null && (Boolean)vals.get("winrm.useHttps") ? 5986 : 5985); } // If there is a tcpPortMapping defined for the connection-port, then use that for ssh/winrm machine port = userAndHostAndPort.getHostAndPort().getPort(); if (tcpPortMappings != null && tcpPortMappings.containsKey(port)) { String override = tcpPortMappings.get(port); HostAndPort hostAndPortOverride = HostAndPort.fromString(override); if (!hostAndPortOverride.hasPort()) { throw new IllegalArgumentException("Invalid portMapping ('"+override+"') for port "+port+" in "+specForErrMsg); } port = hostAndPortOverride.getPort(); host = hostAndPortOverride.getHostText().trim(); } else { host = userAndHostAndPort.getHostAndPort().getHostText().trim(); } machineConfig.put("address", host); try { InetAddress.getByName(host); } catch (Exception e) { throw new IllegalArgumentException("Invalid host '"+host+"' specified in '"+specForErrMsg+"': "+e); } if (userAndHostAndPort.getUser() != null) { checkArgument(!vals.containsKey("user"), "Must not specify user twice for machine: %s", valSanitized); machineConfig.put("user", userAndHostAndPort.getUser()); } if (userAndHostAndPort.getHostAndPort().hasPort()) { checkArgument(!vals.containsKey("port"), "Must not specify port twice for machine: %s", valSanitized); machineConfig.put("port", port); } for (Map.Entry<String, ?> entry : defaults.entrySet()) { if (!machineConfig.containsKey(entry.getKey())) { machineConfig.put(entry.getKey(), entry.getValue()); } } Class<? extends MachineLocation> locationClassHere = locationClass; if (osFamily != null) { locationClassHere = getLocationClass(osFamily); } return LocationSpec.create(locationClassHere).configure(machineConfig); }
Example 18
Source File: JcloudsLocationResolver.java From brooklyn-server with Apache License 2.0 | 4 votes |
@Override public LocationSpec<? extends Location> newLocationSpecFromString(String spec, Map<?, ?> locationFlags, LocationRegistry registry) { Map globalProperties = registry.getProperties(); JcloudsSpecParser details = new JcloudsSpecParser().parse(spec, false); String namedLocation = (String) locationFlags.get(LocationInternal.NAMED_SPEC_NAME.getName()); boolean isProvider = details.isProvider(); String providerOrApi = details.providerOrApi; // gce claims to be an api ... perhaps just a bug? email sent to jclouds dev list, 28 mar 2014 isProvider = isProvider || "google-compute-engine".equals(providerOrApi); if (Strings.isEmpty(providerOrApi)) { throw new IllegalArgumentException("Cloud provider/API type not specified in spec \""+spec+"\""); } if (!isProvider && !details.isApi()) { throw new NoSuchElementException("Cloud provider/API type "+providerOrApi+" is not supported by jclouds"); } // For everything in brooklyn.properties, only use things with correct prefix (and remove that prefix). // But for everything passed in via locationFlags, pass those as-is. // TODO Should revisit the locationFlags: where are these actually used? Reason accepting properties without // full prefix is that the map's context is explicitly this location, rather than being generic properties. Map<String,Object> allProperties = getAllProperties(registry, globalProperties); String regionOrEndpoint = details.parameter; if (regionOrEndpoint==null && isProvider) regionOrEndpoint = (String)locationFlags.get(LocationConfigKeys.CLOUD_REGION_ID.getName()); Map<Object,Object> jcloudsProperties = MutableMap.<Object,Object>copyOf(new JcloudsPropertiesFromBrooklynProperties().getJcloudsProperties(providerOrApi, regionOrEndpoint, namedLocation, allProperties)); jcloudsProperties.putAll(locationFlags); if (regionOrEndpoint!=null) { // apply the regionOrEndpoint (e.g. from the parameter) as appropriate -- but only if it has not been overridden if (isProvider) { // providers from ServiceLoader take a location (endpoint already configured), and optionally a region name // NB blank might be supplied if spec string is "mycloud:" -- that should be respected, // whereas no parameter/regionName ie null value -- "mycloud" -- means don't set if (Strings.isBlank(Strings.toString(jcloudsProperties.get(JcloudsLocationConfig.CLOUD_REGION_ID.getName())))) jcloudsProperties.put(JcloudsLocationConfig.CLOUD_REGION_ID.getName(), regionOrEndpoint); } else { // other "providers" are APIs so take an _endpoint_ (but not a location); // see note above re null here if (Strings.isBlank(Strings.toString(jcloudsProperties.get(JcloudsLocationConfig.CLOUD_ENDPOINT.getName())))) jcloudsProperties.put(JcloudsLocationConfig.CLOUD_ENDPOINT.getName(), regionOrEndpoint); } } return LocationSpec.create(getLocationClass()) .configure(LocationConfigUtils.finalAndOriginalSpecs(spec, jcloudsProperties, globalProperties, namedLocation)) .configure(jcloudsProperties); }
Example 19
Source File: TopologyTemplateFacade.java From SeaCloudsPlatform with Apache License 2.0 | 4 votes |
public TopologyTemplateFacade(Map<String, Object> adp) { this.originalAdp = MutableMap.copyOf(adp); init(); }
Example 20
Source File: ServiceStateLogic.java From brooklyn-server with Apache License 2.0 | 4 votes |
/** update the given key in the given map sensor */ public static <TKey,TVal> void updateMapSensorEntry(Entity entity, AttributeSensor<Map<TKey,TVal>> sensor, final TKey key, final TVal v) { /* * Important to *not* modify the existing attribute value; must make a copy, modify that, and publish. * This is because a Propagator enricher will set this same value on another entity. There was very * strange behaviour when this was done for a SERVICE_UP_INDICATORS sensor - the updates done here * applied to the attribute of both entities! * * Need to do this update atomically (i.e. sequentially) because there is no threading control for * what is calling updateMapSensorEntity. It is called directly on start, on initialising enrichers, * and in event listeners. These calls could be concurrent. */ Function<Map<TKey,TVal>, Maybe<Map<TKey,TVal>>> modifier = new Function<Map<TKey,TVal>, Maybe<Map<TKey,TVal>>>() { @Override public Maybe<Map<TKey, TVal>> apply(Map<TKey, TVal> map) { boolean created = (map==null); if (created) map = MutableMap.of(); boolean changed; if (v == Entities.REMOVE) { changed = map.containsKey(key); if (changed) { map = MutableMap.copyOf(map); map.remove(key); } } else { TVal oldV = map.get(key); if (oldV==null) { changed = (v!=null || !map.containsKey(key)); } else { changed = !oldV.equals(v); } if (changed) { map = MutableMap.copyOf(map); map.put(key, v); } } if (changed || created) { return Maybe.of(map); } else { return Maybe.absent(); } } }; if (!Entities.isNoLongerManaged(entity)) { entity.sensors().modify(sensor, modifier); } }