You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2014/03/24 17:32:03 UTC

[05/24] git commit: [KARAF-2845] Move SingleServiceTracker to util

[KARAF-2845] Move SingleServiceTracker to util


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/e7f67746
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/e7f67746
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/e7f67746

Branch: refs/heads/master
Commit: e7f677469bec4cf253a82ef7756ed551a68e85c9
Parents: a0f482c
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Fri Mar 21 17:55:29 2014 +0100
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Mon Mar 24 17:30:12 2014 +0100

----------------------------------------------------------------------
 region/persist/pom.xml                          |  15 +-
 .../region/persist/internal/Activator.java      |   2 +-
 .../internal/util/SingleServiceTracker.java     | 171 -------------------
 shell/core/pom.xml                              |   1 +
 .../osgi/secured/SecuredSessionFactoryImpl.java |   1 +
 .../osgi/secured/SingleServiceTracker.java      | 171 -------------------
 shell/ssh/pom.xml                               |   3 +-
 .../org/apache/karaf/shell/ssh/Activator.java   |   2 +-
 .../shell/ssh/util/SingleServiceTracker.java    | 171 -------------------
 .../util/tracker/SingleServiceTracker.java      | 171 +++++++++++++++++++
 10 files changed, 190 insertions(+), 518 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/e7f67746/region/persist/pom.xml
----------------------------------------------------------------------
diff --git a/region/persist/pom.xml b/region/persist/pom.xml
index 1ae0793..6eaf68b 100644
--- a/region/persist/pom.xml
+++ b/region/persist/pom.xml
@@ -56,6 +56,12 @@
         </dependency>
 
         <dependency>
+            <groupId>org.apache.karaf</groupId>
+            <artifactId>org.apache.karaf.util</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.compendium</artifactId>
             <scope>provided</scope>
@@ -107,8 +113,13 @@
                 <artifactId>maven-bundle-plugin</artifactId>
                 <configuration>
                     <instructions>
-                        <Bundle-Activator>org.apache.karaf.region.persist.internal.Activator</Bundle-Activator>
-                        <Export-Package>org.apache.karaf.region.persist;version=${project.version};-split-package:=merge-first</Export-Package>
+                        <Bundle-Activator>
+                            org.apache.karaf.region.persist.internal.Activator
+                        </Bundle-Activator>
+                        <Private-Package>
+                            org.apache.karaf.region.persist.internal.*,
+                            org.apache.karaf.util.tracker
+                        </Private-Package>
                     </instructions>
                 </configuration>
             </plugin>

http://git-wip-us.apache.org/repos/asf/karaf/blob/e7f67746/region/persist/src/main/java/org/apache/karaf/region/persist/internal/Activator.java
----------------------------------------------------------------------
diff --git a/region/persist/src/main/java/org/apache/karaf/region/persist/internal/Activator.java b/region/persist/src/main/java/org/apache/karaf/region/persist/internal/Activator.java
index e6ab85b..4705818 100644
--- a/region/persist/src/main/java/org/apache/karaf/region/persist/internal/Activator.java
+++ b/region/persist/src/main/java/org/apache/karaf/region/persist/internal/Activator.java
@@ -23,7 +23,7 @@ package org.apache.karaf.region.persist.internal;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.karaf.region.persist.RegionsPersistence;
-import org.apache.karaf.region.persist.internal.util.SingleServiceTracker;
+import org.apache.karaf.util.tracker.SingleServiceTracker;
 import org.eclipse.equinox.region.RegionDigraph;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;

