You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by zo...@apache.org on 2011/02/27 19:01:02 UTC

svn commit: r1075097 [2/2] - in /aries/tags/jndi-0.1-incubating: ./ jndi-bundle/ jndi-bundle/src/ jndi-bundle/src/main/ jndi-bundle/src/main/java/ jndi-bundle/src/main/java/org/ jndi-bundle/src/main/java/org/apache/ jndi-bundle/src/main/java/org/apache...

Added: aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java (added)
+++ aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/services/ServiceHelper.java Sun Feb 27 18:01:00 2011
@@ -0,0 +1,371 @@
+/*
+ * 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.aries.jndi.services;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.naming.NamingException;
+
+import org.apache.aries.jndi.url.OsgiName;
+import org.apache.aries.util.BundleToClassLoaderAdapter;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * This helper provides access to services registered in the OSGi service registry.
+ * If a matching service cannot be located null may be returned. A caller should not
+ * expect to get the same object if multiple requests are made to this API. A caller
+ * should not expect to get a different object if multiple requests are made to this API.
+ * A caller should avoid caching the returned service. OSGi is a dynamic environment and
+ * the service may become unavailable while a reference to it is held. To minimize this
+ * risk the caller should hold onto the service for the minimum length of time.
+ * 
+ * <p>This API should not be used from within an OSGi bundle. When in an OSGi environment
+ *   the BundleContext for the bundle should be used to obtain the service.
+ * </p>
+ */
+public final class ServiceHelper
+{
+  public static class StackFinder extends SecurityManager
+  {
+    public Class<?>[] getClassContext()
+    {
+      return super.getClassContext();
+    }
+  }
+
+  private static class JNDIServiceDamper implements InvocationHandler
+  {
+    private BundleContext ctx;
+    private ServicePair pair;
+    private String interfaceName;
+    private String filter;
+    private boolean dynamic;
+    
+    public JNDIServiceDamper(BundleContext context, String i, String f, ServicePair service, boolean d)
+    {
+      ctx = context;
+      pair = service;
+      interfaceName = i;
+      filter = f;
+      dynamic = d;
+    }
+    
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+    {
+      if (pair.ref.getBundle() == null) {
+        if (dynamic) pair = findService(ctx, interfaceName, filter);
+        else pair = null;
+      }
+      
+      if (pair == null) {
+        throw new ServiceException(interfaceName, ServiceException.UNREGISTERED);
+      }
+      
+      try {
+        return method.invoke(pair.service, args);
+      } catch (InvocationTargetException ite) {
+        throw ite.getTargetException();
+      }
+    }
+  }
+  
+  private static class ServicePair
+  {
+    private ServiceReference ref;
+    private Object service;
+  }
+  
+  /**
+   * @param env 
+   * @return the bundle context for the caller.
+   * @throws NamingException 
+   */
+  public static BundleContext getBundleContext(Map<String, Object> env) throws NamingException
+  {
+    BundleContext result = null;
+    
+    Object bc = env.get("osgi.service.jndi.bundleContext");
+    
+    if (bc != null && bc instanceof BundleContext) result = (BundleContext) bc;
+    else {
+      ClassLoader cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+        public ClassLoader run()
+        {
+          return Thread.currentThread().getContextClassLoader();
+        }
+      });
+      
+      result = getBundleContext(cl);
+    }
+    
+    if (result == null) {
+      StackTraceElement[] stackTrace =  Thread.currentThread().getStackTrace();
+      
+      StackFinder finder = new StackFinder();
+      Class<?>[] classStack = finder.getClassContext();
+      
+      boolean found = false;
+      boolean foundLookup = false;
+      int i = 0;
+      for (; i < stackTrace.length && !!!found; i++) {
+        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"))) {
+          found = true;
+        }
+      }
+      
+      if (found) {
+        i--; // we need to move back an item because the previous loop leaves us one after where we wanted to be
+        Set<Integer> classLoadersChecked = new HashSet<Integer>();
+        for (; i < classStack.length && result == null; i++) {
+          ClassLoader cl = classStack[i].getClassLoader();
+          int hash = System.identityHashCode(cl);
+          if (!!!classLoadersChecked.contains(hash)) {
+            classLoadersChecked.add(hash);
+            result = getBundleContext(cl);
+          }
+        }
+        // Now we walk the stack looking for the BundleContext
+      }
+    }
+    
+    if (result == null) throw new NamingException("Unable to find BundleContext");
+    
+    return result;
+  }
+
+  private static BundleContext getBundleContext(final ClassLoader cl2)
+  {
+    return AccessController.doPrivileged(new PrivilegedAction<BundleContext>() {
+      public BundleContext run()
+      {
+        ClassLoader cl = cl2;
+        BundleContext result = null;
+        while (result == null && cl != null) {
+          if (cl instanceof BundleReference) {
+            result = ((BundleReference)cl).getBundle().getBundleContext();
+          } else if (cl != null) {
+            cl = cl.getParent();
+          }
+        }
+        
+        return result;
+      }
+    });
+  }
+
+  public static Object getService(OsgiName lookupName, String id, boolean dynamicRebind, Map<String, Object> env) throws NamingException
+  {
+    Object result = null;
+    
+    String interfaceName = lookupName.getInterface();
+    String filter = lookupName.getFilter();
+    String serviceName = lookupName.getServiceName();
+    
+    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 = null;
+    
+    if (!!!lookupName.isServiceNameBased()) pair = findService(ctx, interfaceName, filter);
+    
+    if (pair == null) {
+      interfaceName = null;
+      if (id == null) {
+        filter = "(osgi.jndi.service.name=" + serviceName + ')';
+      } else {
+        filter = "(&(" + Constants.SERVICE_ID + '=' + id + ")(osgi.jndi.service.name=" + serviceName + "))";
+      }
+      pair = findService(ctx, interfaceName, filter);
+    }
+    
+    if (pair != null) {
+      result = proxy(interfaceName, filter, dynamicRebind, ctx, pair);
+    }
+    
+    return result;
+  }
+  
+  private static Object proxy(final String interface1, final String filter, final boolean rebind, 
+                              final BundleContext ctx, final ServicePair pair)
+  {
+    return AccessController.doPrivileged(new PrivilegedAction<Object>() {
+      public Object run()
+      {
+        return proxyPriviledged(interface1, filter, rebind, ctx, pair);
+      }
+    });
+  }
+
+  private static Object proxyPriviledged(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) {
+      }
+    }
+    
+    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;
+  }
+
+  private static ServicePair findService(BundleContext ctx, String interface1, String filter) throws NamingException
+  {
+    ServicePair p = null;
+    
+    try {
+      ServiceReference[] refs = ctx.getServiceReferences(interface1, filter);
+      
+      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);
+          }
+        });
+        
+        for (ServiceReference ref : refs) {
+          Object service = ctx.getService(ref);
+          
+          if (service != null) {
+            p = new ServicePair();
+            p.ref = ref;
+            p.service = service;
+            break;
+          }
+        }
+      }
+      
+    } catch (InvalidSyntaxException e) {
+      // If we get an invalid syntax exception we just ignore it. Null will be returned which
+      // is valid and that may result in a NameNotFoundException if that is the right thing to do
+    }
+    
+    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;
+  }
+
+}

