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>