incubator-aries-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From n..@apache.org
Subject svn commit: r919842 - in /incubator/aries/trunk/jndi/jndi-url/src: main/java/org/apache/aries/jndi/services/ main/java/org/apache/aries/jndi/url/ test/java/org/apache/aries/jndi/url/
Date Sat, 06 Mar 2010 20:20:24 GMT
Author: not
Date: Sat Mar  6 20:20:24 2010
New Revision: 919842

URL: http://svn.apache.org/viewvc?rev=919842&view=rev
Log:
ARIES-128 Implement support for querying multiple services via JNDI url.

Modified:
    incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java
    incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java
    incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java
    incubator/aries/trunk/jndi/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java

Modified: incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java?rev=919842&r1=919841&r2=919842&view=diff
==============================================================================
--- incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java
(original)
+++ incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java
Sat Mar  6 20:20:24 2010
@@ -136,7 +136,9 @@
       boolean foundLookup = false;
       int i = 0;
       for (; i < stackTrace.length && !!!found; i++) {
-        if (!!!foundLookup && "lookup".equals(stackTrace[i].getMethodName())) {
+        if (!!!foundLookup && ("lookup".equals(stackTrace[i].getMethodName()) ||
+                               "list".equals(stackTrace[i].getMethodName()) ||
+                               "listBindings".equals(stackTrace[i].getMethodName()))) {
           foundLookup = true;
         } else if (foundLookup && !!!(stackTrace[i].getClassName().startsWith("org.apache.aries.jndi")
||
                                 stackTrace[i].getClassName().startsWith("javax.naming")))
{
@@ -178,62 +180,80 @@
     return result;
   }
 
-  public static Object getService(String interface1, String filter, String serviceName, boolean
dynamicRebind, Map<String, Object> env) throws NamingException
+  public static Object getService(String interface1, String filter, String serviceName, String
id, boolean dynamicRebind, Map<String, Object> env) throws NamingException
   {
     Object result = null;
     
     BundleContext ctx = getBundleContext(env);
     
+    if (id != null && filter == null) {
+      filter = '(' + Constants.SERVICE_ID + '=' + id + ')';
+    } else if (id != null && filter != null) {
+      filter = "(&(" + Constants.SERVICE_ID + '=' + id + ')' + filter + ')'; 
+    }
+    
     ServicePair pair = findService(ctx, interface1, filter);
     
     if (pair == null) {
       interface1 = null;
-      filter = "(osgi.jndi.service.name=" + serviceName + ")";
+      if (id == null) {
+        filter = "(osgi.jndi.service.name=" + serviceName + ')';
+      } else {
+        filter = "(&(" + Constants.SERVICE_ID + '=' + id + ")(osgi.jndi.service.name="
+ serviceName + "))";
+      }
       pair = findService(ctx, interface1, filter);
     }
     
     if (pair != null) {
-      String[] interfaces = (String[]) pair.ref.getProperty(Constants.OBJECTCLASS);
-      
-      List<Class<?>> clazz = new ArrayList<Class<?>>(interfaces.length);
-      
-      // We load the interface classes the service is registered under using the defining
-      // bundle. This is ok because the service must be able to see the classes to be 
-      // registered using them. We then check to see if isAssignableTo on the reference
-      // works for the owning bundle and the interface name and only use the interface if
-      // true is returned there.
-      
-      // This might seem odd, but equinox and felix return true for isAssignableTo if the
-      // Bundle provided does not import the package. This is under the assumption the
-      // caller will then use reflection. The upshot of doing it this way is that a utility
-      // bundle can be created which centralizes JNDI lookups, but the service will be used
-      // by another bundle. It is true that class space consistency is less safe, but we
-      // are enabling a slightly odd use case anyway.
-      
-      Bundle serviceProviderBundle = pair.ref.getBundle();
-      Bundle owningBundle = ctx.getBundle();
-      
-      for (String interfaceName : interfaces) {
-        try {
-          Class<?> potentialClass = serviceProviderBundle.loadClass(interfaceName);
-          
-          if (pair.ref.isAssignableTo(owningBundle, interfaceName)) clazz.add(potentialClass);
-        } catch (ClassNotFoundException e) {
-        }
-      }
-      
-      if (clazz.isEmpty()) {
-        throw new IllegalArgumentException(Arrays.asList(interfaces).toString());
+      result = proxy(interface1, filter, dynamicRebind, ctx, pair);
+    }
+    
+    return result;
+  }
+
+  private static Object proxy(String interface1, String filter, boolean dynamicRebind,
+      BundleContext ctx, ServicePair pair)
+  {
+    Object result;
+    String[] interfaces = (String[]) pair.ref.getProperty(Constants.OBJECTCLASS);
+    
+    List<Class<?>> clazz = new ArrayList<Class<?>>(interfaces.length);
+    
+    // We load the interface classes the service is registered under using the defining
+    // bundle. This is ok because the service must be able to see the classes to be 
+    // registered using them. We then check to see if isAssignableTo on the reference
+    // works for the owning bundle and the interface name and only use the interface if
+    // true is returned there.
+    
+    // This might seem odd, but equinox and felix return true for isAssignableTo if the
+    // Bundle provided does not import the package. This is under the assumption the
+    // caller will then use reflection. The upshot of doing it this way is that a utility
+    // bundle can be created which centralizes JNDI lookups, but the service will be used
+    // by another bundle. It is true that class space consistency is less safe, but we
+    // are enabling a slightly odd use case anyway.
+    
+    Bundle serviceProviderBundle = pair.ref.getBundle();
+    Bundle owningBundle = ctx.getBundle();
+    
+    for (String interfaceName : interfaces) {
+      try {
+        Class<?> potentialClass = serviceProviderBundle.loadClass(interfaceName);
+        
+        if (pair.ref.isAssignableTo(owningBundle, interfaceName)) clazz.add(potentialClass);
+      } catch (ClassNotFoundException e) {
       }
-      
-      InvocationHandler ih = new JNDIServiceDamper(ctx, interface1, filter, pair, dynamicRebind);
-      
-      // The ClassLoader needs to be able to load the service interface classes so it needs
to be
-      // wrapping the service provider bundle. The class is actually defined on this adapter.
-      
-      result = Proxy.newProxyInstance(new BundleToClassLoaderAdapter(serviceProviderBundle),
clazz.toArray(new Class<?>[clazz.size()]), ih);
     }
     
+    if (clazz.isEmpty()) {
+      throw new IllegalArgumentException(Arrays.asList(interfaces).toString());
+    }
+    
+    InvocationHandler ih = new JNDIServiceDamper(ctx, interface1, filter, pair, dynamicRebind);
+    
+    // The ClassLoader needs to be able to load the service interface classes so it needs
to be
+    // wrapping the service provider bundle. The class is actually defined on this adapter.
+    
+    result = Proxy.newProxyInstance(new BundleToClassLoaderAdapter(serviceProviderBundle),
clazz.toArray(new Class<?>[clazz.size()]), ih);
     return result;
   }
 
@@ -253,8 +273,6 @@
           }
         });
         