Added: aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/AbstractServiceRegistryContext.java
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/AbstractServiceRegistryContext.java?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/AbstractServiceRegistryContext.java (added)
+++ aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/AbstractServiceRegistryContext.java Sun Feb 27 18:01:00 2011
@@ -0,0 +1,191 @@
+/*
+ * 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.aries.jndi.url;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameParser;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+
+public abstract class AbstractServiceRegistryContext implements Context
+{
+
+  /** The environment for this context */
+  protected Map<String, Object> env;
+  /** The name parser for the service registry name space */
+  protected NameParser parser = new OsgiNameParser();
+  private static final String ARIES_SERVICES = "aries:services/";
+
+  @SuppressWarnings("unchecked")
+  public AbstractServiceRegistryContext(Hashtable<?, ?> environment)
+  {
+    env = new HashMap<String, Object>();
+    env.putAll((Map<? extends String, ? extends Object>) environment);
+  }
+
+  @SuppressWarnings("unchecked")
+  public AbstractServiceRegistryContext(Map<?, ?> environment)
+  {
+    env = new HashMap<String, Object>();
+    env.putAll((Map<? extends String, ? extends Object>) environment);
+  }
+
+  public Object addToEnvironment(String propName, Object propVal) throws NamingException
+  {
+    return env.put(propName, propVal);
+  }
+
+  public void bind(Name name, Object obj) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public void bind(String name, Object obj) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public void close() throws NamingException
+  {
+    env = null;
+    parser = null;
+  }
+
+  public Name composeName(Name name, Name prefix) throws NamingException
+  {
+    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
+  {
+    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();
+  }
+
+  public Context createSubcontext(String name) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public void destroySubcontext(Name name) throws NamingException
+  {
+    //No-op we don't support sub-contexts in our context   
+  }
+
+  public void destroySubcontext(String name) throws NamingException
+  {
+    //No-op we don't support sub-contexts in our context
+    
+  }
+
+  public Hashtable<?, ?> getEnvironment() throws NamingException
+  {
+    Hashtable<Object, Object> environment = new Hashtable<Object, Object>();
+    environment.putAll(env);
+    return environment;
+  }
+
+  public String getNameInNamespace() throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public NameParser getNameParser(Name name) throws NamingException
+  {
+    return parser;
+  }
+
+  public NameParser getNameParser(String name) throws NamingException
+  {
+    return parser;
+  }
+
+  public Object lookupLink(Name name) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public Object lookupLink(String name) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public void rebind(Name name, Object obj) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public void rebind(String name, Object obj) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public Object removeFromEnvironment(String propName) throws NamingException
+  {
+    return env.remove(propName);
+  }
+
+  public void rename(Name oldName, Name newName) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public void rename(String oldName, String newName) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public void unbind(Name name) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+  public void unbind(String name) throws NamingException
+  {
+    throw new OperationNotSupportedException();
+  }
+
+}

