You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/02/01 18:51:32 UTC

[50/51] [abbrv] [partial] brooklyn-server git commit: move subdir from incubator up a level as it is promoted to its own repo (first non-incubator commit!)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
index 13f1272..07f69e6 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,7 @@
 
-### HISTORIC REPO: Apache Brooklyn has graduated!
+# [![**Brooklyn**](https://brooklyn.apache.org/style/img/apache-brooklyn-logo-244px-wide.png)](http://brooklyn.apache.org/)
 
-This is the historical **incubator** repo for Apache Brooklyn. 
-This version of the codebase is no longer active. 
-
-**You're probably in the wrong place.**
-
-Visit:
-
-* **The Active Codebase**: at [http://github.com/apache/brooklyn/](http://github.com/apache/brooklyn/)
-* **The Apache Brooklyn Homepage**: at [http://brooklyn.apache.org/](http://brooklyn.apache.org/)
-
-### About the Incubator Project
-
-Apache Brooklyn was in the Apache Incubator until the end of 2015, on version `0.9.0-SNAPSHOT`.
-At this time it graduated to become a top-level Apache Software Foundation project,
-and the code moved from `incubator-brooklyn` to `brooklyn` and several other projects `brooklyn-*`.
-
-Versions `0.8.0-incubating` and before can be found in and built from this repo,
-along with the last commit to `0.9.0-SNAPSHOT` from which development has continued
-in `apache/brooklyn` and sub-projects.
-
-The sub-directories in this project correspond to multiple separate repositories now in the `apache` org.
-The link above to **[the Active Codebase](http://github.com/apache/brooklyn/)** started life exactly 
-as a copy of [`brooklyn/`](brooklyn/) in this folder, 
-as an uber-project for the other `brooklyn-*` folders, including the `server` and the `ui`,
-which are now top-level repos in the `apache` org.
-
-
-### To Build
-
-This historic version of the code can be built with:
-
-    mvn clean install
-
-This creates a build of the last incubator SNAPSHOT version in `usage/dist/target/brooklyn-dist`. Run 
-with `bin/brooklyn launch`. Although really you probably want **[the Active Codebase](http://github.com/apache/brooklyn/)**.
+### Apache Brooklyn Server Sub-Project
 
+This repo contains the core elements to run a Brooklyn server,
+from the API and utils through to the core implementation and the REST server.

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/pom.xml
----------------------------------------------------------------------
diff --git a/api/pom.xml b/api/pom.xml
new file mode 100644
index 0000000..f1994f4
--- /dev/null
+++ b/api/pom.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    
+    <artifactId>brooklyn-api</artifactId>
+    <name>Brooklyn API</name>
+    
+    <description>
+        API classes for Brooklyn
+    </description>
+
+    <parent>
+        <groupId>org.apache.brooklyn</groupId>
+        <artifactId>brooklyn-parent</artifactId>
+        <version>0.9.0-SNAPSHOT</version>  <!-- BROOKLYN_VERSION -->
+        <relativePath>../parent/pom.xml</relativePath>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-utils-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.findbugs</groupId>
+            <artifactId>jsr305</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.brooklyn</groupId>
+            <artifactId>brooklyn-utils-test-support</artifactId>
+            <scope>test</scope>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+    
+</project>

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/catalog/BrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/catalog/BrooklynCatalog.java b/api/src/main/java/org/apache/brooklyn/api/catalog/BrooklynCatalog.java
new file mode 100644
index 0000000..b47d4b1
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/catalog/BrooklynCatalog.java
@@ -0,0 +1,141 @@
+/*
+ * 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.catalog;
+
+import java.util.Collection;
+import java.util.NoSuchElementException;
+
+import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Predicate;
+
+public interface BrooklynCatalog {
+    /** 
+     * Version set in catalog when creator does not supply a version, to mean a low priority item;
+     * and used when requesting to indicate the best version.
+     * (See {@link #getCatalogItem(String, String)} for discussion of the best version.)
+     */
+    static String DEFAULT_VERSION = "0.0.0_DEFAULT_VERSION";
+
+    /** @return The item matching the given given 
+     * {@link CatalogItem#getSymbolicName() symbolicName} 
+     * and optionally {@link CatalogItem#getVersion()},
+     * taking the best version if the version is {@link #DEFAULT_VERSION} or null,
+     * returning null if no matches are found. */
+    CatalogItem<?,?> getCatalogItem(String symbolicName, String version);
+
+    /** @return Deletes the item with the given {@link CatalogItem#getSymbolicName()
+     * symbolicName} and version
+     * @throws NoSuchElementException if not found */
+    void deleteCatalogItem(String symbolicName, String version);
+
+    /** variant of {@link #getCatalogItem(String, String)} which checks (and casts) type for convenience
+     * (returns null if type does not match) */
+    <T,SpecT> CatalogItem<T,SpecT> getCatalogItem(Class<T> type, String symbolicName, String version);
+
+    /** @return All items in the catalog */
+    <T,SpecT> Iterable<CatalogItem<T,SpecT>> getCatalogItems();
+
+    /** convenience for filtering items in the catalog; see CatalogPredicates for useful filters */
+    <T,SpecT> Iterable<CatalogItem<T,SpecT>> getCatalogItems(Predicate<? super CatalogItem<T,SpecT>> filter);
+
+    /** persists the catalog item to the object store, if persistence is enabled */
+    public void persist(CatalogItem<?, ?> catalogItem);
+
+    /** @return The classloader which should be used to load classes and entities;
+     * this includes all the catalog's classloaders in the right order.
+     * This is a wrapper which will update as the underlying catalog items change,
+     * so it is safe for callers to keep a handle on this. */
+    public ClassLoader getRootClassLoader();
+
+    /** creates a spec for the given catalog item, throwing exceptions if any problems */
+    // TODO this should be cached on the item and renamed getSpec(...), else we re-create it too often (every time catalog is listed)
+    <T, SpecT extends AbstractBrooklynObjectSpec<? extends T, SpecT>> SpecT createSpec(CatalogItem<T, SpecT> item);
+
+    /**
+     * Adds an item (represented in yaml) to the catalog.
+     * Fails if the same version exists in catalog.
+     *
+     * @throws IllegalArgumentException if the yaml was invalid
+     * @deprecated since 0.7.0 use {@link #addItems(String, boolean)}
+     */
+    @Deprecated
+    CatalogItem<?,?> addItem(String yaml);
+    
+    /**
+     * Adds an item (represented in yaml) to the catalog.
+     * 
+     * @param forceUpdate If true allows catalog update even when an
+     * item exists with the same symbolicName and version
+     *
+     * @throws IllegalArgumentException if the yaml was invalid
+     * @deprecated since 0.7.0 use {@link #addItems(String, boolean)}
+     */
+    @Deprecated
+    CatalogItem<?,?> addItem(String yaml, boolean forceUpdate);
+    
+    /**
+     * Adds items (represented in yaml) to the catalog.
+     * Fails if the same version exists in catalog.
+     *
+     * @throws IllegalArgumentException if the yaml was invalid
+     */
+    Iterable<? extends CatalogItem<?,?>> addItems(String yaml);
+    
+    /**
+     * Adds items (represented in yaml) to the catalog.
+     * 
+     * @param forceUpdate If true allows catalog update even when an
+     * item exists with the same symbolicName and version
+     *
+     * @throws IllegalArgumentException if the yaml was invalid
+     */
+    Iterable<? extends CatalogItem<?,?>> addItems(String yaml, boolean forceUpdate);
+    
+    /**
+     * adds an item to the 'manual' catalog;
+     * this does not update the classpath or have a record to the java Class
+     *
+     * @deprecated since 0.7.0 Construct catalogs with yaml (referencing OSGi bundles) instead
+     */
+    // TODO maybe this should stay on the API? -AH Apr 2015 
+    @Deprecated
+    void addItem(CatalogItem<?,?> item);
+
+    /**
+     * Creates a catalog item and adds it to the 'manual' catalog,
+     * with the corresponding Class definition (loaded by a classloader)
+     * registered and available in the classloader.
+     * <p>
+     * Note that the class will be available for this session only,
+     * although the record of the item will appear in the catalog DTO if exported,
+     * so it is recommended to edit the 'manual' catalog DTO if using it to
+     * generate a catalog, either adding the appropriate classpath URL or removing this entry.
+     *
+     * @deprecated since 0.7.0 Construct catalogs with OSGi bundles instead.
+     * This is used in a handful of tests which should be rewritten to refer to OSGi bundles.
+     */
+    @Deprecated
+    @VisibleForTesting
+    CatalogItem<?,?> addItem(Class<?> clazz);
+
+    void reset(Collection<CatalogItem<?, ?>> entries);
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/catalog/Catalog.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/catalog/Catalog.java b/api/src/main/java/org/apache/brooklyn/api/catalog/Catalog.java
new file mode 100644
index 0000000..1c6b680
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/catalog/Catalog.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.catalog;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** 
+ * annotation that can be placed on an Application (template), entity or policy 
+ * to give metadata for when used in a catalog and to indicate inclusion in annotation-scanned catalogs
+ * <p>
+ * the "id" field used in the catalog is not exposed here but is always taken as the Class.getName() of the annotated item
+ * if loaded from an annotation.  (the "type" field unsurprisingly is given the same value).  
+ * {@link #name()}, if not supplied, is the SimpleName of the class.
+ */
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.TYPE })
+public @interface Catalog {
+
+    String name() default "";
+    String description() default "";
+    String iconUrl() default "";
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/catalog/CatalogConfig.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/catalog/CatalogConfig.java b/api/src/main/java/org/apache/brooklyn/api/catalog/CatalogConfig.java
new file mode 100644
index 0000000..88d72cb
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/catalog/CatalogConfig.java
@@ -0,0 +1,38 @@
+/*
+ * 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.catalog;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(value = RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.FIELD })
+public @interface CatalogConfig {
+
+    /** a label to be displayed when a config key is exposed as editable in the catalog */ 
+    String label();
+    
+    /** a priority used to determine the order in which config keys are displayed when presenting as editable in the catalog;
+     * a higher value appears higher in the list. the default is 1.
+     * (negative values may be used to indicate advanced config which might not be shown unless requested.) */ 
+    double priority() default 1;
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/catalog/CatalogItem.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/catalog/CatalogItem.java b/api/src/main/java/org/apache/brooklyn/api/catalog/CatalogItem.java
new file mode 100644
index 0000000..795e393
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/catalog/CatalogItem.java
@@ -0,0 +1,153 @@
+/*
+ * 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.catalog;
+
+import java.util.Collection;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.Application;
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+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.mgmt.rebind.RebindSupport;
+import org.apache.brooklyn.api.mgmt.rebind.Rebindable;
+import org.apache.brooklyn.api.mgmt.rebind.mementos.CatalogItemMemento;
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
+
+import com.google.common.annotations.Beta;
+
+@Beta
+public interface CatalogItem<T,SpecT> extends BrooklynObject, Rebindable {
+    
+    public static enum CatalogItemType {
+        TEMPLATE, 
+        ENTITY, 
+        POLICY,
+        LOCATION;
+        
+        public static CatalogItemType ofSpecClass(Class<? extends AbstractBrooklynObjectSpec<?, ?>> type) {
+            if (type==null) return null;
+            if (PolicySpec.class.isAssignableFrom(type)) return POLICY;
+            if (LocationSpec.class.isAssignableFrom(type)) return LOCATION;
+            if (EntitySpec.class.isAssignableFrom(type)) return ENTITY;
+            return null;
+        }
+        public static CatalogItemType ofTargetClass(Class<? extends BrooklynObject> type) {
+            if (type==null) return null;
+            if (Policy.class.isAssignableFrom(type)) return POLICY;
+            if (Location.class.isAssignableFrom(type)) return LOCATION;
+            if (Application.class.isAssignableFrom(type)) return TEMPLATE;
+            if (Entity.class.isAssignableFrom(type)) return ENTITY;
+            return null;
+        }
+    }
+    
+    public static interface CatalogBundle extends OsgiBundleWithUrl {
+        /** @deprecated since 0.9.0, use {@link #isNameResolved()} */
+        public boolean isNamed();
+    }
+
+    /**
+     * @throws UnsupportedOperationException; config not supported for catalog items
+     */
+    @Override
+    ConfigurationSupport config();
+
+    /**
+     * @throws UnsupportedOperationException; subscriptions are not supported for catalog items
+     */
+    @Override
+    SubscriptionSupport subscriptions();
+
+    /** @deprecated since 0.7.0 in favour of {@link CatalogBundle}, kept for rebind compatibility */
+    @Deprecated
+    public static interface CatalogItemLibraries {
+        Collection<String> getBundles();
+    }
+
+    public CatalogItemType getCatalogItemType();
+
+    /** @return The high-level type of this entity, e.g. Entity (not a specific Entity class) */
+    public Class<T> getCatalogItemJavaType();
+
+    /** @return The type of the spec e.g. EntitySpec corresponding to {@link #getCatalogItemJavaType()} */
+    public Class<SpecT> getSpecType();
+    
+    /**
+     * @return The underlying java type of the item represented, if not described via a YAML spec.
+     * Normally null (and the type comes from yaml).
+     * @deprecated since 0.9.0. Use plan based items instead ({@link #getPlanYaml()})
+     */
+    @Deprecated
+    @Nullable public String getJavaType();
+
+    /** @deprecated since 0.7.0. Use {@link #getDisplayName} */
+    @Deprecated
+    public String getName();
+
+    /** @deprecated since 0.7.0. Use {@link #getSymbolicName} */
+    @Deprecated
+    public String getRegisteredTypeName();
+
+    @Nullable public String getDescription();
+
+    @Nullable public String getIconUrl();
+
+    public String getSymbolicName();
+
+    public String getVersion();
+
+    public Collection<CatalogBundle> getLibraries();
+
+    public String toXmlString();
+
+    /** @return The underlying YAML for this item, if known; 
+     * currently including `services:` or `brooklyn.policies:` prefix (but this will likely be removed) */
+    @Nullable public String getPlanYaml();
+
+    @Override
+    RebindSupport<CatalogItemMemento> getRebindSupport();
+    
+    /** Built up from {@link #getSymbolicName()} and {@link #getVersion()}.
+     * 
+     * (It is a bit self-referential having this method on this type of {@link BrooklynObject},
+     * but it is easier this than making the interface hierarchy more complicated.) */
+    @Override
+    public String getCatalogItemId();
+
+    public void setDeprecated(boolean deprecated);
+
+    public void setDisabled(boolean disabled);
+
+    /**
+     * @return True if the item has been deprecated (i.e. its use is discouraged)
+     */
+    boolean isDeprecated();
+    
+    /**
+     * @return True if the item has been disabled (i.e. its use is forbidden, except for pre-existing apps)
+     */
+    boolean isDisabled();
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/effector/Effector.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/effector/Effector.java b/api/src/main/java/org/apache/brooklyn/api/effector/Effector.java
new file mode 100644
index 0000000..82ce6ee
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/effector/Effector.java
@@ -0,0 +1,56 @@
+/*
+ * 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.effector;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.management.MBeanOperationInfo;
+
+import org.apache.brooklyn.api.entity.Entity;
+
+/**
+ * An operation of some kind, carried out by an {@link Entity}.
+ *
+ * Similar to the concepts in the JMX {@link MBeanOperationInfo} class.
+ */
+public interface Effector<T> extends Serializable {
+    /**
+     * human-friendly name of the effector (although frequently this uses java method naming convention)
+     */
+    String getName();
+
+    Class<T> getReturnType();
+
+    /**
+     * canonical name of return type (in case return type does not resolve after serialization)
+     */
+    String getReturnTypeName();
+
+    /**
+     * parameters expected by method, including name and type, optional description and default value
+     */
+    List<ParameterType<?>> getParameters();
+
+    /**
+     * optional description for the effector
+     */
+    String getDescription();
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/effector/ParameterType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/effector/ParameterType.java b/api/src/main/java/org/apache/brooklyn/api/effector/ParameterType.java
new file mode 100644
index 0000000..7f0736d
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/effector/ParameterType.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.effector;
+
+import java.io.Serializable;
+
+import javax.management.MBeanParameterInfo;
+
+/**
+ * Similar to the concepts in the JMX {@link MBeanParameterInfo} class.
+ *
+ * @see Effector
+ */
+public interface ParameterType<T> extends Serializable {
+    
+    public String getName();
+
+    public Class<T> getParameterClass();
+
+    /**
+     * The canonical name of the parameter class; especially useful if the class 
+     * cannot be resolved after deserialization. 
+     */
+    public String getParameterClassName();
+
+    public String getDescription();
+
+    /**
+     * @return The default value for this parameter, if not supplied during an effector call.
+     */
+    public T getDefaultValue();
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/Application.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/Application.java b/api/src/main/java/org/apache/brooklyn/api/entity/Application.java
new file mode 100644
index 0000000..402d004
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/Application.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.entity;
+
+import org.apache.brooklyn.api.mgmt.ManagementContext;
+
+
+/**
+ * An application is the root of the entity hierarchy. In the parent-child relationship, it is
+ * the top-level entity under which the application's entities are all places.
+ * 
+ * The recommended ways to write a new application are to either extend {@link org.apache.brooklyn.entity.factory.ApplicationBuilder} 
+ * or to extend {@link org.apache.brooklyn.core.entity.AbstractApplication}.
+ */
+public interface Application extends Entity {
+    
+    ManagementContext getManagementContext();
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
new file mode 100644
index 0000000..14d3c23
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/Entity.java
@@ -0,0 +1,442 @@
+/*
+ * 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 java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.location.Location;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.objs.BrooklynObject;
+import org.apache.brooklyn.api.objs.EntityAdjunct;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.policy.PolicySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.api.sensor.EnricherSpec;
+import org.apache.brooklyn.api.sensor.Feed;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.sensor.SensorEvent;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
+import org.apache.brooklyn.util.guava.Maybe;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+
+/**
+ * The basic interface for a Brooklyn entity.
+ * <p>
+ * Implementors of entities are strongly encouraged to extend {@link org.apache.brooklyn.core.entity.AbstractEntity}.
+ * <p>
+ * To instantiate an entity, see {@code managementContext.getEntityManager().createEntity(entitySpec)}.
+ * Also see {@link org.apache.brooklyn.core.entity.factory.ApplicationBuilder}, 
+ * {@link org.apache.brooklyn.core.entity.AbstractEntity#addChild(EntitySpec)}, and
+ * {@link org.apache.brooklyn.api.entity.EntitySpec}.
+ * <p>
+ * 
+ * @see org.apache.brooklyn.core.entity.AbstractEntity
+ */
+public interface Entity extends BrooklynObject {
+    /**
+     * The unique identifier for this entity.
+     */
+    @Override
+    String getId();
+    
+    /**
+     * Returns the creation time for this entity, in UTC.
+     */
+    long getCreationTime();
+    
+    /**
+     * A display name; recommended to be a concise single-line description.
+     */
+    String getDisplayName();
+    
+    /** 
+     * A URL pointing to an image which can be used to represent this entity.
+     */
+    @Nullable String getIconUrl();
+    
+    /**
+     * Information about the type of this entity; analogous to Java's object.getClass.
+     */
+    EntityType getEntityType();
+    
+    /**
+     * @return the {@link Application} this entity is registered with, or null if not registered.
+     */
+    Application getApplication();
+
+    /**
+     * @return the id of the {@link Application} this entity is registered with, or null if not registered.
+     */
+    String getApplicationId();
+
+    /**
+     * The parent of this entity, null if no parent.
+     *
+     * The parent is normally the entity responsible for creating/destroying/managing this entity.
+     *
+     * @see #setParent(Entity)
+     * @see #clearParent
+     */
+    Entity getParent();
+    
+    /** 
+     * Return the entities that are children of (i.e. "owned by") this entity
+     */
+    Collection<Entity> getChildren();
+    
+    /**
+     * Sets the entity's display name.
+     */
+    void setDisplayName(String displayName);
+
+    /**
+     * Sets the parent (i.e. "owner") of this entity. Returns this entity, for convenience.
+     *
+     * @see #getParent
+     * @see #clearParent
+     */
+    Entity setParent(Entity parent);
+    
+    /**
+     * Clears the parent (i.e. "owner") of this entity. Also cleans up any references within its parent entity.
+     *
+     * @see #getParent
+     * @see #setParent
+     */
+    void clearParent();
+    
+    /** 
+     * Add a child {@link Entity}, and set this entity as its parent,
+     * returning the added child.
+     * <p>
+     * As with {@link #addChild(EntitySpec)} the child is <b>not</b> brought under management
+     * as part of this call.  It should not be managed prior to this call either.
+     */
+    <T extends Entity> T addChild(T child);
+    
+    /** 
+     * Creates an {@link Entity} from the given spec and adds it, setting this entity as the parent,
+     * returning the added child.
+     * <p>
+     * The added child is <b>not</b> managed as part of this call, even if the parent is managed,
+     * so if adding post-management an explicit call to manage the child will be needed;
+     * see the convenience method <code>Entities.manage(...)</code>. 
+     * */
+    <T extends Entity> T addChild(EntitySpec<T> spec);
+    
+    /** 
+     * Removes the specified child {@link Entity}; its parent will be set to null.
+     * 
+     * @return True if the given entity was contained in the set of children
+     */
+    boolean removeChild(Entity child);
+    
+    /**
+     * @return an immutable thread-safe view of the policies.
+     * 
+     * @deprecated since 0.9.0; see {@link PolicySupport#getPolicies()}
+     */
+    @Deprecated
+    Collection<Policy> getPolicies();
+    
+    /**
+     * @return an immutable thread-safe view of the enrichers.
+     * 
+     * @deprecated since 0.9.0; see {@link EnricherSupport#getEnrichers()}
+     */
+    @Deprecated
+    Collection<Enricher> getEnrichers();
+    
+    /**
+     * The {@link Collection} of {@link Group}s that this entity is a member of.
+     *
+     * Groupings can be used to allow easy management/monitoring of a group of entities.
+     * 
+     * @deprecated since 0.9.0; see {@link GroupSupport#getGroups()} and {@link #groups()}
+     */
+    @Deprecated
+    Collection<Group> getGroups();
+
+    /**
+     * Add this entity as a member of the given {@link Group}. Called by framework.
+     * <p>
+     * Users should call {@link Group#addMember(Entity)} instead; this method will then 
+     * automatically be called. However, the reverse is not true (calling this method will 
+     * not tell the group; this behaviour may change in a future release!)
+     * 
+     * @deprecated since 0.9.0; see {@link GroupSupport#add()} and {@link #groups()}
+     */
+    @Deprecated
+    void addGroup(Group group);
+
+    /**
+     * Removes this entity as a member of the given {@link Group}. Called by framework.
+     * <p>
+     * Users should call {@link Group#removeMember(Entity)} instead; this method will then 
+     * automatically be called. However, the reverse is not true (calling this method will 
+     * not tell the group; this behaviour may change in a future release!)
+     * 
+     * @deprecated since 0.9.0; see {@link GroupSupport#remove()} and {@link #groups()}
+     */
+    @Deprecated
+    void removeGroup(Group group);
+
+    /**
+     * Return all the {@link Location}s this entity is deployed to.
+     */
+    Collection<Location> getLocations();
+
+    /**
+     * Convenience for calling {@link SensorSupport#get(AttributeSensor)},
+     * via code like {@code sensors().get(key)}.
+     */
+    <T> T getAttribute(AttributeSensor<T> sensor);
+    
+    /**
+     * @see {@link #getConfig(ConfigKey)}
+     */
+    <T> T getConfig(HasConfigKey<T> key);
+    
+    /**
+     * Returns the uncoerced value for this config key as set on this entity, if available,
+     * not following any inheritance chains and not taking any default.
+     * 
+     * @deprecated since 0.7.0; use {@code ((EntityInternal)entity).config().getRaw()} or
+     *             {@code ((EntityInternal)entity).config().getLocalRaw()}
+     */
+    @Deprecated
+    Maybe<Object> getConfigRaw(ConfigKey<?> key, boolean includeInherited);
+    
+    /**
+     * @see {@link #getConfigRaw(ConfigKey, boolean)}.
+     * 
+     * @deprecated since 0.7.0
+     */
+    @Deprecated
+    Maybe<Object> getConfigRaw(HasConfigKey<?> key, boolean includeInherited);
+
+    /**
+     * Invokes the given effector, with the given parameters to that effector.
+     */
+    <T> Task<T> invoke(Effector<T> eff, Map<String,?> parameters);
+    
+    /**
+     * Adds the given policy to this entity. Also calls policy.setEntity if available.
+     * 
+     * @deprecated since 0.9.0; see {@link PolicySupport#add(Policy)}
+     */
+    @Deprecated
+    void addPolicy(Policy policy);
+    
+    /**
+     * Adds the given policy to this entity. Also calls policy.setEntity if available.
+     * 
+     * @deprecated since 0.9.0; see {@link PolicySupport#add(PolicySpec)}
+     */
+    @Deprecated
+    <T extends Policy> T addPolicy(PolicySpec<T> policy);
+    
+    /**
+     * Removes the given policy from this entity. 
+     * @return True if the policy existed at this entity; false otherwise
+     * 
+     * @deprecated since 0.9.0; see {@link PolicySupport#remove(Policy)}
+     */
+    @Deprecated
+    boolean removePolicy(Policy policy);
+    
+    /**
+     * Adds the given enricher to this entity. Also calls enricher.setEntity if available.
+     * 
+     * @deprecated since 0.9.0; see {@link EnricherSupport#add(Enricher)}
+     */
+    @Deprecated
+    void addEnricher(Enricher enricher);
+    
+    /**
+     * Adds the given enricher to this entity. Also calls enricher.setEntity if available.
+     * 
+     * @deprecated since 0.9.0; see {@link EnricherSupport#add(EnricherSpec)}
+     */
+    @Deprecated
+    <T extends Enricher> T addEnricher(EnricherSpec<T> enricher);
+    
+    /**
+     * Removes the given enricher from this entity. 
+     * @return True if the policy enricher at this entity; false otherwise
+     * 
+     * @deprecated since 0.9.0; see {@link EnricherSupport#remove(Enricher)}
+     */
+    @Deprecated
+    boolean removeEnricher(Enricher enricher);
+    
+    /**
+     * Adds the given feed to this entity. Also calls feed.setEntity if available.
+     */
+    <T extends Feed> T addFeed(T feed);
+    
+    SensorSupport sensors();
+
+    PolicySupport policies();
+
+    EnricherSupport enrichers();
+
+    GroupSupport groups();
+
+    @Override
+    RelationSupport<Entity> relations();
+    
+    @Beta
+    public interface SensorSupport {
+
+        /**
+         * Gets the value of the given attribute on this entity, or null if has not been set.
+         *
+         * Attributes can be things like workrate and status information, as well as
+         * configuration (e.g. url/jmxHost/jmxPort), etc.
+         */
+        <T> T get(AttributeSensor<T> key);
+
+        /**
+         * Sets the {@link AttributeSensor} data for the given attribute to the specified value.
+         * 
+         * This can be used to "enrich" the entity, such as adding aggregated information, 
+         * rolling averages, etc.
+         * 
+         * @return the old value for the attribute (possibly {@code null})
+         */
+        <T> T set(AttributeSensor<T> attribute, T val);
+
+        /**
+         * Atomically modifies the {@link AttributeSensor}, ensuring that only one modification is done
+         * at a time.
+         * 
+         * If the modifier returns {@link Maybe#absent()} then the attribute will be
+         * left unmodified, and the existing value will be returned.
+         * 
+         * For details of the synchronization model used to achieve this, refer to the underlying 
+         * attribute store (e.g. AttributeMap).
+         * 
+         * @return the old value for the attribute (possibly {@code null})
+         * @since 0.7.0-M2
+         */
+        @Beta
+        <T> T modify(AttributeSensor<T> attribute, Function<? super T, Maybe<T>> modifier);
+
+        /**
+         * Emits a {@link SensorEvent} event on behalf of this entity (as though produced by this entity).
+         * <p>
+         * Note that for attribute sensors it is nearly always recommended to use setAttribute, 
+         * as this method will not update local values.
+         */
+        <T> void emit(Sensor<T> sensor, T value);
+    }
+    
+    public interface AdjunctSupport<T extends EntityAdjunct> extends Iterable<T> {
+        /**
+         * @return A read-only thread-safe iterator over all the instances.
+         */
+        Iterator<T> iterator();
+        
+        int size();
+        boolean isEmpty();
+        
+        /**
+         * Adds an instance.
+         */
+        void add(T val);
+        
+        /**
+         * Removes an instance.
+         */
+        boolean remove(T val);
+    }
+    
+    @Beta
+    public interface PolicySupport extends AdjunctSupport<Policy> {
+        /**
+         * Adds the given policy to this entity. Also calls policy.setEntity if available.
+         */
+        @Override
+        void add(Policy policy);
+        
+        /**
+         * Removes the given policy from this entity. 
+         * @return True if the policy existed at this entity; false otherwise
+         */
+        @Override
+        boolean remove(Policy policy);
+        
+        /**
+         * Adds the given policy to this entity. Also calls policy.setEntity if available.
+         */
+        <T extends Policy> T add(PolicySpec<T> enricher);
+    }
+    
+    @Beta
+    public interface EnricherSupport extends AdjunctSupport<Enricher> {
+        /**
+         * Adds the given enricher to this entity. Also calls enricher.setEntity if available.
+         */
+        @Override
+        void add(Enricher enricher);
+        
+        /**
+         * Removes the given enricher from this entity. 
+         * @return True if the policy enricher at this entity; false otherwise
+         */
+        @Override
+        boolean remove(Enricher enricher);
+        
+        /**
+         * Adds the given enricher to this entity. Also calls enricher.setEntity if available.
+         */
+        <T extends Enricher> T add(EnricherSpec<T> enricher);
+    }
+
+    /**
+     * For managing/querying the group membership of this entity. 
+     * 
+     * Groupings can be used to allow easy management/monitoring of a group of entities.
+     * 
+     * To add/remove this entity from a group, users should call {@link Group#addMember(Entity)} 
+     * and {@link Group#removeMember(Entity)}. In a future release, add/remove methods may be
+     * added here.
+     */
+    @Beta
+    public interface GroupSupport extends Iterable<Group> {
+        /**
+         * A read-only thread-safe iterator over all the {@link Group}s that this entity is a member of.
+         */
+        @Override
+        Iterator<Group> iterator();
+        
+        int size();
+        boolean isEmpty();
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/EntityInitializer.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/EntityInitializer.java b/api/src/main/java/org/apache/brooklyn/api/entity/EntityInitializer.java
new file mode 100644
index 0000000..a9f407a
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/EntityInitializer.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.entity;
+
+import java.util.Map;
+
+import org.apache.brooklyn.api.objs.EntityAdjunct;
+import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.sensor.Feed;
+
+/** 
+ * Instances of this class supply logic which can be used to initialize entities. 
+ * These can be added to an {@link EntitySpec} programmatically, or declared as part
+ * of YAML recipes in a <code>brooklyn.initializers</code> section.
+ * In the case of the latter, implementing classes should define a no-arg constructor
+ * or a {@link Map} constructor so that YAML parameters can be supplied.
+ * <p>
+ * Note that initializers are only invoked on first creation; they are not called 
+ * during a rebind. Instead, the typical pattern is that initializers will create
+ * {@link EntityAdjunct} instances such as {@link Policy} and {@link Feed}
+ * which will be attached during rebind.
+ **/ 
+public interface EntityInitializer {
+    
+    /** Applies initialization logic to a just-built entity.
+     * Invoked immediately after the "init" call on the AbstractEntity constructed.
+     * 
+     * @param entity guaranteed to be the actual implementation instance, 
+     * thus guaranteed to be castable to EntityInternal which is often desired,
+     * or to the type at hand (it is not even a proxy)
+     */
+    public void apply(EntityLocal entity);
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/EntityLocal.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/EntityLocal.java b/api/src/main/java/org/apache/brooklyn/api/entity/EntityLocal.java
new file mode 100644
index 0000000..aeb7249
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/EntityLocal.java
@@ -0,0 +1,175 @@
+/*
+ * 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 java.util.Map;
+
+import org.apache.brooklyn.api.mgmt.SubscriptionContext;
+import org.apache.brooklyn.api.mgmt.SubscriptionHandle;
+import org.apache.brooklyn.api.mgmt.SubscriptionManager;
+import org.apache.brooklyn.api.mgmt.Task;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.api.sensor.SensorEventListener;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.config.ConfigKey.HasConfigKey;
+import org.apache.brooklyn.util.guava.Maybe;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+
+/** 
+ * Extended Entity interface for use in places where the caller should have certain privileges,
+ * such as setting attribute values, adding policies, etc.
+ * 
+ * FIXME Moved from core project to api project because of bug in groovy's covariant return types.
+ * EntityDriver needs to return EntityLocal rather than Entity, to avoid changing a whole load
+ * of sub-types.
+ * FIXME Add {@link setAttribute(AttributeSensorAndConfigKey<?,T>)} back in if/when move it back,
+ * or if we extract an interface for AttributeSensorAndConfigKey.
+ * 
+ * @deprecated since 0.9.0; use {@link Entity} or {@link org.apache.brooklyn.core.entity.EntityInternal}
+ */
+public interface EntityLocal extends Entity {
+    
+    // FIXME Rename to something other than EntityLocal.
+    // Separate out what is specific to "local jvm", and what is here for an SPI rather than API.
+
+    /**
+     * @deprecated since 0.7.0; use {@link #config()}, such as {@code entity.config().set(key, val)}
+     */
+    @Deprecated
+    <T> T setConfig(ConfigKey<T> key, T val);
+    
+    /**
+     * @deprecated since 0.7.0; use {@link #config()}, such as {@code entity.config().set(key, val)}
+     */
+    @Deprecated
+    <T> T setConfig(ConfigKey<T> key, Task<T> val);
+    
+    /**
+     * @deprecated since 0.7.0; use {@link #config()}, such as {@code entity.config().set(key, val)}
+     */
+    @Deprecated
+    <T> T setConfig(HasConfigKey<T> key, T val);
+    
+    /**
+     * @deprecated since 0.7.0; use {@link #config()}, such as {@code entity.config().set(key, val)}
+     */
+    @Deprecated
+    <T> T setConfig(HasConfigKey<T> key, Task<T> val);
+
+    /**
+     * @deprecated since 0.8.0; use {@link SensorSupport#set(AttributeSensor, Object)} via code like {@code sensors().set(attribute, val)}.
+     */
+    <T> T setAttribute(AttributeSensor<T> attribute, T val);
+
+    /**
+     * @deprecated since 0.8.0; use {@link SensorSupport#modify(AttributeSensor, Function)} via code like {@code sensors().modify(attribute, modifier)}.
+     */
+    @Beta
+    <T> T modifyAttribute(AttributeSensor<T> attribute, Function<? super T, Maybe<T>> modifier);
+
+    /**
+     * @deprecated since 0.8.0; use {@link SensorSupport#emit(Sensor, Object)} via code like {@code sensors().emit(sensor, val)}.
+     */
+    <T> void emit(Sensor<T> sensor, T value);
+    
+    /**
+     * @deprecated in 0.5; use {@link #getConfig(ConfigKey)}
+     */
+    <T> T getConfig(ConfigKey<T> key, T defaultValue);
+    
+    /**
+     * @deprecated in 0.5; use {@link #getConfig(HasConfigKey)}
+     */
+    <T> T getConfig(HasConfigKey<T> key, T defaultValue);
+
+    /**
+     * Allow us to subscribe to data from a {@link Sensor} on another entity.
+     * 
+     * @return a subscription id which can be used to unsubscribe
+     *
+     * @see SubscriptionManager#subscribe(Map, Entity, Sensor, SensorEventListener)
+     * 
+     * @deprecated since 0.9.0; see {@link SubscriptionSupportInternal#getSubscriptionContext()}, e.g. with {@code subscriptions().getSubscriptionContext()}
+     */
+    @Deprecated
+    @Beta
+    <T> SubscriptionHandle subscribe(Entity producer, Sensor<T> sensor, SensorEventListener<? super T> listener);
+
+    /**
+     * @see SubscriptionManager#subscribeToChildren(Map, Entity, Sensor, SensorEventListener)
+     * 
+     * @deprecated since 0.9.0; see {@link SubscriptionSupport#subscribeToChildren(Entity, Sensor, SensorEventListener)}, e.g. with {@code subscriptions().subscribeToChildren(...)}
+     */
+    @Deprecated
+    @Beta
+    <T> SubscriptionHandle subscribeToChildren(Entity parent, Sensor<T> sensor, SensorEventListener<? super T> listener);
+ 
+    /**
+     * @see SubscriptionManager#subscribeToMembers(Group, Sensor, SensorEventListener)
+     * 
+     * @deprecated since 0.9.0; see {@link SubscriptionSupport#subscribeToMembers(Entity, Sensor, SensorEventListener)}, e.g. with {@code subscriptions().subscribeToMembers(...)}
+     */
+    @Deprecated
+    @Beta
+    <T> SubscriptionHandle subscribeToMembers(Group group, Sensor<T> sensor, SensorEventListener<? super T> listener);
+
+    /**
+     * Unsubscribes from the given producer.
+     *
+     * @see SubscriptionContext#unsubscribe(SubscriptionHandle)
+     * 
+     * @deprecated since 0.9.0; see {@link SubscriptionSupport#unsubscribe(Entity)}, e.g. with {@code subscriptions().unsubscribe(...)}
+     */
+    @Deprecated
+    @Beta
+    boolean unsubscribe(Entity producer);
+
+    /**
+     * Unsubscribes the given handle.
+     *
+     * @see SubscriptionContext#unsubscribe(SubscriptionHandle)
+     * 
+     * @deprecated since 0.9.0; see {@link SubscriptionSupport#unsubscribe(Entity, SubscriptionHandle)}, e.g. with {@code subscriptions().unsubscribe(...)}
+     */
+    @Deprecated
+    @Beta
+    boolean unsubscribe(Entity producer, SubscriptionHandle handle);
+
+    /**
+     * Removes all policy from this entity. 
+     * @return True if any policies existed at this entity; false otherwise
+     * 
+     * @deprecated since 0.9.0; see {@link PolicySupportInternal#removeAllPolicies()}, e.g. {@code ((EntityInternal)entity).policies().removeAllPolicies()}
+     */
+    @Deprecated
+    boolean removeAllPolicies();
+    
+    /**
+     * Removes all enricher from this entity.
+     * Use with caution as some entities automatically register enrichers; this will remove those enrichers as well.
+     * @return True if any enrichers existed at this entity; false otherwise
+     * 
+     * @deprecated since 0.9.0; see {@link EnricherSupportInternal#removeAllEnrichers()}, e.g. {@code ((EntityInternal)entity).enrichers().removeAllEnrichers()}
+     */
+    @Deprecated
+    boolean removeAllEnrichers();
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java b/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java
new file mode 100644
index 0000000..58cf946
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/EntitySpec.java
@@ -0,0 +1,401 @@
+/*
+ * 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.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 <T> The type of entity to be created
+ * 
+ * @author aled
+ */
+public class EntitySpec<T extends Entity> extends AbstractBrooklynObjectSpec<T,EntitySpec<T>> {
+
+    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 <T extends Entity> EntitySpec<T> create(Class<T> type) {
+        return new EntitySpec<T>(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 <T extends Entity, U extends T> EntitySpec<T> create(Class<T> type, Class<U> implType) {
+        return new EntitySpec<T>(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 <T extends Entity> EntitySpec<T> create(Map<?,?> config, Class<T> type) {
+        return EntitySpec.create(type).configure(config);
+    }
+    
+    /**
+     * Copies entity spec so its configuration can be overridden without modifying the 
+     * original entity spec.
+     */
+    public static <T extends Entity> EntitySpec<T> create(EntitySpec<T> spec) {
+        return create(spec.getType()).copyFrom(spec);
+    }
+    
+    public static <T extends Entity> EntitySpec<T> newInstance(Class<T> type) {
+        return new EntitySpec<T>(type);
+    }
+
+    private Class<? extends T> impl;
+    private Entity parent;
+    private final List<Policy> policies = Lists.newArrayList();
+    private final List<PolicySpec<?>> policySpecs = Lists.newArrayList();
+    private final List<Enricher> enrichers = Lists.newArrayList();
+    private final List<EnricherSpec<?>> enricherSpecs = Lists.newArrayList();
+    private final List<Location> locations = Lists.newArrayList();
+    private final Set<Class<?>> additionalInterfaces = Sets.newLinkedHashSet();
+    private final List<EntityInitializer> entityInitializers = Lists.newArrayList();
+    private final List<EntitySpec<?>> children = Lists.newArrayList();
+    private final List<Entity> members = Lists.newArrayList();
+    private final List<Group> groups = Lists.newArrayList();
+    private volatile boolean immutable;
+    
+    public EntitySpec(Class<T> type) {
+        super(type);
+    }
+
+    @Override
+    protected EntitySpec<T> copyFrom(EntitySpec<T> 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())
+                .locations(otherSpec.getLocations());
+        
+        if (otherSpec.getParent() != null) parent(otherSpec.getParent());
+        if (otherSpec.getImplementation() != null) impl(otherSpec.getImplementation());
+        
+        return this;
+    }
+
+    private List<EntitySpec<?>> copyFromSpecs(List<EntitySpec<?>> children) {
+        return Lists.<EntitySpec<?>,EntitySpec<?>>transform(children, new Function<EntitySpec<?>, EntitySpec<?>>() {
+            @Nullable
+            @Override
+            public EntitySpec<?> apply(@Nullable EntitySpec<?> entitySpec) {
+                return create(entitySpec);
+            }
+        });
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Class<T> getType() {
+        return (Class<T>)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<Class<?>> getAdditionalInterfaces() {
+        return additionalInterfaces;
+    }
+
+    /** @return {@link EntityInitializer} objects which customize the entity to be created */
+    public List<EntityInitializer> getInitializers() {
+        return entityInitializers;
+    }
+    
+    public List<EntitySpec<?>> getChildren() {
+        return children;
+    }
+    
+    public List<Entity> getMembers() {
+        return members;
+    }
+    
+    public List<Group> getGroups() {
+        return groups;
+    }
+    
+    /**
+     * @return The entity's parent
+     */
+    public Entity getParent() {
+        return parent;
+    }
+
+    public List<PolicySpec<?>> getPolicySpecs() {
+        return policySpecs;
+    }
+    
+    public List<Policy> getPolicies() {
+        return policies;
+    }
+    
+    public List<EnricherSpec<?>> getEnricherSpecs() {
+        return enricherSpecs;
+    }
+    
+    public List<Enricher> getEnrichers() {
+        return enrichers;
+    }
+    
+    public List<Location> getLocations() {
+        return locations;
+    }
+
+    public EntitySpec<T> impl(Class<? extends T> val) {
+        checkMutable();
+        checkIsImplementation(checkNotNull(val, "impl"), getType());
+        checkIsNewStyleImplementation(val);
+        impl = val;
+        return this;
+    }
+
+    public EntitySpec<T> additionalInterfaces(Class<?>... vals) {
+        checkMutable();
+        for (Class<?> val : vals) {
+            additionalInterfaces.add(val);
+        }
+        return this;
+    }
+
+    public EntitySpec<T> additionalInterfaces(Iterable<Class<?>> val) {
+        checkMutable();
+        additionalInterfaces.addAll(Sets.newLinkedHashSet(val));
+        return this;
+    }
+
+    public EntitySpec<T> addInitializer(EntityInitializer initializer) {
+        checkMutable();
+        entityInitializers.add(initializer);
+        return this;
+    }
+        
+    public EntitySpec<T> addInitializers(Iterable<? extends EntityInitializer> initializers) {
+        checkMutable();
+        Iterables.addAll(entityInitializers, initializers);
+        return this;
+    }
+
+    /** The supplied class must have a public no-arg constructor. */
+    public EntitySpec<T> addInitializer(Class<? extends EntityInitializer> initializerType) {
+        checkMutable();
+        try {
+            entityInitializers.add(initializerType.newInstance());
+        } catch (Exception e) {
+            throw Throwables.propagate(e);
+        }
+        return this;
+    }
+
+    public EntitySpec<T> 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<T> child(EntitySpec<?> child) {
+        checkMutable();
+        children.add(child);
+        return this;
+    }
+
+    public EntitySpec<T> members(Iterable<? extends Entity> members) {
+        checkMutable();
+        Iterables.addAll(this.members, members);
+        return this;
+    }
+
+    public EntitySpec<T> member(Entity member) {
+        checkMutable();
+        members.add(member);
+        return this;
+    }
+
+    public EntitySpec<T> groups(Iterable<? extends Group> groups) {
+        checkMutable();
+        Iterables.addAll(this.groups, groups);
+        return this;
+    }
+
+    public EntitySpec<T> group(Group group) {
+        checkMutable();
+        groups.add(group);
+        return this;
+    }
+
+    public EntitySpec<T> parent(Entity val) {
+        checkMutable();
+        parent = checkNotNull(val, "parent");
+        return this;
+    }
+
+    /** adds a policy to the spec */
+    public <V> EntitySpec<T> policy(Policy val) {
+        checkMutable();
+        policies.add(checkNotNull(val, "policy"));
+        return this;
+    }
+
+    /** adds a policy to the spec */
+    public <V> EntitySpec<T> policy(PolicySpec<?> val) {
+        checkMutable();
+        policySpecs.add(checkNotNull(val, "policySpec"));
+        return this;
+    }
+
+    /** adds the supplied policies to the spec */
+    public <V> EntitySpec<T> policySpecs(Iterable<? extends PolicySpec<?>> val) {
+        checkMutable();
+        policySpecs.addAll(MutableList.copyOf(checkNotNull(val, "policySpecs")));
+        return this;
+    }
+    
+    /** adds the supplied policies to the spec */
+    public <V> EntitySpec<T> policies(Iterable<? extends Policy> val) {
+        checkMutable();
+        policies.addAll(MutableList.copyOf(checkNotNull(val, "policies")));
+        return this;
+    }
+    
+    /** adds a policy to the spec */
+    public <V> EntitySpec<T> enricher(Enricher val) {
+        checkMutable();
+        enrichers.add(checkNotNull(val, "enricher"));
+        return this;
+    }
+
+    /** adds a policy to the spec */
+    public <V> EntitySpec<T> enricher(EnricherSpec<?> val) {
+        checkMutable();
+        enricherSpecs.add(checkNotNull(val, "enricherSpec"));
+        return this;
+    }
+
+    /** adds the supplied policies to the spec */
+    public <V> EntitySpec<T> enricherSpecs(Iterable<? extends EnricherSpec<?>> val) {
+        checkMutable();
+        enricherSpecs.addAll(MutableList.copyOf(checkNotNull(val, "enricherSpecs")));
+        return this;
+    }
+    
+    /** adds the supplied policies to the spec */
+    public <V> EntitySpec<T> enrichers(Iterable<? extends Enricher> val) {
+        checkMutable();
+        enrichers.addAll(MutableList.copyOf(checkNotNull(val, "enrichers")));
+        return this;
+    }
+    
+    /** adds a location to the spec */
+    public <V> EntitySpec<T> location(Location val) {
+        checkMutable();
+        locations.add(checkNotNull(val, "location"));
+        return this;
+    }
+    
+    /** clears locations defined in the spec */
+    public <V> EntitySpec<T> clearLocations() {
+        checkMutable();
+        locations.clear();
+        return this;        
+    }
+    
+    /** adds the supplied locations to the spec */
+    public <V> EntitySpec<T> locations(Iterable<? extends Location> val) {
+        checkMutable();
+        locations.addAll(MutableList.copyOf(checkNotNull(val, "locations")));
+        return this;
+    }
+
+    /** "seals" this spec, preventing any future changes */
+    public EntitySpec<T> immutable() {
+        immutable = true;
+        return this;
+    }
+
+    private void checkMutable() {
+        if (immutable) throw new IllegalStateException("Cannot modify immutable entity spec "+this);
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/EntityType.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/EntityType.java b/api/src/main/java/org/apache/brooklyn/api/entity/EntityType.java
new file mode 100644
index 0000000..1c3f7b5
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/EntityType.java
@@ -0,0 +1,73 @@
+/*
+ * 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 java.util.NoSuchElementException;
+import java.util.Set;
+
+import org.apache.brooklyn.api.effector.Effector;
+import org.apache.brooklyn.api.objs.BrooklynType;
+import org.apache.brooklyn.api.sensor.Sensor;
+import org.apache.brooklyn.util.guava.Maybe;
+
+/**
+ * Gives type information for an {@link Entity}. It is an immutable snapshot.
+ * 
+ * It reflects a given entity at the time the snapshot was created: if sensors
+ * were added or removed on-the-fly then those changes will be included in subsequent
+ * snapshots. Therefore instances of a given class of entity could have different 
+ * EntityTypes.
+ */
+public interface EntityType extends BrooklynType {
+
+    /**
+     * Sensors available on this entity.
+     */
+    Set<Sensor<?>> getSensors();
+    
+    /**
+     * Effectors available on this entity.
+     */
+    Set<Effector<?>> getEffectors();
+
+    /** @return an effector with the given name, if it exists.
+     */
+    public Maybe<Effector<?>> getEffectorByName(String name);
+        
+    /**
+     * @return the matching effector on this entity
+     * @throws NoSuchElementException If there is no exact match for this signature
+     * <p>
+     * @deprecated since 0.7.0 use {@link #getEffectorByName(String)};
+     * use of multiple effectors with the same name is not supported by the EntityDynamicType implementation,
+     * so should be discouraged.  overloading can be achieved by inspecting the parameters map. 
+     */
+    @Deprecated
+    Effector<?> getEffector(String name, Class<?>... parameterTypes);
+
+    /**
+     * The Sensor with the given name, or null if not found.
+     */
+    Sensor<?> getSensor(String name);
+    
+    /**
+     * @return True if has the sensor with the given name; false otherwise.
+     */
+    boolean hasSensor(String name);
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/EntityTypeRegistry.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/EntityTypeRegistry.java b/api/src/main/java/org/apache/brooklyn/api/entity/EntityTypeRegistry.java
new file mode 100644
index 0000000..4747e5b
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/EntityTypeRegistry.java
@@ -0,0 +1,63 @@
+/*
+ * 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 org.apache.brooklyn.api.entity.drivers.DriverDependentEntity;
+import org.apache.brooklyn.api.entity.drivers.EntityDriver;
+import org.apache.brooklyn.api.location.Location;
+
+/**
+ * A registry of the entity implementations to be used when creating an entity of a given type.
+ * 
+ * A given implementation can only be associated with one entity type interface.
+ */
+public interface EntityTypeRegistry {
+
+    /**
+     * Returns the implementation to be used for the given entity type.
+     *
+     * @param entity the {@link DriverDependentEntity} to create the {@link EntityDriver} for.
+     * @param location the {@link Location} where the {@link DriverDependentEntity} is running.
+     * @param <D>
+     * @return the creates EntityDriver.
+     * @throws IllegalArgumentException If no implementation registered, and the given interface is not annotated with {@link ImplementedBy}
+     * @throws IllegalStateException If the given type is not an interface, or if the implementation class is not a concrete class implementing it
+     */
+    <T extends Entity> Class<? extends T> getImplementedBy(Class<T> type);
+
+    /**
+     * Returns the interface of this entity implementation.
+     * E.g. for use as the fully qualified name in {@code entity.getEntityType().getName()}.
+     * 
+     * @throws IllegalArgumentException If no interface is registered against this implementation, 
+     *         and no super-type of the class is annotated with {@link ImplementedBy} to point at the given class
+     */
+    <T extends Entity> Class<? super T> getEntityTypeOf(Class<T> type);
+
+    /**
+     * Registers the implementation to use for a given entity type.
+     * 
+     * The implementation must be a non-abstract class implementing the given type, and must 
+     * have a no-argument constructor.
+     * 
+     * @throws IllegalArgumentException If this implementation has already been registered for a different type
+     * @throws IllegalStateException If the implClazz is not a concrete class, or does not implement type
+     */
+    <T extends Entity> EntityTypeRegistry registerImplementation(Class<T> type, Class<? extends T> implClazz);
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/Group.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/Group.java b/api/src/main/java/org/apache/brooklyn/api/entity/Group.java
new file mode 100644
index 0000000..05f80e1
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/Group.java
@@ -0,0 +1,71 @@
+/*
+ * 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 java.util.Collection;
+
+/**
+ * An {@link Entity} that groups together other entities.
+ * 
+ * The grouping can be for any purpose, such as allowing easy management/monitoring of
+ * a group of entities. The grouping could be static (i.e. a fixed set of entities)
+ * or dynamic (i.e. contains all entities that match some filter).
+ */
+public interface Group extends Entity {
+    
+    /**
+     * Return the entities that are members of this group.
+     */
+    Collection<Entity> getMembers();
+
+    /**
+     * @return True if it is a member of this group.
+     */
+    boolean hasMember(Entity member);
+
+    /**
+     * Adds the given member, returning true if this modifies the set of members (i.e. it was not already a member).
+     */
+    boolean addMember(Entity member);
+ 
+    /**
+     * Removes the given member, returning true if this modifies the set of members (i.e. it was a member).
+     */
+    boolean removeMember(Entity member);
+    
+    /**
+     * @return The number of members in this group.
+     */
+    Integer getCurrentSize();
+    
+    /** As {@link #addChild(EntitySpec)} followed by {@link #addMember(Entity)} */
+    <T extends Entity> T addMemberChild(EntitySpec<T> spec);
+    
+    /** As {@link #addChild(Entity)} followed by {@link #addMember(Entity)} */
+    <T extends Entity> T addMemberChild(T child);
+    
+    /** As in super, but note this does NOT by default add it as a member; see {@link #addMemberChild(EntitySpec)} */
+    @Override
+    <T extends Entity> T addChild(EntitySpec<T> spec);
+    
+    /** As in super, but note this does NOT by default add it as a member; see {@link #addMemberChild(Entity)} */
+    @Override
+    <T extends Entity> T addChild(T child);
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/ImplementedBy.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/ImplementedBy.java b/api/src/main/java/org/apache/brooklyn/api/entity/ImplementedBy.java
new file mode 100644
index 0000000..f0ee6a1
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/ImplementedBy.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.entity;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * A pointer to the default implementation of an entity.
+ * 
+ * A common naming convention is for the implementation class to have the suffix "Impl",
+ * but this is not required.
+ * 
+ * See {@link EntityTypeRegistry} for how to override the implementation to be used, if
+ * the class referenced by this annotation is not desired.
+ * 
+ * @author aled
+ */
+@Retention(RUNTIME)
+@Target(TYPE)
+public @interface ImplementedBy {
+
+  /**
+   * The implementation type.
+   */
+  Class<? extends Entity> value();
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/DriverDependentEntity.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/drivers/DriverDependentEntity.java b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/DriverDependentEntity.java
new file mode 100644
index 0000000..b59e9cc
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/DriverDependentEntity.java
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.Entity;
+
+/**
+ * An Entity that needs to have a driver.
+ *
+ * @param <D>
+ */
+public interface DriverDependentEntity<D extends EntityDriver> extends Entity {
+
+    Class<D> getDriverInterface();
+    
+    @Nullable D getDriver();
+    
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/EntityDriver.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/drivers/EntityDriver.java b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/EntityDriver.java
new file mode 100644
index 0000000..e2bb0bd
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/EntityDriver.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import org.apache.brooklyn.api.entity.EntityLocal;
+import org.apache.brooklyn.api.location.Location;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * The EntityDriver provides an abstraction between the Entity and the environment (the {@link Location} it is running
+ * in, so that an entity is not tightly coupled to a specific Location. E.g. you could have a TomcatEntity that uses
+ * a TomcatDriver (an interface) and you could have different driver implementations like the
+ * TomcatSshDriver/TomcatWindowsDriver and if in the future support for Puppet needs to be added, a TomcatPuppetDriver
+ * could be added.
+ *
+ * @author Peter Veentjer.
+ * @see DriverDependentEntity
+ * @see EntityDriverManager
+ */
+public interface EntityDriver {
+
+    /**
+     * The entity instance that this is a driver for.
+     * 
+     * FIXME The signature of this will change to return Entity instead of EntityLocal.
+     * This is a temporary workaround for groovy not supporting covariant return types,
+     * see http://jira.codehaus.org/browse/GROOVY-5418. It is fixed in groovy 2.0.4 so
+     * we will need to upgrade from 1.8.6 first.
+     */
+    @Beta
+    EntityLocal getEntity();
+
+    /**
+     * The location the entity is running in.
+     */
+    Location getLocation();
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d03f254b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/EntityDriverManager.java
----------------------------------------------------------------------
diff --git a/api/src/main/java/org/apache/brooklyn/api/entity/drivers/EntityDriverManager.java b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/EntityDriverManager.java
new file mode 100644
index 0000000..b2ad37e
--- /dev/null
+++ b/api/src/main/java/org/apache/brooklyn/api/entity/drivers/EntityDriverManager.java
@@ -0,0 +1,49 @@
+/*
+ * 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;
+
+import org.apache.brooklyn.api.location.Location;
+
+/**
+ * Responsible for creating a driver for a given entity/location. Also used for customizing which 
+ * type of driver should be used by entities in given locations.
+ * 
+ * The idea is that an entity should not be tightly coupled to a specific driver implementation, 
+ * so that there is flexibility for driver changes, without changing the entity itself. The 
+ * advantage is that drivers can easily be reconfigured, replaced or new drivers for different 
+ * environments can be added, without needing to modify Brooklyn.
+ * 
+ * To obtain an instance of a driver, use {@link #build(DriverDependentEntity, Location)}.
+ * This will use the registered driver types, or if one is not registered will fallback to the 
+ * default strategy.
+ */
+public interface EntityDriverManager {
+
+    /**
+     * Builds a new {@link EntityDriver} for the given entity/location.
+     *
+     * @param entity the {@link DriverDependentEntity} to create the {@link EntityDriver} for.
+     * @param location the {@link Location} where the {@link DriverDependentEntity} is running.
+     * @param <D>
+     * @return the creates EntityDriver.
+     */
+    <D extends EntityDriver> D build(DriverDependentEntity<D> entity, Location location);
+    
+    <D extends EntityDriver> void registerDriver(Class<D> driverInterface, Class<? extends Location> locationClazz, Class<? extends D> driverClazz);
+}