You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2015/08/19 13:10:14 UTC
[56/72] [abbrv] incubator-brooklyn git commit: BROOKLYN-162 - jclouds
last few package prefixes needed,
and tidy in core and elsewhere related (or observed in the process)
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/LocationPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/LocationPredicates.java b/core/src/main/java/org/apache/brooklyn/location/core/LocationPredicates.java
new file mode 100644
index 0000000..3491dc4
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/LocationPredicates.java
@@ -0,0 +1,108 @@
+/*
+ * 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.location.core;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Predicate;
+
+public class LocationPredicates {
+
+ public static <T> Predicate<Location> idEqualTo(final T val) {
+ return new Predicate<Location>() {
+ @Override
+ public boolean apply(@Nullable Location input) {
+ return (input != null) && Objects.equal(input.getId(), val);
+ }
+ };
+ }
+
+ public static <T> Predicate<Location> displayNameEqualTo(final T val) {
+ return new Predicate<Location>() {
+ @Override
+ public boolean apply(@Nullable Location input) {
+ return (input != null) && Objects.equal(input.getDisplayName(), val);
+ }
+ };
+ }
+
+ public static <T> Predicate<Location> configEqualTo(final ConfigKey<T> configKey, final T val) {
+ return new Predicate<Location>() {
+ @Override
+ public boolean apply(@Nullable Location input) {
+ return (input != null) && Objects.equal(input.getConfig(configKey), val);
+ }
+ };
+ }
+
+ public static <T> Predicate<Location> configEqualTo(final HasConfigKey<T> configKey, final T val) {
+ return new Predicate<Location>() {
+ @Override
+ public boolean apply(@Nullable Location input) {
+ return (input != null) && Objects.equal(input.getConfig(configKey), val);
+ }
+ };
+ }
+
+ /**
+ * Returns a predicate that determines if a given location is a direct child of this {@code parent}.
+ */
+ public static <T> Predicate<Location> isChildOf(final Location parent) {
+ return new Predicate<Location>() {
+ @Override
+ public boolean apply(@Nullable Location input) {
+ return (input != null) && Objects.equal(input.getParent(), parent);
+ }
+ };
+ }
+
+ /**
+ * Returns a predicate that determines if a given location is a descendant of this {@code ancestor}.
+ */
+ public static <T> Predicate<Location> isDescendantOf(final Location ancestor) {
+ return new Predicate<Location>() {
+ @Override
+ public boolean apply(@Nullable Location input) {
+ // assumes impossible to have cycles in location-hierarchy
+ Location contenderAncestor = (input == null) ? input : input.getParent();
+ while (contenderAncestor != null) {
+ if (Objects.equal(contenderAncestor, ancestor)) {
+ return true;
+ }
+ contenderAncestor = contenderAncestor.getParent();
+ }
+ return false;
+ }
+ };
+ }
+
+ public static <T> Predicate<Location> managed() {
+ return new Predicate<Location>() {
+ @Override
+ public boolean apply(@Nullable Location input) {
+ return (input != null) && Locations.isManaged(input);
+ }
+ };
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/LocationPropertiesFromBrooklynProperties.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/LocationPropertiesFromBrooklynProperties.java b/core/src/main/java/org/apache/brooklyn/location/core/LocationPropertiesFromBrooklynProperties.java
new file mode 100644
index 0000000..fd1b92a
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/LocationPropertiesFromBrooklynProperties.java
@@ -0,0 +1,223 @@
+/*
+ * 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.location.core;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.brooklyn.core.config.ConfigUtils;
+import org.apache.brooklyn.core.internal.BrooklynProperties;
+import org.apache.brooklyn.core.server.BrooklynServerConfig;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.core.internal.ssh.SshTool;
+import org.apache.brooklyn.util.os.Os;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicates;
+import com.google.common.base.Strings;
+import com.google.common.collect.Maps;
+
+/**
+ * The properties to use for locations, loaded from brooklyn.properties file.
+ *
+ * @author aledsage
+ **/
+public class LocationPropertiesFromBrooklynProperties {
+
+ private static final Logger LOG = LoggerFactory.getLogger(LocationPropertiesFromBrooklynProperties.class);
+
+ @SuppressWarnings("deprecation")
+ protected static final Map<String, String> DEPRECATED_KEYS_MAPPING = new DeprecatedKeysMappingBuilder(LOG)
+ .camelToHyphen(LocationConfigKeys.DISPLAY_NAME)
+ .camelToHyphen(LocationConfigKeys.PRIVATE_KEY_FILE)
+ .camelToHyphen(LocationConfigKeys.PRIVATE_KEY_DATA)
+ .camelToHyphen(LocationConfigKeys.PRIVATE_KEY_PASSPHRASE)
+ .camelToHyphen(LocationConfigKeys.PUBLIC_KEY_FILE)
+ .camelToHyphen(LocationConfigKeys.PUBLIC_KEY_DATA)
+ .camelToHyphen(LocationConfigKeys.CALLER_CONTEXT)
+ .build();
+
+ /**
+ * Finds the properties that apply to location, stripping off the prefixes.
+ *
+ * Order of preference (in ascending order) is:
+ * <ol>
+ * <li>brooklyn.location.*
+ * <li>brooklyn.location.provider.*
+ * <li>brooklyn.location.named.namedlocation.*
+ * </ol>
+ * <p>
+ * Converts deprecated hyphenated properties to the non-deprecated camelCase format.
+ */
+ public Map<String, Object> getLocationProperties(String provider, String namedLocation, Map<String, ?> properties) {
+ ConfigBag result = ConfigBag.newInstance();
+
+ if (!Strings.isNullOrEmpty(provider))
+ result.put(LocationConfigKeys.CLOUD_PROVIDER, provider);
+ // named properties are preferred over providerOrApi properties
+ result.putAll(transformDeprecated(getGenericLocationSingleWordProperties(properties)));
+ if (!Strings.isNullOrEmpty(provider)) result.putAll(transformDeprecated(getScopedLocationProperties(provider, properties)));
+ if (!Strings.isNullOrEmpty(namedLocation)) result.putAll(transformDeprecated(getNamedLocationProperties(namedLocation, properties)));
+
+ setLocalTempDir(properties, result);
+
+ return result.getAllConfigRaw();
+ }
+
+ /** allow the temp dir where ssh temporary files on the brooklyn server side are placed */
+ public static void setLocalTempDir(Map<String,?> source, ConfigBag target) {
+ // TODO better would be to use BrooklynServerConfig, requiring management passed in
+ String brooklynDataDir = (String) source.get(BrooklynServerConfig.getMgmtBaseDir(source));
+ if (brooklynDataDir != null && brooklynDataDir.length() > 0) {
+ String tempDir = Os.mergePaths(brooklynDataDir, "tmp", "ssh");
+ target.putIfAbsentAndNotNull(SshTool.PROP_LOCAL_TEMP_DIR, tempDir);
+ Os.deleteOnExitEmptyParentsUpTo(new File(tempDir), new File(brooklynDataDir));
+ }
+ }
+
+ /**
+ * Gets the named provider (e.g. if using a property like {@code brooklyn.location.named.myfavourite=localhost}, then
+ * {@code getNamedProvider("myfavourite", properties)} will return {@code "localhost"}).
+ */
+ protected String getNamedProvider(String namedLocation, Map<String, ?> properties) {
+ String key = String.format("brooklyn.location.named.%s", namedLocation);
+ return (String) properties.get(key);
+ }
+
+ /**
+ * Returns those properties in the form "brooklyn.location.xyz", where "xyz" is any
+ * key that does not contain dots. We do this special (sub-optimal!) filtering
+ * because we want to exclude brooklyn.location.named.*, brooklyn.location.jclouds.*, etc.
+ * We only want those properties that are to be generic for all locations.
+ *
+ * Strips off the prefix in the returned map.
+ */
+ protected Map<String, Object> getGenericLocationSingleWordProperties(Map<String, ?> properties) {
+ return getMatchingSingleWordProperties("brooklyn.location.", properties);
+ }
+
+ /**
+ * Gets all properties that start with {@code "brooklyn.location."+scopeSuffix+"."}, stripping off
+ * the prefix in the returned map.
+ */
+ protected Map<String, Object> getScopedLocationProperties(String scopeSuffix, Map<String, ?> properties) {
+ checkArgument(!scopeSuffix.startsWith("."), "scopeSuffix \"%s\" should not start with \".\"", scopeSuffix);
+ checkArgument(!scopeSuffix.endsWith("."), "scopeSuffix \"%s\" should not end with \".\"", scopeSuffix);
+ String prefix = String.format("brooklyn.location.%s.", scopeSuffix);
+ return ConfigUtils.filterForPrefixAndStrip(properties, prefix).asMapWithStringKeys();
+ }
+
+ /**
+ * Gets all properties that start with the given {@code fullPrefix}, stripping off
+ * the prefix in the returned map.
+ */
+ protected Map<String, Object> getMatchingProperties(String fullPrefix, Map<String, ?> properties) {
+ return ConfigUtils.filterForPrefixAndStrip(properties, fullPrefix).asMapWithStringKeys();
+ }
+
+ /**
+ * Gets all properties that start with either of the given prefixes. The {@code fullPreferredPrefix}
+ * properties will override any duplicates in {@code fullDeprecatedPrefix}. If there are any
+ * properties that match the {@code fullDeprecatedPrefix}, then a warning will be logged.
+ *
+ * @see #getMatchingProperties(String, Map)
+ */
+ protected Map<String, Object> getMatchingProperties(String fullPreferredPrefix, String fullDeprecatedPrefix, Map<String, ?> properties) {
+ Map<String, Object> deprecatedResults = getMatchingProperties(fullDeprecatedPrefix, properties);
+ Map<String, Object> results = getMatchingProperties(fullPreferredPrefix, properties);
+
+ if (deprecatedResults.size() > 0) {
+ LOG.warn("Deprecated use of properties prefix "+fullDeprecatedPrefix+"; instead use "+fullPreferredPrefix);
+ return MutableMap.<String, Object>builder()
+ .putAll(deprecatedResults)
+ .putAll(results)
+ .build();
+ } else {
+ return results;
+ }
+ }
+
+ /**
+ * Gets all properties that start with the given {@code fullPrefix}, stripping off
+ * the prefix in the returned map.
+ *
+ * Returns only those properties whose key suffix is a single word (i.e. contains no dots).
+ * We do this special (sub-optimal!) filtering because we want sub-scoped things
+ * (e.g. could want brooklyn.location.privateKeyFile, but not brooklyn.location.named.*).
+ */
+ protected Map<String, Object> getMatchingSingleWordProperties(String fullPrefix, Map<String, ?> properties) {
+ BrooklynProperties filteredProperties = ConfigUtils.filterForPrefixAndStrip(properties, fullPrefix);
+ return ConfigUtils.filterFor(filteredProperties, Predicates.not(Predicates.containsPattern("\\."))).asMapWithStringKeys();
+ }
+
+ /**
+ * Gets all single-word properties that start with either of the given prefixes. The {@code fullPreferredPrefix}
+ * properties will override any duplicates in {@code fullDeprecatedPrefix}. If there are any
+ * properties that match the {@code fullDeprecatedPrefix}, then a warning will be logged.
+ *
+ * @see #getMatchingSingleWordProperties(String, Map)
+ */
+ protected Map<String, Object> getMatchingSingleWordProperties(String fullPreferredPrefix, String fullDeprecatedPrefix, Map<String, ?> properties) {
+ Map<String, Object> deprecatedResults = getMatchingSingleWordProperties(fullDeprecatedPrefix, properties);
+ Map<String, Object> results = getMatchingSingleWordProperties(fullPreferredPrefix, properties);
+
+ if (deprecatedResults.size() > 0) {
+ LOG.warn("Deprecated use of properties prefix "+fullDeprecatedPrefix+"; instead use "+fullPreferredPrefix);
+ return MutableMap.<String, Object>builder()
+ .putAll(deprecatedResults)
+ .putAll(results)
+ .build();
+ } else {
+ return results;
+ }
+ }
+
+ protected Map<String, Object> getNamedLocationProperties(String locationName, Map<String, ?> properties) {
+ checkArgument(!Strings.isNullOrEmpty(locationName), "locationName should not be blank");
+ String prefix = String.format("brooklyn.location.named.%s.", locationName);
+ return ConfigUtils.filterForPrefixAndStrip(properties, prefix).asMapWithStringKeys();
+ }
+
+ protected Map<String, Object> transformDeprecated(Map<String, ?> properties) {
+ Map<String,Object> result = Maps.newLinkedHashMap();
+ Map<String, String> deprecatedKeysMapping = getDeprecatedKeysMapping();
+
+ for (Map.Entry<String,?> entry : properties.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ if (deprecatedKeysMapping.containsKey(key)) {
+ String transformedKey = deprecatedKeysMapping.get(key);
+ LOG.warn("Deprecated key {}, transformed to {}; will not be supported in future versions", new Object[] {key, transformedKey});
+ result.put(transformedKey, value);
+ } else {
+ result.put(key, value);
+ }
+ }
+
+ return result;
+ }
+
+ protected Map<String,String> getDeprecatedKeysMapping() {
+ return DEPRECATED_KEYS_MAPPING;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/Locations.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/Locations.java b/core/src/main/java/org/apache/brooklyn/location/core/Locations.java
new file mode 100644
index 0000000..663624f
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/Locations.java
@@ -0,0 +1,160 @@
+/*
+ * 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.location.core;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.api.mgmt.LocationManager;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.entity.core.Entities;
+import org.apache.brooklyn.location.core.internal.LocationInternal;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.yaml.Yamls;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableList;
+
+public class Locations {
+
+ private static final Logger log = LoggerFactory.getLogger(Locations.class);
+
+ public static final LocationsFilter USE_FIRST_LOCATION = new LocationsFilter() {
+ private static final long serialVersionUID = 3100091615409115890L;
+
+ @Override
+ public List<Location> filterForContext(List<Location> locations, Object context) {
+ if (locations.size()<=1) return locations;
+ return ImmutableList.of(locations.get(0));
+ }
+ };
+
+ public interface LocationsFilter extends Serializable {
+ public List<Location> filterForContext(List<Location> locations, Object context);
+ }
+
+ /** as {@link Machines#findUniqueMachineLocation(Iterable)} */
+ public static Maybe<MachineLocation> findUniqueMachineLocation(Iterable<? extends Location> locations) {
+ return Machines.findUniqueMachineLocation(locations);
+ }
+
+ /** as {@link Machines#findUniqueSshMachineLocation(Iterable)} */
+ public static Maybe<SshMachineLocation> findUniqueSshMachineLocation(Iterable<? extends Location> locations) {
+ return Machines.findUniqueSshMachineLocation(locations);
+ }
+
+ /** if no locations are supplied, returns locations on the entity, or in the ancestors, until it finds a non-empty set,
+ * or ultimately the empty set if no locations are anywhere */
+ public static Collection<? extends Location> getLocationsCheckingAncestors(Collection<? extends Location> locations, Entity entity) {
+ // look in ancestors if location not set here
+ Entity ancestor = entity;
+ while ((locations==null || locations.isEmpty()) && ancestor!=null) {
+ locations = ancestor.getLocations();
+ ancestor = ancestor.getParent();
+ }
+ return locations;
+ }
+
+ public static boolean isManaged(Location loc) {
+ ManagementContext mgmt = ((LocationInternal)loc).getManagementContext();
+ return (mgmt != null) && mgmt.isRunning() && mgmt.getLocationManager().isManaged(loc);
+ }
+
+ public static void unmanage(Location loc) {
+ if (isManaged(loc)) {
+ ManagementContext mgmt = ((LocationInternal)loc).getManagementContext();
+ mgmt.getLocationManager().unmanage(loc);
+ }
+ }
+
+ /**
+ * Registers the given location (and all its children) with the management context.
+ * @throws IllegalStateException if the parent location is not already managed
+ *
+ * @since 0.6.0 (added only for backwards compatibility, where locations are being created directly; previously in {@link Entities}).
+ * @deprecated in 0.6.0; use {@link LocationManager#createLocation(LocationSpec)} instead.
+ */
+ public static void manage(Location loc, ManagementContext managementContext) {
+ if (!managementContext.getLocationManager().isManaged(loc)) {
+ log.warn("Deprecated use of unmanaged location ("+loc+"); will be managed automatically now but not supported in future versions");
+ // FIXME this occurs MOST OF THE TIME e.g. including BrooklynLauncher.location(locationString)
+ // not sure what is the recommend way to convert from locationString to locationSpec, or the API we want to expose;
+ // deprecating some of the LocationRegistry methods seems sensible?
+ log.debug("Stack trace for location of: Deprecated use of unmanaged location; will be managed automatically now but not supported in future versions", new Exception("TRACE for: Deprecated use of unmanaged location"));
+ managementContext.getLocationManager().manage(loc);
+ }
+ }
+
+ public static Location coerce(ManagementContext mgmt, Object rawO) {
+ if (rawO==null)
+ return null;
+ if (rawO instanceof Location)
+ return (Location)rawO;
+
+ Object raw = rawO;
+ if (raw instanceof String)
+ raw = Yamls.parseAll((String)raw).iterator().next();
+
+ String name;
+ Map<?, ?> flags = null;
+ if (raw instanceof Map) {
+ // for yaml, take the key, and merge with locationFlags
+ Map<?,?> tm = ((Map<?,?>)raw);
+ if (tm.size()!=1) {
+ throw new IllegalArgumentException("Location "+rawO+" is invalid; maps must have only one key, being the location spec string");
+ }
+ name = (String) tm.keySet().iterator().next();
+ flags = (Map<?, ?>) tm.values().iterator().next();
+
+ } else if (raw instanceof String) {
+ name = (String)raw;
+
+ } else {
+ throw new IllegalArgumentException("Location "+rawO+" is invalid; can only parse strings or maps");
+ }
+ return mgmt.getLocationRegistry().resolve(name, flags);
+ }
+
+ public static Collection<? extends Location> coerceToCollection(ManagementContext mgmt, Object rawO) {
+ if (rawO==null) return null;
+ Object raw = rawO;
+ if (raw instanceof Collection) {
+ List<Location> result = MutableList.<Location>of();
+ for (Object o: (Collection<?>)raw)
+ result.add(coerce(mgmt, o));
+ return result;
+ }
+ if (raw instanceof String) {
+ raw = Yamls.parseAll((String)raw).iterator().next();
+ if (raw instanceof Collection)
+ return coerceToCollection(mgmt, raw);
+ }
+ return Collections.singletonList( coerce(mgmt, raw) );
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/Machines.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/Machines.java b/core/src/main/java/org/apache/brooklyn/location/core/Machines.java
new file mode 100644
index 0000000..164e4ae
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/Machines.java
@@ -0,0 +1,191 @@
+/*
+ * 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.location.core;
+
+import java.net.InetAddress;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.entity.core.Attributes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Iterables;
+
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation;
+import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation.LocalhostMachine;
+import org.apache.brooklyn.location.ssh.SshMachineLocation;
+import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.util.guava.Maybe;
+import org.apache.brooklyn.util.net.HasNetworkAddresses;
+
+/** utilities for working with MachineLocations */
+public class Machines {
+
+ private static final Logger log = LoggerFactory.getLogger(Machines.class);
+
+ public static Maybe<String> getSubnetHostname(Location where) {
+ // TODO Should we look at HasNetworkAddresses? But that's not a hostname.
+ String hostname = null;
+ if (where instanceof HasSubnetHostname) {
+ hostname = ((HasSubnetHostname) where).getSubnetHostname();
+ }
+ if (hostname == null && where instanceof MachineLocation) {
+ InetAddress addr = ((MachineLocation) where).getAddress();
+ if (addr != null) hostname = addr.getHostAddress();
+ }
+ log.debug("computed subnet hostname {} for {}", hostname, where);
+ // TODO if Maybe.absent(message) appears, could/should use that
+ // TODO If no machine available, should we throw new IllegalStateException("Cannot find hostname for "+where);
+ return Maybe.fromNullable(hostname);
+ }
+
+ public static Maybe<String> getSubnetIp(Location where) {
+ // TODO Too much duplication between the ip and hostname methods
+ String result = null;
+ if (where instanceof HasSubnetHostname) {
+ result = ((HasSubnetHostname) where).getSubnetIp();
+ }
+ if (where instanceof HasNetworkAddresses) {
+ Set<String> privateAddrs = ((HasNetworkAddresses) where).getPrivateAddresses();
+ if (privateAddrs.size() > 0) {
+ result = Iterables.get(privateAddrs, 0);
+ }
+ }
+ if (result == null && where instanceof MachineLocation) {
+ InetAddress addr = ((MachineLocation) where).getAddress();
+ if (addr != null) result = addr.getHostAddress();
+ }
+ log.debug("computed subnet host ip {} for {}", result, where);
+ return Maybe.fromNullable(result);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> Maybe<T> findUniqueElement(Iterable<?> items, Class<T> type) {
+ if (items==null) return null;
+ Iterator<?> i = items.iterator();
+ T result = null;
+ while (i.hasNext()) {
+ Object candidate = i.next();
+ if (type.isInstance(candidate)) {
+ if (result==null) result = (T)candidate;
+ else {
+ if (log.isTraceEnabled())
+ log.trace("Multiple instances of "+type+" in "+items+"; ignoring");
+ return Maybe.absent(new IllegalStateException("Multiple instances of "+type+" in "+items+"; expected a single one"));
+ }
+ }
+ }
+ if (result==null)
+ return Maybe.absent(new IllegalStateException("No instances of "+type+" available (in "+items+")"));
+ return Maybe.of(result);
+ }
+
+ public static Maybe<MachineLocation> findUniqueMachineLocation(Iterable<? extends Location> locations) {
+ return findUniqueElement(locations, MachineLocation.class);
+ }
+
+ public static Maybe<SshMachineLocation> findUniqueSshMachineLocation(Iterable<? extends Location> locations) {
+ return findUniqueElement(locations, SshMachineLocation.class);
+ }
+
+ public static Maybe<WinRmMachineLocation> findUniqueWinRmMachineLocation(Iterable<? extends Location> locations) {
+ return findUniqueElement(locations, WinRmMachineLocation.class);
+ }
+
+ public static Maybe<String> findSubnetHostname(Iterable<? extends Location> ll) {
+ Maybe<MachineLocation> l = findUniqueMachineLocation(ll);
+ if (!l.isPresent()) {
+ return Maybe.absent();
+// throw new IllegalStateException("Cannot find hostname for among "+ll);
+ }
+ return Machines.getSubnetHostname(l.get());
+ }
+
+ public static Maybe<String> findSubnetHostname(Entity entity) {
+ String sh = entity.getAttribute(Attributes.SUBNET_HOSTNAME);
+ if (sh!=null) return Maybe.of(sh);
+ return findSubnetHostname(entity.getLocations());
+ }
+
+ public static Maybe<String> findSubnetOrPublicHostname(Entity entity) {
+ String hn = entity.getAttribute(Attributes.HOSTNAME);
+ if (hn!=null) {
+ // attributes already set, see if there was a SUBNET_HOSTNAME set
+ // note we rely on (public) hostname being set _after_ subnet_hostname,
+ // to prevent tiny possibility of races resulting in hostname being returned
+ // becasue subnet is still being looked up -- see MachineLifecycleEffectorTasks
+ Maybe<String> sn = findSubnetHostname(entity);
+ if (sn.isPresent()) return sn;
+ // short-circuit discovery if attributes have been set already
+ return Maybe.of(hn);
+ }
+
+ Maybe<MachineLocation> l = findUniqueMachineLocation(entity.getLocations());
+ if (!l.isPresent()) return Maybe.absent();
+ InetAddress addr = l.get().getAddress();
+ if (addr==null) return Maybe.absent();
+ return Maybe.fromNullable(addr.getHostName());
+ }
+
+ public static Maybe<String> findSubnetOrPrivateIp(Entity entity) {
+ // see comments in findSubnetOrPrivateHostname
+ String hn = entity.getAttribute(Attributes.ADDRESS);
+ if (hn!=null) {
+ Maybe<String> sn = findSubnetIp(entity);
+ if (sn.isPresent()) return sn;
+ return Maybe.of(hn);
+ }
+
+ Maybe<MachineLocation> l = findUniqueMachineLocation(entity.getLocations());
+ if (!l.isPresent()) return Maybe.absent();
+ InetAddress addr = l.get().getAddress();
+ if (addr==null) return Maybe.absent();
+ return Maybe.fromNullable(addr.getHostAddress());
+ }
+
+ public static Maybe<String> findSubnetIp(Entity entity) {
+ String sh = entity.getAttribute(Attributes.SUBNET_ADDRESS);
+ if (sh!=null) return Maybe.of(sh);
+ return findSubnetIp(entity.getLocations());
+ }
+
+ public static Maybe<String> findSubnetIp(Iterable<? extends Location> ll) {
+ // TODO Or if can't find MachineLocation, should we throw new IllegalStateException("Cannot find hostname for among "+ll);
+ Maybe<MachineLocation> l = findUniqueMachineLocation(ll);
+ return (l.isPresent()) ? Machines.getSubnetIp(l.get()) : Maybe.<String>absent();
+ }
+
+ /** returns whether it is localhost (and has warned) */
+ public static boolean warnIfLocalhost(Collection<? extends Location> locations, String message) {
+ if (locations.size()==1) {
+ Location l = locations.iterator().next();
+ if (l instanceof LocalhostMachineProvisioningLocation || l instanceof LocalhostMachine) {
+ log.warn(message);
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/MultiLocation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/MultiLocation.java b/core/src/main/java/org/apache/brooklyn/location/core/MultiLocation.java
new file mode 100644
index 0000000..9f52244
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/MultiLocation.java
@@ -0,0 +1,166 @@
+/*
+ * 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.location.core;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.location.MachineLocation;
+import org.apache.brooklyn.api.location.MachineProvisioningLocation;
+import org.apache.brooklyn.api.location.NoMachinesAvailableException;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.location.cloud.AbstractAvailabilityZoneExtension;
+import org.apache.brooklyn.location.cloud.AvailabilityZoneExtension;
+import org.apache.brooklyn.util.collections.MutableList;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.core.flags.SetFromFlag;
+import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.text.Strings;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.reflect.TypeToken;
+
+/** A location which consists of multiple locations stitched together to form availability zones.
+ * The first location will be used by default, but if an {@link AvailabilityZoneExtension}-aware entity
+ * is used, it may stripe across each of the locations. See notes at {@link AvailabilityZoneExtension}. */
+public class MultiLocation<T extends MachineLocation> extends AbstractLocation implements MachineProvisioningLocation<T> {
+
+ private static final long serialVersionUID = 7993091317970457862L;
+
+ @SuppressWarnings("serial")
+ @SetFromFlag("subLocations")
+ public static final ConfigKey<List<MachineProvisioningLocation<?>>> SUB_LOCATIONS = ConfigKeys.newConfigKey(
+ new TypeToken<List<MachineProvisioningLocation<?>>>() {},
+ "subLocations",
+ "The sub-machines that this location can delegate to");
+
+ @Override
+ public void init() {
+ super.init();
+ List<MachineProvisioningLocation<?>> subLocs = getSubLocations();
+ checkState(subLocs.size() >= 1, "sub-locations must not be empty");
+ AvailabilityZoneExtension azExtension = new AvailabilityZoneExtensionImpl(getManagementContext(), subLocs);
+ addExtension(AvailabilityZoneExtension.class, azExtension);
+ }
+
+ public T obtain() throws NoMachinesAvailableException {
+ return obtain(MutableMap.of());
+ }
+
+ /** finds (creates) and returns a {@link MachineLocation};
+ * this always tries the first sub-location, moving on the second and subsequent if the first throws {@link NoMachinesAvailableException}.
+ * (if you want striping across locations, see notes in {@link AvailabilityZoneExtension}.) */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T obtain(Map<?, ?> flags) throws NoMachinesAvailableException {
+ List<MachineProvisioningLocation<?>> sublocsList = getSubLocations();
+ Iterator<MachineProvisioningLocation<?>> sublocs = sublocsList.iterator();
+ List<NoMachinesAvailableException> errors = MutableList.of();
+ while (sublocs.hasNext()) {
+ try {
+ return (T) sublocs.next().obtain(flags);
+ } catch (NoMachinesAvailableException e) {
+ errors.add(e);
+ }
+ }
+ Exception wrapped;
+ String msg;
+ if (errors.size()>1) {
+ wrapped = new CompoundRuntimeException(errors.size()+" sublocation exceptions, including: "+
+ Exceptions.collapseText(errors.get(0)), errors);
+ msg = Exceptions.collapseText(wrapped);
+ } else if (errors.size()==1) {
+ wrapped = errors.get(0);
+ msg = wrapped.getMessage();
+ if (Strings.isBlank(msg)) msg = wrapped.toString();
+ } else {
+ msg = "no sub-locations set for this multi-location";
+ wrapped = null;
+ }
+ throw new NoMachinesAvailableException("No machines available in any of the "+sublocsList.size()+" location"+Strings.s(sublocsList.size())+
+ " configured here: "+msg, wrapped);
+ }
+
+ public List<MachineProvisioningLocation<?>> getSubLocations() {
+ return getRequiredConfig(SUB_LOCATIONS);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public MachineProvisioningLocation<T> newSubLocation(Map<?, ?> newFlags) {
+ // TODO shouldn't have to copy config bag as it should be inherited (but currently it is not used inherited everywhere; just most places)
+ return getManagementContext().getLocationManager().createLocation(LocationSpec.create(getClass())
+ .parent(this)
+ .configure(config().getLocalBag().getAllConfig()) // FIXME Should this just be inherited?
+ .configure(newFlags));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void release(T machine) {
+ ((MachineProvisioningLocation<T>)machine.getParent()).release(machine);
+ }
+
+ @Override
+ public Map<String, Object> getProvisioningFlags(Collection<String> tags) {
+ return Maps.<String,Object>newLinkedHashMap();
+ }
+
+ @SuppressWarnings("unchecked")
+ protected MachineProvisioningLocation<T> firstSubLoc() {
+ return (MachineProvisioningLocation<T>) Iterables.get(getSubLocations(), 0);
+ }
+
+ protected <K> K getRequiredConfig(ConfigKey<K> key) {
+ return checkNotNull(getConfig(key), key.getName());
+ }
+
+ public static class AvailabilityZoneExtensionImpl extends AbstractAvailabilityZoneExtension implements AvailabilityZoneExtension {
+
+ private final List<MachineProvisioningLocation<?>> subLocations;
+
+ public AvailabilityZoneExtensionImpl(ManagementContext managementContext, List<MachineProvisioningLocation<?>> subLocations) {
+ super(managementContext);
+ this.subLocations = ImmutableList.copyOf(subLocations);
+ }
+
+ @Override
+ protected List<Location> doGetAllSubLocations() {
+ return ImmutableList.<Location>copyOf(subLocations);
+ }
+
+ @Override
+ protected boolean isNameMatch(Location loc, Predicate<? super String> namePredicate) {
+ return namePredicate.apply(loc.getDisplayName());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/MultiLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/MultiLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/core/MultiLocationResolver.java
new file mode 100644
index 0000000..e20661f
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/MultiLocationResolver.java
@@ -0,0 +1,145 @@
+/*
+ * 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.location.core;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationRegistry;
+import org.apache.brooklyn.api.location.LocationResolver;
+import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.exceptions.Exceptions;
+import org.apache.brooklyn.util.text.KeyValueParser;
+import org.apache.brooklyn.util.text.StringEscapes.JavaStringEscapes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+public class MultiLocationResolver implements LocationResolver {
+
+ private static final Logger LOG = LoggerFactory.getLogger(MultiLocationResolver.class);
+
+ private static final String MULTI = "multi";
+
+ private static final Pattern PATTERN = Pattern.compile("(" + MULTI + "|" + MULTI.toUpperCase() + ")" + ":" + "\\((.*)\\)$");
+
+ private volatile ManagementContext managementContext;
+
+ @Override
+ public void init(ManagementContext managementContext) {
+ this.managementContext = checkNotNull(managementContext, "managementContext");
+ }
+
+ @Override
+ public Location newLocationFromString(Map locationFlags, String spec, LocationRegistry registry) {
+ // FIXME pass all flags into the location
+
+ Map globalProperties = registry.getProperties();
+ Map<String,?> locationArgs;
+ if (spec.equalsIgnoreCase(MULTI)) {
+ locationArgs = MutableMap.copyOf(locationFlags);
+ } else {
+ Matcher matcher = PATTERN.matcher(spec);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException("Invalid location '" + spec + "'; must specify something like multi(targets=named:foo)");
+ }
+ String args = matcher.group(2);
+ // TODO we are ignoring locationFlags after this (apart from named), looking only at these args
+ locationArgs = KeyValueParser.parseMap(args);
+ }
+ String namedLocation = (String) locationFlags.get("named");
+
+ Map<String, Object> filteredProperties = new LocationPropertiesFromBrooklynProperties().getLocationProperties(null, namedLocation, globalProperties);
+ MutableMap<String, Object> flags = MutableMap.<String, Object>builder()
+ .putAll(filteredProperties)
+ .putAll(locationFlags)
+ .removeAll("named")
+ .putAll(locationArgs).build();
+
+ if (locationArgs.get("targets") == null) {
+ throw new IllegalArgumentException("target must be specified in single-machine spec");
+ }
+
+ // TODO do we need to pass location flags etc into the children to ensure they are inherited?
+ List<Location> targets = Lists.newArrayList();
+ Object targetSpecs = locationArgs.remove("targets");
+ try {
+ if (targetSpecs instanceof String) {
+ for (String targetSpec : JavaStringEscapes.unwrapJsonishListIfPossible((String)targetSpecs)) {
+ targets.add(managementContext.getLocationRegistry().resolve(targetSpec));
+ }
+ } else if (targetSpecs instanceof Iterable) {
+ for (Object targetSpec: (Iterable<?>)targetSpecs) {
+ if (targetSpec instanceof String) {
+ targets.add(managementContext.getLocationRegistry().resolve((String)targetSpec));
+ } else {
+ Set<?> keys = ((Map<?,?>)targetSpec).keySet();
+ if (keys.size()!=1)
+ throw new IllegalArgumentException("targets supplied to MultiLocation must be a list of single-entry maps (got map of size "+keys.size()+": "+targetSpec+")");
+ Object key = keys.iterator().next();
+ Object flagsS = ((Map<?,?>)targetSpec).get(key);
+ targets.add(managementContext.getLocationRegistry().resolve((String)key, (Map<?,?>)flagsS));
+ }
+ }
+ } else throw new IllegalArgumentException("targets must be supplied to MultiLocation, either as string spec or list of single-entry maps each being a location spec");
+
+ MultiLocation result = managementContext.getLocationManager().createLocation(LocationSpec.create(MultiLocation.class)
+ .configure(flags)
+ .configure("subLocations", targets)
+ .configure(LocationConfigUtils.finalAndOriginalSpecs(spec, locationFlags, globalProperties, namedLocation)));
+
+ // TODO Important workaround for BasicLocationRegistry.resolveForPeeking.
+ // That creates a location (from the resolver) and immediately unmanages it.
+ // The unmanage *must* remove all the targets created here; otherwise we have a leak.
+ // Adding the targets as children achieves this.
+ for (Location target : targets) {
+ target.setParent(result);
+ }
+ return result;
+
+ } catch (Exception e) {
+ // Must clean up after ourselves: don't leak sub-locations on error
+ if (LOG.isDebugEnabled()) LOG.debug("Problem resolving MultiLocation; cleaning up any sub-locations and rethrowing: "+e);
+ for (Location target : targets) {
+ Locations.unmanage(target);
+ }
+ throw Exceptions.propagate(e);
+ }
+ }
+
+ @Override
+ public String getPrefix() {
+ return MULTI;
+ }
+
+ @Override
+ public boolean accepts(String spec, LocationRegistry registry) {
+ return BasicLocationRegistry.isResolverPrefixForSpec(this, spec, true);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/NamedLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/NamedLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/core/NamedLocationResolver.java
new file mode 100644
index 0000000..08976de
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/NamedLocationResolver.java
@@ -0,0 +1,97 @@
+/*
+ * 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.location.core;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationDefinition;
+import org.apache.brooklyn.api.location.LocationRegistry;
+import org.apache.brooklyn.api.location.LocationResolver;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.location.core.internal.LocationInternal;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.text.Strings;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Allows you to say, in your brooklyn.properties:
+ *
+ * brooklyn.location.named.foo=localhost
+ * brooklyn.location.named.foo.user=bob
+ * brooklyn.location.named.foo.privateKeyFile=~/.ssh/custom-key-for-bob
+ * brooklyn.location.named.foo.privateKeyPassphrase=WithAPassphrase
+ * <p>
+ * or
+ * <p>
+ * brooklyn.location.named.bob-aws-east=jclouds:aws-ec2:us-east-1
+ * brooklyn.location.named.bob-aws-east.identity=BobId
+ * brooklyn.location.named.bob-aws-east.credential=BobCred
+ * <p>
+ * then you can simply refer to: foo or named:foo (or bob-aws-east or named:bob-aws-east) in any location spec
+ */
+public class NamedLocationResolver implements LocationResolver {
+
+ public static final Logger log = LoggerFactory.getLogger(NamedLocationResolver.class);
+
+ public static final String NAMED = "named";
+
+ @SuppressWarnings("unused")
+ private ManagementContext managementContext;
+
+ @Override
+ public void init(ManagementContext managementContext) {
+ this.managementContext = checkNotNull(managementContext, "managementContext");
+ }
+
+ @Override
+ @SuppressWarnings({ "rawtypes" })
+ public Location newLocationFromString(Map locationFlags, String spec, LocationRegistry registry) {
+ String name = spec;
+ ConfigBag lfBag = ConfigBag.newInstance(locationFlags).putIfAbsent(LocationInternal.ORIGINAL_SPEC, name);
+ name = Strings.removeFromStart(spec, getPrefix()+":");
+ if (name.toLowerCase().startsWith(NAMED+":")) {
+ // since 0.7.0
+ log.warn("Deprecated use of 'named:' prefix with wrong case ("+spec+"); support may be removed in future versions");
+ name = spec.substring( (NAMED+":").length() );
+ }
+
+ LocationDefinition ld = registry.getDefinedLocationByName(name);
+ if (ld==null) throw new NoSuchElementException("No named location defined matching '"+name+"'");
+ return ((BasicLocationRegistry)registry).resolveLocationDefinition(ld, lfBag.getAllConfig(), name);
+ }
+
+ @Override
+ public String getPrefix() {
+ return NAMED;
+ }
+
+ /** accepts anything starting named:xxx or xxx where xxx is a defined location name */
+ @Override
+ public boolean accepts(String spec, LocationRegistry registry) {
+ if (BasicLocationRegistry.isResolverPrefixForSpec(this, spec, false)) return true;
+ if (registry.getDefinedLocationByName(spec)!=null) return true;
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/PortRanges.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/PortRanges.java b/core/src/main/java/org/apache/brooklyn/location/core/PortRanges.java
new file mode 100644
index 0000000..72346f1
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/PortRanges.java
@@ -0,0 +1,257 @@
+/*
+ * 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.location.core;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.brooklyn.api.location.PortRange;
+import org.apache.brooklyn.util.core.flags.TypeCoercions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+
+public class PortRanges {
+
+ public static final int MAX_PORT = 65535;
+ public static final PortRange ANY_HIGH_PORT = new LinearPortRange(1024, MAX_PORT);
+
+ public static class SinglePort implements PortRange, Serializable {
+ private static final long serialVersionUID = 7446781416534230401L;
+
+ final int port;
+ private SinglePort(int port) { this.port = port; }
+
+ @Override
+ public Iterator<Integer> iterator() {
+ return Collections.singletonList(port).iterator();
+ }
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+ @Override
+ public boolean asBoolean() {
+ return true;
+ }
+ @Override
+ public String toString() {
+ return //getClass().getName()+"["+
+ ""+port; //+"]";
+ }
+ public int hashCode() {
+ return Objects.hashCode(port);
+ }
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof SinglePort) && port == ((SinglePort)obj).port;
+ }
+ }
+
+ public static class LinearPortRange implements PortRange, Serializable {
+ private static final long serialVersionUID = -9165280509363743508L;
+
+ final int start, end, delta;
+ private LinearPortRange(int start, int end, int delta) {
+ this.start = start;
+ this.end = end;
+ this.delta = delta;
+ checkArgument(start > 0 && start <= MAX_PORT, "start port %s out of range", start);
+ checkArgument(end > 0 && end <= MAX_PORT, "end port %s out of range", end);
+ checkArgument(delta > 0 ? start <= end : start >= end, "start and end out of order: %s to %s, delta %s", start, end, delta);
+ checkArgument(delta != 0, "delta must be non-zero");
+ }
+ public LinearPortRange(int start, int end) {
+ this(start, end, (start<=end?1:-1));
+ }
+
+ @Override
+ public Iterator<Integer> iterator() {
+ return new Iterator<Integer>() {
+ int next = start;
+ boolean hasNext = true;
+
+ @Override
+ public boolean hasNext() {
+ return hasNext;
+ }
+
+ @Override
+ public Integer next() {
+ if (!hasNext)
+ throw new NoSuchElementException("Exhausted available ports");
+ int result = next;
+ next += delta;
+ if ((delta>0 && next>end) || (delta<0 && next<end)) hasNext = false;
+ return result;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+ @Override
+ public boolean asBoolean() {
+ return true;
+ }
+ @Override
+ public String toString() {
+ return //getClass().getName()+"["+
+ start+"-"+end; //+"]";
+ }
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(start, end, delta);
+ }
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof LinearPortRange)) return false;
+ LinearPortRange o = (LinearPortRange) obj;
+ return start == o.start && end == o.end && delta == o.delta;
+ }
+ }
+
+ public static class AggregatePortRange implements PortRange, Serializable {
+ private static final long serialVersionUID = 7332682500816739660L;
+
+ final List<PortRange> ranges;
+ private AggregatePortRange(List<PortRange> ranges) {
+ this.ranges = ImmutableList.copyOf(ranges);
+ }
+ @Override
+ public Iterator<Integer> iterator() {
+ return Iterables.concat(ranges).iterator();
+ }
+ @Override
+ public boolean isEmpty() {
+ for (PortRange r: ranges)
+ if (!r.isEmpty()) return false;
+ return true;
+ }
+ @Override
+ public boolean asBoolean() {
+ return !isEmpty();
+ }
+ @Override
+ public String toString() {
+ String s = "";
+ for (PortRange r: ranges) {
+ if (s.length()>0) s+=",";
+ s += r;
+ }
+ return //getClass().getName()+"["+
+ s; //+"]";
+ }
+ public int hashCode() {
+ return Objects.hashCode(ranges);
+ }
+ @Override
+ public boolean equals(Object obj) {
+ return (obj instanceof AggregatePortRange) && ranges.equals(((AggregatePortRange)obj).ranges);
+ }
+ }
+
+ public static PortRange fromInteger(int x) {
+ return new SinglePort(x);
+ }
+
+ public static PortRange fromCollection(Collection<?> c) {
+ List<PortRange> l = new ArrayList<PortRange>();
+ for (Object o: c) {
+ if (o instanceof Integer) l.add(fromInteger((Integer)o));
+ else if (o instanceof String) l.add(fromString((String)o));
+ else if (o instanceof Collection) l.add(fromCollection((Collection<?>)o));
+ else l.add(TypeCoercions.coerce(o, PortRange.class));
+ }
+ return new AggregatePortRange(l);
+ }
+
+ /** parses a string representation of ports, as "80,8080,8000,8080-8099" */
+ public static PortRange fromString(String s) {
+ List<PortRange> l = new ArrayList<PortRange>();
+ for (String si: s.split(",")) {
+ si = si.trim();
+ int start, end;
+ if (si.endsWith("+")) {
+ String si2 = si.substring(0, si.length()-1).trim();
+ start = Integer.parseInt(si2);
+ end = MAX_PORT;
+ } else if (si.indexOf('-')>0) {
+ int v = si.indexOf('-');
+ start = Integer.parseInt(si.substring(0, v).trim());
+ end = Integer.parseInt(si.substring(v+1).trim());
+ } else if (si.length()==0) {
+ //nothing, ie empty range, just continue
+ continue;
+ } else {
+ //should be number on its own
+ l.add(new SinglePort(Integer.parseInt(si)));
+ continue;
+ }
+ l.add(new LinearPortRange(start, end));
+ }
+ if (l.size() == 1) {
+ return l.get(0);
+ } else {
+ return new AggregatePortRange(l);
+ }
+ }
+
+ private static AtomicBoolean initialized = new AtomicBoolean(false);
+ /** performs the language extensions required for this project */
+ @SuppressWarnings("rawtypes")
+ public static void init() {
+ if (initialized.get()) return;
+ synchronized (initialized) {
+ if (initialized.get()) return;
+ TypeCoercions.registerAdapter(Integer.class, PortRange.class, new Function<Integer,PortRange>() {
+ public PortRange apply(Integer x) { return fromInteger(x); }
+ });
+ TypeCoercions.registerAdapter(String.class, PortRange.class, new Function<String,PortRange>() {
+ public PortRange apply(String x) { return fromString(x); }
+ });
+ TypeCoercions.registerAdapter(Collection.class, PortRange.class, new Function<Collection,PortRange>() {
+ public PortRange apply(Collection x) { return fromCollection(x); }
+ });
+ initialized.set(true);
+ }
+ }
+
+ static {
+ init();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/RegistryLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/RegistryLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/core/RegistryLocationResolver.java
new file mode 100644
index 0000000..9ac62d7
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/RegistryLocationResolver.java
@@ -0,0 +1,42 @@
+/*
+ * 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.location.core;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationRegistry;
+import org.apache.brooklyn.api.location.LocationResolver;
+
+/**
+ * Extension to LocationResolver which can take a registry.
+ *
+ * @deprecated since 0.6; the LocationResolver always takes the LocationRegistry now
+ */
+@Deprecated
+public interface RegistryLocationResolver extends LocationResolver {
+
+ @Override
+ @SuppressWarnings("rawtypes")
+ Location newLocationFromString(Map locationFlags, String spec, LocationRegistry registry);
+
+ @Override
+ boolean accepts(String spec, LocationRegistry registry);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/SupportsPortForwarding.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/SupportsPortForwarding.java b/core/src/main/java/org/apache/brooklyn/location/core/SupportsPortForwarding.java
new file mode 100644
index 0000000..d0af5a4
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/SupportsPortForwarding.java
@@ -0,0 +1,39 @@
+/*
+ * 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.location.core;
+
+import org.apache.brooklyn.util.net.Cidr;
+
+import com.google.common.net.HostAndPort;
+
+public interface SupportsPortForwarding {
+
+ /** returns an endpoint suitable for contacting the indicated private port on this object,
+ * from the given Cidr, creating it if necessary and possible;
+ * may return null if forwarding not available
+ */
+ public HostAndPort getSocketEndpointFor(Cidr accessor, int privatePort);
+
+ /** marker on a location to indicate that port forwarding should be done automatically
+ * for attempts to access from Brooklyn
+ */
+ public interface RequiresPortForwarding extends SupportsPortForwarding {
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationDynamicType.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationDynamicType.java b/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationDynamicType.java
new file mode 100644
index 0000000..83316ec
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationDynamicType.java
@@ -0,0 +1,40 @@
+/*
+ * 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.location.core.internal;
+
+import org.apache.brooklyn.core.objs.BrooklynDynamicType;
+import org.apache.brooklyn.location.core.AbstractLocation;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationType;
+
+public class LocationDynamicType extends BrooklynDynamicType<Location, AbstractLocation> {
+
+ public LocationDynamicType(AbstractLocation location) {
+ super(location);
+ }
+
+ public LocationType getSnapshot() {
+ return (LocationType) super.getSnapshot();
+ }
+
+ @Override
+ protected LocationTypeSnapshot newSnapshot() {
+ return new LocationTypeSnapshot(name, value(configKeys));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationInternal.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationInternal.java b/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationInternal.java
new file mode 100644
index 0000000..9ec449b
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationInternal.java
@@ -0,0 +1,93 @@
+/*
+ * 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.location.core.internal;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+import org.apache.brooklyn.api.mgmt.rebind.RebindSupport;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.LocationMemento;
+import org.apache.brooklyn.config.ConfigInheritance;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+import org.apache.brooklyn.core.objs.BrooklynObjectInternal;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Information about locations private to Brooklyn.
+ */
+public interface LocationInternal extends BrooklynObjectInternal, Location {
+
+ @Beta
+ public static final ConfigKey<String> ORIGINAL_SPEC = ConfigKeys.newStringConfigKey("spec.original", "The original spec used to instantiate a location");
+ @Beta
+ public static final ConfigKey<String> FINAL_SPEC = ConfigKeys.newStringConfigKey("spec.final", "The actual spec (in a chain) which instantiates a location");
+ @Beta
+ public static final ConfigKey<String> NAMED_SPEC_NAME = ConfigKeys.newStringConfigKey("spec.named.name", "The name on the (first) named spec in a chain");
+
+ /**
+ * Registers the given extension for the given type. If an extension already existed for
+ * this type, then this will override it.
+ *
+ * @throws NullPointerException if extensionType or extension are null
+ * @throws IllegalArgumentException if extension does not implement extensionType
+ */
+ <T> void addExtension(Class<T> extensionType, T extension);
+
+ /**
+ * Get a record of the metadata of this location.
+ * <p/>
+ * <p>Metadata records are used to record an audit trail of events relating to location usage
+ * (for billing purposes, for example). Implementations (and subclasses) should override this
+ * method to return information useful for this purpose.</p>
+ *
+ * @return
+ */
+ public Map<String, String> toMetadataRecord();
+
+ /**
+ * @deprecated since 0.7.0; use {@link #config()}, such as {@code ((LocationInternal)location).config().getLocalBag()}
+ */
+ @Deprecated
+ ConfigBag getLocalConfigBag();
+
+ /**
+ * Returns all config, including that inherited from parents.
+ *
+ * This method does not respect {@link ConfigInheritance} and so usage is discouraged.
+ *
+ * @deprecated since 0.7.0; use {@link #config()}, such as {@code ((LocationInternal)location).config().getBag()}
+ */
+ @Deprecated
+ ConfigBag getAllConfigBag();
+
+ /**
+ * Users are strongly discouraged from calling or overriding this method.
+ * It is for internal calls only, relating to persisting/rebinding entities.
+ * This method may change (or be removed) in a future release without notice.
+ */
+ @Override
+ @Beta
+ RebindSupport<LocationMemento> getRebindSupport();
+
+ ManagementContext getManagementContext();
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationTypeSnapshot.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationTypeSnapshot.java b/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationTypeSnapshot.java
new file mode 100644
index 0000000..b272b72
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/core/internal/LocationTypeSnapshot.java
@@ -0,0 +1,40 @@
+/*
+ * 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.location.core.internal;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.sensor.EnricherType;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.objs.BrooklynTypeSnapshot;
+
+public class LocationTypeSnapshot extends BrooklynTypeSnapshot implements EnricherType {
+
+ private static final long serialVersionUID = 9150132836104748237L;
+
+ LocationTypeSnapshot(String name, Map<String, ConfigKey<?>> configKeys) {
+ super(name, configKeys);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ return (obj instanceof LocationTypeSnapshot) && super.equals(obj);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/geo/HostGeoInfo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/geo/HostGeoInfo.java b/core/src/main/java/org/apache/brooklyn/location/geo/HostGeoInfo.java
index dde47a6..fc88cd2 100644
--- a/core/src/main/java/org/apache/brooklyn/location/geo/HostGeoInfo.java
+++ b/core/src/main/java/org/apache/brooklyn/location/geo/HostGeoInfo.java
@@ -26,8 +26,8 @@ import javax.annotation.Nullable;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.api.location.AddressableLocation;
import org.apache.brooklyn.api.location.Location;
-import org.apache.brooklyn.location.basic.AbstractLocation;
-import org.apache.brooklyn.location.basic.LocationConfigKeys;
+import org.apache.brooklyn.location.core.AbstractLocation;
+import org.apache.brooklyn.location.core.LocationConfigKeys;
import org.apache.brooklyn.util.core.flags.TypeCoercions;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.guava.Maybe;
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/a1ad34d7/core/src/main/java/org/apache/brooklyn/location/localhost/LocalhostLocationResolver.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/location/localhost/LocalhostLocationResolver.java b/core/src/main/java/org/apache/brooklyn/location/localhost/LocalhostLocationResolver.java
new file mode 100644
index 0000000..37d885d
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/location/localhost/LocalhostLocationResolver.java
@@ -0,0 +1,76 @@
+/*
+ * 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.location.localhost;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.location.LocationRegistry;
+import org.apache.brooklyn.api.location.LocationResolver;
+import org.apache.brooklyn.location.core.AbstractLocationResolver;
+import org.apache.brooklyn.location.core.LocationConfigUtils;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+
+/**
+ * Examples of valid specs:
+ * <ul>
+ * <li>localhost
+ * <li>localhost()
+ * <li>localhost(name=abc)
+ * <li>localhost(name="abc")
+ * </ul>
+ *
+ * @author alex, aled
+ */
+public class LocalhostLocationResolver extends AbstractLocationResolver implements LocationResolver.EnableableLocationResolver {
+
+ public static final String LOCALHOST = "localhost";
+
+ @Override
+ public String getPrefix() {
+ return LOCALHOST;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return LocationConfigUtils.isEnabled(managementContext, "brooklyn.location.localhost");
+ }
+
+ @Override
+ protected Class<? extends Location> getLocationType() {
+ return LocalhostMachineProvisioningLocation.class;
+ }
+
+ @Override
+ protected SpecParser getSpecParser() {
+ return new AbstractLocationResolver.SpecParser(getPrefix()).setExampleUsage("\"localhost\" or \"localhost(displayName=abc)\"");
+ }
+
+ @Override
+ protected Map<String, Object> getFilteredLocationProperties(String provider, String namedLocation, Map<String, ?> globalProperties) {
+ return new LocalhostPropertiesFromBrooklynProperties().getLocationProperties("localhost", namedLocation, globalProperties);
+ }
+
+ @Override
+ protected ConfigBag extractConfig(Map<?,?> locationFlags, String spec, LocationRegistry registry) {
+ ConfigBag config = super.extractConfig(locationFlags, spec, registry);
+ config.putAsStringKeyIfAbsent("name", "localhost");
+ return config;
+ }
+}