Added: aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/Activator.java
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/Activator.java?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/Activator.java (added)
+++ aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/Activator.java Sun Feb 27 18:01:00 2011
@@ -0,0 +1,46 @@
+/*
+ * 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.aries.jndi.url;
+
+import java.util.Hashtable;
+
+import javax.naming.spi.ObjectFactory;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator {
+
+  private ServiceRegistration reg;
+	
+  public void start(BundleContext context)
+  {
+    Hashtable<Object, Object> props = new Hashtable<Object, Object>();
+    props.put("osgi.jndi.urlScheme", new String[] {"osgi", "aries"} );
+    reg = context.registerService(ObjectFactory.class.getName(), new OsgiURLContextFactory(), props);
+  }
+
+
+  public void stop(BundleContext context)
+  {
+	reg.unregister();
+  }
+
+}

Added: aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiName.java
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiName.java?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiName.java (added)
+++ aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiName.java Sun Feb 27 18:01:00 2011
@@ -0,0 +1,162 @@
+/*
+ * 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.aries.jndi.url;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.naming.CompositeName;
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+
+/**
+ * A composite name for the aries namespace. This provides useful utility methods
+ * for accessing the name.
+ * 
+ * component 0: osgi:service, aries:services, osgi:servicelist
+ * component 1: interface
+ * component 2: filter
+ */
+public final class OsgiName extends CompositeName
+{
+  /** The serial version UID */
+  private static final long serialVersionUID = 6617580228852444656L;
+  public static final String OSGI_SCHEME = "osgi";
+  public static final String ARIES_SCHEME = "aries";
+  public static final String SERVICE_PATH = "service";
+  public static final String SERVICES_PATH = "services";
+  public static final String SERVICE_LIST_PATH = "servicelist";
+  public static final String FRAMEWORK_PATH = "framework";
+  
+  public OsgiName(String name) throws InvalidNameException
+  {
+    super(split(name));
+  }
+
+  public OsgiName(Name name) throws InvalidNameException
+  {
+    this(name.toString());
+  }
+
+  private static Enumeration<String> split(String name)
+  {
+    List<String> elements = new ArrayList<String>();
+
+    StringBuilder builder = new StringBuilder();
+    
+    int len = name.length();
+    int count = 0;
+    
+    for (int i = 0; i < len; i++) {
+      char c = name.charAt(i);
+      
+      if (c == '/' && count == 0) {
+        elements.add(builder.toString());
+        builder = new StringBuilder();
+        continue;
+      } else if (c == '(') count++;
+      else if (c == ')') count++;
+      
+      builder.append(c);
+    }
+    
+    elements.add(builder.toString());
+    
+    return Collections.enumeration(elements);
+  }
+
+  public boolean hasFilter()
+  {
+    return size() == 3;
+  }
+  
+  public boolean isServiceNameBased()
+  {
+    return size() > 3;
+  }
+  
+  public String getScheme()
+  {
+    String part0 = get(0);
+    int index = part0.indexOf(':');
+    
+    String result;
+    
+    if (index > 0) {
+      result = part0.substring(0, index);
+    } else {
+      result = null;
+    }
+    
+    return result;
+  }
+  
+  public String getSchemePath()
+  {
+    String part0 = get(0);
+    int index = part0.indexOf(':');
+    
+    String result;
+    
+    if (index > 0) {
+      result = part0.substring(index + 1);
+    } else {
+      result = null;
+    }
+    
+    return result;
+  }
+  
+  public String getInterface()
+  {
+    return get(1);
+  }
+  
+  public String getFilter()
+  {
+    return hasFilter() ? get(2) : null;
+  }
+  
+  public String getServiceName()
+  {
+    Enumeration<String> parts = getAll();
+    parts.nextElement();
+    
+    StringBuilder builder = new StringBuilder();
+    
+    if (parts.hasMoreElements()) {
+
+      while (parts.hasMoreElements()) {
+        builder.append(parts.nextElement());
+        builder.append('/');
+      }
+    
+      builder.deleteCharAt(builder.length() - 1);
+    }
+    
+    return builder.toString();
+  }
+
+  public boolean hasInterface()
+  {
+    return size() > 1;
+  }
+}
\ No newline at end of file

Added: aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiNameParser.java
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiNameParser.java?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiNameParser.java (added)
+++ aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiNameParser.java Sun Feb 27 18:01:00 2011
@@ -0,0 +1,73 @@
+/*
+ * 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.aries.jndi.url;
+
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+import javax.naming.NameParser;
+import javax.naming.NamingException;
+
+/**
+ * A parser for the aries namespace
+ */
+public final class OsgiNameParser implements NameParser
+{
+  private static final String OSGI_SCHEME = "osgi";
+  private static final String ARIES_SCHEME = "aries";
+  private static final String SERVICE_PATH = "service";
+  private static final String SERVICES_PATH = "services";
+  private static final String SERVICE_LIST_PATH = "servicelist";
+  private static final String FRAMEWORK_PATH = "framework";
+  
+  public Name parse(String name) throws NamingException
+  {
+    OsgiName result = new OsgiName(name);
+    
+    String urlScheme = result.getScheme();
+    String schemePath = result.getSchemePath();
+    
+    if (!!!(OSGI_SCHEME.equals(urlScheme) || ARIES_SCHEME.equals(urlScheme))) {
+      throw new InvalidNameException(name);
+    }
+    
+    if (ARIES_SCHEME.equals(urlScheme) && !!!SERVICES_PATH.equals(schemePath)) {
+      throw new InvalidNameException(name);
+    }
+    
+    if (OSGI_SCHEME.equals(urlScheme) && !!!( SERVICE_PATH.equals(schemePath) || 
+                                              SERVICE_LIST_PATH.equals(schemePath) || 
+                                              FRAMEWORK_PATH.equals(schemePath))) {
+      throw new InvalidNameException(name);
+    }
+    
+    return result;
+  }
+
+  @Override
+  public boolean equals(Object other)
+  {
+    return other instanceof OsgiNameParser;
+  }
+  
+  @Override
+  public int hashCode()
+  {
+    return 100003;
+  }
+}
\ No newline at end of file