-        Bundle b = ctx.getBundle();
-        
         for (ServiceReference ref : refs) {
           Object service = ctx.getService(ref);
           
@@ -273,4 +291,51 @@
     
     return p;
   }
+
+  public static ServiceReference[] getServiceReferences(String interface1, String filter,
+      String serviceName, Map<String, Object> env) throws NamingException
+  {
+    BundleContext ctx = getBundleContext(env);
+    ServiceReference[] refs = null;
+
+    try {
+      refs = ctx.getServiceReferences(interface1, filter);
+      
+      if (refs == null || refs.length == 0) {
+        refs = ctx.getServiceReferences(null, "(osgi.jndi.service.name=" + serviceName +
')');
+      }
+    } catch (InvalidSyntaxException e) {
+      throw (NamingException) new NamingException(e.getFilter()).initCause(e);
+    }
+    
+    if (refs != null) {
+      // natural order is the exact opposite of the order we desire.
+      Arrays.sort(refs, new Comparator<ServiceReference>() {
+        public int compare(ServiceReference o1, ServiceReference o2)
+        {
+          return o2.compareTo(o1);
+        }
+      });
+    }
+    
+    return refs;
+  }
+
+  public static Object getService(BundleContext ctx, ServiceReference ref)
+  {
+    Object service = ctx.getService(ref);
+    
+    Object result = null;
+    
+    if (service != null) {
+      ServicePair pair = new ServicePair();
+      pair.ref = ref;
+      pair.service = service;
+      
+      result = proxy(null, null, false, ctx, pair);
+    }
+    
+    return result;
+  }
+
 }

Modified: incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java?rev=919842&r1=919841&r2=919842&view=diff
==============================================================================
--- incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java
(original)
+++ incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java
Sat Mar  6 20:20:24 2010
@@ -186,7 +186,7 @@
       result = ServiceHelper.getBundleContext(env);
     } else if ((OsgiName.SERVICE_PATH.equals(pathFragment) && OsgiName.OSGI_SCHEME.equals(schemeName))
||
                (OsgiName.SERVICES_PATH.equals(pathFragment) && OsgiName.ARIES_SCHEME.equals(schemeName)))
{
-      result = ServiceHelper.getService(validName.getInterface(), validName.getFilter(),
serviceName, true, env);
+      result = ServiceHelper.getService(validName.getInterface(), validName.getFilter(),
serviceName, null, true, env);
     } else if (OsgiName.SERVICE_LIST_PATH.equals(pathFragment)) {
       result = new ServiceRegistryListContext(env, validName);
     } else {

Modified: incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java?rev=919842&r1=919841&r2=919842&view=diff
==============================================================================
--- incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java
(original)
+++ incubator/aries/trunk/jndi/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java
Sat Mar  6 20:20:24 2010
@@ -21,25 +21,91 @@
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
+import java.util.NoSuchElementException;
 
 import javax.naming.Binding;
 import javax.naming.Context;
 import javax.naming.Name;
 import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
 import javax.naming.NameParser;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 import javax.naming.OperationNotSupportedException;
 
+import org.apache.aries.jndi.services.ServiceHelper;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
 public class ServiceRegistryListContext implements Context
 {
+  private static final String ARIES_SERVICES = "aries:services/";
   private Map<String, Object> env;
   /** The name parser for the service registry name space */
   private NameParser parser = new OsgiNameParser();
+  /** The osgi lookup name **/
+  private OsgiName parentName;
+  
+  private interface ThingManager<T>
+  {
+    public T get(BundleContext ctx, ServiceReference ref);
+    public void release(BundleContext ctx, ServiceReference ref);
+  }
+  
+  private class ServiceNamingEnumeration<T> implements NamingEnumeration<T>
+  {
+    private BundleContext ctx;
+    private ServiceReference[] refs;
+    private int position = 0;
+    private ThingManager<T> mgr;
+    private T last;
+    
+    private ServiceNamingEnumeration(BundleContext context, ServiceReference[] theRefs, ThingManager<T>
manager)
+    {
+      ctx = context;
+      refs = theRefs;
+      mgr = manager;
+    }
+    
+    public void close() throws NamingException
+    {
+      mgr.release(ctx, refs[position - 1]);
+      last = null;
+    }
+
+    public boolean hasMore() throws NamingException
+    {
+      return hasMore();
+    }
+
+    public T next() throws NamingException
+    {
+      return nextElement();
+    }
+
+    public boolean hasMoreElements()
+    {
+      return position < refs.length;
+    }
+
+    public T nextElement()
+    {
+      if (!!!hasMoreElements()) throw new NoSuchElementException();
+      
+      if (position > 0) mgr.release(ctx, refs[position - 1]);
+      
+      last = mgr.get(ctx, refs[position++]);
+      
+      return last;
+    }
+    
+  }
   
   public ServiceRegistryListContext(Map<String, Object> env, OsgiName validName)
   {
     this.env = new HashMap<String, Object>(env);
+    parentName = validName;
   }
 
   public Object addToEnvironment(String propName, Object propVal) throws NamingException
@@ -65,16 +131,32 @@
 
   public Name composeName(Name name, Name prefix) throws NamingException
   {
-    // TODO Auto-generated method stub
-    return null;
+    String result = prefix + "/" + name;
+
+    String ns = ARIES_SERVICES;
+    
+    if (result.startsWith(ns)) {
+      ns = "";
+    }
+    
+    return parser.parse(ns + result);
   }
 
   public String composeName(String name, String prefix) throws NamingException
   {
-    // TODO Auto-generated method stub
-    return null;
-  }
+    String result = prefix + "/" + name;
 
+    String ns = ARIES_SERVICES;
+    
+    if (result.startsWith(ns)) {
+      ns = "";
+    }
+    
+    parser.parse(ns + result);
+    
+    return result;
+  }
+  
   public Context createSubcontext(Name name) throws NamingException
   {
     throw new OperationNotSupportedException();
@@ -104,8 +186,7 @@
 
   public String getNameInNamespace() throws NamingException
   {
-    // TODO Auto-generated method stub
-    return null;
+    throw new OperationNotSupportedException();
   }
 
   public NameParser getNameParser(Name name) throws NamingException
@@ -125,8 +206,30 @@
 
   public NamingEnumeration<NameClassPair> list(String name) throws NamingException
   {
-    // TODO Auto-generated method stub
-    return null;
+    if (!!!"".equals(name)) throw new NameNotFoundException(name);
+    
+    final BundleContext ctx = ServiceHelper.getBundleContext(env);
+    final ServiceReference[] refs = ServiceHelper.getServiceReferences(parentName.getInterface(),
parentName.getFilter(), parentName.getServiceName(), env);
+    
+    return new ServiceNamingEnumeration<NameClassPair>(ctx, refs, new ThingManager<NameClassPair>()
{
+      public NameClassPair get(BundleContext ctx, ServiceReference ref)
+      {
+        String serviceId = String.valueOf(ref.getProperty(Constants.SERVICE_ID));
+        String className = null;
+        Object service = ctx.getService(ref);
+        if (service != null) {
+          className = service.getClass().getName();
+        }
+
+        ctx.ungetService(ref);
+        
+        return new NameClassPair(serviceId, className, true);
+      }
+
+      public void release(BundleContext ctx, ServiceReference ref)
+      {
+      }
+    });
   }
 
   public NamingEnumeration<Binding> listBindings(Name name) throws NamingException
@@ -136,8 +239,26 @@
 
   public NamingEnumeration<Binding> listBindings(String name) throws NamingException
   {
-    // TODO Auto-generated method stub
-    return null;
+    if (!!!"".equals(name)) throw new NameNotFoundException(name);
+    
+    final BundleContext ctx = ServiceHelper.getBundleContext(env);
+    final ServiceReference[] refs = ServiceHelper.getServiceReferences(parentName.getInterface(),
parentName.getFilter(), parentName.getServiceName(), env);
+
+    return new ServiceNamingEnumeration<Binding>(ctx, refs, new ThingManager<Binding>()
{
+      public Binding get(BundleContext ctx, ServiceReference ref)
+      {
+        String serviceId = String.valueOf(ref.getProperty(Constants.SERVICE_ID));
+        
+        Object service = ServiceHelper.getService(ctx, ref);
+
+        return new Binding(serviceId, service, true);
+      }
+
+      public void release(BundleContext ctx, ServiceReference ref)
+      {
+        ctx.ungetService(ref);
+      }
+    });
   }
 
   public Object lookup(Name name) throws NamingException
@@ -147,7 +268,15 @@
 
   public Object lookup(String name) throws NamingException
   {
-    return null;
+    Object result = null;
+    
+    result = ServiceHelper.getService(parentName.getInterface(), parentName.getFilter(),
parentName.getServiceName(), name, false, env);
+    
+    if (result == null) {
+      throw new NameNotFoundException(name.toString());
+    }
+    
+    return result;
   }
 
   public Object lookupLink(Name name) throws NamingException

Modified: incubator/aries/trunk/jndi/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java
URL: http://svn.apache.org/viewvc/incubator/aries/trunk/jndi/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java?rev=919842&r1=919841&r2=919842&view=diff
==============================================================================
--- incubator/aries/trunk/jndi/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java
(original)
+++ incubator/aries/trunk/jndi/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java
Sat Mar  6 20:20:24 2010
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.lang.reflect.Field;
 import java.util.Hashtable;
@@ -48,6 +49,7 @@
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceException;
 import org.osgi.framework.ServiceFactory;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
@@ -314,8 +316,168 @@
     
     Skeleton.getSkeleton(t).assertCalledExactNumberOfTimes(new MethodCall(Runnable.class,
"run"), 1);
     Skeleton.getSkeleton(t2).assertCalledExactNumberOfTimes(new MethodCall(Runnable.class,
"run"), 1);
-  }  
+  }
+  
+  @Test
+  public void checkServiceListLookup() throws NamingException
+  {
+    BundleMock mock = new BundleMock("scooby.doo", new Properties());
+    
+    Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+
+    InitialContext ctx = new InitialContext();
+    
+    String className = Runnable.class.getName();
+    
+    Runnable t = Skeleton.newMock(Runnable.class);
+    
+    // we don't want the default service
+    reg.unregister();
+    
+    ServiceRegistration reg = bc.registerService(className, t, null);
+    ServiceRegistration reg2 = bc.registerService("java.lang.Thread", new Thread(), null);
+    
+    Context ctx2 = (Context) ctx.lookup("osgi:servicelist/java.lang.Runnable");
+    
+    Runnable r = (Runnable) ctx2.lookup(String.valueOf(reg.getReference().getProperty(Constants.SERVICE_ID)));
 
+    r.run();
+    
+    Skeleton.getSkeleton(t).assertCalled(new MethodCall(Runnable.class, "run"));
+    
+    reg.unregister();
+    
+    try {
+      r.run();
+      fail("Should have received a ServiceException");
+    } catch (ServiceException e) {
+      assertEquals("service exception has the wrong type", ServiceException.UNREGISTERED,
e.getType());
+    }
+    
+    try {
+      ctx2.lookup(String.valueOf(reg2.getReference().getProperty(Constants.SERVICE_ID)));
+      fail("Expected a NameNotFoundException");
+    } catch (NameNotFoundException e) {
+    }
+  }
+  
+  @Test
+  public void checkServiceListList() throws NamingException
+  {
+    BundleMock mock = new BundleMock("scooby.doo", new Properties());
+    
+    Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+
+    InitialContext ctx = new InitialContext();
+    
+    String className = Runnable.class.getName();
+    
+    Runnable t = Skeleton.newMock(Runnable.class);
+    
+    // we don't want the default service
+    reg.unregister();
+    
+    ServiceRegistration reg = bc.registerService(className, t, null);
+    ServiceRegistration reg2 = bc.registerService(className, new Thread(), null);
+    
+    NamingEnumeration<NameClassPair> ne = ctx.list("osgi:servicelist/" + className);
+    
+    assertTrue(ne.hasMoreElements());
+    
+    NameClassPair ncp = ne.nextElement();
+    
+    assertEquals(String.valueOf(reg.getReference().getProperty(Constants.SERVICE_ID)), ncp.getName());
+    assertTrue("Class name not correct. Was: " + ncp.getClassName(), ncp.getClassName().contains("Proxy"));
+    
+    assertTrue(ne.hasMoreElements());
+    
+    ncp = ne.nextElement();
+    
+    assertEquals(String.valueOf(reg2.getReference().getProperty(Constants.SERVICE_ID)), ncp.getName());
+    assertEquals("Class name not correct.", Thread.class.getName(), ncp.getClassName());
+    
+    assertFalse(ne.hasMoreElements());
+  }
+
+  @Test
+  public void checkServiceListListBindings() throws NamingException
+  {
+    BundleMock mock = new BundleMock("scooby.doo", new Properties());
+    
+    Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+
+    InitialContext ctx = new InitialContext();
+    
+    String className = Runnable.class.getName();
+    
+    MethodCall run = new MethodCall(Runnable.class, "run");
+    
+    Runnable t = Skeleton.newMock(Runnable.class);
+    Runnable t2 = Skeleton.newMock(Runnable.class);
+    
+    // we don't want the default service
+    reg.unregister();
+    
+    ServiceRegistration reg = bc.registerService(className, t, null);
+    ServiceRegistration reg2 = bc.registerService(className, t2, null);
+    
+    NamingEnumeration<Binding> ne = ctx.listBindings("osgi:servicelist/" + className);
+    
+    assertTrue(ne.hasMoreElements());
+    
+    Binding bnd = ne.nextElement();
+    
+    assertEquals(String.valueOf(reg.getReference().getProperty(Constants.SERVICE_ID)), bnd.getName());
+    assertTrue("Class name not correct. Was: " + bnd.getClassName(), bnd.getClassName().contains("Proxy"));
+    
+    Runnable r = (Runnable) bnd.getObject();
+    
+    assertNotNull(r);
+    
+    r.run();
+    
+    Skeleton.getSkeleton(t).assertCalledExactNumberOfTimes(run, 1);
+    Skeleton.getSkeleton(t2).assertNotCalled(run);
+    
+    assertTrue(ne.hasMoreElements());
+    
+    bnd = ne.nextElement();
+    
+    assertEquals(String.valueOf(reg2.getReference().getProperty(Constants.SERVICE_ID)), bnd.getName());
+    assertTrue("Class name not correct. Was: " + bnd.getClassName(), bnd.getClassName().contains("Proxy"));
+    
+    r = (Runnable) bnd.getObject();
+    
+    assertNotNull(r);
+    
+    r.run();
+    
+    Skeleton.getSkeleton(t).assertCalledExactNumberOfTimes(run, 1);
+    Skeleton.getSkeleton(t2).assertCalledExactNumberOfTimes(run, 1);
+    
+    assertFalse(ne.hasMoreElements());
+  }
+
+  @Test(expected=ServiceException.class)
+  public void checkProxyWhenServiceGoes() throws ServiceException, NamingException
+  {
+    BundleMock mock = new BundleMock("scooby.doo", new Properties());
+    
+    Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+
+    InitialContext ctx = new InitialContext();
+    
+    Runnable r = (Runnable) ctx.lookup("osgi:service/java.lang.Runnable");
+    
+    r.run();
+    
+    Skeleton.getSkeleton(service).assertCalled(new MethodCall(Runnable.class, "run"));
+    
+    reg.unregister();
+    
+    r.run();
+  }
+  
   @Test
   public void checkServiceOrderObserved() throws NamingException
   {



Mime
View raw message