org.apache.brooklyn.api.entity.EntitySpec Maven / Gradle / Ivy
/*
* 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;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
import org.apache.brooklyn.api.location.Location;
import org.apache.brooklyn.api.location.LocationSpec;
import org.apache.brooklyn.api.policy.Policy;
import org.apache.brooklyn.api.policy.PolicySpec;
import org.apache.brooklyn.api.sensor.Enricher;
import org.apache.brooklyn.api.sensor.EnricherSpec;
import org.apache.brooklyn.util.collections.MutableList;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
/**
* Gives details of an entity to be created. It describes the entity's configuration, and is
* reusable to create multiple entities with the same configuration.
*
* To create an EntitySpec, it is strongly encouraged to use {@link #create(Class)} etc.
* Users who need to implement this are strongly encouraged to extend
* {@link org.apache.brooklyn.api.entity.EntitySpec}.
*
* @param The type of entity to be created
*
* @author aled
*/
public class EntitySpec extends AbstractBrooklynObjectSpec> {
private static final long serialVersionUID = -2247153452919128990L;
/**
* Creates a new {@link EntitySpec} instance for an entity of the given type. The returned
* {@link EntitySpec} can then be customized.
*
* @param type An {@link Entity} interface
*/
public static EntitySpec create(Class type) {
return new EntitySpec(type);
}
/**
* Creates a new {@link EntitySpec} instance for an entity of the given type. The returned
* {@link EntitySpec} can then be customized.
*
* @param type An {@link Entity} interface
* @param implType An {@link Entity} implementation, which implements the {@code type} interface
*/
public static EntitySpec create(Class type, Class implType) {
return new EntitySpec(type).impl(implType);
}
/**
* Creates a new {@link EntitySpec} instance with the given config, for an entity of the given type.
*
* This is primarily for groovy code; equivalent to {@code EntitySpec.create(type).configure(config)}.
*
* @param config The spec's configuration (see {@link EntitySpec#configure(Map)}).
* @param type An {@link Entity} interface
*/
public static EntitySpec create(Map,?> config, Class type) {
return EntitySpec.create(type).configure(config);
}
/**
* Copies entity spec so its configuration can be overridden without modifying the
* original entity spec.
*/
public static EntitySpec create(EntitySpec spec) {
return create(spec.getType()).copyFrom(spec);
}
public static EntitySpec newInstance(Class type) {
return new EntitySpec(type);
}
private Class extends T> impl;
private Entity parent;
private final List policies = Lists.newArrayList();
private final List> policySpecs = Lists.newArrayList();
private final List enrichers = Lists.newArrayList();
private final List> enricherSpecs = Lists.newArrayList();
private final List locations = Lists.newArrayList();
private final List> locationSpecs = Lists.newArrayList();
private final Set> additionalInterfaces = Sets.newLinkedHashSet();
private final List entityInitializers = Lists.newArrayList();
private final List> children = Lists.newArrayList();
private final List members = Lists.newArrayList();
private final List groups = Lists.newArrayList();
private volatile boolean immutable;
public EntitySpec(Class type) {
super(type);
}
@Override
protected EntitySpec copyFrom(EntitySpec otherSpec) {
super.copyFrom(otherSpec)
.additionalInterfaces(otherSpec.getAdditionalInterfaces())
.policySpecs(otherSpec.getPolicySpecs())
.policies(otherSpec.getPolicies())
.enricherSpecs(otherSpec.getEnricherSpecs())
.enrichers(otherSpec.getEnrichers())
.addInitializers(otherSpec.getInitializers())
.children(copyFromSpecs(otherSpec.getChildren()))
.members(otherSpec.getMembers())
.groups(otherSpec.getGroups())
.locationSpecs(otherSpec.getLocationSpecs())
.locations(otherSpec.getLocations());
if (otherSpec.getParent() != null) parent(otherSpec.getParent());
if (otherSpec.getImplementation() != null) impl(otherSpec.getImplementation());
return this;
}
private List> copyFromSpecs(List> children) {
return Lists.,EntitySpec>>transform(children, new Function, EntitySpec>>() {
@Nullable
@Override
public EntitySpec> apply(@Nullable EntitySpec> entitySpec) {
return create(entitySpec);
}
});
}
@Override
@SuppressWarnings("unchecked")
public Class getType() {
return (Class)super.getType();
}
@Override
protected void checkValidType(Class extends T> type) {
// EntitySpec does nothing. Other specs do check it's an implementation etc.
}
/**
* @return The implementation of the entity; if not null. this overrides any defaults or other configuration
*
* @see ImplementedBy on the entity interface classes for how defaults are defined.
* @see EntityTypeRegistry for how implementations can be defined globally
*/
@Nullable
public Class extends T> getImplementation() {
return impl;
}
/**
* @return Additional interfaces (other than just {@link #getType()}) that this entity implements;
* important for when accessing entity through a proxy to determine which interfaces the proxy exposes.
*/
public Set> getAdditionalInterfaces() {
return additionalInterfaces;
}
/** @return {@link EntityInitializer} objects which customize the entity to be created */
public List getInitializers() {
return entityInitializers;
}
public List> getChildren() {
return children;
}
public List getMembers() {
return members;
}
public List getGroups() {
return groups;
}
/**
* @return The entity's parent
*/
public Entity getParent() {
return parent;
}
public List> getPolicySpecs() {
return policySpecs;
}
/** @deprecated since 0.9.0 in future only {@link #getPolicySpecs()} will be supported */ @Deprecated
public List getPolicies() {
return policies;
}
public List> getEnricherSpecs() {
return enricherSpecs;
}
/** @deprecated since 0.9.0 in future only {@link #getEnricherSpecs()} will be supported */ @Deprecated
public List getEnrichers() {
return enrichers;
}
public List> getLocationSpecs() {
return locationSpecs;
}
/** @deprecated since 0.9.0 in future only {@link #getLocationSpecs()} will be supported */ @Deprecated
public List getLocations() {
return locations;
}
public EntitySpec impl(Class extends T> val) {
checkMutable();
checkIsImplementation(checkNotNull(val, "impl"), getType());
checkIsNewStyleImplementation(val);
impl = val;
return this;
}
public EntitySpec additionalInterfaces(Class>... vals) {
checkMutable();
for (Class> val : vals) {
additionalInterfaces.add(val);
}
return this;
}
public EntitySpec additionalInterfaces(Iterable> val) {
checkMutable();
additionalInterfaces.addAll(Sets.newLinkedHashSet(val));
return this;
}
public EntitySpec addInitializer(EntityInitializer initializer) {
checkMutable();
entityInitializers.add(initializer);
return this;
}
public EntitySpec addInitializers(Iterable extends EntityInitializer> initializers) {
checkMutable();
Iterables.addAll(entityInitializers, initializers);
return this;
}
/** The supplied class must have a public no-arg constructor. */
public EntitySpec addInitializer(Class extends EntityInitializer> initializerType) {
checkMutable();
try {
entityInitializers.add(initializerType.newInstance());
} catch (Exception e) {
throw Throwables.propagate(e);
}
return this;
}
public EntitySpec children(Iterable extends EntitySpec>> children) {
checkMutable();
Iterables.addAll(this.children, children);
return this;
}
/** The supplied class must have a public no-arg constructor. */
public EntitySpec child(EntitySpec> child) {
checkMutable();
children.add(child);
return this;
}
public EntitySpec members(Iterable extends Entity> members) {
checkMutable();
Iterables.addAll(this.members, members);
return this;
}
public EntitySpec member(Entity member) {
checkMutable();
members.add(member);
return this;
}
public EntitySpec groups(Iterable extends Group> groups) {
checkMutable();
Iterables.addAll(this.groups, groups);
return this;
}
public EntitySpec group(Group group) {
checkMutable();
groups.add(group);
return this;
}
public EntitySpec parent(Entity val) {
checkMutable();
parent = checkNotNull(val, "parent");
return this;
}
/** adds a policy to the spec
* @deprecated since 0.9.0 pass a spec, using {@link #policy(EnricherSpec)} */ @Deprecated
public EntitySpec policy(Policy val) {
checkMutable();
policies.add(checkNotNull(val, "policy"));
return this;
}
/** adds a policy to the spec */
public EntitySpec policy(PolicySpec> val) {
checkMutable();
policySpecs.add(checkNotNull(val, "policySpec"));
return this;
}
/** adds the supplied policies to the spec */
public EntitySpec policySpecs(Iterable extends PolicySpec>> val) {
checkMutable();
policySpecs.addAll(MutableList.copyOf(checkNotNull(val, "policySpecs")));
return this;
}
/** adds the supplied policies to the spec
* @deprecated since 0.9.0 pass a spec, using {@link #policySpecs(Iterable)} */ @Deprecated
public EntitySpec policies(Iterable extends Policy> val) {
checkMutable();
policies.addAll(MutableList.copyOf(checkNotNull(val, "policies")));
return this;
}
/** adds an enricher to the spec
* @deprecated since 0.9.0 pass a spec, using {@link #enricher(EnricherSpec)} */ @Deprecated
public EntitySpec enricher(Enricher val) {
checkMutable();
enrichers.add(checkNotNull(val, "enricher"));
return this;
}
/** adds an enricher to the spec */
public EntitySpec enricher(EnricherSpec> val) {
checkMutable();
enricherSpecs.add(checkNotNull(val, "enricherSpec"));
return this;
}
/** adds the supplied policies to the spec */
public EntitySpec enricherSpecs(Iterable extends EnricherSpec>> val) {
checkMutable();
enricherSpecs.addAll(MutableList.copyOf(checkNotNull(val, "enricherSpecs")));
return this;
}
/** adds the supplied policies to the spec
* @deprecated since 0.9.0 pass a spec, using {@link #enricherSpecs(Iterable)} */ @Deprecated
public EntitySpec enrichers(Iterable extends Enricher> val) {
checkMutable();
enrichers.addAll(MutableList.copyOf(checkNotNull(val, "enrichers")));
return this;
}
/** adds a location to the spec
* @deprecated since 0.9.0 pass a spec, using {@link #enricherSpecs(Iterable)} */
@Deprecated
// there are still many places in tests where we use this;
// in some we want to force the use of a given location.
// TODO we could perhaps introduce an ExistingLocation class which can generate a spec based on an ID to formalize this?
public EntitySpec location(Location val) {
checkMutable();
locations.add(checkNotNull(val, "location"));
return this;
}
/** adds a location to the spec */
public EntitySpec location(LocationSpec> val) {
checkMutable();
locationSpecs.add(checkNotNull(val, "location"));
return this;
}
/** adds the supplied locations to the spec */
public EntitySpec locationSpecs(Iterable extends LocationSpec>> val) {
checkMutable();
locationSpecs.addAll(MutableList.copyOf(checkNotNull(val, "locations")));
return this;
}
/** adds the supplied locations to the spec
* @deprecated since 0.9.0 pass a spec, using {@link #locationSpecs(Iterable)} */ @Deprecated
public EntitySpec locations(Iterable extends Location> val) {
checkMutable();
locations.addAll(MutableList.copyOf(checkNotNull(val, "locations")));
return this;
}
/** clears locations defined in the spec */
public EntitySpec clearLocations() {
checkMutable();
locationSpecs.clear();
locations.clear();
return this;
}
/** "seals" this spec, preventing any future changes */
public EntitySpec immutable() {
immutable = true;
return this;
}
private void checkMutable() {
if (immutable) throw new IllegalStateException("Cannot modify immutable entity spec "+this);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy