You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by ge...@apache.org on 2017/05/09 16:23:14 UTC

[2/3] brooklyn-server git commit: Add support for managing enrichers within the catalog (automatically scanned and YAML parsed, same as entities or policies)

Add support for managing enrichers within the catalog (automatically scanned and YAML parsed, same as entities or policies)


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/02305e71
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/02305e71
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/02305e71

Branch: refs/heads/master
Commit: 02305e71616fb0083f9f6bdd745c267b89718526
Parents: fc575d7
Author: Thomas Bouron <th...@cloudsoftcorp.com>
Authored: Fri Apr 14 20:07:35 2017 +0100
Committer: Thomas Bouron <th...@cloudsoftcorp.com>
Committed: Tue May 9 17:20:27 2017 +0100

----------------------------------------------------------------------
 .../brooklyn/api/catalog/CatalogItem.java       |   5 +
 .../spi/creation/CampInternalUtils.java         |  52 ++++++++++
 .../brooklyn/spi/creation/CampResolver.java     |   3 +
 .../spi/creation/CampTypePlanTransformer.java   |   1 +
 .../core/catalog/CatalogPredicates.java         |   4 +
 .../catalog/internal/BasicBrooklynCatalog.java  |   5 +
 .../catalog/internal/CatalogClasspathDo.java    |   8 ++
 .../internal/CatalogEnricherItemDto.java        |  43 ++++++++
 .../catalog/internal/CatalogItemBuilder.java    |   7 ++
 .../internal/JavaCatalogToSpecTransformer.java  |   6 ++
 .../core/network/OnPublicNetworkEnricher.java   |   2 +
 .../core/network/OnSubnetNetworkEnricher.java   |   2 +
 .../core/typereg/RegisteredTypePredicates.java  |   2 +
 .../brooklyn/enricher/stock/Aggregator.java     |   3 +-
 .../brooklyn/enricher/stock/Combiner.java       |   3 +-
 .../apache/brooklyn/enricher/stock/Joiner.java  |   3 +-
 .../brooklyn/enricher/stock/MapAggregator.java  |   2 +
 .../enricher/stock/PercentageEnricher.java      |   2 +
 .../brooklyn/enricher/stock/Propagator.java     |   3 +-
 .../brooklyn/enricher/stock/Transformer.java    |   7 +-
 .../brooklyn/enricher/stock/UpdatingMap.java    |   2 +
 .../YamlRollingTimeWindowMeanEnricher.java      |   3 +
 .../stock/YamlTimeWeightedDeltaEnricher.java    |   2 +
 .../enricher/stock/reducer/Reducer.java         |   4 +-
 core/src/main/resources/catalog.bom             |  60 ++++++++++-
 .../internal/CatalogItemBuilderTest.java        |   7 ++
 .../typereg/RegisteredTypePredicatesTest.java   |   3 +
 .../init/src/main/resources/catalog-classes.bom |  84 ++++++++++++++++
 .../brooklyn/policy/enricher/DeltaEnricher.java |   5 +-
 .../policy/enricher/HttpLatencyDetector.java    |   3 +-
 .../policy/enricher/RollingMeanEnricher.java    |   5 +-
 .../enricher/RollingTimeWindowMeanEnricher.java |   5 +-
 .../enricher/TimeFractionDeltaEnricher.java     |   5 +-
 .../enricher/TimeWeightedDeltaEnricher.java     |   7 +-
 .../policy/ha/ServiceFailureDetector.java       |   3 +-
 policy/src/main/resources/catalog.bom           |  30 ++++++
 .../apache/brooklyn/rest/api/CatalogApi.java    |  40 ++++++++
 .../rest/domain/CatalogEnricherSummary.java     |  80 +++++++++++++++
 .../rest/domain/EnricherConfigSummary.java      |  79 +++++++++++++++
 .../rest/resources/CatalogResource.java         |  55 ++++++++++-
 .../rest/transform/CatalogTransformer.java      |  27 ++++-
 .../rest/transform/EntityTransformer.java       |  10 ++
 .../CatalogResourcePerformanceTest.java         |  15 ++-
 .../rest/resources/CatalogResourceTest.java     |  99 +++++++++++++++++++
 .../test/osgi/entities/SimpleEnricher.java      |  42 ++++++++
 .../brooklyn/util/osgi/OsgiTestResources.java   |   1 +
 .../osgi/brooklyn-test-osgi-entities.jar        | Bin 22067 -> 22900 bytes
 47 files changed, 813 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/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
index 83159ba..c8f9731 100644
--- a/api/src/main/java/org/apache/brooklyn/api/catalog/CatalogItem.java
+++ b/api/src/main/java/org/apache/brooklyn/api/catalog/CatalogItem.java
@@ -35,6 +35,8 @@ 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.sensor.Enricher;
+import org.apache.brooklyn.api.sensor.EnricherSpec;
 import org.apache.brooklyn.api.typereg.OsgiBundleWithUrl;
 
 import com.google.common.annotations.Beta;
@@ -46,11 +48,13 @@ public interface CatalogItem<T,SpecT> extends BrooklynObject, Rebindable {
         TEMPLATE, 
         ENTITY, 
         POLICY,
+        ENRICHER,
         LOCATION;
         
         public static CatalogItemType ofSpecClass(Class<? extends AbstractBrooklynObjectSpec<?, ?>> type) {
             if (type==null) return null;
             if (PolicySpec.class.isAssignableFrom(type)) return POLICY;
+            if (EnricherSpec.class.isAssignableFrom(type)) return ENRICHER;
             if (LocationSpec.class.isAssignableFrom(type)) return LOCATION;
             if (EntitySpec.class.isAssignableFrom(type)) return ENTITY;
             return null;
@@ -58,6 +62,7 @@ public interface CatalogItem<T,SpecT> extends BrooklynObject, Rebindable {
         public static CatalogItemType ofTargetClass(Class<? extends BrooklynObject> type) {
             if (type==null) return null;
             if (Policy.class.isAssignableFrom(type)) return POLICY;
+            if (Enricher.class.isAssignableFrom(type)) return ENRICHER;
             if (Location.class.isAssignableFrom(type)) return LOCATION;
             if (Application.class.isAssignableFrom(type)) return TEMPLATE;
             if (Entity.class.isAssignableFrom(type)) return ENTITY;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java
index 7501552..1bc29fc 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampInternalUtils.java
@@ -38,6 +38,8 @@ import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.api.objs.SpecParameter;
 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.api.typereg.RegisteredType;
 import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext;
 import org.apache.brooklyn.camp.CampPlatform;
@@ -144,6 +146,38 @@ class CampInternalUtils {
         return spec;
     }
 
+    static EnricherSpec<?> createEnricherSpec(String yamlPlan, BrooklynClassLoadingContext loader, Set<String> encounteredCatalogTypes) {
+        DeploymentPlan plan = makePlanFromYaml(loader.getManagementContext(), yamlPlan);
+
+        //Would ideally re-use the EnricherSpecResolver
+        //but it is CAMP specific and there is no easy way to get hold of it.
+        Object enrichers = checkNotNull(plan.getCustomAttributes().get(BasicBrooklynCatalog.ENRICHERS_KEY), "enricher config");
+        if (!(enrichers instanceof Iterable<?>)) {
+            throw new IllegalStateException("The value of " + BasicBrooklynCatalog.ENRICHERS_KEY + " must be an Iterable.");
+        }
+
+        Object policy = Iterables.getOnlyElement((Iterable<?>)enrichers);
+
+        return createEnricherSpec(loader, policy, encounteredCatalogTypes);
+    }
+
+    @SuppressWarnings("unchecked")
+    static EnricherSpec<?> createEnricherSpec(BrooklynClassLoadingContext loader, Object enricher, Set<String> encounteredCatalogTypes) {
+        Map<String, Object> itemMap;
+        if (enricher instanceof String) {
+            itemMap = ImmutableMap.<String, Object>of("type", enricher);
+        } else if (enricher instanceof Map) {
+            itemMap = (Map<String, Object>) enricher;
+        } else {
+            throw new IllegalStateException("Enricher expected to be string or map. Unsupported object type " + enricher.getClass().getName() + " (" + enricher.toString() + ")");
+        }
+
+        String versionedId = (String) checkNotNull(Yamls.getMultinameAttribute(itemMap, "enricher_type", "enricherType", "type"), "enricher type");
+        EnricherSpec<? extends Enricher> spec = resolveEnricherSpec(versionedId, loader, encounteredCatalogTypes);
+        initConfigAndParameters(spec, itemMap, loader);
+        return spec;
+    }
+
     static LocationSpec<?> createLocationSpec(String yamlPlan, BrooklynClassLoadingContext loader, Set<String> encounteredTypes) {
         DeploymentPlan plan = makePlanFromYaml(loader.getManagementContext(), yamlPlan);
         Object locations = checkNotNull(plan.getCustomAttributes().get(BasicBrooklynCatalog.LOCATIONS_KEY), "location config");
@@ -217,6 +251,24 @@ class CampInternalUtils {
         return spec;
     }
 
+    @SuppressWarnings("unchecked")
+    private static EnricherSpec<? extends Enricher> resolveEnricherSpec(
+            String versionedId,
+            BrooklynClassLoadingContext loader,
+            Set<String> encounteredCatalogTypes) {
+
+        EnricherSpec<? extends Enricher> spec;
+        RegisteredType item = loader.getManagementContext().getTypeRegistry().get(versionedId);
+        if (item != null && !encounteredCatalogTypes.contains(item.getSymbolicName())) {
+            RegisteredTypeLoadingContext context = RegisteredTypeLoadingContexts.alreadyEncountered(encounteredCatalogTypes);
+            return loader.getManagementContext().getTypeRegistry().createSpec(item, context, EnricherSpec.class);
+        } else {
+            // TODO-type-registry pass the loader in to the above, and allow it to load with the loader
+            spec = EnricherSpec.create(loader.loadClass(versionedId, Enricher.class));
+        }
+        return spec;
+    }
+
     private static LocationSpec<?> resolveLocationSpec(
             String type,
             Map<String, Object> brooklynConfig,

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
index f68ffad..55853d7 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampResolver.java
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.classloading.BrooklynClassLoadingContext;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext;
 import org.apache.brooklyn.camp.CampPlatform;
@@ -102,6 +103,8 @@ class CampResolver {
         supers.addIfNotNull(expectedType);
         if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Policy.class)) {
             spec = CampInternalUtils.createPolicySpec(planYaml, loader, encounteredTypes);
+        } else if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Enricher.class)) {
+            spec = CampInternalUtils.createEnricherSpec(planYaml, loader, encounteredTypes);
         } else if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Location.class)) {
             spec = CampInternalUtils.createLocationSpec(planYaml, loader, encounteredTypes);
         } else if (RegisteredTypes.isAnyTypeSubtypeOf(supers, Application.class)) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampTypePlanTransformer.java
----------------------------------------------------------------------
diff --git a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampTypePlanTransformer.java b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampTypePlanTransformer.java
index afeba41..d8ec7fb 100644
--- a/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampTypePlanTransformer.java
+++ b/camp/camp-brooklyn/src/main/java/org/apache/brooklyn/camp/brooklyn/spi/creation/CampTypePlanTransformer.java
@@ -54,6 +54,7 @@ public class CampTypePlanTransformer extends AbstractTypePlanTransformer {
         // TODO these should become legacy
         if (plan.get().containsKey("brooklyn.locations")) return 0.7;
         if (plan.get().containsKey("brooklyn.policies")) return 0.7;
+        if (plan.get().containsKey("brooklyn.enrichers")) return 0.7;
         return 0;
     }
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/core/catalog/CatalogPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/CatalogPredicates.java b/core/src/main/java/org/apache/brooklyn/core/catalog/CatalogPredicates.java
index 6232c77..849cdd8 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/CatalogPredicates.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/CatalogPredicates.java
@@ -35,6 +35,8 @@ import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.mgmt.rebind.mementos.Memento;
 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.core.catalog.internal.CatalogUtils;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
 import org.apache.brooklyn.core.mgmt.persist.XmlMementoSerializer;
@@ -143,6 +145,8 @@ public class CatalogPredicates {
             CatalogPredicates.<Entity,EntitySpec<?>>isCatalogItemType(CatalogItemType.ENTITY);
     public static final Predicate<CatalogItem<Policy,PolicySpec<?>>> IS_POLICY = 
             CatalogPredicates.<Policy,PolicySpec<?>>isCatalogItemType(CatalogItemType.POLICY);
+    public static final Predicate<CatalogItem<Enricher,EnricherSpec<?>>> IS_ENRICHER =
+            CatalogPredicates.<Enricher,EnricherSpec<?>>isCatalogItemType(CatalogItemType.ENRICHER);
     public static final Predicate<CatalogItem<Location,LocationSpec<?>>> IS_LOCATION = 
             CatalogPredicates.<Location,LocationSpec<?>>isCatalogItemType(CatalogItemType.LOCATION);
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
index 31b6ce5..161e1ca 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/BasicBrooklynCatalog.java
@@ -83,6 +83,7 @@ import com.google.common.collect.Maps;
  * to isolate classpaths. with osgi everything is just put into the "manual additions" catalog. */
 public class BasicBrooklynCatalog implements BrooklynCatalog {
     public static final String POLICIES_KEY = "brooklyn.policies";
+    public static final String ENRICHERS_KEY = "brooklyn.enrichers";
     public static final String LOCATIONS_KEY = "brooklyn.locations";
     public static final String NO_VERSION = "0.0.0.SNAPSHOT";
 
@@ -800,6 +801,7 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
 
                 attemptType("services", CatalogItemType.ENTITY);
                 attemptType(POLICIES_KEY, CatalogItemType.POLICY);
+                attemptType(ENRICHERS_KEY, CatalogItemType.ENRICHER);
                 attemptType(LOCATIONS_KEY, CatalogItemType.LOCATION);
             }
             
@@ -1169,6 +1171,9 @@ public class BasicBrooklynCatalog implements BrooklynCatalog {
                     case POLICY:
                         dto.setPlanYaml(POLICIES_KEY + ": [{ type: "+dto.getJavaType()+" }]");
                         break;
+                    case ENRICHER:
+                        dto.setPlanYaml(ENRICHERS_KEY + ": [{ type: "+dto.getJavaType()+" }]");
+                        break;
                     case LOCATION:
                         dto.setPlanYaml(LOCATIONS_KEY + ": [{ type: "+dto.getJavaType()+" }]");
                         break;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogClasspathDo.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogClasspathDo.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogClasspathDo.java
index c41eed9..9cdc705 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogClasspathDo.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogClasspathDo.java
@@ -35,6 +35,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.ImplementedBy;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.core.entity.factory.ApplicationBuilder;
 import org.apache.brooklyn.core.mgmt.BrooklynTags;
 import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
@@ -227,6 +228,12 @@ public class CatalogClasspathDo {
                     addCatalogEntry(new CatalogPolicyItemDto(), c);
                     count++;
                 }
+
+                Iterable<Class<? extends Enricher>> enrichers = this.excludeInvalidClasses(scanner.getSubTypesOf(Enricher.class));
+                for (Class<?> c: enrichers) {
+                    addCatalogEntry(new CatalogEnricherItemDto(), c);
+                    count++;
+                }
                 
                 Iterable<Class<? extends Location>> locations = this.excludeInvalidClasses(scanner.getSubTypesOf(Location.class));
                 for (Class<?> c: locations) {
@@ -292,6 +299,7 @@ public class CatalogClasspathDo {
         if (ApplicationBuilder.class.isAssignableFrom(c)) return addCatalogEntry(new CatalogTemplateItemDto(), c);
         if (Entity.class.isAssignableFrom(c)) return addCatalogEntry(new CatalogEntityItemDto(), c);
         if (Policy.class.isAssignableFrom(c)) return addCatalogEntry(new CatalogPolicyItemDto(), c);
+        if (Enricher.class.isAssignableFrom(c)) return addCatalogEntry(new CatalogEnricherItemDto(), c);
         if (Location.class.isAssignableFrom(c)) return addCatalogEntry(new CatalogLocationItemDto(), c);
         throw new IllegalStateException("Cannot add "+c+" to catalog: unsupported type "+c.getName());
     }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogEnricherItemDto.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogEnricherItemDto.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogEnricherItemDto.java
new file mode 100644
index 0000000..904a307
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogEnricherItemDto.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.core.catalog.internal;
+
+import org.apache.brooklyn.api.sensor.Enricher;
+import org.apache.brooklyn.api.sensor.EnricherSpec;
+
+
+public class CatalogEnricherItemDto extends CatalogItemDtoAbstract<Enricher,EnricherSpec<?>> {
+    
+    @Override
+    public CatalogItemType getCatalogItemType() {
+        return CatalogItemType.ENRICHER;
+    }
+
+    @Override
+    public Class<Enricher> getCatalogItemJavaType() {
+        return Enricher.class;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Override
+    public Class<EnricherSpec<?>> getSpecType() {
+        return (Class)EnricherSpec.class;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemBuilder.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemBuilder.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemBuilder.java
index 299abdb..82ab357 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemBuilder.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogItemBuilder.java
@@ -35,6 +35,7 @@ public class CatalogItemBuilder<CIConcreteType extends CatalogItemDtoAbstract<?,
         case ENTITY: return newEntity(symbolicName, version);
         case TEMPLATE: return newTemplate(symbolicName, version);
         case POLICY: return newPolicy(symbolicName, version);
+        case ENRICHER: return newEnricher(symbolicName, version);
         case LOCATION: return newLocation(symbolicName, version);
         }
         throw new IllegalStateException("Unexpected itemType: "+itemType);
@@ -58,6 +59,12 @@ public class CatalogItemBuilder<CIConcreteType extends CatalogItemDtoAbstract<?,
                 .version(version);
     }
 
+    public static CatalogItemBuilder<CatalogEnricherItemDto> newEnricher(String symbolicName, String version) {
+        return new CatalogItemBuilder<CatalogEnricherItemDto>(new CatalogEnricherItemDto())
+                .symbolicName(symbolicName)
+                .version(version);
+    }
+
     public static CatalogItemBuilder<CatalogLocationItemDto> newLocation(String symbolicName, String version) {
         return new CatalogItemBuilder<CatalogLocationItemDto>(new CatalogLocationItemDto())
                 .symbolicName(symbolicName)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
index 41d6d71..f320e5d 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/JavaCatalogToSpecTransformer.java
@@ -28,6 +28,8 @@ import org.apache.brooklyn.api.internal.AbstractBrooklynObjectSpec;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 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.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.mgmt.classloading.BrooklynClassLoadingContextSequential;
 import org.apache.brooklyn.core.objs.BasicSpecParameter;
@@ -103,6 +105,10 @@ public class JavaCatalogToSpecTransformer implements PlanToSpecTransformer {
                 @SuppressWarnings("unchecked")
                 Class<Policy> policyType = (Class<Policy>)type;
                 spec = PolicySpec.create(policyType);
+            } else if (Enricher.class.isAssignableFrom(type)) {
+                @SuppressWarnings("unchecked")
+                Class<Enricher> enricherType = (Class<Enricher>)type;
+                spec = EnricherSpec.create(enricherType);
             } else {
                 throw new IllegalStateException("Catalog item " + item + " java type " + javaType + " is not a Brooklyn supported object.");
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/core/network/OnPublicNetworkEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/network/OnPublicNetworkEnricher.java b/core/src/main/java/org/apache/brooklyn/core/network/OnPublicNetworkEnricher.java
index 878c1d5..3f0101b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/network/OnPublicNetworkEnricher.java
+++ b/core/src/main/java/org/apache/brooklyn/core/network/OnPublicNetworkEnricher.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.core.network;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.location.MachineLocation;
@@ -67,6 +68,7 @@ import com.google.common.reflect.TypeToken;
  * </pre>
  */
 @Beta
+@Catalog(name = "Public Network Advertiser", description = "Advertises entity's public mapped ports. This can be used with sensors of type URI, HostAndPort or plain integer port values")
 public class OnPublicNetworkEnricher extends AbstractOnNetworkEnricher {
 
     // TODO Need more logging, particularly for when the value has *not* been transformed.

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/core/network/OnSubnetNetworkEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/network/OnSubnetNetworkEnricher.java b/core/src/main/java/org/apache/brooklyn/core/network/OnSubnetNetworkEnricher.java
index f1b36c2..e75606f 100644
--- a/core/src/main/java/org/apache/brooklyn/core/network/OnSubnetNetworkEnricher.java
+++ b/core/src/main/java/org/apache/brooklyn/core/network/OnSubnetNetworkEnricher.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.core.network;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.MachineLocation;
 import org.apache.brooklyn.config.ConfigKey;
@@ -51,6 +52,7 @@ import com.google.common.net.HostAndPort;
  * </pre>
  */
 @Beta
+@Catalog(name = "Subnet Network Advertiser", description = "Advertises entity's subnet mapped ports. This can be used with sensors of type URI, HostAndPort or plain integer port values")
 public class OnSubnetNetworkEnricher extends AbstractOnNetworkEnricher {
 
     // TODO This is a temporary measure while we discuss and implement 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java
index 2c02874..e480cd1 100644
--- a/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java
+++ b/core/src/main/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicates.java
@@ -25,6 +25,7 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.api.policy.Policy;
+import org.apache.brooklyn.api.sensor.Enricher;
 import org.apache.brooklyn.api.typereg.RegisteredType;
 import org.apache.brooklyn.api.typereg.RegisteredTypeLoadingContext;
 import org.apache.brooklyn.core.mgmt.entitlement.Entitlements;
@@ -198,6 +199,7 @@ public class RegisteredTypePredicates {
     public static final Predicate<RegisteredType> IS_ENTITY = subtypeOf(Entity.class);
     public static final Predicate<RegisteredType> IS_LOCATION = subtypeOf(Location.class);
     public static final Predicate<RegisteredType> IS_POLICY = subtypeOf(Policy.class);
+    public static final Predicate<RegisteredType> IS_ENRICHER = subtypeOf(Enricher.class);
 
     public static Predicate<RegisteredType> entitledToSee(final ManagementContext mgmt) {
         return new EntitledToSee(mgmt);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/Aggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Aggregator.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Aggregator.java
index d10b55e..f94c652 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/Aggregator.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Aggregator.java
@@ -25,6 +25,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
@@ -47,7 +48,7 @@ import com.google.common.reflect.TypeToken;
 
 /** Building on {@link AbstractAggregator} for a single source sensor (on multiple children and/or members) */
 @SuppressWarnings("serial")
-//@Catalog(name="Aggregator", description="Aggregates attributes from multiple entities into a single attribute value; see Enrichers.builder().aggregating(...)")
+@Catalog(name="Aggregator", description="Aggregates sensors from multiple entities into a single sensor value")
 public class Aggregator<T,U> extends AbstractAggregator<T,U> implements SensorEventListener<T> {
 
     private static final Logger LOG = LoggerFactory.getLogger(Aggregator.class);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/Combiner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Combiner.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Combiner.java
index d0c1efd..961e16a 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/Combiner.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Combiner.java
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
@@ -49,7 +50,7 @@ import com.google.common.collect.Iterables;
 import com.google.common.reflect.TypeToken;
 
 @SuppressWarnings("serial")
-//@Catalog(name="Combiner", description="Combines attributes; see Enrichers.builder().combining(...)")
+@Catalog(name="Combiner", description="Combines and apply a transformation to sensors of an entity")
 public class Combiner<T,U> extends AbstractEnricher implements SensorEventListener<T> {
 
     private static final Logger LOG = LoggerFactory.getLogger(Combiner.class);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/Joiner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Joiner.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Joiner.java
index 731d26d..51f599e 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/Joiner.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Joiner.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.enricher.stock;
 
 import java.util.Map;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
@@ -39,7 +40,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.reflect.TypeToken;
 
-//@Catalog(name="Transformer", description="Transforms attributes of an entity; see Enrichers.builder().transforming(...)")
+@Catalog(name="Joiner", description="Joins entity's sensors into another one, i.e. creates a comma separated string from a list")
 @SuppressWarnings("serial")
 public class Joiner<T> extends AbstractEnricher implements SensorEventListener<T> {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/MapAggregator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/MapAggregator.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/MapAggregator.java
index fc4f3b1..8266f3b 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/MapAggregator.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/MapAggregator.java
@@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Maps;
 import com.google.common.reflect.TypeToken;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.config.ConfigKey;
@@ -35,6 +36,7 @@ import org.apache.brooklyn.util.collections.MutableMap;
  * Building on {@link AbstractMultipleSensorAggregator} for a pair of source sensors(on multiple children and/or members)
  * that are used as key-value pairs in a generated Map.
  */
+@Catalog(name = "Map Aggregator", description = "Aggregates a pair of sensors on multiple children and/or members that are used as key-value pairs in a generated Map")
 @SuppressWarnings("serial")
 public class MapAggregator<U> extends AbstractMultipleSensorAggregator<U> {
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/PercentageEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/PercentageEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/PercentageEnricher.java
index 3ae3847..f0ddb8e 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/PercentageEnricher.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/PercentageEnricher.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.enricher.stock;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -43,6 +44,7 @@ import org.apache.brooklyn.util.math.MathFunctions;
  * The Enricher subscribes to events from these sensors, and will emit the ratio
  * of current to total as a target sensor.
  */
+@Catalog(name = "Percentage Transformer", description = "Computes and advertises the percentage based on a current and total values")
 public class PercentageEnricher extends AbstractEnricher implements SensorEventListener<Number> {
 
     private static final Logger LOG = LoggerFactory.getLogger(PercentageEnricher.class);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/Propagator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Propagator.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Propagator.java
index 90182a4..21b7ffe 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/Propagator.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Propagator.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
@@ -53,7 +54,7 @@ import com.google.common.collect.Maps;
 import com.google.common.reflect.TypeToken;
 
 @SuppressWarnings("serial")
-//@Catalog(name="Propagator", description="Propagates attributes from one entity to another; see Enrichers.builder().propagating(...)")
+@Catalog(name="Propagator", description="Propagates sensors from one entity to another")
 public class Propagator extends AbstractEnricher implements SensorEventListener<Object> {
 
     private static final Logger LOG = LoggerFactory.getLogger(Propagator.class);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java
index 3eae2d1..ffd1fb6 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/Transformer.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.enricher.stock;
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.config.ConfigKey;
@@ -33,7 +34,7 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Function;
 import com.google.common.reflect.TypeToken;
 
-//@Catalog(name="Transformer", description="Transforms attributes of an entity; see Enrichers.builder().transforming(...)")
+@Catalog(name="Transformer", description="Transforms sensors of an entity")
 @SuppressWarnings("serial")
 public class Transformer<T,U> extends AbstractTransformer<T,U> {
 
@@ -113,9 +114,9 @@ public class Transformer<T,U> extends AbstractTransformer<T,U> {
             // If it's a special marker-object, then don't try to transform it
             return (U) rawVal;
         }
-        
+
         // evaluate immediately, or return null.
-        // For vals that implement ImmediateSupplier, we'll use that to get the value 
+        // For vals that implement ImmediateSupplier, we'll use that to get the value
         // (or Maybe.absent) without blocking.
         // Otherwise, the Tasks.resolving will give it its best shot at resolving without
         // blocking on external events (such as waiting for another entity's sensor).

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/UpdatingMap.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/UpdatingMap.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/UpdatingMap.java
index d37bf06..501d199 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/UpdatingMap.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/UpdatingMap.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.enricher.stock;
 
 import java.util.Map;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
@@ -59,6 +60,7 @@ import com.google.common.reflect.TypeToken;
  * @param <TVal> value type in target sensor map
  */
 @SuppressWarnings("serial")
+@Catalog(name = "Map Updater", description = "Updates an entry in a sensor Map")
 public class UpdatingMap<S,TKey,TVal> extends AbstractEnricher implements SensorEventListener<S> {
 
     private static final Logger LOG = LoggerFactory.getLogger(UpdatingMap.class);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricher.java
index e125758..6c51abd 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricher.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlRollingTimeWindowMeanEnricher.java
@@ -20,6 +20,8 @@ package org.apache.brooklyn.enricher.stock;
 
 import java.util.Iterator;
 import java.util.LinkedList;
+
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.Sensor;
 import org.apache.brooklyn.api.sensor.SensorEvent;
@@ -52,6 +54,7 @@ import com.google.common.base.Function;
  * <p>
  * The default average when no data has been received is 0, with a confidence of 0
  */
+@Catalog(name = "YAML Rolling Average", description = "Transforms sensor data into a rolling average based on a time window.")
 public class YamlRollingTimeWindowMeanEnricher<T extends Number> extends AbstractTransformer<T,Double> {
     
     public static ConfigKey<Duration> WINDOW_DURATION = ConfigKeys.newConfigKey(Duration.class, "enricher.window.duration",

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricher.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricher.java
index 9193e28..dab8c8a 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricher.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/YamlTimeWeightedDeltaEnricher.java
@@ -18,6 +18,7 @@
  */
 package org.apache.brooklyn.enricher.stock;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.config.ConfigKey;
@@ -38,6 +39,7 @@ import com.google.common.base.Function;
  * <p>
  * Suitable for configuration from YAML.
  */
+@Catalog(name = "YAML Time-weighted Delta", description = "Converts an absolute count sensor into a delta sensor")
 public class YamlTimeWeightedDeltaEnricher<T extends Number> extends AbstractTransformer<T,Double> {
     private static final Logger LOG = LoggerFactory.getLogger(YamlTimeWeightedDeltaEnricher.class);
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/Reducer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/Reducer.java b/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/Reducer.java
index 9d5ca33..c24869d 100644
--- a/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/Reducer.java
+++ b/core/src/main/java/org/apache/brooklyn/enricher/stock/reducer/Reducer.java
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
@@ -47,6 +48,7 @@ import com.google.common.collect.Lists;
 import com.google.common.reflect.TypeToken;
 
 @SuppressWarnings("serial")
+@Catalog(name = "Reducer", description = "Applies a transformation to a sensor")
 public class Reducer extends AbstractEnricher implements SensorEventListener<Object> {
 
     private static final Logger LOG = LoggerFactory.getLogger(Reducer.class);
@@ -63,7 +65,7 @@ public class Reducer extends AbstractEnricher implements SensorEventListener<Obj
     @SetFromFlag("transformation")
     public static final ConfigKey<String> REDUCER_FUNCTION_TRANSFORMATION = ConfigKeys.newStringConfigKey(
             "enricher.reducerFunction.transformation",
-            "A string matching a pre-defined named reducer function, such as joiner");
+            "A string matching a pre-defined named reducer function, such as joiner, formatString, etc");
     public static final ConfigKey<Map<String, Object>> PARAMETERS = ConfigKeys.newConfigKey(new TypeToken<Map<String, Object>>() {},
             "enricher.reducerFunction.parameters",
             "A map of parameters to pass into the reducer function");

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/main/resources/catalog.bom
----------------------------------------------------------------------
diff --git a/core/src/main/resources/catalog.bom b/core/src/main/resources/catalog.bom
index a2fff9a..19f4929 100644
--- a/core/src/main/resources/catalog.bom
+++ b/core/src/main/resources/catalog.bom
@@ -16,8 +16,9 @@
 # under the License.
 
 brooklyn.catalog:
-    version: "0.12.0-SNAPSHOT" # BROOKLYN_VERSION
-    itemType: entity
+  version: "0.12.0-SNAPSHOT" # BROOKLYN_VERSION
+  items:
+  - itemType: entity
     items:
     - id: org.apache.brooklyn.entity.group.QuarantineGroup
       item:
@@ -58,3 +59,58 @@ brooklyn.catalog:
     - id: org.apache.brooklyn.entity.group.DynamicFabric
       item:
         type: org.apache.brooklyn.entity.group.DynamicFabric
+
+  - itemType: enricher
+    items:
+    - id: org.apache.brooklyn.core.network.OnPublicNetworkEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.core.network.OnPublicNetworkEnricher
+    - id: org.apache.brooklyn.core.network.OnSubnetNetworkEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.core.network.OnSubnetNetworkEnricher
+    - id: org.apache.brooklyn.enricher.stock.Aggregator
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.Aggregator
+    - id: org.apache.brooklyn.enricher.stock.Combiner
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.Combiner
+    - id: org.apache.brooklyn.enricher.stock.Joiner
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.Joiner
+    - id: org.apache.brooklyn.enricher.stock.MapAggregator
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.MapAggregator
+    - id: org.apache.brooklyn.enricher.stock.PercentageEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.PercentageEnricher
+    - id: org.apache.brooklyn.enricher.stock.Propagator
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.Propagator
+    - id: org.apache.brooklyn.enricher.stock.Transformer
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.Transformer
+    - id: org.apache.brooklyn.enricher.stock.UpdatingMap
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.UpdatingMap
+    - id: org.apache.brooklyn.enricher.stock.YamlRollingTimeWindowMeanEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.YamlRollingTimeWindowMeanEnricher
+    - id: org.apache.brooklyn.enricher.stock.YamlTimeWeightedDeltaEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.YamlTimeWeightedDeltaEnricher
+    - id: org.apache.brooklyn.enricher.stock.reducer.Reducer
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.reducer.Reducer
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogItemBuilderTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogItemBuilderTest.java b/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogItemBuilderTest.java
index 1441797..f930b6e 100644
--- a/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogItemBuilderTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/catalog/internal/CatalogItemBuilderTest.java
@@ -79,6 +79,13 @@ public class CatalogItemBuilderTest {
     }
 
     @Test
+    public void testNewEnricherReturnCatalogEnricherItemDto() {
+        final CatalogItem catalogItem = CatalogItemBuilder.newEnricher(symbolicName, version).build();
+
+        assertTrue(catalogItem != null);
+    }
+
+    @Test
     public void testNewTemplateReturnCatalogTemplateItemDto() {
         final CatalogItem<?, ?> catalogItem = CatalogItemBuilder.newTemplate(symbolicName, version).build();
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/core/src/test/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicatesTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicatesTest.java b/core/src/test/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicatesTest.java
index 08b63c7..d86d5a5 100644
--- a/core/src/test/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicatesTest.java
+++ b/core/src/test/java/org/apache/brooklyn/core/typereg/RegisteredTypePredicatesTest.java
@@ -81,6 +81,9 @@ public class RegisteredTypePredicatesTest extends BrooklynMgmtUnitTestSupport {
 
         assertTrue(RegisteredTypePredicates.IS_ENTITY.apply(item));
         assertFalse(RegisteredTypePredicates.IS_LOCATION.apply(item));
+        assertFalse(RegisteredTypePredicates.IS_APPLICATION.apply(item));
+        assertFalse(RegisteredTypePredicates.IS_ENRICHER.apply(item));
+        assertFalse(RegisteredTypePredicates.IS_POLICY.apply(item));
     }
     
     @Test

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/karaf/init/src/main/resources/catalog-classes.bom
----------------------------------------------------------------------
diff --git a/karaf/init/src/main/resources/catalog-classes.bom b/karaf/init/src/main/resources/catalog-classes.bom
index be49e73..3cb90ac 100644
--- a/karaf/init/src/main/resources/catalog-classes.bom
+++ b/karaf/init/src/main/resources/catalog-classes.bom
@@ -106,6 +106,90 @@ brooklyn.catalog:
         name: Auto-scaler
         description: Policy that is attached to a Resizable entity and dynamically 
 
+  # org.apache.brooklyn.enrichers
+  - itemType: enricher
+    items:
+    - id: org.apache.brooklyn.core.network.OnPublicNetworkEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.core.network.OnPublicNetworkEnricher
+    - id: org.apache.brooklyn.core.network.OnSubnetNetworkEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.core.network.OnSubnetNetworkEnricher
+    - id: org.apache.brooklyn.enricher.stock.Aggregator
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.Aggregator
+    - id: org.apache.brooklyn.enricher.stock.Combiner
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.Combiner
+    - id: org.apache.brooklyn.enricher.stock.Joiner
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.Joiner
+    - id: org.apache.brooklyn.enricher.stock.MapAggregator
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.MapAggregator
+    - id: org.apache.brooklyn.enricher.stock.PercentageEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.PercentageEnricher
+    - id: org.apache.brooklyn.enricher.stock.Propagator
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.Propagator
+    - id: org.apache.brooklyn.enricher.stock.Transformer
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.Transformer
+    - id: org.apache.brooklyn.enricher.stock.UpdatingMap
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.UpdatingMap
+    - id: org.apache.brooklyn.enricher.stock.YamlRollingTimeWindowMeanEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.YamlRollingTimeWindowMeanEnricher
+    - id: org.apache.brooklyn.enricher.stock.YamlTimeWeightedDeltaEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.YamlTimeWeightedDeltaEnricher
+    - id: org.apache.brooklyn.enricher.stock.reducer.Reducer
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.enricher.stock.reducer.Reducer
+    - id: org.apache.brooklyn.policy.enricher.DeltaEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.DeltaEnricher
+    - id: org.apache.brooklyn.policy.enricher.HttpLatencyDetector
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.HttpLatencyDetector
+    - id: org.apache.brooklyn.policy.enricher.RollingMeanEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.RollingMeanEnricher
+    - id: org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher
+    - id: org.apache.brooklyn.policy.enricher.TimeFractionDeltaEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.TimeFractionDeltaEnricher
+    - id: org.apache.brooklyn.policy.enricher.TimeWeightedDeltaEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.TimeWeightedDeltaEnricher
+    - id: org.apache.brooklyn.policy.ha.ServiceFailureDetector
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.ha.ServiceFailureDetector
+
     # org.apache.brooklyn.software-base
   - itemType: entity
     items:

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/policy/src/main/java/org/apache/brooklyn/policy/enricher/DeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/DeltaEnricher.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/DeltaEnricher.java
index 2f41bfd..1320e45 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/DeltaEnricher.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/DeltaEnricher.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.policy.enricher;
 
 import static org.apache.brooklyn.util.JavaGroovyEquivalents.elvis;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
@@ -30,8 +31,8 @@ import org.apache.brooklyn.util.core.flags.TypeCoercions;
 /**
  * Converts an absolute sensor into a delta sensor (i.e. the diff between the current and previous value)
  */
-//@Catalog(name="Delta", description="Converts an absolute sensor into a delta sensor "
-//        + "(i.e. the diff between the current and previous value)")
+@Catalog(name="Delta", description="Converts an absolute sensor into a delta sensor "
+        + "(i.e. the diff between the current and previous value)")
 public class DeltaEnricher<T extends Number> extends AbstractTransformingEnricher<T> {
     Number last = 0;
 

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
index 92c5463..84e9dd7 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/HttpLatencyDetector.java
@@ -27,6 +27,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
@@ -65,7 +66,7 @@ import com.google.common.reflect.TypeToken;
  * optionally returned from sensors.  It does not currently support POST 
  * and has limited support for https.
  */
-//@Catalog(name="HTTP Latency Detector", description="An Enricher which computes latency in accessing a URL, normally by periodically polling that URL")
+@Catalog(name="HTTP Latency Detector", description="Computes latency in accessing a URL, normally by periodically polling that URL")
 public class HttpLatencyDetector extends AbstractEnricher implements Enricher {
 
     private static final Logger log = LoggerFactory.getLogger(HttpLatencyDetector.class);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.java
index 0e6dd76..082b851 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingMeanEnricher.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.policy.enricher;
 
 import java.util.LinkedList;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.SensorEvent;
@@ -32,8 +33,8 @@ import org.apache.brooklyn.util.javalang.JavaClassNames;
 * Transforms a sensor into a rolling average based on a fixed window size. This is useful for smoothing sample type metrics, 
 * such as latency or CPU time
 */
-//@Catalog(name="Rolling Mean", description="Transforms a sensor into a rolling average based on a fixed "
-//        + "window size. This is useful for smoothing sample type metrics, such as latency or CPU time")
+@Catalog(name="Rolling Mean", description="Transforms a sensor into a rolling average based on a fixed "
+        + "window size. This is useful for smoothing sample type metrics, such as latency or CPU time")
 public class RollingMeanEnricher<T extends Number> extends AbstractTypeTransformingEnricher<T,Double> {
     private LinkedList<T> values = new LinkedList<T>();
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.java
index b59fdd0..cd16eaa 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/RollingTimeWindowMeanEnricher.java
@@ -21,6 +21,7 @@ package org.apache.brooklyn.policy.enricher;
 import java.util.Iterator;
 import java.util.LinkedList;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
@@ -63,8 +64,8 @@ import com.google.common.base.Preconditions;
  * marking as @Beta in 0.7.0 timeframe 
  */
 @Beta
-//@Catalog(name="Rolling Mean in Time Window", description="Transforms a sensor's data into a rolling average "
-//        + "based on a time window.")
+@Catalog(name="Rolling Mean in Time Window", description="Transforms a sensor's data into a rolling average "
+        + "based on a time window.")
 public class RollingTimeWindowMeanEnricher<T extends Number> extends AbstractTypeTransformingEnricher<T,Double> {
     
     public static ConfigKey<Double> CONFIDENCE_REQUIRED_TO_PUBLISH = ConfigKeys.newDoubleConfigKey("confidenceRequired",

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricher.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricher.java
index 9e49b6b..e8db170 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricher.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeFractionDeltaEnricher.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.policy.enricher;
 
 import java.util.concurrent.TimeUnit;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.brooklyn.api.entity.Entity;
@@ -40,8 +41,8 @@ import org.apache.brooklyn.util.time.Duration;
  * 
  * It also configured with the time units for the values.
  */
-//@Catalog(name="Time-fraction Delta", description="Converts an absolute measure of time into a fraction of time, "
-//        + "based on the delta between consecutive values and the elapsed time between those values.")
+@Catalog(name="Time-fraction Delta", description="Converts an absolute measure of time into a fraction of time, "
+        + "based on the delta between consecutive values and the elapsed time between those values.")
 public class TimeFractionDeltaEnricher<T extends Number> extends AbstractTypeTransformingEnricher<T,Double> {
     private static final Logger LOG = LoggerFactory.getLogger(TimeFractionDeltaEnricher.class);
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeWeightedDeltaEnricher.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeWeightedDeltaEnricher.java b/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeWeightedDeltaEnricher.java
index fbf9960..3f48433 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeWeightedDeltaEnricher.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/enricher/TimeWeightedDeltaEnricher.java
@@ -20,6 +20,7 @@ package org.apache.brooklyn.policy.enricher;
 
 import groovy.lang.Closure;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.api.sensor.Sensor;
@@ -49,9 +50,9 @@ import com.google.common.base.Functions;
  * marking as @Beta in 0.7.0 timeframe 
  */
 @Beta
-//@Catalog(name="Time-weighted Delta", description="Converts an absolute sensor into a delta sensor "
-//        + "(i.e. the diff between the current and previous value), presented as a units/timeUnit "
-//        + "based on the event timing.")
+@Catalog(name="Time-weighted Delta", description="Converts an absolute sensor into a delta sensor "
+        + "(i.e. the diff between the current and previous value), presented as a units/timeUnit "
+        + "based on the event timing.")
 public class TimeWeightedDeltaEnricher<T extends Number> extends AbstractTypeTransformingEnricher<T,Double> {
     private static final Logger LOG = LoggerFactory.getLogger(TimeWeightedDeltaEnricher.class);
     

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
----------------------------------------------------------------------
diff --git a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
index 429c6e8..bc3e10a 100644
--- a/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
+++ b/policy/src/main/java/org/apache/brooklyn/policy/ha/ServiceFailureDetector.java
@@ -23,6 +23,7 @@ import java.util.Map.Entry;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import org.apache.brooklyn.api.catalog.Catalog;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.BasicConfigKey;
@@ -55,7 +56,7 @@ import org.apache.brooklyn.util.time.Time;
  * (or until another process manually sets {@link Attributes#SERVICE_STATE_ACTUAL} to {@value Lifecycle#ON_FIRE},
  * which this enricher will not clear until all problems have gone away)
  */
-//@Catalog(name="Service Failure Detector", description="HA policy for deteting failure of a service")
+@Catalog(name="Service Failure Detector", description="Emits a new sensor if the current entity fails")
 public class ServiceFailureDetector extends ServiceStateLogic.ComputeServiceState {
 
     // TODO Remove duplication between this and MemberFailureDetectionPolicy.

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/policy/src/main/resources/catalog.bom
----------------------------------------------------------------------
diff --git a/policy/src/main/resources/catalog.bom b/policy/src/main/resources/catalog.bom
index d57ac8d..fc637d0 100644
--- a/policy/src/main/resources/catalog.bom
+++ b/policy/src/main/resources/catalog.bom
@@ -60,3 +60,33 @@ brooklyn.catalog:
         type: org.apache.brooklyn.policy.autoscaling.AutoScalerPolicy
         name: Auto-scaler
         description: Policy that is attached to a Resizable entity and dynamically 
+
+    # Enrichers
+    - id: org.apache.brooklyn.policy.enricher.DeltaEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.DeltaEnricher
+    - id: org.apache.brooklyn.policy.enricher.HttpLatencyDetector
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.HttpLatencyDetector
+    - id: org.apache.brooklyn.policy.enricher.RollingMeanEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.RollingMeanEnricher
+    - id: org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.RollingTimeWindowMeanEnricher
+    - id: org.apache.brooklyn.policy.enricher.TimeFractionDeltaEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.TimeFractionDeltaEnricher
+    - id: org.apache.brooklyn.policy.enricher.TimeWeightedDeltaEnricher
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.enricher.TimeWeightedDeltaEnricher
+    - id: org.apache.brooklyn.policy.ha.ServiceFailureDetector
+      itemType: enricher
+      item:
+        type: org.apache.brooklyn.policy.ha.ServiceFailureDetector
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
index a891a18..972c2a6 100644
--- a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/api/CatalogApi.java
@@ -33,6 +33,7 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.apache.brooklyn.rest.domain.CatalogEnricherSummary;
 import org.apache.brooklyn.rest.domain.CatalogEntitySummary;
 import org.apache.brooklyn.rest.domain.CatalogItemSummary;
 import org.apache.brooklyn.rest.domain.CatalogLocationSummary;
@@ -359,4 +360,43 @@ public interface CatalogApi {
         @PathParam("itemId") String itemId,
         @ApiParam(name = "disabled", value = "Whether or not the catalog item is disabled", required = true)
         boolean disabled);
+
+    @GET
+    @Path("/enrichers")
+    @ApiOperation(value = "List available enrichers types optionally matching a query",
+            response = CatalogItemSummary.class,
+            responseContainer = "List")
+    public List<CatalogEnricherSummary> listEnrichers(
+            @ApiParam(name = "regex", value = "Regular expression to search for")
+            @QueryParam("regex") @DefaultValue("") String regex,
+            @ApiParam(name = "fragment", value = "Substring case-insensitive to search for")
+            @QueryParam("fragment") @DefaultValue("") String fragment,
+            @ApiParam(name = "allVersions", value = "Include all versions (defaults false, only returning the best version)")
+            @QueryParam("allVersions") @DefaultValue("false") boolean includeAllVersions);
+
+    @GET
+    @Path("/enrichers/{enricherId}/{version}")
+    @ApiOperation(value = "Fetch an enricher's definition from the catalog",
+            response = CatalogItemSummary.class,
+            responseContainer = "List")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Enricher not found")
+    })
+    public CatalogEnricherSummary getEnricher(
+            @ApiParam(name = "enricherId", value = "The ID of the enricher to retrieve", required = true)
+            @PathParam("enricherId") String enricherId,
+            @ApiParam(name = "version", value = "The version identifier of the enricher to retrieve", required = true)
+            @PathParam("version") String version) throws Exception;
+
+    @DELETE
+    @Path("/enrichers/{enricherId}/{version}")
+    @ApiOperation(value = "Deletes a specific version of an enricher's definition from the catalog")
+    @ApiResponses(value = {
+            @ApiResponse(code = 404, message = "Enricher not found")
+    })
+    public void deleteEnricher(
+            @ApiParam(name = "enricherId", value = "The ID of the enricher to delete", required = true)
+            @PathParam("enricherId") String enricherId,
+            @ApiParam(name = "version", value = "The version identifier of the enricher to delete", required = true)
+            @PathParam("version") String version) throws Exception;
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
new file mode 100644
index 0000000..b0a0403
--- /dev/null
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/CatalogEnricherSummary.java
@@ -0,0 +1,80 @@
+/*
+ * 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.rest.domain;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.collect.ImmutableSet;
+
+public class CatalogEnricherSummary extends CatalogItemSummary {
+
+    private static final long serialVersionUID = -588856488327394445L;
+
+    @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
+    private final Set<EnricherConfigSummary> config;
+
+    public CatalogEnricherSummary(
+            @JsonProperty("symbolicName") String symbolicName,
+            @JsonProperty("version") String version,
+            @JsonProperty("name") String name,
+            @JsonProperty("javaType") String javaType,
+            @JsonProperty("itemType") String itemType,
+            @JsonProperty("planYaml") String planYaml,
+            @JsonProperty("description") String description,
+            @JsonProperty("iconUrl") String iconUrl,
+            @JsonProperty("config") Set<EnricherConfigSummary> config,
+            @JsonProperty("tags") Set<Object> tags,
+            @JsonProperty("deprecated") boolean deprecated,
+            @JsonProperty("links") Map<String, URI> links
+        ) {
+        super(symbolicName, version, name, javaType, itemType, planYaml, description, iconUrl, tags, deprecated, links);
+        // TODO expose config from enrichers
+        this.config = (config == null) ? ImmutableSet.<EnricherConfigSummary>of() : config;
+    }
+
+    public Set<EnricherConfigSummary> getConfig() {
+        return config;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof CatalogEnricherSummary)) return false;
+        if (!super.equals(o)) return false;
+        CatalogEnricherSummary that = (CatalogEnricherSummary) o;
+        return Objects.equals(config, that.config);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), config);
+    }
+
+    @Override
+    public String toString() {
+        return "CatalogEnricherSummary{" +
+                "config=" + config +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java
----------------------------------------------------------------------
diff --git a/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java
new file mode 100644
index 0000000..276cd6b
--- /dev/null
+++ b/rest/rest-api/src/main/java/org/apache/brooklyn/rest/domain/EnricherConfigSummary.java
@@ -0,0 +1,79 @@
+/*
+ * 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.rest.domain;
+
+import java.net.URI;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.brooklyn.config.ConfigKey;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.google.common.collect.ImmutableMap;
+
+public class EnricherConfigSummary extends ConfigSummary {
+
+    private static final long serialVersionUID = 4339330833863794513L;
+
+    @JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+    private final Map<String, URI> links;
+
+    public EnricherConfigSummary(
+            @JsonProperty("name") String name,
+            @JsonProperty("type") String type,
+            @JsonProperty("description") String description,
+            @JsonProperty("defaultValue") Object defaultValue,
+            @JsonProperty("reconfigurable") boolean reconfigurable,
+            @JsonProperty("links") Map<String, URI> links) {
+        super(name, type, description, defaultValue, reconfigurable, null, null, null);
+        this.links = (links == null) ? ImmutableMap.<String, URI>of() : ImmutableMap.copyOf(links);
+    }
+
+    public EnricherConfigSummary(ConfigKey<?> config, String label, Double priority, Map<String, URI> links) {
+        super(config, label, priority);
+        this.links = links != null ? ImmutableMap.copyOf(links) : null;
+    }
+
+    @Override
+    public Map<String, URI> getLinks() {
+        return links;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof EnricherConfigSummary)) return false;
+        if (!super.equals(o)) return false;
+        EnricherConfigSummary that = (EnricherConfigSummary) o;
+        return Objects.equals(links, that.links);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(super.hashCode(), links);
+    }
+
+    @Override
+    public String toString() {
+        return "EnricherConfigSummary{" +
+                "links=" + links +
+                '}';
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/02305e71/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
----------------------------------------------------------------------
diff --git a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
index f0dbf34..7a7f7f7 100644
--- a/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
+++ b/rest/rest-resources/src/main/java/org/apache/brooklyn/rest/resources/CatalogResource.java
@@ -33,6 +33,7 @@ import java.util.jar.Attributes;
 import java.util.jar.Manifest;
 
 import javax.annotation.Nullable;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
@@ -46,6 +47,8 @@ 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.api.typereg.RegisteredType;
 import org.apache.brooklyn.core.catalog.CatalogPredicates;
 import org.apache.brooklyn.core.catalog.internal.BasicBrooklynCatalog;
@@ -57,6 +60,7 @@ import org.apache.brooklyn.core.mgmt.internal.ManagementContextInternal;
 import org.apache.brooklyn.core.typereg.BasicManagedBundle;
 import org.apache.brooklyn.core.typereg.RegisteredTypePredicates;
 import org.apache.brooklyn.rest.api.CatalogApi;
+import org.apache.brooklyn.rest.domain.CatalogEnricherSummary;
 import org.apache.brooklyn.rest.domain.CatalogEntitySummary;
 import org.apache.brooklyn.rest.domain.CatalogItemSummary;
 import org.apache.brooklyn.rest.domain.CatalogLocationSummary;
@@ -92,6 +96,8 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import com.google.common.io.Files;
 
+import io.swagger.annotations.ApiParam;
+
 @HaHotStateRequired
 public class CatalogResource extends AbstractBrooklynRestResource implements CatalogApi {
 
@@ -498,6 +504,53 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
         CatalogUtils.setDisabled(mgmt(), itemId, disabled);
     }
 
+    @Override
+    public List<CatalogEnricherSummary> listEnrichers(@ApiParam(name = "regex", value = "Regular expression to search for") @DefaultValue("") String regex, @ApiParam(name = "fragment", value = "Substring case-insensitive to search for") @DefaultValue("") String fragment, @ApiParam(name = "allVersions", value = "Include all versions (defaults false, only returning the best version)") @DefaultValue("false") boolean includeAllVersions) {
+        Predicate<CatalogItem<Enricher, EnricherSpec<?>>> filter =
+                Predicates.and(
+                        CatalogPredicates.IS_ENRICHER,
+                        CatalogPredicates.<Enricher, EnricherSpec<?>>disabled(false));
+        List<CatalogItemSummary> result = getCatalogItemSummariesMatchingRegexFragment(filter, regex, fragment, includeAllVersions);
+        return castList(result, CatalogEnricherSummary.class);
+    }
+
+    @Override
+    public CatalogEnricherSummary getEnricher(@ApiParam(name = "enricherId", value = "The ID of the enricher to retrieve", required = true) String enricherId, @ApiParam(name = "version", value = "The version identifier of the enricher to retrieve", required = true) String version) throws Exception {
+        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.SEE_CATALOG_ITEM, enricherId+(Strings.isBlank(version)?"":":"+version))) {
+            throw WebResourceUtils.forbidden("User '%s' is not authorized to see catalog entry",
+                    Entitlements.getEntitlementContext().user());
+        }
+
+        version = processVersion(version);
+
+        @SuppressWarnings("unchecked")
+        CatalogItem<? extends Enricher, EnricherSpec<?>> result =
+                (CatalogItem<? extends Enricher, EnricherSpec<?>>)brooklyn().getCatalog().getCatalogItem(enricherId, version);
+
+        if (result==null) {
+            throw WebResourceUtils.notFound("Enricher with id '%s:%s' not found", enricherId, version);
+        }
+
+        return CatalogTransformer.catalogEnricherSummary(brooklyn(), result, ui.getBaseUriBuilder());
+    }
+
+    @Override
+    public void deleteEnricher(@ApiParam(name = "enricherId", value = "The ID of the enricher to delete", required = true) String enricherId, @ApiParam(name = "version", value = "The version identifier of the enricher to delete", required = true) String version) throws Exception {
+        if (!Entitlements.isEntitled(mgmt().getEntitlementManager(), Entitlements.MODIFY_CATALOG_ITEM, StringAndArgument.of(enricherId+(Strings.isBlank(version) ? "" : ":"+version), "delete"))) {
+            throw WebResourceUtils.forbidden("User '%s' is not authorized to modify catalog",
+                    Entitlements.getEntitlementContext().user());
+        }
+
+        RegisteredType item = mgmt().getTypeRegistry().get(enricherId, version);
+        if (item == null) {
+            throw WebResourceUtils.notFound("Enricher with id '%s:%s' not found", enricherId, version);
+        } else if (!RegisteredTypePredicates.IS_ENRICHER.apply(item)) {
+            throw WebResourceUtils.preconditionFailed("Item with id '%s:%s' not an enricher", enricherId, version);
+        } else {
+            brooklyn().getCatalog().deleteCatalogItem(item.getSymbolicName(), item.getVersion());
+        }
+    }
+
     private Response getCatalogItemIcon(RegisteredType result) {
         String url = result.getIconUrl();
         if (url==null) {
@@ -559,4 +612,4 @@ public class CatalogResource extends AbstractBrooklynRestResource implements Cat
         return result;
     }
 }
- 
+