You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by sv...@apache.org on 2016/04/11 11:02:00 UTC

[1/4] brooklyn-server git commit: Support removal of catalog entries from bundle BOM when the bundle is stopped.

Repository: brooklyn-server
Updated Branches:
  refs/heads/master a9f9df458 -> 06f68e134


Support removal of catalog entries from bundle BOM when the bundle is stopped.

This change follows on from https://github.com/apache/brooklyn-server/pull/80.

With this change any catalog members that were added by scanning the bundle's
catalog.bom when the bundle started will be removed upon stopping the bundle.


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

Branch: refs/heads/master
Commit: 7a1d51c6c9d0ea084ad09be51a27dec06fb0d365
Parents: 3896826
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Apr 5 14:22:05 2016 +0100
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Apr 5 14:22:05 2016 +0100

----------------------------------------------------------------------
 .../catalog/internal/CatalogBomScanner.java     | 81 ++++++++++++--------
 1 file changed, 48 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/7a1d51c6/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
index 4477f62..5b2d52b 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
@@ -18,12 +18,14 @@
  */
 package org.apache.brooklyn.core.catalog.internal;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
+import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.collections.MutableMap;
+import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.stream.Streams;
 import org.apache.brooklyn.util.yaml.Yamls;
@@ -67,12 +69,12 @@ public class CatalogBomScanner {
 
     private String[] bundleIds(Bundle bundle) {
         return new String[] {
-            String.valueOf(bundle.getBundleId()), String.valueOf(bundle.getState()), bundle.getSymbolicName()
+            String.valueOf(bundle.getBundleId()), bundle.getSymbolicName(), bundle.getVersion().toString()
         };
     }
 
 
-    public class CatalogPopulator extends BundleTracker<Long> {
+    public class CatalogPopulator extends BundleTracker<Iterable<? extends CatalogItem<?, ?>>> {
 
         private ServiceReference<ManagementContext> mgmtContextReference;
         private ManagementContext managementContext;
@@ -100,44 +102,63 @@ public class CatalogBomScanner {
             return managementContext;
         }
 
+        /**
+         * Scans the bundle being added for a catalog.bom file and adds any entries in it to the catalog.
+         *
+         * @param bundle The bundle being added to the bundle context.
+         * @param bundleEvent The event of the addition.
+         *
+         * @return The items added to the catalog; these will be tracked by the {@link BundleTracker} mechanism
+         *         and supplied to the {@link #removedBundle(Bundle, BundleEvent, Iterable)} method.
+         */
         @Override
-        public Long addingBundle(Bundle bundle, BundleEvent bundleEvent) {
-
-            final BundleContext bundleContext = FrameworkUtil.getBundle(CatalogBomScanner.class).getBundleContext();
-            if (bundleContext == null) {
-                LOG.info("Bundle context not yet established for bundle {} {} {}", bundleIds(bundle));
-                return null;
-            }
-
-            scanForCatalog(bundle);
-
-            return bundle.getBundleId();
+        public Iterable<? extends CatalogItem<?, ?>> addingBundle(Bundle bundle, BundleEvent bundleEvent) {
+            return scanForCatalog(bundle);
         }
 
-        @Override
-        public void modifiedBundle(Bundle bundle, BundleEvent event, Long bundleId) {
-            sanityCheck(bundle, bundleId);
-            LOG.info("Modified bundle {} {} {}", bundleIds(bundle));
-        }
 
         @Override
-        public void removedBundle(Bundle bundle, BundleEvent bundleEvent, Long bundleId) {
-            sanityCheck(bundle, bundleId);
-            LOG.info("Unloading catalog BOM from {} {} {}", bundleIds(bundle));
+        public void removedBundle(Bundle bundle, BundleEvent bundleEvent, Iterable<? extends CatalogItem<?, ?>> items) {
+            LOG.debug("Unloading catalog BOM entries from {} {} {}", bundleIds(bundle));
+            List<Exception> exceptions = MutableList.of();
+            final BrooklynCatalog catalog = getManagementContext().getCatalog();
+            for (CatalogItem<?, ?> item : items) {
+                LOG.debug("Unloading {} {} from catalog", item.getSymbolicName(), item.getVersion());
+
+                try {
+                    catalog.deleteCatalogItem(item.getSymbolicName(), item.getVersion());
+                } catch (Exception e) {
+                    LOG.warn("Caught {} unloading {} {} from catalog", new String [] {
+                        e.getMessage(), item.getSymbolicName(), item.getVersion()
+                    });
+                    exceptions.add(e);
+                }
+            }
+
+            if (0 < exceptions.size()) {
+                throw new CompoundRuntimeException(
+                    "Caught exceptions unloading catalog from bundle " + bundle.getBundleId(),
+                    exceptions);
+            }
         }
 
-        private void scanForCatalog(Bundle bundle) {
-            LOG.info("Scanning for catalog items in bundle {} {} {}", bundleIds(bundle));
+        private Iterable<? extends CatalogItem<?, ?>> scanForCatalog(Bundle bundle) {
+            LOG.debug("Scanning for catalog items in bundle {} {} {}", bundleIds(bundle));
             final URL bom = bundle.getResource(CATALOG_BOM_URL);
 
             if (null != bom) {
-                LOG.info("Found catalog BOM in {} {} {}", bundleIds(bundle));
+                LOG.debug("Found catalog BOM in {} {} {}", bundleIds(bundle));
                 String bomText = readBom(bom);
                 String bomWithLibraryPath = addLibraryDetails(bundle, bomText);
-                for (CatalogItem<?, ?> item : getManagementContext().getCatalog().addItems(bomWithLibraryPath)) {
-                    LOG.debug("Added to catalog: {}", item.getSymbolicName());
+                final Iterable<? extends CatalogItem<?, ?>> catalogItems =
+                    getManagementContext().getCatalog().addItems(bomWithLibraryPath);
+                for (CatalogItem<?, ?> item : catalogItems) {
+                    LOG.debug("Added to catalog: {}, {}", item.getSymbolicName(), item.getVersion());
                 }
+
+                return catalogItems;
             }
+            return ImmutableList.of();
         }
 
         private String addLibraryDetails(Bundle bundle, String bomText) {
@@ -174,12 +195,6 @@ public class CatalogBomScanner {
             }
         }
 
-        private void sanityCheck(Bundle bundle, Long bundleId) {
-            if (bundleId != bundle.getBundleId()) {
-                throw new RuntimeException("Unexpected ID supplied for bundle " + bundle + " (" + bundleId + ")");
-            }
-        }
-
     }
 
 }


[3/4] brooklyn-server git commit: Code review comments: gobble exceptions on stopping bundle.

Posted by sv...@apache.org.
Code review comments: gobble exceptions on stopping bundle.

Gobble exception to avoid possibility of causing problems stopping bundle.


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

Branch: refs/heads/master
Commit: 47421cbae6ed5fe0e7581ae5212fc2b31c60a5a9
Parents: 84720cf
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Thu Apr 7 09:49:30 2016 +0100
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Mon Apr 11 09:57:24 2016 +0100

----------------------------------------------------------------------
 .../core/catalog/internal/CatalogBomScanner.java     | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/47421cba/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
index 782055a..01d25f5 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
@@ -25,14 +25,11 @@ import org.apache.brooklyn.api.catalog.BrooklynCatalog;
 import org.apache.brooklyn.api.catalog.CatalogItem;
 import org.apache.brooklyn.api.mgmt.ManagementContext;
 import org.apache.brooklyn.util.collections.MutableList;
-import org.apache.brooklyn.util.exceptions.CompoundRuntimeException;
 import org.apache.brooklyn.util.exceptions.Exceptions;
 import org.apache.brooklyn.util.stream.Streams;
 import org.apache.brooklyn.util.yaml.Yamls;
 import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
-import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.ServiceReference;
 import org.osgi.util.tracker.BundleTracker;
 import org.slf4j.Logger;
@@ -124,7 +121,6 @@ public class CatalogBomScanner {
                 return;
             }
             LOG.debug("Unloading catalog BOM entries from {} {} {}", bundleIds(bundle));
-            List<Exception> exceptions = MutableList.of();
             final BrooklynCatalog catalog = getManagementContext().getCatalog();
             for (CatalogItem<?, ?> item : items) {
                 LOG.debug("Unloading {} {} from catalog", item.getSymbolicName(), item.getVersion());
@@ -132,18 +128,13 @@ public class CatalogBomScanner {
                 try {
                     catalog.deleteCatalogItem(item.getSymbolicName(), item.getVersion());
                 } catch (Exception e) {
-                    LOG.warn("Caught {} unloading {} {} from catalog", new String [] {
+                    // Gobble exception to avoid possibility of causing problems stopping bundle.
+                    LOG.warn("Caught {} unloading {} {} from catalog, ignoring", new String [] {
                         e.getMessage(), item.getSymbolicName(), item.getVersion()
                     });
-                    exceptions.add(e);
+                    Exceptions.propagateIfFatal(e);
                 }
             }
-
-            if (0 < exceptions.size()) {
-                throw new CompoundRuntimeException(
-                    "Caught exceptions unloading catalog from bundle " + bundle.getBundleId(),
-                    exceptions);
-            }
         }
 
         private Iterable<? extends CatalogItem<?, ?>> scanForCatalog(Bundle bundle) {


[4/4] brooklyn-server git commit: Closes #100

Posted by sv...@apache.org.
Closes #100

Support removal of catalog entries from bundle BOM when the bundle is stopped.

This change follows on from https://github.com/apache/brooklyn-server/pull/80.

With this change any catalog members that were added by scanning the bundle's
catalog.bom when the bundle started will be removed upon stopping the bundle.


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

Branch: refs/heads/master
Commit: 06f68e134b24f3e6a93601dbbd0e9603862f3c05
Parents: a9f9df4 47421cb
Author: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Authored: Mon Apr 11 12:01:47 2016 +0300
Committer: Svetoslav Neykov <sv...@cloudsoftcorp.com>
Committed: Mon Apr 11 12:01:47 2016 +0300

----------------------------------------------------------------------
 .../catalog/internal/CatalogBomScanner.java     | 98 ++++++++++++--------
 .../resources/OSGI-INF/blueprint/blueprint.xml  | 50 +++++-----
 2 files changed, 82 insertions(+), 66 deletions(-)
----------------------------------------------------------------------



[2/4] brooklyn-server git commit: Code review comments.

Posted by sv...@apache.org.
Code review comments.

https://github.com/apache/brooklyn-server/pull/80#discussion_r57442437
https://github.com/apache/brooklyn-server/pull/80#discussion_r57442486
https://github.com/apache/brooklyn-server/pull/80#discussion_r57442585
https://github.com/apache/brooklyn-server/pull/80#discussion-diff-57442710


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

Branch: refs/heads/master
Commit: 84720cfa88bd98eed6b73918d3f250bee1291157
Parents: 7a1d51c
Author: Geoff Macartney <ge...@cloudsoftcorp.com>
Authored: Tue Apr 5 15:06:13 2016 +0100
Committer: Geoff Macartney <ge...@cloudsoftcorp.com>
Committed: Tue Apr 5 15:06:13 2016 +0100

----------------------------------------------------------------------
 .../catalog/internal/CatalogBomScanner.java     | 32 ++++++++-----
 .../resources/OSGI-INF/blueprint/blueprint.xml  | 50 ++++++++++----------
 2 files changed, 46 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/84720cfa/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
index 5b2d52b..782055a 100644
--- a/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
+++ b/core/src/main/java/org/apache/brooklyn/core/catalog/internal/CatalogBomScanner.java
@@ -40,6 +40,7 @@ import org.slf4j.LoggerFactory;
 import org.yaml.snakeyaml.Yaml;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.List;
 import java.util.Map;
@@ -119,6 +120,9 @@ public class CatalogBomScanner {
 
         @Override
         public void removedBundle(Bundle bundle, BundleEvent bundleEvent, Iterable<? extends CatalogItem<?, ?>> items) {
+            if (!items.iterator().hasNext()) {
+                return;
+            }
             LOG.debug("Unloading catalog BOM entries from {} {} {}", bundleIds(bundle));
             List<Exception> exceptions = MutableList.of();
             final BrooklynCatalog catalog = getManagementContext().getCatalog();
@@ -143,32 +147,38 @@ public class CatalogBomScanner {
         }
 
         private Iterable<? extends CatalogItem<?, ?>> scanForCatalog(Bundle bundle) {
-            LOG.debug("Scanning for catalog items in bundle {} {} {}", bundleIds(bundle));
-            final URL bom = bundle.getResource(CATALOG_BOM_URL);
 
+            Iterable<? extends CatalogItem<?, ?>> catalogItems = ImmutableList.of();
+
+            final URL bom = bundle.getResource(CATALOG_BOM_URL);
             if (null != bom) {
                 LOG.debug("Found catalog BOM in {} {} {}", bundleIds(bundle));
                 String bomText = readBom(bom);
                 String bomWithLibraryPath = addLibraryDetails(bundle, bomText);
-                final Iterable<? extends CatalogItem<?, ?>> catalogItems =
-                    getManagementContext().getCatalog().addItems(bomWithLibraryPath);
+                catalogItems = getManagementContext().getCatalog().addItems(bomWithLibraryPath);
                 for (CatalogItem<?, ?> item : catalogItems) {
                     LOG.debug("Added to catalog: {}, {}", item.getSymbolicName(), item.getVersion());
                 }
 
-                return catalogItems;
+            } else {
+                LOG.debug("No BOM found in {} {} {}", bundleIds(bundle));
             }
-            return ImmutableList.of();
+
+            return catalogItems;
         }
 
         private String addLibraryDetails(Bundle bundle, String bomText) {
             final Map<String, Object> bom = (Map<String, Object>)Iterables.getOnlyElement(Yamls.parseAll(bomText));
             final Object catalog = bom.get(BROOKLYN_CATALOG);
-            if (null != catalog && catalog instanceof Map<?, ?>) {
-                addLibraryDetails(bundle, (Map<String, Object>) catalog);
+            if (null != catalog) {
+                if (catalog instanceof Map<?, ?>) {
+                    addLibraryDetails(bundle, (Map<String, Object>) catalog);
+                } else {
+                    LOG.warn("Unexpected syntax for {} (expected Map), ignoring", BROOKLYN_CATALOG);
+                }
             }
             final String updatedBom = new Yaml().dump(bom);
-            LOG.debug("Updated catalog bom:\n{}", updatedBom);
+            LOG.trace("Updated catalog bom:\n{}", updatedBom);
             return updatedBom;
         }
 
@@ -188,8 +198,8 @@ public class CatalogBomScanner {
         }
 
         private String readBom(URL bom) {
-            try {
-                return Streams.readFullyString(bom.openStream());
+            try (final InputStream ins = bom.openStream()) {
+                return Streams.readFullyString(ins);
             } catch (IOException e) {
                 throw Exceptions.propagate("Error loading Catalog BOM from " + bom, e);
             }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/84720cfa/karaf/init/src/main/resources/OSGI-INF/blueprint/blueprint.xml
----------------------------------------------------------------------
diff --git a/karaf/init/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/karaf/init/src/main/resources/OSGI-INF/blueprint/blueprint.xml
index 51dfce8..36c0fef 100644
--- a/karaf/init/src/main/resources/OSGI-INF/blueprint/blueprint.xml
+++ b/karaf/init/src/main/resources/OSGI-INF/blueprint/blueprint.xml
@@ -25,62 +25,62 @@ limitations under the License.
 
     <!-- Makes sure core bundle is already started -->
     <reference id="brooklynVersion"
-               interface="org.apache.brooklyn.core.BrooklynVersionService"/>
+               interface="org.apache.brooklyn.core.BrooklynVersionService" />
 
     <reference id="systemService"
                interface="org.apache.karaf.system.SystemService" />
 
     <cm:property-placeholder persistent-id="org.apache.brooklyn.osgilauncher" update-strategy="reload">
         <cm:default-properties>
-            <cm:property name="ignoreCatalogErrors" value="true"/>
-            <cm:property name="ignorePersistenceErrors" value="true"/>
-            <cm:property name="highAvailabilityMode" value="DISABLED"/>
-            <cm:property name="persistMode" value="DISABLED"/>
-            <cm:property name="persistenceDir" value=""/>
-            <cm:property name="persistenceLocation" value=""/>
-            <cm:property name="persistPeriod" value="1s"/>
-            <cm:property name="globalBrooklynPropertiesFile" value="~/.brooklyn/brooklyn.properties"/>
-            <cm:property name="localBrooklynPropertiesFile" value=""/> <!-- used to be settable through cli params -->
+            <cm:property name="ignoreCatalogErrors" value="true" />
+            <cm:property name="ignorePersistenceErrors" value="true" />
+            <cm:property name="highAvailabilityMode" value="DISABLED" />
+            <cm:property name="persistMode" value="DISABLED" />
+            <cm:property name="persistenceDir" value="" />
+            <cm:property name="persistenceLocation" value="" />
+            <cm:property name="persistPeriod" value="1s" />
+            <cm:property name="globalBrooklynPropertiesFile" value="~/.brooklyn/brooklyn.properties" />
+            <cm:property name="localBrooklynPropertiesFile" value="" /> <!-- used to be settable through cli params -->
         </cm:default-properties>
     </cm:property-placeholder>
 
     <bean id="propertiesBuilderFactory"
           class="org.apache.brooklyn.launcher.common.BrooklynPropertiesFactoryHelper">
-        <argument value="${globalBrooklynPropertiesFile}"/>
-        <argument value="${localBrooklynPropertiesFile}"/>
+        <argument value="${globalBrooklynPropertiesFile}" />
+        <argument value="${localBrooklynPropertiesFile}" />
     </bean>
 
     <bean id="propertiesBuilder"
           class="org.apache.brooklyn.core.internal.BrooklynProperties.Factory.Builder"
           factory-ref="propertiesBuilderFactory"
-          factory-method="createPropertiesBuilder"/>
+          factory-method="createPropertiesBuilder" />
 
     <bean id="launcher"
           class="org.apache.brooklyn.launcher.osgi.OsgiLauncher"
           init-method="init"
           destroy-method="destroy">
 
-        <property name="brooklynVersion" ref="brooklynVersion"/>
-        <property name="brooklynPropertiesBuilder" ref="propertiesBuilder"/>
+        <property name="brooklynVersion" ref="brooklynVersion" />
+        <property name="brooklynPropertiesBuilder" ref="propertiesBuilder" />
 
-        <property name="ignoreCatalogErrors" value="${ignoreCatalogErrors}"/>
-        <property name="ignorePersistenceErrors" value="${ignorePersistenceErrors}"/>
-        <property name="highAvailabilityMode" value="${highAvailabilityMode}"/>
-        <property name="persistMode" value="${persistMode}"/>
-        <property name="persistenceDir" value="${persistenceDir}"/>
-        <property name="persistenceLocation" value="${persistenceLocation}"/>
-        <property name="persistPeriod" value="${persistPeriod}"/>
+        <property name="ignoreCatalogErrors" value="${ignoreCatalogErrors}" />
+        <property name="ignorePersistenceErrors" value="${ignorePersistenceErrors}" />
+        <property name="highAvailabilityMode" value="${highAvailabilityMode}" />
+        <property name="persistMode" value="${persistMode}" />
+        <property name="persistenceDir" value="${persistenceDir}" />
+        <property name="persistenceLocation" value="${persistenceLocation}" />
+        <property name="persistPeriod" value="${persistPeriod}" />
     </bean>
 
     <bean id="localManagementContextService"
           class="org.apache.brooklyn.core.mgmt.internal.LocalManagementContext"
           factory-ref="launcher"
-          factory-method="getManagementContext"/>
+          factory-method="getManagementContext" />
 
     <bean id="campPlatform"
           class="org.apache.brooklyn.camp.CampPlatform"
           factory-ref="launcher"
-          factory-method="getCampPlatform"/>
+          factory-method="getCampPlatform" />
 
     <service interface="org.apache.brooklyn.core.mgmt.ShutdownHandler">
         <bean class="org.apache.brooklyn.launcher.osgi.OsgiShutdownHandler" />
@@ -98,7 +98,7 @@ limitations under the License.
                     availability="optional">
 
         <reference-listener bind-method="bind" unbind-method="unbind">
-            <bean class="org.apache.brooklyn.core.catalog.internal.CatalogBomScanner"/>
+            <bean class="org.apache.brooklyn.core.catalog.internal.CatalogBomScanner" />
         </reference-listener>
     </reference-list>