aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n..@apache.org
Subject svn commit: r1143948 - in /aries/trunk/jmx/jmx-core-whiteboard: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/aries/ src/main/java/org/apache/aries/jmx/ src/main/java/org/apache/aries/jmx/core/ s...
Date Thu, 07 Jul 2011 18:12:14 GMT
Author: not
Date: Thu Jul  7 18:12:14 2011
New Revision: 1143948

URL: http://svn.apache.org/viewvc?rev=1143948&view=rev
Log:
ARIES-686 Provide a repackaging of the jmx core bundle that uses the whiteboard pattern to
register the MBeans. This will reuse a lot of the code in jmx-core, but gets it registered
with the MBeanServer  using the jmx-whiteboard project.

Added:
    aries/trunk/jmx/jmx-core-whiteboard/   (with props)
    aries/trunk/jmx/jmx-core-whiteboard/pom.xml
    aries/trunk/jmx/jmx-core-whiteboard/src/
    aries/trunk/jmx/jmx-core-whiteboard/src/main/
    aries/trunk/jmx/jmx-core-whiteboard/src/main/java/
    aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/
    aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/apache/
    aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/apache/aries/
    aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/apache/aries/jmx/
    aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/apache/aries/jmx/core/
    aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/apache/aries/jmx/core/whiteboard/
    aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/apache/aries/jmx/core/whiteboard/Activator.java

Propchange: aries/trunk/jmx/jmx-core-whiteboard/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Jul  7 18:12:14 2011
@@ -0,0 +1,5 @@
+target
+.settings
+.classpath
+.project
+velocity.log

Added: aries/trunk/jmx/jmx-core-whiteboard/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/jmx/jmx-core-whiteboard/pom.xml?rev=1143948&view=auto
==============================================================================
--- aries/trunk/jmx/jmx-core-whiteboard/pom.xml (added)
+++ aries/trunk/jmx/jmx-core-whiteboard/pom.xml Thu Jul  7 18:12:14 2011
@@ -0,0 +1,106 @@
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.aries</groupId>
+        <artifactId>java5-parent</artifactId>
+        <version>0.4.1-SNAPSHOT</version>
+        <relativePath />
+    </parent>
+
+    <groupId>org.apache.aries.jmx</groupId>
+    <artifactId>org.apache.aries.jmx.core.whiteboard</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Aries JMX Core via Whiteboards</name>
+    <version>0.3.1-SNAPSHOT</version>
+    <description>
+        This bundle contains an implementation of the JMX Core specification which registers
the
+        MBeans as services in the service registry. This allows the whiteboard module to
be
+        used to register the MBeans.
+    </description>
+
+     <scm>
+         <connection>scm:svn:http://svn.apache.org/repos/asf/aries/trunk/jmx/jmx-core-whiteboard</connection>
+         <developerConnection>scm:svn:https://svn.apache.org/repos/asf/aries/trunk/jmx/jmx-core-whiteboard</developerConnection>
+         <url>http://svn.apache.org/viewvc/aries/trunk/jmx/jmx-core-whiteboard</url>
+     </scm>
+
+    <properties>
+        <aries.osgi.activator>
+            org.apache.aries.jmx.core.whiteboard.Activator
+        </aries.osgi.activator>
+        <!-- Export package versions are maintained in packageinfo files -->
+        <aries.osgi.export.pkg>
+          org.apache.aries.jmx.codec
+        </aries.osgi.export.pkg>
+        <aries.osgi.private.pkg>
+          org.apache.aries.jmx*
+        </aries.osgi.private.pkg>
+        <aries.osgi.dynamic>
+            org.osgi.jmx.service.cm;version="[1.3.0,2)",
+            org.osgi.jmx.service.permissionadmin;version="[1.2.0,2)",
+            org.osgi.jmx.service.provisioning;version="[1.2.0,2)",
+            org.osgi.jmx.service.useradmin;version="[1.1.0,2)",
+            org.osgi.service.cm;version="[1.3.0,2)",
+            org.osgi.service.permissionadmin;version="[1.2.0,2)",
+            org.osgi.service.provisioning;version="[1.2.0,2)",
+            org.osgi.service.useradmin;version="[1.1.0,2)"
+        </aries.osgi.dynamic>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.aries.jmx</groupId>
+            <artifactId>org.apache.aries.jmx.api</artifactId>
+            <version>0.3.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.aries.jmx</groupId>
+            <artifactId>org.apache.aries.jmx.core</artifactId>
+            <version>0.3.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.aries</groupId>
+            <artifactId>org.apache.aries.util</artifactId>
+            <version>0.4-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-all</artifactId>
+            <scope>test</scope>
+            <version>1.8.2</version>
+        </dependency>
+        <dependency>
+             <groupId>junit</groupId>
+             <artifactId>junit</artifactId>
+             <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+ </project>