http://git-wip-us.apache.org/repos/asf/karaf/blob/e7f67746/region/persist/src/main/java/org/apache/karaf/region/persist/internal/util/SingleServiceTracker.java
----------------------------------------------------------------------
diff --git a/region/persist/src/main/java/org/apache/karaf/region/persist/internal/util/SingleServiceTracker.java b/region/persist/src/main/java/org/apache/karaf/region/persist/internal/util/SingleServiceTracker.java
deleted file mode 100644
index 16f554f..0000000
--- a/region/persist/src/main/java/org/apache/karaf/region/persist/internal/util/SingleServiceTracker.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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.karaf.region.persist.internal.util;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-
-//This is from aries util
-public final class SingleServiceTracker<T> {
-    public static interface SingleServiceListener {
-        public void serviceFound();
-
-        public void serviceLost();
-
-        public void serviceReplaced();
-    }
-
-    private final BundleContext ctx;
-    private final String className;
-    private final AtomicReference<T> service = new AtomicReference<T>();
-    private final AtomicReference<ServiceReference> ref = new AtomicReference<ServiceReference>();
-    private final AtomicBoolean open = new AtomicBoolean(false);
-    private final SingleServiceListener serviceListener;
-    private String filterString;
-    private Filter filter;
-
-    private final ServiceListener listener = new ServiceListener() {
-        public void serviceChanged(ServiceEvent event) {
-            if (open.get()) {
-                if (event.getType() == ServiceEvent.UNREGISTERING) {
-                    ServiceReference deadRef = event.getServiceReference();
-                    if (deadRef.equals(ref.get())) {
-                        findMatchingReference(deadRef);
-                    }
-                } else if (event.getType() == ServiceEvent.REGISTERED && ref.get() == null) {
-                    findMatchingReference(null);
-                }
-            }
-        }
-    };
-
-    public SingleServiceTracker(BundleContext context, Class<T> clazz, SingleServiceListener sl) {
-        ctx = context;
-        this.className = clazz.getName();
-        serviceListener = sl;
-    }
-
-    public SingleServiceTracker(BundleContext context, Class<T> clazz, String filterString, SingleServiceListener sl) throws InvalidSyntaxException {
-        this(context, clazz, sl);
-        this.filterString = filterString;
-        if (filterString != null) filter = context.createFilter(filterString);
-    }
-
-    public T getService() {
-        return service.get();
-    }
-
-    public ServiceReference getServiceReference() {
-        return ref.get();
-    }
-
-    public void open() {
-        if (open.compareAndSet(false, true)) {
-            try {
-                String filterString = '(' + Constants.OBJECTCLASS + '=' + className + ')';
-                if (filter != null) filterString = "(&" + filterString + filter + ')';
-                ctx.addServiceListener(listener, filterString);
-                findMatchingReference(null);
-            } catch (InvalidSyntaxException e) {
-                // this can never happen. (famous last words :)
-            }
-        }
-    }
-
-    private void findMatchingReference(ServiceReference original) {
-        boolean clear = true;
-        ServiceReference ref = ctx.getServiceReference(className);
-        if (ref != null && (filter == null || filter.match(ref))) {
-            @SuppressWarnings("unchecked")
-            T service = (T) ctx.getService(ref);
-            if (service != null) {
-                clear = false;
-
-                // We do the unget out of the lock so we don't exit this class while holding a lock.
-                if (!!!update(original, ref, service)) {
-                    ctx.ungetService(ref);
-                }
-            }
-        } else if (original == null) {
-            clear = false;
-        }
-
-        if (clear) {
-            update(original, null, null);
-        }
-    }
-
-    private boolean update(ServiceReference deadRef, ServiceReference newRef, T service) {
-        boolean result = false;
-        int foundLostReplaced = -1;
-
-        // Make sure we don't try to get a lock on null
-        Object lock;
-
-        // we have to choose our lock.
-        if (newRef != null) lock = newRef;
-        else if (deadRef != null) lock = deadRef;
-        else lock = this;
-
-        // This lock is here to ensure that no two threads can set the ref and service
-        // at the same time.
-        synchronized (lock) {
-            if (open.get()) {
-                result = this.ref.compareAndSet(deadRef, newRef);
-                if (result) {
-                    this.service.set(service);
-
-                    if (deadRef == null && newRef != null) foundLostReplaced = 0;
-                    if (deadRef != null && newRef == null) foundLostReplaced = 1;
-                    if (deadRef != null && newRef != null) foundLostReplaced = 2;
-                }
-            }
-        }
-
-        if (serviceListener != null) {
-            if (foundLostReplaced == 0) serviceListener.serviceFound();
-            else if (foundLostReplaced == 1) serviceListener.serviceLost();
-            else if (foundLostReplaced == 2) serviceListener.serviceReplaced();
-        }
-
-        return result;
-    }
-
-    public void close() {
-        if (open.compareAndSet(true, false)) {
-            ctx.removeServiceListener(listener);
-
-            synchronized (this) {
-                ServiceReference deadRef = ref.getAndSet(null);
-                service.set(null);
-                if (deadRef != null) ctx.ungetService(deadRef);
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/e7f67746/shell/core/pom.xml
----------------------------------------------------------------------
diff --git a/shell/core/pom.xml b/shell/core/pom.xml
index 47c1d34..c45f473 100644
--- a/shell/core/pom.xml
+++ b/shell/core/pom.xml
@@ -154,6 +154,7 @@
                         <Private-Package>
                             org.apache.karaf.service.guard.tools,
                             org.apache.karaf.shell.impl.*,
+                            org.apache.karaf.util.tracker,
                             org.apache.felix.utils.properties,
                             org.apache.felix.utils.extender,
                             org.apache.felix.utils.manifest,

http://git-wip-us.apache.org/repos/asf/karaf/blob/e7f67746/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java
index 567575d..6c4048a 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SecuredSessionFactoryImpl.java
@@ -37,6 +37,7 @@ import org.apache.karaf.service.guard.tools.ACLConfigurationParser;
 import org.apache.karaf.shell.api.console.Command;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.impl.console.SessionFactoryImpl;
+import org.apache.karaf.util.tracker.SingleServiceTracker;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;

http://git-wip-us.apache.org/repos/asf/karaf/blob/e7f67746/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SingleServiceTracker.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SingleServiceTracker.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SingleServiceTracker.java
deleted file mode 100644
index fb57ee1..0000000
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/osgi/secured/SingleServiceTracker.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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.karaf.shell.impl.console.osgi.secured;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-
-//This is from aries util
-public final class SingleServiceTracker<T> {
-    public static interface SingleServiceListener {
-        public void serviceFound();
-
-        public void serviceLost();
-
-        public void serviceReplaced();
-    }
-
-    private final BundleContext ctx;
-    private final String className;
-    private final AtomicReference<T> service = new AtomicReference<T>();
-    private final AtomicReference<ServiceReference> ref = new AtomicReference<ServiceReference>();
-    private final AtomicBoolean open = new AtomicBoolean(false);
-    private final SingleServiceListener serviceListener;
-    private String filterString;
-    private Filter filter;
-
-    private final ServiceListener listener = new ServiceListener() {
-        public void serviceChanged(ServiceEvent event) {
-            if (open.get()) {
-                if (event.getType() == ServiceEvent.UNREGISTERING) {
-                    ServiceReference deadRef = event.getServiceReference();
-                    if (deadRef.equals(ref.get())) {
-                        findMatchingReference(deadRef);
-                    }
-                } else if (event.getType() == ServiceEvent.REGISTERED && ref.get() == null) {
-                    findMatchingReference(null);
-                }
-            }
-        }
-    };
-
-    public SingleServiceTracker(BundleContext context, Class<T> clazz, SingleServiceListener sl) {
-        ctx = context;
-        this.className = clazz.getName();
-        serviceListener = sl;
-    }
-
-    public SingleServiceTracker(BundleContext context, Class<T> clazz, String filterString, SingleServiceListener sl) throws InvalidSyntaxException {
-        this(context, clazz, sl);
-        this.filterString = filterString;
-        if (filterString != null) filter = context.createFilter(filterString);
-    }
-
-    public T getService() {
-        return service.get();
-    }
-
-    public ServiceReference getServiceReference() {
-        return ref.get();
-    }
-
-    public void open() {
-        if (open.compareAndSet(false, true)) {
-            try {
-                String filterString = '(' + Constants.OBJECTCLASS + '=' + className + ')';
-                if (filter != null) filterString = "(&" + filterString + filter + ')';
-                ctx.addServiceListener(listener, filterString);
-                findMatchingReference(null);
-            } catch (InvalidSyntaxException e) {
-                // this can never happen. (famous last words :)
-            }
-        }
-    }
-
-    private void findMatchingReference(ServiceReference original) {
-        boolean clear = true;
-        ServiceReference ref = ctx.getServiceReference(className);
-        if (ref != null && (filter == null || filter.match(ref))) {
-            @SuppressWarnings("unchecked")
-            T service = (T) ctx.getService(ref);
-            if (service != null) {
-                clear = false;
-
-                // We do the unget out of the lock so we don't exit this class while holding a lock.
-                if (!!!update(original, ref, service)) {
-                    ctx.ungetService(ref);
-                }
-            }
-        } else if (original == null) {
-            clear = false;
-        }
-
-        if (clear) {
-            update(original, null, null);
-        }
-    }
-
-    private boolean update(ServiceReference deadRef, ServiceReference newRef, T service) {
-        boolean result = false;
-        int foundLostReplaced = -1;
-
-        // Make sure we don't try to get a lock on null
-        Object lock;
-
-        // we have to choose our lock.
-        if (newRef != null) lock = newRef;
-        else if (deadRef != null) lock = deadRef;
-        else lock = this;
-
-        // This lock is here to ensure that no two threads can set the ref and service
-        // at the same time.
-        synchronized (lock) {
-            if (open.get()) {
-                result = this.ref.compareAndSet(deadRef, newRef);
-                if (result) {
-                    this.service.set(service);
-
-                    if (deadRef == null && newRef != null) foundLostReplaced = 0;
-                    if (deadRef != null && newRef == null) foundLostReplaced = 1;
-                    if (deadRef != null && newRef != null) foundLostReplaced = 2;
-                }
-            }
-        }
-
-        if (serviceListener != null) {
-            if (foundLostReplaced == 0) serviceListener.serviceFound();
-            else if (foundLostReplaced == 1) serviceListener.serviceLost();
-            else if (foundLostReplaced == 2) serviceListener.serviceReplaced();
-        }
-
-        return result;
-    }
-
-    public void close() {
-        if (open.compareAndSet(true, false)) {
-            ctx.removeServiceListener(listener);
-
-            synchronized (this) {
-                ServiceReference deadRef = ref.getAndSet(null);
-                service.set(null);
-                if (deadRef != null) ctx.ungetService(deadRef);
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/e7f67746/shell/ssh/pom.xml
----------------------------------------------------------------------
diff --git a/shell/ssh/pom.xml b/shell/ssh/pom.xml
index 84135eb..cffaa0b 100644
--- a/shell/ssh/pom.xml
+++ b/shell/ssh/pom.xml
@@ -104,7 +104,8 @@
                             *
                         </Import-Package>
                         <Private-Package>
-                            org.apache.karaf.util
+                            org.apache.karaf.util,
+                            org.apache.karaf.util.tracker
                         </Private-Package>
                         <Bundle-Activator>org.apache.karaf.shell.ssh.Activator</Bundle-Activator>
                     </instructions>

http://git-wip-us.apache.org/repos/asf/karaf/blob/e7f67746/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/Activator.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/Activator.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/Activator.java
index 575c871..af5fd54 100644
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/Activator.java
+++ b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/Activator.java
@@ -29,9 +29,9 @@ import java.util.concurrent.Callable;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 import org.apache.karaf.shell.api.action.lifecycle.Manager;
-import org.apache.karaf.shell.ssh.util.SingleServiceTracker;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.util.tracker.SingleServiceTracker;
 import org.apache.sshd.SshServer;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.server.command.ScpCommandFactory;

http://git-wip-us.apache.org/repos/asf/karaf/blob/e7f67746/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/util/SingleServiceTracker.java
----------------------------------------------------------------------
diff --git a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/util/SingleServiceTracker.java b/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/util/SingleServiceTracker.java
deleted file mode 100644
index c883dc0..0000000
--- a/shell/ssh/src/main/java/org/apache/karaf/shell/ssh/util/SingleServiceTracker.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * 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.karaf.shell.ssh.util;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceEvent;
-import org.osgi.framework.ServiceListener;
-import org.osgi.framework.ServiceReference;
-
-//This is from aries util
-public final class SingleServiceTracker<T> {
-    public static interface SingleServiceListener {
-        public void serviceFound();
-
-        public void serviceLost();
-
-        public void serviceReplaced();
-    }
-
-    private final BundleContext ctx;
-    private final String className;
-    private final AtomicReference<T> service = new AtomicReference<T>();
-    private final AtomicReference<ServiceReference> ref = new AtomicReference<ServiceReference>();
-    private final AtomicBoolean open = new AtomicBoolean(false);
-    private final SingleServiceListener serviceListener;
-    private String filterString;
-    private Filter filter;
-
-    private final ServiceListener listener = new ServiceListener() {
-        public void serviceChanged(ServiceEvent event) {
-            if (open.get()) {
-                if (event.getType() == ServiceEvent.UNREGISTERING) {
-                    ServiceReference deadRef = event.getServiceReference();
-                    if (deadRef.equals(ref.get())) {
-                        findMatchingReference(deadRef);
-                    }
-                } else if (event.getType() == ServiceEvent.REGISTERED && ref.get() == null) {
-                    findMatchingReference(null);
-                }
-            }
-        }
-    };
-
-    public SingleServiceTracker(BundleContext context, Class<T> clazz, SingleServiceListener sl) {
-        ctx = context;
-        this.className = clazz.getName();
-        serviceListener = sl;
-    }
-
-    public SingleServiceTracker(BundleContext context, Class<T> clazz, String filterString, SingleServiceListener sl) throws InvalidSyntaxException {
-        this(context, clazz, sl);
-        this.filterString = filterString;
-        if (filterString != null) filter = context.createFilter(filterString);
-    }
-
-    public T getService() {
-        return service.get();
-    }
-
-    public ServiceReference getServiceReference() {
-        return ref.get();
-    }
-
-    public void open() {
-        if (open.compareAndSet(false, true)) {
-            try {
-                String filterString = '(' + Constants.OBJECTCLASS + '=' + className + ')';
-                if (filter != null) filterString = "(&" + filterString + filter + ')';
-                ctx.addServiceListener(listener, filterString);
-                findMatchingReference(null);
-            } catch (InvalidSyntaxException e) {
-                // this can never happen. (famous last words :)
-            }
-        }
-    }
-
-    private void findMatchingReference(ServiceReference original) {
-        boolean clear = true;
-        ServiceReference ref = ctx.getServiceReference(className);
-        if (ref != null && (filter == null || filter.match(ref))) {
-            @SuppressWarnings("unchecked")
-            T service = (T) ctx.getService(ref);
-            if (service != null) {
-                clear = false;
-
-                // We do the unget out of the lock so we don't exit this class while holding a lock.
-                if (!!!update(original, ref, service)) {
-                    ctx.ungetService(ref);
-                }
-            }
-        } else if (original == null) {
-            clear = false;
-        }
-
-        if (clear) {
-            update(original, null, null);
-        }
-    }
-
-    private boolean update(ServiceReference deadRef, ServiceReference newRef, T service) {
-        boolean result = false;
-        int foundLostReplaced = -1;
-
-        // Make sure we don't try to get a lock on null
-        Object lock;
-
-        // we have to choose our lock.
-        if (newRef != null) lock = newRef;
-        else if (deadRef != null) lock = deadRef;
-        else lock = this;
-
-        // This lock is here to ensure that no two threads can set the ref and service
-        // at the same time.
-        synchronized (lock) {
-            if (open.get()) {
-                result = this.ref.compareAndSet(deadRef, newRef);
-                if (result) {
-                    this.service.set(service);
-
-                    if (deadRef == null && newRef != null) foundLostReplaced = 0;
-                    if (deadRef != null && newRef == null) foundLostReplaced = 1;
-                    if (deadRef != null && newRef != null) foundLostReplaced = 2;
-                }
-            }
-        }
-
-        if (serviceListener != null) {
-            if (foundLostReplaced == 0) serviceListener.serviceFound();
-            else if (foundLostReplaced == 1) serviceListener.serviceLost();
-            else if (foundLostReplaced == 2) serviceListener.serviceReplaced();
-        }
-
-        return result;
-    }
-
-    public void close() {
-        if (open.compareAndSet(true, false)) {
-            ctx.removeServiceListener(listener);
-
-            synchronized (this) {
-                ServiceReference deadRef = ref.getAndSet(null);
-                service.set(null);
-                if (deadRef != null) ctx.ungetService(deadRef);
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/karaf/blob/e7f67746/util/src/main/java/org/apache/karaf/util/tracker/SingleServiceTracker.java
----------------------------------------------------------------------
diff --git a/util/src/main/java/org/apache/karaf/util/tracker/SingleServiceTracker.java b/util/src/main/java/org/apache/karaf/util/tracker/SingleServiceTracker.java
new file mode 100644
index 0000000..c96e73a
--- /dev/null
+++ b/util/src/main/java/org/apache/karaf/util/tracker/SingleServiceTracker.java
@@ -0,0 +1,171 @@
+/*
+ * 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.karaf.util.tracker;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+//This is from aries util
+public final class SingleServiceTracker<T> {
+    public static interface SingleServiceListener {
+        public void serviceFound();
+
+        public void serviceLost();
+
+        public void serviceReplaced();
+    }
+
+    private final BundleContext ctx;
+    private final String className;
+    private final AtomicReference<T> service = new AtomicReference<T>();
+    private final AtomicReference<ServiceReference> ref = new AtomicReference<ServiceReference>();
+    private final AtomicBoolean open = new AtomicBoolean(false);
+    private final SingleServiceListener serviceListener;
+    private String filterString;
+    private Filter filter;
+
+    private final ServiceListener listener = new ServiceListener() {
+        public void serviceChanged(ServiceEvent event) {
+            if (open.get()) {
+                if (event.getType() == ServiceEvent.UNREGISTERING) {
+                    ServiceReference deadRef = event.getServiceReference();
+                    if (deadRef.equals(ref.get())) {
+                        findMatchingReference(deadRef);
+                    }
+                } else if (event.getType() == ServiceEvent.REGISTERED && ref.get() == null) {
+                    findMatchingReference(null);
+                }
+            }
+        }
+    };
+
+    public SingleServiceTracker(BundleContext context, Class<T> clazz, SingleServiceListener sl) {
+        ctx = context;
+        this.className = clazz.getName();
+        serviceListener = sl;
+    }
+
+    public SingleServiceTracker(BundleContext context, Class<T> clazz, String filterString, SingleServiceListener sl) throws InvalidSyntaxException {
+        this(context, clazz, sl);
+        this.filterString = filterString;
+        if (filterString != null) filter = context.createFilter(filterString);
+    }
+
+    public T getService() {
+        return service.get();
+    }
+
+    public ServiceReference getServiceReference() {
+        return ref.get();
+    }
+
+    public void open() {
+        if (open.compareAndSet(false, true)) {
+            try {
+                String filterString = '(' + Constants.OBJECTCLASS + '=' + className + ')';
+                if (filter != null) filterString = "(&" + filterString + filter + ')';
+                ctx.addServiceListener(listener, filterString);
+                findMatchingReference(null);
+            } catch (InvalidSyntaxException e) {
+                // this can never happen. (famous last words :)
+            }
+        }
+    }
+
+    private void findMatchingReference(ServiceReference original) {
+        boolean clear = true;
+        ServiceReference ref = ctx.getServiceReference(className);
+        if (ref != null && (filter == null || filter.match(ref))) {
+            @SuppressWarnings("unchecked")
+            T service = (T) ctx.getService(ref);
+            if (service != null) {
+                clear = false;
+
+                // We do the unget out of the lock so we don't exit this class while holding a lock.
+                if (!!!update(original, ref, service)) {
+                    ctx.ungetService(ref);
+                }
+            }
+        } else if (original == null) {
+            clear = false;
+        }
+
+        if (clear) {
+            update(original, null, null);
+        }
+    }
+
+    private boolean update(ServiceReference deadRef, ServiceReference newRef, T service) {
+        boolean result = false;
+        int foundLostReplaced = -1;
+
+        // Make sure we don't try to get a lock on null
+        Object lock;
+
+        // we have to choose our lock.
+        if (newRef != null) lock = newRef;
+        else if (deadRef != null) lock = deadRef;
+        else lock = this;
+
+        // This lock is here to ensure that no two threads can set the ref and service
+        // at the same time.
+        synchronized (lock) {
+            if (open.get()) {
+                result = this.ref.compareAndSet(deadRef, newRef);
+                if (result) {
+                    this.service.set(service);
+
+                    if (deadRef == null && newRef != null) foundLostReplaced = 0;
+                    if (deadRef != null && newRef == null) foundLostReplaced = 1;
+                    if (deadRef != null && newRef != null) foundLostReplaced = 2;
+                }
+            }
+        }
+
+        if (serviceListener != null) {
+            if (foundLostReplaced == 0) serviceListener.serviceFound();
+            else if (foundLostReplaced == 1) serviceListener.serviceLost();
+            else if (foundLostReplaced == 2) serviceListener.serviceReplaced();
+        }
+
+        return result;
+    }
+
+    public void close() {
+        if (open.compareAndSet(true, false)) {
+            ctx.removeServiceListener(listener);
+
+            synchronized (this) {
+                ServiceReference deadRef = ref.getAndSet(null);
+                service.set(null);
+                if (deadRef != null) ctx.ungetService(deadRef);
+            }
+        }
+    }
+}