Added: aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiURLContextFactory.java
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiURLContextFactory.java?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiURLContextFactory.java (added)
+++ aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/OsgiURLContextFactory.java Sun Feb 27 18:01:00 2011
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.jndi.url;
+
+import java.util.Hashtable;
+
+import javax.naming.ConfigurationException;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.spi.ObjectFactory;
+
+/**
+ * A factory for the aries JNDI context
+ */
+public class OsgiURLContextFactory implements ObjectFactory
+{
+  public Object getObjectInstance(Object obj, Name name, Context nameCtx,
+      Hashtable<?, ?> environment) throws Exception
+  {
+    if (obj == null) {
+      return new ServiceRegistryContext(environment);
+    } else if (obj instanceof String) {
+      Context ctx = null;
+      try {
+        
+        ctx = new ServiceRegistryContext(environment);
+        
+        return ctx.lookup((String)obj);
+      } finally {
+        if (ctx != null) ctx.close();
+      }
+    } else if (obj instanceof String[]) {
+      // Try each URL until either lookup succeeds or they all fail
+      String[] urls = (String[])obj;
+      if (urls.length == 0) throw new ConfigurationException("0");
+      Context context = new ServiceRegistryContext(environment);
+      try
+      {
+        NamingException ne = null;
+        for(int i=0; i< urls.length; i++)
+        {
+          try
+          {
+            return context.lookup(urls[i]);
+          }
+          catch(NamingException e)
+          {
+            ne = e;
+          }
+        }
+        throw ne;
+      }
+      finally
+      {
+        context.close();
+      }    
+      
+    }
+
+    return null;
+  }
+
+}

Added: aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java (added)
+++ aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryContext.java Sun Feb 27 18:01:00 2011
@@ -0,0 +1,141 @@
+/*
+ * 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.aries.jndi.url;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+import org.apache.aries.jndi.services.ServiceHelper;
+
+/**
+ * A JNDI context for looking stuff up from the service registry.
+ */
+public class ServiceRegistryContext extends AbstractServiceRegistryContext implements Context
+{
+  /** The parent name, if one is provided, of this context */
+  private OsgiName parentName;
+
+  /**
+   * Why Mr Java this class does indeed take a fine copy of the provided 
+   * environment. One might imagine that it is worried that the provider is
+   * not to be trusted.
+   * 
+   * @param environment
+   */
+  public ServiceRegistryContext(Hashtable<?, ?> environment)
+  {
+    super(environment);
+  }
+
+  public ServiceRegistryContext(OsgiName validName, Map<String, Object> env) 
+  {
+    super(env);
+    parentName = validName;
+  }
+
+  public NamingEnumeration<NameClassPair> list(final Name name) throws NamingException
+  {
+    return new ServiceRegistryListContext(env, convert(name)).list("");
+  }
+
+  public NamingEnumeration<NameClassPair> list(String name) throws NamingException
+  {
+    return list(parse(name));
+  }
+
+  public NamingEnumeration<Binding> listBindings(final Name name) throws NamingException
+  {
+    return new ServiceRegistryListContext(env, convert(name)).listBindings("");
+  }
+
+  public NamingEnumeration<Binding> listBindings(String name) throws NamingException
+  {
+    return listBindings(parse(name));
+  }
+
+  public Object lookup(Name name) throws NamingException
+  {
+    Object result;
+    
+    OsgiName validName = convert(name);
+    
+    String pathFragment = validName.getSchemePath();
+    String schemeName = validName.getScheme();
+    
+    if (validName.hasInterface()) {
+      if (OsgiName.FRAMEWORK_PATH.equals(pathFragment) && "bundleContext".equals(validName.getServiceName())) {
+        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, null, true, env);
+      } else if (OsgiName.SERVICE_LIST_PATH.equals(pathFragment)) {
+        result = new ServiceRegistryListContext(env, validName);
+      } else {
+        result = null;
+      }
+    } else {
+      result = new ServiceRegistryContext(validName, env);
+    }
+    
+    if (result == null) {
+      throw new NameNotFoundException(name.toString());
+    }
+    
+    return result;
+  }
+
+  private OsgiName convert(Name name) throws NamingException
+  {
+    OsgiName result;
+    
+    if (name instanceof OsgiName) {
+      result = (OsgiName) name;
+    } else {
+      if (parentName != null) {
+        result = new OsgiName(parentName.toString() + "/" + name.toString());
+      } else {
+        result = (OsgiName)parser.parse(name.toString());
+      }
+    }
+    
+    return result;
+  }
+  
+  private Name parse(String name) throws NamingException
+  {
+    if (parentName != null) {
+        name = parentName.toString() + "/" + name;
+    }
+    
+    return parser.parse(name);
+  }
+  
+  public Object lookup(String name) throws NamingException
+  {
+    return lookup(parse(name));
+  }
+}

Added: aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java (added)
+++ aries/tags/jndi-0.1-incubating/jndi-url/src/main/java/org/apache/aries/jndi/url/ServiceRegistryListContext.java Sun Feb 27 18:01:00 2011
@@ -0,0 +1,182 @@
+/*
+ * 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.aries.jndi.url;
+
+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.NamingEnumeration;
+import javax.naming.NamingException;
+
+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 extends AbstractServiceRegistryContext implements Context
+{
+  /** 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 static 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 hasMoreElements();
+    }
+
+    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)
+  {
+    super(env);
+    parentName = validName;
+  }
+
+  public NamingEnumeration<NameClassPair> list(Name name) throws NamingException
+  {
+    return list(name.toString());
+  }
+
+  public NamingEnumeration<NameClassPair> list(String name) throws NamingException
+  {
+    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
+  {
+    return listBindings(name.toString());
+  }
+
+  public NamingEnumeration<Binding> listBindings(String name) throws NamingException
+  {
+    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
+  {
+    return lookup(name.toString());
+  }
+
+  public Object lookup(String name) throws NamingException
+  {
+    Object result = null;
+    
+    result = ServiceHelper.getService(parentName, name, false, env);
+    
+    if (result == null) {
+      throw new NameNotFoundException(name.toString());
+    }
+    
+    return result;
+  }
+}
\ No newline at end of file

Added: aries/tags/jndi-0.1-incubating/jndi-url/src/test/java/org/apache/aries/jndi/url/OsgiNameParserTest.java
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/jndi-url/src/test/java/org/apache/aries/jndi/url/OsgiNameParserTest.java?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/jndi-url/src/test/java/org/apache/aries/jndi/url/OsgiNameParserTest.java (added)
+++ aries/tags/jndi-0.1-incubating/jndi-url/src/test/java/org/apache/aries/jndi/url/OsgiNameParserTest.java Sun Feb 27 18:01:00 2011
@@ -0,0 +1,123 @@
+/*
+ * 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.aries.jndi.url;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import javax.naming.InvalidNameException;
+import javax.naming.NameParser;
+import javax.naming.NamingException;
+
+import org.junit.Test;
+
+/**
+ * This is where we test the service registry name parser.
+ */
+public class OsgiNameParserTest
+{
+  /** The parser we are going to use for testing */
+  private NameParser parser = new OsgiNameParser();
+
+  /**
+   * OK, so we check that we can call checkNames multiple times.
+   * @throws NamingException
+   */
+  @Test
+  public void checkValidNames() throws NamingException
+  {
+    checkName("aries","services","java.lang.Runnable","(a=b)");
+    checkName("aries","services","java.lang.Runnable");
+    checkName("osgi","service","java.lang.Runnable");
+    checkName("osgi","service","java.lang.Runnable", "(a=b)");
+    checkName("osgi","servicelist","java.lang.Runnable");
+    checkName("osgi","servicelist","java.lang.Runnable", "(a=b)");
+    checkName("osgi","servicelist","jdbc", "grok", "DataSource");
+    checkName("osgi", "framework", "bundleContext");
+    checkName("osgi","service","javax.sql.DataSource", "(osgi.jndi.servicee.name=jdbc/myDataSource)");
+    checkName("osgi","service","javax.sql.DataSource", "(&(a=/b)(c=/d))");
+    checkName("osgi", "service");
+  }
+  
+  /**
+   * Make sure it fails if we try to parse something that isn't in aries:services
+   * @throws NamingException
+   */
+  @Test(expected=InvalidNameException.class)
+  public void checkOutsideNamespace() throws NamingException
+  {
+    checkName("java","comp","env","jms","cf");
+  }
+  
+  @Test(expected=InvalidNameException.class)
+  public void checkIncorrectPath() throws NamingException
+  {
+    checkName("osgi", "services", "java.lang.Runnable"); 
+  }
+  
+  @Test(expected=InvalidNameException.class)
+  public void checkIllegalPath() throws NamingException
+  {
+    checkName("osgi", "wibble", "java.lang.Runnable"); 
+  }
+  
+  private void checkName(String scheme, String path, String ... elements)
+    throws NamingException
+  {
+    StringBuilder builder = new StringBuilder();
+    StringBuilder serviceName = new StringBuilder();
+    
+    builder.append(scheme);
+    builder.append(':');
+    builder.append(path);
+
+    if (elements.length > 0) {
+      builder.append('/');
+      
+      for (String element : elements) {
+        serviceName.append(element);
+        serviceName.append('/');
+      }
+  
+      serviceName.deleteCharAt(serviceName.length() - 1);
+      
+      builder.append(serviceName);
+    }
+    
+    OsgiName n = (OsgiName) parser.parse(builder.toString());
+    
+    assertEquals(scheme, n.getScheme());
+    assertEquals(path, n.getSchemePath());
+    
+    if (elements.length > 1) {
+      assertEquals(elements[0], n.getInterface());
+      if (elements.length == 2) {
+        assertTrue("There is no filter in the name", n.hasFilter());
+        assertEquals(elements[1], n.getFilter());
+      } else assertFalse(n.hasFilter());
+    }
+    
+    if (elements.length == 1) {
+      assertFalse("There is a filter in the name", n.hasFilter());
+    }
+    
+    assertEquals(serviceName.toString(), n.getServiceName());
+  }
+}
\ No newline at end of file

