All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.brooklyn.api.entity.EntitySpec Maven / Gradle / Ivy

There is a newer version: 1.1.0
Show newest version
/*
 * 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 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 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 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 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 initializers) {
        checkMutable();
        Iterables.addAll(entityInitializers, initializers);
        return this;
    }

    /** The supplied class must have a public no-arg constructor. */
    public EntitySpec addInitializer(Class initializerType) {
        checkMutable();
        try {
            entityInitializers.add(initializerType.newInstance());
        } catch (Exception e) {
            throw Throwables.propagate(e);
        }
        return this;
    }

    public EntitySpec children(Iterable> 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 members) {
        checkMutable();
        Iterables.addAll(this.members, members);
        return this;
    }

    public EntitySpec member(Entity member) {
        checkMutable();
        members.add(member);
        return this;
    }

    public EntitySpec groups(Iterable 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> 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 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> 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 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> 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 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