http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/downloads/DownloadResolver.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/drivers/downloads/DownloadResolver.java b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/downloads/DownloadResolver.java new file mode 100644 index 0000000..56befa4 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/downloads/DownloadResolver.java @@ -0,0 +1,58 @@ +/* + * 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.api.entity.drivers.downloads; + +import java.util.List; + +import com.google.common.annotations.Beta; + +/** + * Gives download details for an entity or an entity add-on. + * Returned by the {@link DownloadResolverManager}, when queried for a specific entity or entity add-on. + * + * @author aled + */ +public interface DownloadResolver { + /** + * The targets (normally URLs) for downloading the artifact. These should be tried in-order + * until one works. + */ + public List<String> getTargets(); + + /** + * The name of the artifact. + * The caller is free to use this name, or not. But using this name gives consistency particularly + * between brooklyn local-repos and brooklyn install directories. + */ + public String getFilename(); + + /** + * The name of the directory in the expanded artifact (e.g. if it's a tar.gz file then the name of + * the directory within it). If no value is known, the defaultVal will be returned. + * + * This can return null if the artifact is not an archive (and if defaultVal is null). + * + * TODO The driver needs to know what will happen when an install archive is unpacked (e.g. an + * AS7 install tgz may be automatically expanded into a directory named "jboss-as-7.1.1-FINAL"). + * However, it's unclear where the best place to encode that is. The driver supplying the default + * seems sensible. + */ + @Beta + public String getUnpackedDirectoryName(String defaultVal); +}
http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/downloads/DownloadResolverManager.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/drivers/downloads/DownloadResolverManager.java b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/downloads/DownloadResolverManager.java new file mode 100644 index 0000000..3597041 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/downloads/DownloadResolverManager.java @@ -0,0 +1,158 @@ +/* + * 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.api.entity.drivers.downloads; + +import java.util.List; +import java.util.Map; + +import org.apache.brooklyn.api.entity.drivers.EntityDriver; + +import com.google.common.base.Function; + +/** + * Used by an {@link EntityDriver} to obtain the download locations when installing an entity. + * + * Most commonly, the {@link DownloadResolver}'s targets are URIs. However, an EntityDriver + * implementation is free to interpret the String however is appropriate (e.g. the name of a + * custom package to install from the enterprise's package manager repository). + + * Also supports registering other "resolvers" for determining where to download the installers + * from, for different entities. + * + * When using {@link resolve(EntityDriver)} to get the list of things to try (in-order until one succeeds), + * the manager will go through each of the registered resolvers in-order to get their contributions. + * These contributions are split into "primary" and "fallback". All of the primaries will be added to the + * list first, and then all of the fallbacks. + * + * @author aled + */ +public interface DownloadResolverManager { + + /** + * For installing the main entity. + * Returns a list of options, to be tried in order until one of them works. + */ + public DownloadResolver newDownloader(EntityDriver driver); + + /** + * For installing the main entity. + * Returns a list of options, to be tried in order until one of them works. + */ + public DownloadResolver newDownloader(EntityDriver driver, Map<String,?> properties); + + /** + * For installing an entity add-on. + * Returns a list of options, to be tried in order until one of them works. + * This is used for resolving the download for an "add-on" - e.g. an additional module required + * during an entity's installation. Common properties include: + * <ul> + * <li>addonversion: the required version of the add-on + * </ul> + */ + public DownloadResolver newDownloader(EntityDriver driver, String addonName, Map<String,?> addonProperties); + + /** + * Registers a producer, to be tried before all other producers. + * + * A "producer" will generate the download targets to be tried, when installing a given entity + * or entity add-on. + * + * The function should not return null (instead see {@code BasicDownloadTargets.empty()}). + * + * @see registerResolver(Function) + */ + public void registerPrimaryProducer(Function<? super DownloadRequirement, ? extends DownloadTargets> resolver); + + /** + * Registers a producer, to be tried after all other registered producers have been tried. + * The function should not return null (instead see {@code BasicDownloadTargets.empty()}). + */ + public void registerProducer(Function<? super DownloadRequirement, ? extends DownloadTargets> resolver); + + /** + * Registers a producer for generating the expected filename of the download artifact. + * + * If all such registered producers return null, then default behaviour is to infer the download + * name from the first target in the {@link resolve(EntityDriver)} result. + */ + public void registerFilenameProducer(Function<? super DownloadRequirement, String> producer); + + /** + * Gives artifact meta-data for what is required to be downloaded. + * + * @author aled + */ + public interface DownloadRequirement { + /** + * The {@link EntityDriver} that this download is for. + */ + public EntityDriver getEntityDriver(); + + /** + * The name of the add-on to be downloaded, or null if it is the main installed. + * For example, can be used to specify nginx sticky-module or pcre download. + */ + public String getAddonName(); + + /** + * Default properties for this download. These will be made available when resolving the + * download template. + * + * For the main entity download, properties include: + * <ul> + * <li>fileSuffix: expected file suffix + * </ul> + * + * For an add-on, common properties include: + * <ul> + * <li>version: version of the add-on to be used + * <li>fileSuffix: expected file suffix + * </ul> + */ + public Map<String, ?> getProperties(); + } + + + /** + * Describes the download locations, and their order, to try. + * + * @author aled + */ + public interface DownloadTargets { + /** + * Gets the locations to try (in-order). + */ + public List<String> getPrimaryLocations(); + + /** + * Gets the locations to try (in-order), to be used only after all primary locations + * have been tried. + */ + public List<String> getFallbackLocations(); + + /** + * Indicates whether or not the results of this resolver are the last that should be used. + * If returns false, {@link resolve(EntityDriver)} will not iterate over any other resolvers. + * + * For example, useful in an enterprise to disable any other resolvers that would have + * resulted in going out to the public internet. + */ + public boolean canContinueResolving(); + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java new file mode 100644 index 0000000..789d282 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/internal/AbstractBrooklynObjectSpec.java @@ -0,0 +1,319 @@ +/* + * 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.api.internal; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.Serializable; +import java.lang.reflect.Modifier; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.brooklyn.api.mgmt.EntityManager; +import org.apache.brooklyn.api.mgmt.Task; +import org.apache.brooklyn.api.objs.BrooklynObject; +import org.apache.brooklyn.api.objs.SpecParameter; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.config.ConfigKey.HasConfigKey; +import org.apache.brooklyn.util.collections.MutableSet; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.annotations.Beta; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.common.collect.Maps; + +/** Defines a spec for creating a {@link BrooklynObject}. + * <p> + * In addition to the contract defined by the code, + * subclasses should provide a public static <code>create(Class)</code> + * method to create an instance of the spec for the target type indicated by the argument. + * <p> + * The spec is then passed to type-specific methods, + * e.g. {@link EntityManager#createEntity(org.apache.brooklyn.api.entity.EntitySpec)} + * to create a managed instance of the target type. */ +public abstract class AbstractBrooklynObjectSpec<T,SpecT extends AbstractBrooklynObjectSpec<T,SpecT>> implements Serializable { + + private static final long serialVersionUID = 3010955277740333030L; + + private static final Logger log = LoggerFactory.getLogger(AbstractBrooklynObjectSpec.class); + + private final Class<? extends T> type; + private String displayName; + private String catalogItemId; + private Set<Object> tags = MutableSet.of(); + private List<SpecParameter<?>> parameters = ImmutableList.of(); + + protected final Map<String, Object> flags = Maps.newLinkedHashMap(); + protected final Map<ConfigKey<?>, Object> config = Maps.newLinkedHashMap(); + + protected AbstractBrooklynObjectSpec(Class<? extends T> type) { + checkValidType(type); + this.type = type; + this.catalogItemId = ApiObjectsFactory.get().getCatalogItemIdFromContext(); + } + + @SuppressWarnings("unchecked") + protected SpecT self() { + return (SpecT) this; + } + + @Override + public String toString() { + return Objects.toStringHelper(this).add("type", getType()).toString()+"@"+Integer.toHexString(System.identityHashCode(this)); + } + + protected abstract void checkValidType(Class<? extends T> type); + + public SpecT displayName(String val) { + displayName = val; + return self(); + } + + public SpecT catalogItemId(String val) { + catalogItemId = val; + return self(); + } + // TODO in many places (callers to this method) we prefer a wrapper item ID; + // that is right, because the wrapper's defn will refer to the wrapped, + // but we might need also to collect the item ID's so that *all* can be searched. + // e.g. if R3 references R2 which references R1 any one of these might supply config keys + // referencing resources or types in their local bundles. + @Beta + public SpecT catalogItemIdIfNotNull(String val) { + if (val!=null) { + catalogItemId = val; + } + return self(); + } + + + public SpecT tag(Object tag) { + tags.add(tag); + return self(); + } + + /** adds the given tags */ + public SpecT tags(Iterable<Object> tagsToAdd) { + return tagsAdd(tagsToAdd); + } + /** adds the given tags */ + public SpecT tagsAdd(Iterable<Object> tagsToAdd) { + Iterables.addAll(this.tags, tagsToAdd); + return self(); + } + /** replaces tags with the given */ + public SpecT tagsReplace(Iterable<Object> tagsToReplace) { + this.tags.clear(); + Iterables.addAll(this.tags, tagsToReplace); + return self(); + } + + // TODO which semantics are correct? replace has been the behaviour; + // add breaks tests and adds unwanted parameters, + // but replacing will cause some desired parameters to be lost. + // i (AH) think ideally the caller should remove any parameters which + // have been defined as config keys, and then add the others; + // or actually we should always add, since this is really defining the config keys, + // and maybe extend the SpecParameter object to be able to advertise whether + // it is a CatalogConfig or merely a config key, maybe introducing displayable, or even priority + // (but note part of the reason for CatalogConfig.priority is that java reflection doesn't preserve field order) . + // see also comments on the camp SpecParameterResolver. + @Beta + public SpecT parameters(List<? extends SpecParameter<?>> parameters) { + return parametersReplace(parameters); + } + /** adds the given parameters */ + @Beta + public SpecT parametersAdd(List<? extends SpecParameter<?>> parameters) { + // parameters follows immutable pattern, unlike the other fields + Builder<SpecParameter<?>> result = ImmutableList.<SpecParameter<?>>builder(); + if (this.parameters!=null) + result.addAll(this.parameters); + result.addAll( checkNotNull(parameters, "parameters") ); + this.parameters = result.build(); + return self(); + } + /** replaces parameters with the given */ + @Beta + public SpecT parametersReplace(List<? extends SpecParameter<?>> parameters) { + this.parameters = ImmutableList.copyOf( checkNotNull(parameters, "parameters") ); + return self(); + } + + /** + * @return The type (often an interface) this spec represents and which will be instantiated from it + */ + public Class<? extends T> getType() { + return type; + } + + /** + * @return The display name of the object + */ + public final String getDisplayName() { + return displayName; + } + + public final String getCatalogItemId() { + return catalogItemId; + } + + public final Set<Object> getTags() { + return ImmutableSet.copyOf(tags); + } + + /** A list of configuration options that the entity supports. */ + public final List<SpecParameter<?>> getParameters() { + //Could be null after rebind + if (parameters != null) { + return ImmutableList.copyOf(parameters); + } else { + return ImmutableList.of(); + } + } + + // TODO Duplicates method in BasicEntityTypeRegistry and InternalEntityFactory.isNewStyleEntity + protected final void checkIsNewStyleImplementation(Class<?> implClazz) { + try { + implClazz.getConstructor(new Class[0]); + } catch (NoSuchMethodException e) { + throw new IllegalStateException("Implementation "+implClazz+" must have a no-argument constructor"); + } catch (SecurityException e) { + throw Exceptions.propagate(e); + } + + if (implClazz.isInterface()) throw new IllegalStateException("Implementation "+implClazz+" is an interface, but must be a non-abstract class"); + if (Modifier.isAbstract(implClazz.getModifiers())) throw new IllegalStateException("Implementation "+implClazz+" is abstract, but must be a non-abstract class"); + } + + // TODO Duplicates method in BasicEntityTypeRegistry + protected final void checkIsImplementation(Class<?> val, Class<? super T> requiredInterface) { + if (!requiredInterface.isAssignableFrom(val)) throw new IllegalStateException("Implementation "+val+" does not implement "+requiredInterface.getName()); + if (val.isInterface()) throw new IllegalStateException("Implementation "+val+" is an interface, but must be a non-abstract class"); + if (Modifier.isAbstract(val.getModifiers())) throw new IllegalStateException("Implementation "+val+" is abstract, but must be a non-abstract class"); + } + + protected SpecT copyFrom(SpecT otherSpec) { + return displayName(otherSpec.getDisplayName()) + .configure(otherSpec.getConfig()) + .configure(otherSpec.getFlags()) + .tags(otherSpec.getTags()) + .catalogItemId(otherSpec.getCatalogItemId()) + .parameters(otherSpec.getParameters()); + } + + @Override + public boolean equals(Object obj) { + if (obj==null) return false; + if (!obj.getClass().equals(getClass())) return false; + AbstractBrooklynObjectSpec<?,?> other = (AbstractBrooklynObjectSpec<?,?>)obj; + if (!Objects.equal(getDisplayName(), other.getDisplayName())) return false; + if (!Objects.equal(getCatalogItemId(), other.getCatalogItemId())) return false; + if (!Objects.equal(getType(), other.getType())) return false; + if (!Objects.equal(getTags(), other.getTags())) return false; + if (!Objects.equal(getParameters(), other.getParameters())) return false; + return true; + } + + @Override + public int hashCode() { + return Objects.hashCode(getCatalogItemId(), getDisplayName(), getType(), getTags()); + } + + /** strings inserted as flags, config keys inserted as config keys; + * if you want to force one or the other, create a ConfigBag and convert to the appropriate map type */ + public SpecT configure(Map<?,?> val) { + for (Map.Entry<?, ?> entry: val.entrySet()) { + if (entry.getKey()==null) throw new NullPointerException("Null key not permitted"); + if (entry.getKey() instanceof CharSequence) + flags.put(entry.getKey().toString(), entry.getValue()); + else if (entry.getKey() instanceof ConfigKey<?>) + config.put((ConfigKey<?>)entry.getKey(), entry.getValue()); + else if (entry.getKey() instanceof HasConfigKey<?>) + config.put(((HasConfigKey<?>)entry.getKey()).getConfigKey(), entry.getValue()); + else { + log.warn("Spec "+this+" ignoring unknown config key "+entry.getKey()); + } + } + return self(); + } + + public SpecT configure(CharSequence key, Object val) { + flags.put(checkNotNull(key, "key").toString(), val); + return self(); + } + + public <V> SpecT configure(ConfigKey<V> key, V val) { + config.put(checkNotNull(key, "key"), val); + return self(); + } + + public <V> SpecT configureIfNotNull(ConfigKey<V> key, V val) { + return (val != null) ? configure(key, val) : self(); + } + + public <V> SpecT configure(ConfigKey<V> key, Task<? extends V> val) { + config.put(checkNotNull(key, "key"), val); + return self(); + } + + public <V> SpecT configure(HasConfigKey<V> key, V val) { + config.put(checkNotNull(key, "key").getConfigKey(), val); + return self(); + } + + public <V> SpecT configure(HasConfigKey<V> key, Task<? extends V> val) { + config.put(checkNotNull(key, "key").getConfigKey(), val); + return self(); + } + + public <V> SpecT removeConfig(ConfigKey<V> key) { + config.remove( checkNotNull(key, "key") ); + return self(); + } + + /** Clears the config map, removing any config previously set. */ + public void clearConfig() { + config.clear(); + } + + /** + * @return Read-only construction flags + * @see SetFromFlag declarations on the policy type + */ + public Map<String, ?> getFlags() { + return Collections.unmodifiableMap(flags); + } + + /** + * @return Read-only configuration values + */ + public Map<ConfigKey<?>, Object> getConfig() { + return Collections.unmodifiableMap(config); + } + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/internal/ApiObjectsFactory.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/ApiObjectsFactory.java b/api/src/main/java/org/apache/brooklyn/api/internal/ApiObjectsFactory.java new file mode 100644 index 0000000..51c0185 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/internal/ApiObjectsFactory.java @@ -0,0 +1,61 @@ +/* + * 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.api.internal; + +import java.util.ServiceLoader; + +import org.apache.brooklyn.util.guava.Maybe; + +import com.google.common.annotations.Beta; + +/** + * This class grants access to implementations in core for operations needed in API classes. + * The majority of the API classes are interfaces or have minimal behaviour, but there are a + * few instances where more complex behaviour from core is desired. + * <p> + * This class acts as a bridge for those instances. See the concrete implementation of the + * {@link ApiObjectsFactoryInterface} in brooklyn-core class ApiObjectsFactoryImpl. + */ +@Beta +public class ApiObjectsFactory { + + private static Maybe<ApiObjectsFactoryInterface> INSTANCE; + + private static synchronized ApiObjectsFactoryInterface getFactoryInstance() { + // defer initialization to allow any other static initialization to complete, + // and use maybe so we (1) don't check multiple times, but (2) do throw error in the caller's stack + if (INSTANCE!=null) return INSTANCE.get(); + + ServiceLoader<ApiObjectsFactoryInterface> LOADER = ServiceLoader.load(ApiObjectsFactoryInterface.class); + for (ApiObjectsFactoryInterface item : LOADER) { + INSTANCE = Maybe.of(item); + return INSTANCE.get(); + } + INSTANCE = Maybe.absent("Implementation of " + ApiObjectsFactoryInterface.class + " not found on classpath; " + + "can be caused by IDE not copying resources, or by something else clobbering non-class resources needed for service loading"); + return INSTANCE.get(); + } + + /** + * Create (if necessary) and return the concrete implementation from core for the + * methods exposed here. */ + public static ApiObjectsFactoryInterface get() { + return getFactoryInstance(); + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/internal/ApiObjectsFactoryInterface.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/internal/ApiObjectsFactoryInterface.java b/api/src/main/java/org/apache/brooklyn/api/internal/ApiObjectsFactoryInterface.java new file mode 100644 index 0000000..6257524 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/internal/ApiObjectsFactoryInterface.java @@ -0,0 +1,29 @@ +/* + * 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.api.internal; + +/** + * Methods from downstream projects used in API classes at runtime. + * See {@link ApiObjectsFactory}. + */ +public interface ApiObjectsFactoryInterface { + + public String getCatalogItemIdFromContext(); + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/AddressableLocation.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/AddressableLocation.java b/api/src/main/java/org/apache/brooklyn/api/location/AddressableLocation.java new file mode 100644 index 0000000..31c3b29 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/AddressableLocation.java @@ -0,0 +1,43 @@ +/* + * 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.api.location; + +import java.net.InetAddress; + +/** A location that has an IP address. + * <p> + * This IP address may be a machine (usually the MachineLocation sub-interface), + * or often an entry point for a service. + */ +public interface AddressableLocation extends Location { + + /** + * Return the single most appropriate address for this location. + * (An implementation or sub-interface definition may supply more information + * on the precise semantics of the address.) + * + * Should not return null, but in some "special cases" (e.g. CloudFoundryLocation it + * may return null if the location is not configured correctly). Users should expect + * a non-null result and treat null as a programming error or misconfiguration. + * Implementors of this interface should strive to not return null (and then we'll + * remove this caveat from the javadoc!). + */ + InetAddress getAddress(); + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/BasicMachineLocationCustomizer.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/BasicMachineLocationCustomizer.java b/api/src/main/java/org/apache/brooklyn/api/location/BasicMachineLocationCustomizer.java new file mode 100644 index 0000000..99d4fee --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/BasicMachineLocationCustomizer.java @@ -0,0 +1,41 @@ +/* + * 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.api.location; + +import com.google.common.annotations.Beta; + +/** + * A default no-op implementation, which can be extended to override the appropriate methods. + * + * Sub-classing will give the user some protection against future API changes - note that + * {@link MachineLocationCustomizer} is marked {@link Beta}. + */ +@Beta +public class BasicMachineLocationCustomizer implements MachineLocationCustomizer { + + @Override + public void customize(MachineLocation machine) { + // no-op + } + + @Override + public void preRelease(MachineLocation machine) { + // no-op + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/HardwareDetails.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/HardwareDetails.java b/api/src/main/java/org/apache/brooklyn/api/location/HardwareDetails.java new file mode 100644 index 0000000..7e4cc49 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/HardwareDetails.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.api.location; + +import javax.annotation.Nullable; + +/** + * @since 0.7.0 + */ +public interface HardwareDetails { + + /** + * The number of CPUs on the machine + */ + @Nullable + Integer getCpuCount(); + + /** + * Amount of RAM in megabytes + */ + @Nullable + Integer getRam(); + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/Location.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/Location.java b/api/src/main/java/org/apache/brooklyn/api/location/Location.java new file mode 100644 index 0000000..ea43bfd --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/Location.java @@ -0,0 +1,137 @@ +/* + * 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.api.location; + +import java.util.Collection; +import java.util.Map; + +import org.apache.brooklyn.api.objs.BrooklynObject; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.config.ConfigKey.HasConfigKey; + +/** + * A location that an entity can be in. Examples of locations include a single machine + * or a pool of machines, or a region within a given cloud. + */ +public interface Location extends BrooklynObject { + + /** + * A unique id for this location. + */ + @Override + String getId(); + + /** + * Get the name assigned to this location. + * + * @return the name assigned to the location. + * @since 0.6 (previously getName()) + */ + @Override + String getDisplayName(); + + /** + * Get the 'parent' of this location. Locations are organized into a tree hierarchy, and this method will return a reference + * to the parent of this location, or {@code null} if this location is the tree root. + * + * @return a reference to the parent of this location, or {@code null} if this location is the tree root. + * @since 0.6 (previously getParentLocation()) + */ + Location getParent(); + + /** + * Get the 'children' of this location. Locations are organized into a tree hierarchy, and this method will return a + * collection containing the children of this location. This collection is an unmodifiable view of the data. + * + * @return a collection containing the children of this location. + * @since 0.6 (previously getChildLocations()) + */ + Collection<Location> getChildren(); + + /** + * Set the 'parent' of this location. If this location was previously a child of a different location, it is removed from + * the other location first. It is valid to pass in {@code null} to indicate that the location should be disconnected + * from its parent. + * + * Adds this location as a child of the new parent (see {@code getChildLocations()}). + * + * @param newParent the new parent location object, or {@code null} to clear the parent reference. + * @since 0.6 (previously setParentLocation(Location)) + */ + void setParent(Location newParent); + + /** + * @return meta-data about the location (usually a long line, or a small number of lines). + * + * @since 0.6 + */ + String toVerboseString(); + + /** + * Answers true if this location equals or is an ancestor of the given location. + */ + boolean containsLocation(Location potentialDescendent); + + /** + * Convenience method for {@code config().get(key)} + * + * @see {@link #getConfig(ConfigKey)} + */ + <T> T getConfig(HasConfigKey<T> key); + + /** + * True iff the indication config key is set, either inherited (second argument true) or locally-only (second argument false). + * + * @deprecated since 0.7.0; use {@link #config()}, such as {@code ((LocationInternal)location).config().getRaw(key).isPresent()} + */ + @Deprecated + boolean hasConfig(ConfigKey<?> key, boolean includeInherited); + + /** + * Returns all config set, either inherited (argument true) or locally-only (argument false). + * + * @deprecated since 0.7.0; use {@link #config()}, such as {@code policy.config().getBag()} + */ + @Deprecated + public Map<String,Object> getAllConfig(boolean includeInherited); + + /** + * Whether this location has support for the given extension type. + * See additional comments in {@link #getExtension(Class)}. + * + * @throws NullPointerException if extensionType is null + */ + boolean hasExtension(Class<?> extensionType); + + /** + * Returns an extension of the given type. Note that the type must be an exact match for + * how the extension was registered (e.g. {@code getExtension(Object.class)} will not match + * anything, even though registered extension extend {@link Object}. + * <p> + * This will not look at extensions of {@link #getParent()}. + * + * @throws IllegalArgumentException if this location does not support the given extension type + * @throws NullPointerException if extensionType is null + */ + <T> T getExtension(Class<T> extensionType); + + @Override + RelationSupport<Location> relations(); + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/LocationDefinition.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/LocationDefinition.java b/api/src/main/java/org/apache/brooklyn/api/location/LocationDefinition.java new file mode 100644 index 0000000..2bbe74c --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/LocationDefinition.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.api.location; + +import java.util.Map; + +import org.apache.brooklyn.api.mgmt.ManagementContext; + +/** + * Defines a location, where the {@link #getSpec()} is like a serialized representation + * of the location so that Brooklyn can create a corresponding location. + * + * Examples include a complete description (e.g. giving a list of machines in a pool), or + * a name that matches a named location defined in the brooklyn poperties. + * + * Users are not expected to implement this, or to use the interface directly. See + * {@link LocationRegistry#resolve(String)} and {@link ManagementContext#getLocationRegistry()}. + */ +public interface LocationDefinition { + + public String getId(); + public String getName(); + public String getSpec(); + public Map<String,Object> getConfig(); + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/LocationNotAvailableException.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/LocationNotAvailableException.java b/api/src/main/java/org/apache/brooklyn/api/location/LocationNotAvailableException.java new file mode 100644 index 0000000..de1c09d --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/LocationNotAvailableException.java @@ -0,0 +1,35 @@ +/* + * 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.api.location; + + +/** + * Indicates that a {@link ProvisioningLocation} is not able to provision a requested location + */ +public class LocationNotAvailableException extends Exception { + private static final long serialVersionUID = 1079817235289265761L; + + public LocationNotAvailableException(String s) { + super(s); + } + + public LocationNotAvailableException(String s, Throwable throwable) { + super(s, throwable); + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/LocationRegistry.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/LocationRegistry.java b/api/src/main/java/org/apache/brooklyn/api/location/LocationRegistry.java new file mode 100644 index 0000000..50fbc6a --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/LocationRegistry.java @@ -0,0 +1,128 @@ +/* + * 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.api.location; + +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; + +import javax.annotation.Nullable; + +import org.apache.brooklyn.util.guava.Maybe; + +import com.google.common.annotations.Beta; + +/** + * The registry of the sorts of locations that brooklyn knows about. Given a + * {@LocationDefinition} or a {@link String} representation of a spec, this can + * be used to create a {@link Location} instance. + */ +@SuppressWarnings("rawtypes") +public interface LocationRegistry { + + /** map of ID (possibly randomly generated) to the definition (spec, name, id, and props; + * where spec is the spec as defined, for instance possibly another named:xxx location) */ + public Map<String,LocationDefinition> getDefinedLocations(); + + /** returns a LocationDefinition given its ID (usually a random string), or null if none */ + public LocationDefinition getDefinedLocationById(String id); + + /** returns a LocationDefinition given its name (e.g. for named locations, supply the bit after the "named:" prefix), + * or null if none */ + public LocationDefinition getDefinedLocationByName(String name); + + /** adds or updates the given defined location */ + public void updateDefinedLocation(LocationDefinition l); + + /** removes the defined location from the registry (applications running there are unaffected) */ + public void removeDefinedLocation(String id); + + /** Returns a fully populated (config etc) location from the given definition, with optional add'l flags. + * the location will be managed by default, unless the manage parameter is false, + * or the manage parameter is null and the CREATE_UNMANAGED flag is set. + * <p> + * The manage parameter is {@link Boolean} so that null can be used to say rely on anything in the flags. + * + * @since 0.7.0, but beta and likely to change as the semantics of this class are tuned */ + @Beta + public Maybe<Location> resolve(LocationDefinition ld, Boolean manage, Map locationFlags); + + /** As {@link #resolve(LocationDefinition, Boolean, Map), with the location managed, and no additional flags, + * unwrapping the result (throwing if not resolvable) */ + public Location resolve(LocationDefinition l); + + /** Returns a location created from the given spec, which might correspond to a definition, or created on-the-fly. + * Optional flags can be passed through to underlying the location. + * @since 0.7.0, but beta and likely to change as the semantics of this class are tuned */ + @Beta + public Maybe<Location> resolve(String spec, Boolean manage, Map locationFlags); + + /** efficiently returns for inspection only a fully populated (config etc) location from the given definition; + * the value might be unmanaged so it is not meant for any use other than inspection, + * but callers should prefer this when they don't wish to create a new location which will be managed in perpetuity! + * + * @deprecated since 0.7.0, use {@link #resolve(LocationDefinition, Boolean, Map)} */ + @Deprecated + public Location resolveForPeeking(LocationDefinition l); + + /** returns fully populated (config etc) location from the given definition, with overrides; + * @deprecated since 0.7.0, use {@link #resolve(LocationDefinition, Boolean, Map)} */ + @Deprecated + public Location resolve(LocationDefinition l, Map<?,?> locationFlags); + + /** See {@link #resolve(String, Boolean, Map)}; asks for the location to be managed, and supplies no additional flags, + * and unwraps the result (throwing if the spec cannot be resolve) */ + public Location resolve(String spec); + + /** Returns true/false depending whether spec seems like a valid location, + * that is it has a chance of being resolved (depending on the spec) but NOT guaranteed, + * as it is not passed to the spec; + * see {@link #resolve(String, Boolean, Map)} which has stronger guarantees + * @deprecated since 0.7.0, not really needed, and semantics are weak; use {@link #resolve(String, Boolean, Map)} */ + @Deprecated + public boolean canMaybeResolve(String spec); + + /** As {@link #resolve(String, Boolean, Map)}, but unwrapped + * @throws NoSuchElementException if the spec cannot be resolved */ + public Location resolve(String spec, @Nullable Map locationFlags); + + /** as {@link #resolve(String)} but returning null (never throwing) + * @deprecated since 0.7.0 use {@link #resolve(String, Boolean, Map)} */ + @Deprecated + public Location resolveIfPossible(String spec); + + /** + * As {@link #resolve(String)} but takes collections (of strings or locations) + * <p> + * Expects a collection of elements being individual location spec strings or locations, + * and returns a list of resolved (newly created and managed) locations. + * <p> + * From 0.7.0 this no longer flattens lists (nested lists are disallowed) + * or parses comma-separated elements (they are resolved as-is) + */ + public List<Location> resolve(Iterable<?> spec); + + /** Takes a string, interpreted as a comma-separated (or JSON style, when you need internal double quotes or commas) list; + * or a list, passed to {@link #resolve(Iterable)}; or null/empty (empty list), + * and returns a list of resolved (created and managed) locations */ + public List<Location> resolveList(Object specList); + + public Map getProperties(); + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/LocationResolver.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/LocationResolver.java b/api/src/main/java/org/apache/brooklyn/api/location/LocationResolver.java new file mode 100644 index 0000000..4ddb5e4 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/LocationResolver.java @@ -0,0 +1,57 @@ +/* + * 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.api.location; + +import java.util.Map; + +import org.apache.brooklyn.api.mgmt.ManagementContext; + +import com.google.common.annotations.Beta; + +/** + * Provides a way of creating location instances of a particular type. + */ +public interface LocationResolver { + + void init(ManagementContext managementContext); + + /** the prefix that this resolver will attend to */ + String getPrefix(); + + /** whether the spec is something which should be passed to this resolver */ + boolean accepts(String spec, LocationRegistry registry); + + /** + * Similar to {@link #newLocationFromString(Map, String)} + * but passing in a reference to the registry itself (from which the base properties are discovered) + * and including flags (e.g. user, key, cloud credential) which are known to be for this location. + * <p> + * introduced to support locations which refer to other locations, e.g. NamedLocationResolver + **/ + @SuppressWarnings("rawtypes") + Location newLocationFromString(Map locationFlags, String spec, LocationRegistry registry); + + /** @since 0.7.0 exploring this as a mechanism to disable locations */ + @Beta + public interface EnableableLocationResolver extends LocationResolver { + /** whether the location is enabled */ + boolean isEnabled(); + } + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/LocationSpec.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/LocationSpec.java b/api/src/main/java/org/apache/brooklyn/api/location/LocationSpec.java new file mode 100644 index 0000000..b66ebea --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/LocationSpec.java @@ -0,0 +1,168 @@ +/* + * 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.api.location; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.Collections; +import java.util.Map; + +import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec; +import org.apache.brooklyn.config.ConfigKey; + +import com.google.common.collect.Maps; + +/** + * Gives details of a location to be created. It describes the location's configuration, and is + * reusable to create multiple locations with the same configuration. + * + * To create a LocationSpec, it is strongly encouraged to use {@code create(...)} methods. + * + * @param <T> The type of location to be created + * + * @author aled + */ +public class LocationSpec<T extends Location> extends AbstractBrooklynObjectSpec<T,LocationSpec<T>> { + + // TODO Would like to add `configure(ConfigBag)`, but `ConfigBag` is in core rather than api + + private final static long serialVersionUID = 1L; + + /** + * Creates a new {@link LocationSpec} instance for a location of the given type. The returned + * {@link LocationSpec} can then be customized. + * + * @param type A {@link Location} class + */ + public static <T extends Location> LocationSpec<T> create(Class<T> type) { + return new LocationSpec<T>(type); + } + + /** + * Creates a new {@link LocationSpec} instance with the given config, for a location of the given type. + * + * This is primarily for groovy code; equivalent to {@code LocationSpec.create(type).configure(config)}. + * + * @param config The spec's configuration (see {@link LocationSpec#configure(Map)}). + * @param type A {@link Location} class + */ + public static <T extends Location> LocationSpec<T> create(Map<?,?> config, Class<T> type) { + return LocationSpec.create(type).configure(config); + } + + /** + * Copies entity spec so its configuration can be overridden without modifying the + * original entity spec. + */ + public static <T extends Location> LocationSpec<T> create(LocationSpec<T> spec) { + // need this to get LocationSpec<T> rather than LocationSpec<? extends T> + @SuppressWarnings("unchecked") + Class<T> exactType = (Class<T>)spec.getType(); + + return create(exactType).copyFrom(spec); + } + + private String id; + private Location parent; + private final Map<Class<?>, Object> extensions = Maps.newLinkedHashMap(); + + protected LocationSpec(Class<T> type) { + super(type); + } + + @Override + protected LocationSpec<T> copyFrom(LocationSpec<T> otherSpec) { + LocationSpec<T> result = super.copyFrom(otherSpec).extensions(otherSpec.getExtensions()); + if (otherSpec.getParent() != null) result.parent(otherSpec.getParent()); + if (otherSpec.getId() != null) result.id(otherSpec.getId()); + return result; + } + + protected void checkValidType(Class<? extends T> type) { + checkIsImplementation(type, Location.class); + checkIsNewStyleImplementation(type); + } + + /** + * @deprecated since 0.7.0; instead let the management context pick a random+unique id + */ + @Deprecated + public LocationSpec<T> id(String val) { + id = val; + return this; + } + + public LocationSpec<T> parent(Location val) { + parent = checkNotNull(val, "parent"); + return this; + } + + public <E> LocationSpec<T> extension(Class<E> extensionType, E extension) { + extensions.put(checkNotNull(extensionType, "extensionType"), checkNotNull(extension, "extension")); + return this; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public <E> LocationSpec<T> extensions(Map<Class<?>, ?> extensions) { + for (Map.Entry<Class<?>, ?> entry : extensions.entrySet()) { + extension((Class)entry.getKey(), entry.getValue()); + } + return this; + } + + /** + * @return The id of the location to be created, or null if brooklyn can auto-generate an id + * + * @deprecated since 0.7.0; instead let the management context pick a random+unique id + */ + @Deprecated + public String getId() { + return id; + } + + /** + * @return The location's parent + */ + public Location getParent() { + return parent; + } + + /** + * @return Read-only construction flags + * @see SetFromFlag declarations on the location type + */ + public Map<String, ?> getFlags() { + return Collections.unmodifiableMap(flags); + } + + /** + * @return Read-only configuration values + */ + public Map<ConfigKey<?>, Object> getConfig() { + return Collections.unmodifiableMap(config); + } + + /** + * @return Read-only extension values + */ + public Map<Class<?>, Object> getExtensions() { + return Collections.unmodifiableMap(extensions); + } + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/LocationType.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/LocationType.java b/api/src/main/java/org/apache/brooklyn/api/location/LocationType.java new file mode 100644 index 0000000..8032333 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/LocationType.java @@ -0,0 +1,32 @@ +/* + * 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.api.location; + +import org.apache.brooklyn.api.objs.BrooklynType; + +import com.google.common.annotations.Beta; + +/** + * Gives type information for a {@link Location}. It is immutable. + + * @since 0.7.0 + */ +@Beta +public interface LocationType extends BrooklynType { +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/MachineDetails.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/MachineDetails.java b/api/src/main/java/org/apache/brooklyn/api/location/MachineDetails.java new file mode 100644 index 0000000..ae8b1c2 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/MachineDetails.java @@ -0,0 +1,34 @@ +/* + * 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.api.location; + +import javax.annotation.Nonnull; + +/** + * @since 0.7.0 + */ +public interface MachineDetails { + + @Nonnull + HardwareDetails getHardwareDetails(); + + @Nonnull + OsDetails getOsDetails(); + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/MachineLocation.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/MachineLocation.java b/api/src/main/java/org/apache/brooklyn/api/location/MachineLocation.java new file mode 100644 index 0000000..7483ec5 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/MachineLocation.java @@ -0,0 +1,46 @@ +/* + * 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.api.location; + +import java.net.InetAddress; + +import org.apache.brooklyn.util.net.HasNetworkAddresses; + +/** + * A location that is a machine. + * + * This interface marks a {@link Location} being a network node with an IP address, + * and supports appropriate operations on the node. + */ +public interface MachineLocation extends AddressableLocation, HasNetworkAddresses { + /** + * @return the machine's network address. + */ + InetAddress getAddress(); + + /** @deprecated since 0.7.0. Use getMachineDetails().getOsDetails() instead. */ + @Deprecated + OsDetails getOsDetails(); + + /* + * @return hardware and operating system-specific details for the machine. + */ + MachineDetails getMachineDetails(); + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/MachineLocationCustomizer.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/MachineLocationCustomizer.java b/api/src/main/java/org/apache/brooklyn/api/location/MachineLocationCustomizer.java new file mode 100644 index 0000000..a9b4e2e --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/MachineLocationCustomizer.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.api.location; + +import com.google.common.annotations.Beta; + +/** + * Customization hooks to allow apps to perform specific customisation of obtained machines. + * <p> + * Users are strongly encouraged to sub-class {@link BasicMachineLocationCustomizer}, to give + * some protection against this {@link Beta} API changing in future releases. + */ +@Beta +public interface MachineLocationCustomizer { + + /** + * Override to configure the given machine once it has been created (prior to any use). + */ + void customize(MachineLocation machine); + + /** + * Override to handle machine-related cleanup prior to {@link MachineProvisioningLocation} + * releasing the machine. + */ + void preRelease(MachineLocation machine); +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/MachineManagementMixins.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/MachineManagementMixins.java b/api/src/main/java/org/apache/brooklyn/api/location/MachineManagementMixins.java new file mode 100644 index 0000000..f7c091b --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/MachineManagementMixins.java @@ -0,0 +1,91 @@ +/* + * 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.api.location; + +import java.util.Map; + +import com.google.common.annotations.Beta; + +/** + * Defines mixins for interesting locations. + */ +public class MachineManagementMixins { + + public interface RichMachineProvisioningLocation<T extends MachineLocation> extends + MachineProvisioningLocation<T>, ListsMachines, GivesMachineMetadata, KillsMachines {} + + public interface ListsMachines { + /** + * @return A map of machine ID to metadata record for all machines known in a given cloud location. + */ + Map<String,MachineMetadata> listMachines(); + } + + public interface GivesMachineMetadata { + /** + * @return the {@link MachineMetadata} for a given (brooklyn) machine location instance, + * or null if not matched. + */ + MachineMetadata getMachineMetadata(MachineLocation location); + } + + public interface KillsMachines { + /** Kills the indicated machine; throws if not recognised or possible */ + void killMachine(MachineLocation machine); + + /** Kills the machine indicated by the given (server-side) machine id; + * note, the ID is the _cloud-service_ ID, + * that is, pass in getMetadata(machineLocation).getId() not the machineLocation.getId() */ + void killMachine(String cloudServiceId); + } + + /** very lightweight machine record */ + public interface MachineMetadata { + /** The cloud service ID -- distinct from any Brooklyn {@link Location#getId()} */ + String getId(); + String getName(); + String getPrimaryIp(); + Boolean isRunning(); + /** original metadata object, if available; e.g. ComputeMetadata when using jclouds */ + Object getOriginalMetadata(); + } + + /** + * Implement to indicate that a location can suspend and resume machines. + */ + @Beta + public interface SuspendResumeLocation extends SuspendsMachines, ResumesMachines {} + + @Beta + public interface SuspendsMachines { + /** + * Suspend the indicated machine. + */ + void suspendMachine(MachineLocation location); + } + + @Beta + public interface ResumesMachines { + /** + * Resume the indicated machine. + */ + MachineLocation resumeMachine(Map<?, ?> flags); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/MachineProvisioningLocation.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/MachineProvisioningLocation.java b/api/src/main/java/org/apache/brooklyn/api/location/MachineProvisioningLocation.java new file mode 100644 index 0000000..1fcf785 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/MachineProvisioningLocation.java @@ -0,0 +1,72 @@ +/* + * 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.api.location; + +import java.util.Collection; +import java.util.Map; + +/** + * A location that is able to provision new machines within its location. + * + * This interface extends {@link Location} to add the ability to provision {@link MachineLocation}s in this location. + */ +public interface MachineProvisioningLocation<T extends MachineLocation> extends ProvisioningLocation<T> { + /** + * Obtain a machine in this location. + * + * @param flags Details of the desired machine (e.g. image, size, open ports, etc; some flag support is limited to selected providers). + * "callerContext" can be specified to have custom logging and error messages (useful if starting machines in parallel) + * @return a machine that is a child of this location. + * @throws NoMachinesAvailableException if there are no machines available in this location (or impls may return null, but that is discouraged) + */ + @Override + T obtain(Map<?,?> flags) throws NoMachinesAvailableException; + + /** + * Creates a new location of the same type, but with additional creation instructions in the form of flags, + * e.g. for specifying subnets, security groups, etc + * <p> + * Implementers who wish to subclass this provisioning location for additional functionality + * in a specific cloud can use the relevant implementation of this method as a guide. + */ + MachineProvisioningLocation<T> newSubLocation(Map<?,?> newFlags); + + /** + * Release a previously-obtained machine. + * + * @param machine a {@link MachineLocation} previously obtained from a call to {@link #obtain()} + * @throws IllegalStateException if the machine did not come from a call to {@link #obtain()} or it has already been released. + */ + @Override + void release(T machine); + + /** + * Gets flags, suitable as an argument to {@link #obtain(Map)}. The tags provided give + * hints about the machine required. The provisioning-location could be configured to + * understand those tags. + * + * For example, an AWS-location could be configured to understand that a particular entity + * type (e.g. "TomcatServer") requires a particular AMI in that region, so would return the + * required image id. + * + * @param tags + * @return + */ + Map<String,Object> getProvisioningFlags(Collection<String> tags); +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/NoMachinesAvailableException.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/NoMachinesAvailableException.java b/api/src/main/java/org/apache/brooklyn/api/location/NoMachinesAvailableException.java new file mode 100644 index 0000000..f13c1ff --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/NoMachinesAvailableException.java @@ -0,0 +1,35 @@ +/* + * 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.api.location; + + +/** + * Indicates no machines are available in a given location. + */ +public class NoMachinesAvailableException extends LocationNotAvailableException { + private static final long serialVersionUID = 1079817235289265761L; + + public NoMachinesAvailableException(String s) { + super(s); + } + + public NoMachinesAvailableException(String s, Throwable throwable) { + super(s, throwable); + } +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/OsDetails.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/OsDetails.java b/api/src/main/java/org/apache/brooklyn/api/location/OsDetails.java new file mode 100644 index 0000000..9baac9e --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/OsDetails.java @@ -0,0 +1,46 @@ +/* + * 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.api.location; + +import javax.annotation.Nullable; + +public interface OsDetails { + + /** The name of the operating system, e.g. "Debian" or "Red Hat Enterprise Linux Server" */ + @Nullable + String getName(); + + /** + * The version of the operating system. Generally numeric (e.g. "6.3") but occasionally + * alphabetic (e.g. Debian's "Squeeze"). + */ + @Nullable + String getVersion(); + + /** The operating system's architecture, e.g. "x86" or "x86_64" */ + @Nullable + String getArch(); + + boolean is64bit(); + + boolean isWindows(); + boolean isLinux(); + boolean isMac(); + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/PortRange.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/PortRange.java b/api/src/main/java/org/apache/brooklyn/api/location/PortRange.java new file mode 100644 index 0000000..108f0dd --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/PortRange.java @@ -0,0 +1,48 @@ +/* + * 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.api.location; + +/** + * A range of ports (indicator for Location and other APIs). + * Using methods {@code PortRanges.fromXxx(...)} this is adaptable from a number, a string, or a collection of numbers or a strings. + * String may be of the form: + * <li> "80": just 80 + * <li> "8080-8090": limited range sequentially; ie try 8080, then 8081, ..., then 8090, then give up + * <li> "8080-8000": as above, but descending; ie try 8080, then 8079, ..., then 8000, then give up + * <li> "8000+": unlimited range sequentially; ie try 8000, then 8001, then 8002, etc + * <li> "80,8080,8000,8080-8099": different ranges, in order; ie try 80, then 8080, then 8000, then 8080 (again), then 8081, ..., then 8099, then give up + * Ranges (but not lists) may be preceeded by "!" to indicate a randomly selected port: + * + * @see brooklyn.location.basic.PortRanges + */ +//MAYDO could have: <li> "~32168-65535" (or "~32168-"): try randomly selected numbers in range 32168-65535 (MAX_PORT) until all have been tried +public interface PortRange extends Iterable<Integer> { + /** + * Whether there are any ports in the range. + */ + boolean isEmpty(); + + /** + * Note: this method is only here for use with "groovy truth". Users are strongly discouraged + * from calling it directly. + * + * @return {@code !isEmpty()}; i.e. true if there is at least one port in the range; false otherwise + */ + boolean asBoolean(); +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/PortSupplier.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/PortSupplier.java b/api/src/main/java/org/apache/brooklyn/api/location/PortSupplier.java new file mode 100644 index 0000000..02c4398 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/PortSupplier.java @@ -0,0 +1,50 @@ +/* + * 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.api.location; + +/** Mixin interface for location which allows it to supply ports from a given range */ +public interface PortSupplier { + + /** + * Reserve a specific port for an application. If your application requires a specific port - for example, port 80 for a web + * server - you should reserve this port before starting your application. Using this method, you will be able to detect if + * another application has already claimed this port number. + * + * @param portNumber the required port number. + * @return {@code true} if the port was successfully reserved; {@code false} if it has been previously reserved. + */ + boolean obtainSpecificPort(int portNumber); + + /** + * Reserve a port for your application, with a port number in a specific range. If your application requires a port, but it does + * not mind exactly which port number - for example, a port for internal JMX monitoring - call this method. + * + * @param range the range of acceptable port numbers. + * @return the port number that has been reserved, or -1 if there was no available port in the acceptable range. + */ + int obtainPort(PortRange range); + + /** + * Release a previously reserved port. + * + * @param portNumber the port number from a call to {@link #obtainPort(PortRange)} or {@link #obtainSpecificPort(int)} + */ + void releasePort(int portNumber); + +} http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/location/ProvisioningLocation.java ---------------------------------------------------------------------- diff --git a/api/src/main/java/org/apache/brooklyn/api/location/ProvisioningLocation.java b/api/src/main/java/org/apache/brooklyn/api/location/ProvisioningLocation.java new file mode 100644 index 0000000..25bd209 --- /dev/null +++ b/api/src/main/java/org/apache/brooklyn/api/location/ProvisioningLocation.java @@ -0,0 +1,44 @@ +/* + * 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.api.location; + +import java.util.Map; + +/** + * A location that is able to provision new locations within it. + */ +public interface ProvisioningLocation<T extends Location> extends Location { + /** + * Obtain a new (sub)-location in the location represented by this class. + * + * @param flags Constraints and details of the location to be provisioned + * @return the location provisioned + * @throws LocationNotAvailableException if could not provision such a location + */ + T obtain(Map<?,?> flags) throws LocationNotAvailableException; + + /** + * Release a previously-obtained location. + * + * @param location a location previously obtained + * @throws IllegalStateException if the machine did not come from a call to {@link #obtain()} or it has already been released. + */ + void release(T machine); + +}