Added: aries/tags/jndi-0.1-incubating/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java (added)
+++ aries/tags/jndi-0.1-incubating/jndi-url/src/test/java/org/apache/aries/jndi/url/ServiceRegistryContextTest.java Sun Feb 27 18:01:00 2011
@@ -0,0 +1,660 @@
+/*
+ * 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.aries.jndi.url;
+
+import static org.junit.Assert.assertEquals;
+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.sql.SQLException;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.spi.ObjectFactory;
+import javax.sql.DataSource;
+
+import org.apache.aries.jndi.ContextHelper;
+import org.apache.aries.jndi.OSGiObjectFactoryBuilder;
+import org.apache.aries.mocks.BundleContextMock;
+import org.apache.aries.mocks.BundleMock;
+import org.apache.aries.unittest.mocks.MethodCall;
+import org.apache.aries.unittest.mocks.Skeleton;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+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;
+
+/**
+ * Tests for our JNDI implementation for the service registry.
+ */
+public class ServiceRegistryContextTest
+{
+  /** The service we register by default */
+  private Runnable service;
+  /** The bundle context for the test */
+  private BundleContext bc;
+  /** The service registration for the service */
+  private ServiceRegistration reg;
+  
+  /**
+   * This method does the setup to ensure we always have a service.
+   * @throws NamingException 
+   * @throws NoSuchFieldException 
+   * @throws SecurityException 
+   * @throws IllegalAccessException 
+   * @throws IllegalArgumentException 
+   */
+  @Before
+  public void registerService() throws NamingException, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException 
+  {
+    bc =  Skeleton.newMock(new BundleContextMock(), BundleContext.class);
+    new Activator().start(bc);
+    new org.apache.aries.jndi.startup.Activator().start(bc);
+    
+    Field f = ContextHelper.class.getDeclaredField("context");
+    f.setAccessible(true);
+    f.set(null, bc);
+    f = OSGiObjectFactoryBuilder.class.getDeclaredField("context");
+    f.setAccessible(true);
+    f.set(null, bc);
+
+
+    service = Skeleton.newMock(Runnable.class);
+    
+    registerService(service);
+  }
+  
+  /**
+   * Register a service in our map.
+   * 
+   * @param service2 The service to register.
+   */
+  private void registerService(Runnable service2)
+  {
+    ServiceFactory factory = Skeleton.newMock(ServiceFactory.class);
+    Skeleton skel = Skeleton.getSkeleton(factory);
+    
+    skel.setReturnValue(new MethodCall(ServiceFactory.class, "getService", Bundle.class, ServiceRegistration.class), service2);
+    
+    Hashtable<String, String> props = new Hashtable<String, String>();
+    props.put("rubbish", "smelly");
+    
+    reg = bc.registerService(new String[] {"java.lang.Runnable"}, factory, props);
+  }
+  
+  /**
+   * Make sure we clear the caches out before the next test.
+   */
+  @After
+  public void teardown()
+  {
+    BundleContextMock.clear();
+    
+    Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
+  }
+  
+  @Test
+  public void testBaseLookup() throws NamingException
+  {
+     BundleMock mock = new BundleMock("scooby.doo", new Properties());
+        
+     Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+
+     InitialContext ctx = new InitialContext();
+     
+     Context ctx2 = (Context) ctx.lookup("osgi:service");
+     
+     Runnable r = (Runnable) ctx2.lookup("java.lang.Runnable");
+     
+     assertNotNull(r);
+  }
+  
+  /**
+   * This test checks that we correctly register and deregister the url context
+   * object factory in the service registry.
+   */
+  @Test
+  public void testJNDIRegistration()
+  {
+    ServiceReference ref = bc.getServiceReference(ObjectFactory.class.getName());
+    
+    assertNotNull("The aries url context object factory was not registered", ref);
+    
+    ObjectFactory factory = (ObjectFactory) bc.getService(ref);
+    
+    assertNotNull("The aries url context object factory was null", factory);
+  }
+  
+  @Test
+  public void jndiLookupServiceNameTest() throws NamingException, SQLException
+  {
+    InitialContext ctx = new InitialContext(new Hashtable<Object, Object>());
+    
+    BundleMock mock = new BundleMock("scooby.doo", new Properties());
+    
+    Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+    
+    DataSource first = Skeleton.newMock(DataSource.class);
+    DataSource second = Skeleton.newMock(DataSource.class);
+    
+    Hashtable<String, String> properties = new Hashtable<String, String>();
+    properties.put("osgi.jndi.service.name", "jdbc/myDataSource");
+    
+    bc.registerService(DataSource.class.getName(), first, properties);
+
+    properties = new Hashtable<String, String>();
+    properties.put("osgi.jndi.service.name", "jdbc/myDataSource2");
+    
+    bc.registerService(DataSource.class.getName(), second, properties);
+    
+    DataSource s = (DataSource) ctx.lookup("osgi:service/jdbc/myDataSource");
+    
+    assertNotNull(s);
+    
+    s = (DataSource) ctx.lookup("osgi:service/javax.sql.DataSource/(osgi.jndi.service.name=jdbc/myDataSource2)");
+    
+    assertNotNull(s);
+    
+    s.isWrapperFor(DataSource.class); // don't care about the method, just need to call something.
+    
+    Skeleton.getSkeleton(second).assertCalled(new MethodCall(DataSource.class, "isWrapperFor", Class.class));
+  }
+  
+  /**
+   * This test does a simple JNDI lookup to prove that works.
+   * @throws NamingException
+   */
+  @Test
+  public void simpleJNDILookup() throws NamingException
+  {
+    System.setProperty(Context.URL_PKG_PREFIXES, "helloMatey");
+        
+    InitialContext ctx = new InitialContext(new Hashtable<Object, Object>());
+    
+    BundleMock mock = new BundleMock("scooby.doo", new Properties());
+    
+    Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+    
+    Runnable s = (Runnable) ctx.lookup("aries:services/java.lang.Runnable");
+    
+    assertNotNull("We didn't get a service back from our lookup :(", s);
+    
+    s.run();
+    
+    Skeleton.getSkeleton(service).assertCalledExactNumberOfTimes(new MethodCall(Runnable.class, "run"), 1);
+    
+    Skeleton skel = Skeleton.getSkeleton(mock.getBundleContext());
+    
+    skel.assertCalled(new MethodCall(BundleContext.class, "getServiceReferences", "java.lang.Runnable", null));
+
+    mock = new BundleMock("scooby.doo", new Properties());
+    
+    Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+
+    s = (Runnable) ctx.lookup("osgi:service/java.lang.Runnable");
+    
+    // Check we have the packages set correctly
+    
+    String packages = System.getProperty(Context.URL_PKG_PREFIXES, null);
+    
+    assertTrue(ctx.getEnvironment().containsValue(packages));
+
+    assertNotNull("We didn't get a service back from our lookup :(", s);
+
+    s.run();
+    
+    Skeleton.getSkeleton(service).assertCalledExactNumberOfTimes(new MethodCall(Runnable.class, "run"), 2);
+
+    skel = Skeleton.getSkeleton(mock.getBundleContext());
+    skel.assertCalled(new MethodCall(BundleContext.class, "getServiceReferences", "java.lang.Runnable", null));
+  }
+
+  /**
+   * This test checks that we can pass a filter in without things blowing up.
+   * Right now our mock service registry does not implement filtering, so the
+   * effect is the same as simpleJNDILookup, but we at least know it is not
+   * blowing up.
+   * 
+   * @throws NamingException
+   */
+  @Test
+  public void jndiLookupWithFilter() throws NamingException
+  {
+    BundleMock mock = new BundleMock("scooby.doo", new Properties());
+    
+    Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+
+    InitialContext ctx = new InitialContext();
+    
+    Object s = ctx.lookup("aries:services/java.lang.Runnable/(rubbish=smelly)");
+    
+    assertNotNull("We didn't get a service back from our lookup :(", s);
+    
+    service.run();
+    
+    Skeleton.getSkeleton(service).assertCalledExactNumberOfTimes(new MethodCall(Runnable.class, "run"), 1);
+
+    Skeleton.getSkeleton(mock.getBundleContext()).assertCalled(new MethodCall(BundleContext.class, "getServiceReferences", "java.lang.Runnable", "(rubbish=smelly)"));
+  }
+  
+  /**
+   * Check that we get a NameNotFoundException if we lookup after the service
+   * has been unregistered.
+   * 
+   * @throws NamingException
+   */
+  @Test(expected=NameNotFoundException.class)
+  public void testLookupWhenServiceHasBeenRemoved() throws NamingException
+  {
+    reg.unregister();
+
+    BundleMock mock = new BundleMock("scooby.doo", new Properties());
+    
+    Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+
+    InitialContext ctx = new InitialContext();
+    
+    ctx.lookup("aries:services/java.lang.Runnable");
+  }
+  
+  /**
+   * Check that we get a NameNotFoundException if we lookup something not in the
+   * registry.
+   * 
+   * @throws NamingException
+   */
+  @Test(expected=NameNotFoundException.class)
+  public void testLookupForServiceWeNeverHad() throws NamingException
+  {
+    BundleMock mock = new BundleMock("scooby.doo", new Properties());
+    
+    Thread.currentThread().setContextClassLoader(mock.getClassLoader());
+
+    InitialContext ctx = new InitialContext();
+    
+    ctx.lookup("aries:services/java.lang.Integer");
+  }
+  
+  /**
+   * This test checks that we can list the contents of the repository using the
+   * list method
+   * 
+   * @throws NamingException
+   */
+  public void listRepositoryContents() throws NamingException
+  {
+    InitialContext ctx = new InitialContext();
+    
+    NamingEnumeration<NameClassPair> serviceList = ctx.list("aries:services/java.lang.Runnable/(rubbish=smelly)");
+    
+    checkThreadRetrievedViaListMethod(serviceList);
+    
+    assertFalse("The repository contained more objects than we expected", serviceList.hasMoreElements());
+    
+    //Now add a second service
+    
+    registerService(new Thread());
+    
+    serviceList = ctx.list("aries:services/java.lang.Runnable/(rubbish=smelly)");
+    
+    checkThreadRetrievedViaListMethod(serviceList);
+    
+    checkThreadRetrievedViaListMethod(serviceList);
+    
+    assertFalse("The repository contained more objects than we expected", serviceList.hasMoreElements());
+  }
+
+  @Test
+  public void checkProxyDynamism() 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);
+    Runnable t2 = Skeleton.newMock(Runnable.class);
+    
+    // we don't want the default service
+    reg.unregister();
+    
+    ServiceRegistration reg = bc.registerService(className, t, null);
+    bc.registerService(className, t2, null);
+    
+    Runnable r = (Runnable) ctx.lookup("osgi:service/java.lang.Runnable");
+    
+    r.run();
+    
+    Skeleton.getSkeleton(t).assertCalledExactNumberOfTimes(new MethodCall(Runnable.class, "run"), 1);
+    Skeleton.getSkeleton(t2).assertNotCalled(new MethodCall(Runnable.class, "run"));
+    
+    reg.unregister();
+    
+    r.run();
+    
+    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
+  {
+    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);
+    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);
+    
+    Runnable r = (Runnable) ctx.lookup("osgi:service/java.lang.Runnable");
+    
+    r.run();
+    
+    Skeleton.getSkeleton(t).assertCalledExactNumberOfTimes(new MethodCall(Runnable.class, "run"), 1);
+    Skeleton.getSkeleton(t2).assertNotCalled(new MethodCall(Runnable.class, "run"));
+    
+    reg.unregister();
+    reg2.unregister();
+    
+    Hashtable<String, Object> props = new Hashtable<String, Object>();
+    props.put(Constants.SERVICE_RANKING, 55);
+    
+    t = Skeleton.newMock(Runnable.class);
+    t2 = Skeleton.newMock(Runnable.class);
+
+    bc.registerService(className, t, null);
+    bc.registerService(className, t2, props);
+    
+    r = (Runnable) ctx.lookup("osgi:service/java.lang.Runnable");
+    
+    r.run();
+    
+    Skeleton.getSkeleton(t).assertNotCalled(new MethodCall(Runnable.class, "run"));
+    Skeleton.getSkeleton(t2).assertCalledExactNumberOfTimes(new MethodCall(Runnable.class, "run"), 1);
+  }
+  
+  /**
+   * Check that the NamingEnumeration passed in has another element, which represents a java.lang.Thread
+   * @param serviceList
+   * @throws NamingException
+   */
+  private void checkThreadRetrievedViaListMethod(NamingEnumeration<NameClassPair> serviceList)
+      throws NamingException
+  {
+    assertTrue("The repository was empty", serviceList.hasMoreElements());
+    
+    NameClassPair ncp = serviceList.next();
+    
+    assertNotNull("We didn't get a service back from our lookup :(", ncp);
+    
+    assertNotNull("The object from the SR was null", ncp.getClassName());
+    
+    assertEquals("The service retrieved was not of the correct type", "java.lang.Thread", ncp.getClassName());
+    
+    assertEquals("aries:services/java.lang.Runnable/(rubbish=smelly)", ncp.getName().toString());
+  }
+  
+  /**
+   * This test checks that we can list the contents of the repository using the
+   * list method
+   * 
+   * @throws NamingException
+   */
+  public void listRepositoryBindings() throws NamingException
+  {
+    InitialContext ctx = new InitialContext();
+    
+    NamingEnumeration<Binding> serviceList = ctx.listBindings("aries:services/java.lang.Runnable/(rubbish=smelly)");
+    
+    Object returnedService = checkThreadRetrievedViaListBindingsMethod(serviceList);
+    
+    assertFalse("The repository contained more objects than we expected", serviceList.hasMoreElements());
+    
+    assertTrue("The returned service was not the service we expected", returnedService == service);
+    
+    //Now add a second service
+    Thread secondService = new Thread();
+    registerService(secondService);
+    
+    serviceList = ctx.listBindings("aries:services/java.lang.Runnable/(rubbish=smelly)");
+    
+    Object returnedService1 = checkThreadRetrievedViaListBindingsMethod(serviceList);
+    
+    Object returnedService2 = checkThreadRetrievedViaListBindingsMethod(serviceList);
+    
+    assertFalse("The repository contained more objects than we expected", serviceList.hasMoreElements());
+    
+    assertTrue("The services were not the ones we expected!",(returnedService1 == service || returnedService2 == service) && (returnedService1 == secondService || returnedService2 == secondService) && (returnedService1 != returnedService2));
+    
+  }
+
+  /**
+   * Check that the NamingEnumeration passed in has another element, which represents a java.lang.Thread
+   * @param serviceList
+   * @return the object in the registry
+   * @throws NamingException
+   */
+  private Object checkThreadRetrievedViaListBindingsMethod(NamingEnumeration<Binding> serviceList)
+      throws NamingException
+  {
+    assertTrue("The repository was empty", serviceList.hasMoreElements());
+    
+    Binding binding = serviceList.nextElement();
+    
+    assertNotNull("We didn't get a service back from our lookup :(", binding);
+    
+    assertNotNull("The object from the SR was null", binding.getObject());
+    
+    assertTrue("The service retrieved was not of the correct type", binding.getObject() instanceof Thread);
+    
+    assertEquals("aries:services/java.lang.Runnable/(rubbish=smelly)", binding.getName().toString());
+    
+    return binding.getObject();
+  }
+  
+}
\ No newline at end of file

Added: aries/tags/jndi-0.1-incubating/pom.xml
URL: http://svn.apache.org/viewvc/aries/tags/jndi-0.1-incubating/pom.xml?rev=1075097&view=auto
==============================================================================
--- aries/tags/jndi-0.1-incubating/pom.xml (added)
+++ aries/tags/jndi-0.1-incubating/pom.xml Sun Feb 27 18:01:00 2011
@@ -0,0 +1,90 @@
+<!--
+ 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">
+
+    <parent>
+        <groupId>org.apache.aries</groupId>
+        <artifactId>java5-parent</artifactId>
+        <version>0.1-incubating</version>
+    </parent>  
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.aries.jndi</groupId>
+    <artifactId>jndi</artifactId>
+    <name>Apache Aries JNDI</name>
+    <version>0.1-incubating</version>
+    <packaging>pom</packaging>
+
+    <description>
+        JNDI support for OSGi
+    </description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/incubator/aries/tags/jndi-0.1-incubating</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/incubator/aries/tags/jndi-0.1-incubating</developerConnection>
+        <url>http://svn.apache.org/viewvc/incubator/aries/tags/jndi-0.1-incubating</url>
+    </scm>
+    
+    <dependencyManagement>
+        <dependencies>
+            <!-- internal dependencies -->
+            <dependency>
+                <groupId>org.apache.aries.jndi</groupId>
+                <artifactId>org.apache.aries.jndi.core</artifactId>
+                <version>${version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.aries.jndi</groupId>
+                <artifactId>org.apache.aries.jndi.url</artifactId>
+                <version>${version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.aries.jndi</groupId>
+                <artifactId>org.apache.aries.jndi</artifactId>
+                <version>${version}</version>
+            </dependency>
+            <!-- external dependencies -->
+            <dependency>
+                <groupId>org.apache.aries.testsupport</groupId>
+                <artifactId>org.apache.aries.testsupport.unit</artifactId>
+                <version>0.1-incubating</version>
+            </dependency>
+            <dependency>
+            	<groupId>org.apache.aries</groupId>
+            	<artifactId>org.apache.aries.util</artifactId>
+            	<version>0.1-incubating</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+    
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <modules>
+        <module>jndi-core</module>
+        <module>jndi-url</module>
+        <module>jndi-bundle</module>
+    </modules>
+
+</project>