Added: aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/apache/aries/jmx/core/whiteboard/Activator.java
URL: http://svn.apache.org/viewvc/aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/apache/aries/jmx/core/whiteboard/Activator.java?rev=1143948&view=auto
==============================================================================
--- aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/apache/aries/jmx/core/whiteboard/Activator.java
(added)
+++ aries/trunk/jmx/jmx-core-whiteboard/src/main/java/org/apache/aries/jmx/core/whiteboard/Activator.java
Thu Jul  7 18:12:14 2011
@@ -0,0 +1,432 @@
+/*
+ * 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 WARRANTIESOR 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.aries.jmx.core.whiteboard;
+
+import java.util.Hashtable;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.aries.jmx.Logger;
+import org.apache.aries.jmx.framework.BundleState;
+import org.apache.aries.jmx.framework.Framework;
+import org.apache.aries.jmx.framework.PackageState;
+import org.apache.aries.jmx.framework.ServiceState;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.jmx.framework.BundleStateMBean;
+import org.osgi.jmx.framework.FrameworkMBean;
+import org.osgi.jmx.framework.PackageStateMBean;
+import org.osgi.jmx.framework.ServiceStateMBean;
+import org.osgi.jmx.service.cm.ConfigurationAdminMBean;
+import org.osgi.jmx.service.permissionadmin.PermissionAdminMBean;
+import org.osgi.jmx.service.provisioning.ProvisioningServiceMBean;
+import org.osgi.jmx.service.useradmin.UserAdminMBean;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.permissionadmin.PermissionAdmin;
+import org.osgi.service.provisioning.ProvisioningService;
+import org.osgi.service.startlevel.StartLevel;
+import org.osgi.service.useradmin.UserAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+public class Activator implements BundleActivator, ServiceTrackerCustomizer
+{
+  private ServiceTracker tracker;
+  private BundleContext ctx;
+  private ConcurrentMap<Long, ServiceRegistration> _provisioningMBeans = new ConcurrentHashMap<Long,
ServiceRegistration>();
+  private ConcurrentMap<Long, ServiceRegistration> _userAdminMBeans = new ConcurrentHashMap<Long,
ServiceRegistration>();
+  private ConcurrentMap<Long, ServiceRegistration> _configAdminMBeans = new ConcurrentHashMap<Long,
ServiceRegistration>();
+
+  private AtomicReference<ServiceRegistration> _serviceStateMbean = new AtomicReference<ServiceRegistration>();
+  private AtomicReference<ServiceRegistration> _permissionAdminMbean = new AtomicReference<ServiceRegistration>();
+  private AtomicReference<ServiceRegistration> _packageStateMbean = new AtomicReference<ServiceRegistration>();
+  private AtomicReference<ServiceRegistration> _bundleState = new AtomicReference<ServiceRegistration>();
+  private AtomicReference<ServiceRegistration> _framework = new AtomicReference<ServiceRegistration>();
+
+  private AtomicReference<ServiceReference> _startLevel = new AtomicReference<ServiceReference>();
+  private AtomicReference<ServiceReference> _packageAdmin = new AtomicReference<ServiceReference>();
+
+  private static final String PACKAGE_ADMIN = "org.osgi.service.packageadmin.PackageAdmin";
+  private static final String START_LEVEL = "org.osgi.service.startlevel.StartLevel";
+  private static final String PERMISSION_ADMIN = "org.osgi.service.permissionadmin.PermissionAdmin";
+  private static final String CONFIG_ADMIN = "org.osgi.service.cm.ConfigurationAdmin";
+  private static final String USER_ADMIN = "org.osgi.service.useradmin.UserAdmin";
+  private static final String PROVISIONING_SERVICE = "org.osgi.service.provisioning.ProvisioningService";
+
+  private Logger logger;
+  
+  private class MBeanServiceProxy<T> implements ServiceFactory
+  {
+    private Factory<T> objectFactory;
+    private AtomicReference<T> result = new AtomicReference<T>();
+    
+    private MBeanServiceProxy(Factory<T> factory) {
+      objectFactory = factory;
+    }
+    
+    public Object getService(Bundle bundle, ServiceRegistration registration)
+    {
+      if (result.get() == null) {
+        result.compareAndSet(null, objectFactory.create());
+      }
+      return result.get();
+    }
+    
+    public void ungetService(Bundle bundle, ServiceRegistration registration, Object service)
+    {
+    }
+  }
+
+  private interface Factory<T>
+  {
+    public abstract T create();
+  }
+  
+  private abstract class BaseFactory<T> implements Factory<T>
+  {
+    public abstract T create(PackageAdmin pa, StartLevel sl);
+    public final T create()
+    {
+      StartLevel sl = null;
+      PackageAdmin pa = null;
+      
+      ServiceReference slRef = _startLevel.get();
+      if (slRef != null) {
+        sl = (StartLevel) ctx.getService(slRef);
+      }
+      ServiceReference paRef = _packageAdmin.get();
+      
+      if (paRef != null) {
+        pa = (PackageAdmin) ctx.getService(paRef);
+      }
+      
+      if (pa == null) {
+        ctx.ungetService(slRef);
+      }
+      
+      if (sl != null && pa != null) {
+        return create(pa, sl);
+      } else {
+        return null;
+      }
+    }
+  }
+
+  public void start(BundleContext context) throws Exception
+  {
+    ctx = context;
+    logger = new Logger(ctx);
+    
+    Filter filter = getFilter(context, PACKAGE_ADMIN, START_LEVEL,
+        PERMISSION_ADMIN, CONFIG_ADMIN, USER_ADMIN,
+        PROVISIONING_SERVICE);
+
+    tracker = new ServiceTracker(context, filter, this);
+    tracker.open();
+    
+    registerMBean(ServiceStateMBean.class.getName(), new Factory<ServiceStateMBean>()
{
+      public ServiceStateMBean create()
+      {
+        return new ServiceState(ctx, logger);
+      }
+    }, ServiceStateMBean.OBJECTNAME, _serviceStateMbean );
+  }
+
+  private Filter getFilter(BundleContext ctx, String ... services) throws InvalidSyntaxException
+  {
+    StringBuilder builder = new StringBuilder("(|");
+    
+    for (String type : services) {
+      builder.append('(');
+      builder.append(Constants.OBJECTCLASS);
+      builder.append('=');
+      builder.append(type);
+      builder.append(')');
+    }
+    
+    builder.append(')');
+    return ctx.createFilter(builder.toString());
+  }
+
+  public void stop(BundleContext context) throws Exception
+  {
+    tracker.close();
+  }
+
+  public Object addingService(ServiceReference reference)
+  {
+    Object tracked = null;
+    
+    String[] types = (String[]) reference.getProperty(Constants.OBJECTCLASS);
+    
+    for (String t : types) {
+      if (PACKAGE_ADMIN.equals(t)) {
+        foundPackageAdmin(reference);
+        tracked = reference;
+      } else if (START_LEVEL.equals(t)) {
+        foundStartLevel(reference);
+        tracked = reference;
+      } else if (PERMISSION_ADMIN.equals(t)) {
+        foundPermissionAdmin(reference);
+        tracked = reference;
+      } else if (CONFIG_ADMIN.equals(t)) {
+        foundConfigAdmin(reference);
+        tracked = reference;
+      } else if (USER_ADMIN.equals(t)) {
+        foundUserAdmin(reference);
+        tracked = reference;
+      } else if (PROVISIONING_SERVICE.equals(t)) {
+        foundProvisioningService(reference);
+        tracked = reference;
+      }
+    }
+    
+    return tracked;
+  }
+
+  private <T> void registerMBean(String type, Factory<T> factory, String objectName,
AtomicReference<ServiceRegistration> result)
+  {
+    synchronized (result) {
+      ServiceRegistration reg = registerAnMbean(type, factory, objectName);
+      
+      if (!!!result.compareAndSet(null, reg)) {
+        reg.unregister();
+      }
+    }
+  }
+  
+  private <T> void registerMBean(String type, Factory<T> factory, String objectName,
ConcurrentMap<Long, ServiceRegistration> mbeans,
+      ServiceReference referencedServices, String underlyingType)
+  {
+    try {
+      Class.forName(underlyingType);
+      if (referencedServices.isAssignableTo(ctx.getBundle(), underlyingType)) {
+        ServiceRegistration reg = registerAnMbean(type, factory, objectName);
+  
+        Long id = (Long) reg.getReference().getProperty(Constants.SERVICE_ID);
+        mbeans.put(id, reg);
+      }
+    } catch (ClassNotFoundException e) {
+    }
+  }
+
+  private <T> ServiceRegistration registerAnMbean(String type, Factory<T> factory,
String objectName)
+  {
+    Hashtable<String, Object> properties = new Hashtable<String, Object>();
+    properties.put("jmx.objectname", objectName);
+    
+    Object service = new MBeanServiceProxy<T>(factory);
+    
+    ServiceRegistration reg = ctx.registerService(type, service, properties);
+    return reg;
+  }
+  
+  private void foundPermissionAdmin(final ServiceReference reference)
+  {
+    registerMBean(PermissionAdminMBean.class.getName(), new Factory<PermissionAdminMBean>()
{
+      public PermissionAdminMBean create()
+      {
+        PermissionAdmin service = (PermissionAdmin) ctx.getService(reference);
+        
+        if (service == null) return null;
+        else return new org.apache.aries.jmx.permissionadmin.PermissionAdmin(service);
+      }
+    }, PermissionAdminMBean.OBJECTNAME, _permissionAdminMbean);
+  }
+
+  private void foundProvisioningService(final ServiceReference reference)
+  {
+    registerMBean(ProvisioningServiceMBean.class.getName(), new Factory<ProvisioningServiceMBean>()
{
+        public ProvisioningServiceMBean create()
+        {
+          ProvisioningService service = (ProvisioningService) ctx.getService(reference);
+          
+          if (service == null) return null;
+          else return new org.apache.aries.jmx.provisioning.ProvisioningService(service);
+        }
+      }, ProvisioningServiceMBean.OBJECTNAME, _provisioningMBeans, reference, ProvisioningService.class.getName());
+  }
+
+  private void foundUserAdmin(final ServiceReference reference)
+  {
+    try {
+      Class.forName(UserAdmin.class.getName());
+      if (reference.isAssignableTo(ctx.getBundle(), UserAdmin.class.getName())) {
+        registerMBean(UserAdminMBean.class.getName(), new Factory<UserAdminMBean>()
{
+          public UserAdminMBean create()
+          {
+            UserAdmin service = (UserAdmin) ctx.getService(reference);
+            
+            if (service == null) return null;
+            else return new org.apache.aries.jmx.useradmin.UserAdmin(service);
+          }
+        }, UserAdminMBean.OBJECTNAME, _userAdminMBeans, reference, UserAdmin.class.getName());
+      }
+    } catch (ClassNotFoundException e) {
+    }
+  }
+
+  private void foundConfigAdmin(final ServiceReference reference)
+  {
+    registerMBean(ConfigurationAdminMBean.class.getName(), new Factory<ConfigurationAdminMBean>()
{
+      public ConfigurationAdminMBean create()
+      {
+        ConfigurationAdmin service = (ConfigurationAdmin) ctx.getService(reference);
+        
+        if (service == null) return null;
+        else return new org.apache.aries.jmx.cm.ConfigurationAdmin(service);
+      }
+    }, ConfigurationAdminMBean.OBJECTNAME, _configAdminMBeans, reference, ConfigurationAdmin.class.getName());
+  }
+
+  private void foundStartLevel(final ServiceReference reference)
+  {
+    if (_startLevel.compareAndSet(null, reference)) {
+      registerBundleStateAndFrameworkIfPossible();
+    }
+  }
+
+  private void foundPackageAdmin(final ServiceReference reference)
+  {
+    registerMBean(PackageStateMBean.class.getName(), new Factory<PackageStateMBean>()
{
+      public PackageStateMBean create()
+      {
+        PackageAdmin service = (PackageAdmin) ctx.getService(reference);
+        
+        if (service == null) return null;
+        else return new PackageState(ctx, service);
+      }
+    }, PackageStateMBean.OBJECTNAME, _packageStateMbean);
+    
+    if (_packageAdmin.compareAndSet(null, reference)) {
+      registerBundleStateAndFrameworkIfPossible();
+    }
+  }
+
+  // This method is synchronized to ensure that notification of StartLevel and PackageAdmin
+  // on different threads at the same time doesn't cause problems. It only affects these
services
+  // so it shouldn't be too expensive.
+  private synchronized void registerBundleStateAndFrameworkIfPossible()
+  {
+      if (_bundleState.get() == null && _startLevel.get() != null && _packageAdmin.get()
!= null) {
+        registerMBean(BundleStateMBean.class.getName(), new BaseFactory<BundleStateMBean>()
{
+          @Override
+          public BundleStateMBean create(PackageAdmin pa, StartLevel sl)
+          {
+            return new BundleState(ctx, pa, sl, logger);
+          }
+        }, BundleStateMBean.OBJECTNAME, _bundleState);
+      }
+      if (_framework.get() == null && _startLevel.get() != null && _packageAdmin.get()
!= null) {
+        registerMBean(FrameworkMBean.class.getName(), new BaseFactory<FrameworkMBean>()
{
+          @Override
+          public FrameworkMBean create(PackageAdmin pa, StartLevel sl)
+          {
+            return new Framework(ctx, sl, pa);
+          }
+        }, FrameworkMBean.OBJECTNAME, _framework);
+      }
+  }
+
+  public void modifiedService(ServiceReference reference, Object service)
+  {
+  }
+
+  public void removedService(ServiceReference reference, Object service)
+  {
+    String[] types = (String[]) reference.getProperty(Constants.OBJECTCLASS);
+    
+    for (String t : types) {
+      if (PackageAdmin.class.getName().equals(t)) {
+        lostPackageAdmin(reference);
+      } else if (StartLevel.class.getName().equals(t)) {
+        lostStartLevel(reference);
+      } else if (PermissionAdmin.class.getName().equals(t)) {
+        lostPermissionAdmin(reference);
+      } else if (ConfigurationAdmin.class.getName().equals(t)) {
+        lostConfigAdmin(reference);
+      } else if (UserAdmin.class.getName().equals(t)) {
+        lostUserAdmin(reference);
+      } else if (ProvisioningService.class.getName().equals(t)) {
+        lostProvisioningService(reference);
+      }
+    }
+    
+  }
+
+  private void lostProvisioningService(ServiceReference reference)
+  {
+    unregister(reference, _provisioningMBeans);
+  }
+
+  private void lostUserAdmin(ServiceReference reference)
+  {
+    unregister(reference, _userAdminMBeans);
+  }
+
+  private void lostConfigAdmin(ServiceReference reference)
+  {
+    unregister(reference, _configAdminMBeans);
+  }
+  
+  private void unregister(ServiceReference reference, ConcurrentMap<Long, ServiceRegistration>
mbeans)
+  {
+    Long id = (Long) reference.getProperty(Constants.SERVICE_ID);
+    ServiceRegistration reg = mbeans.remove(id);
+    if (reg != null) reg.unregister();
+  }
+
+  private void lostPermissionAdmin(ServiceReference reference)
+  {
+    safeUnregister(_permissionAdminMbean);
+  }
+
+  private void lostStartLevel(ServiceReference reference)
+  {
+    if (_startLevel.compareAndSet(reference, null)) {
+      safeUnregister(_bundleState);
+      safeUnregister(_framework);
+    }
+  }
+
+  private void lostPackageAdmin(ServiceReference reference)
+  {
+    if (_packageAdmin.compareAndSet(reference, null)) {
+      safeUnregister(_bundleState);
+      safeUnregister(_framework);
+      
+      safeUnregister(_packageStateMbean);
+    }
+  }
+
+  private void safeUnregister(AtomicReference<ServiceRegistration> atomicRegistration)
+  {
+    ServiceRegistration reg = atomicRegistration.getAndSet(null);
+    if (reg != null) reg.unregister();
+  }
+}
\ No newline at end of file



Mime
View raw message