Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Nettleton2010-06-24 14:17:31 +0000
committerBob Nettleton2010-06-24 14:17:31 +0000
commit907ad7a18fdf81ce25bacb436472dfb98adcbfa7 (patch)
tree4b60c3ae46c4598dc93ca88da7d8cb828e5e69d8
downloadorg.eclipse.gemini.naming-907ad7a18fdf81ce25bacb436472dfb98adcbfa7.tar.gz
org.eclipse.gemini.naming-907ad7a18fdf81ce25bacb436472dfb98adcbfa7.tar.xz
org.eclipse.gemini.naming-907ad7a18fdf81ce25bacb436472dfb98adcbfa7.zip
Initial Checkin for the Gemini Naming Project.
This checkin includes: the source code for Gemini Naming, the unit and integration tests for this project, as well as maven build files for the Gemini Naming Project. The code in this checkin is tracked by the following CQs: 3960 - Initial Contribution of Gemini Naming Source Code 4037 - Initial Contribution of Gemini Naming Test Source Code
-rw-r--r--framework/pom.xml69
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/Activator.java232
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/BuilderSupportedInitialContextFactory.java31
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/BuilderUtils.java244
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/CloseableContextManager.java29
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/CloseableProviderAdmin.java29
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ContextManagerImpl.java133
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ContextManagerServiceFactoryImpl.java99
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ContextWrapperImpl.java250
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/DefaultInitialContextFactory.java69
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/DefaultRuntimeInitialContextFactoryBuilder.java65
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/DirContextWrapperImpl.java158
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/FactoryManager.java61
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/InitialContextFactoryWrapper.java66
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/InvocationHandlerFactory.java43
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/NotSupportedContext.java183
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/OSGiInitialContextFactoryBuilder.java1086
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/OSGiServiceListContext.java238
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/OSGiURLContextFactory.java174
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/OSGiURLContextFactoryServiceFactory.java32
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/OSGiURLParser.java100
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ProviderAdminImpl.java85
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ReflectionUtils.java226
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ReflectiveInvokeAction.java56
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/SecurityAwareContextManagerImpl.java152
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/SecurityAwareProviderAdminImpl.java123
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/SecurityUtils.java66
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ServiceAwareContextFactory.java187
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ServiceBasedNamingEnumeration.java109
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ServiceInvocationHandler.java176
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ServiceProxyInfo.java50
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/ServiceUtils.java105
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/TraditionalInitialContextFactoryBuilder.java143
-rw-r--r--framework/src/main/java/org/eclipse/gemini/naming/TraditionalObjectFactoryBuilder.java171
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/ActivatorTestCase.java309
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/BuilderUtilsTestCase.java162
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/ContextWrapperImplTestCase.java274
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/DefaultInitialContextFactoryTestCase.java60
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/DefaultRuntimeInitialContextFactoryBuilderTestCase.java95
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/DirContextWrapperImplTestCase.java161
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/InitialContextFactoryWrapperTestCase.java137
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/NotSupportedContextTestCase.java299
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/OSGiServiceListContextTestCase.java402
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/OSGiURLContextFactoryTestCase.java153
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/OSGiURLParserTestCase.java122
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/ReflectionUtilsTestCase.java340
-rw-r--r--framework/src/test/java/org/eclipse/gemini/naming/ServiceProxyInfoTestCase.java57
-rw-r--r--integration-testing/pom.xml90
-rw-r--r--integration-testing/src/test/java/org/eclipse/gemini/naming/test/ContextAdminTestCase.java247
-rw-r--r--integration-testing/src/test/java/org/eclipse/gemini/naming/test/ContextManagerTestCase.java919
-rw-r--r--integration-testing/src/test/java/org/eclipse/gemini/naming/test/FactoryResolutionTestCase.java797
-rw-r--r--integration-testing/src/test/java/org/eclipse/gemini/naming/test/NamingTestCase.java75
-rw-r--r--lib/osgi.enterprise.jarbin0 -> 358005 bytes
-rw-r--r--pom.xml110
54 files changed, 9849 insertions, 0 deletions
diff --git a/framework/pom.xml b/framework/pom.xml
new file mode 100644
index 0000000..6bf440e
--- /dev/null
+++ b/framework/pom.xml
@@ -0,0 +1,69 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.eclipse.gemini.naming</groupId>
+ <artifactId>org.eclipse.gemini.naming.impl.bundle-Incubation</artifactId>
+ <packaging>bundle</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>Gemini Naming Implementation Bundle</name>
+ <url>http://maven.apache.org</url>
+
+ <parent>
+ <groupId>org.eclipse.gemini.naming</groupId>
+ <artifactId>org.eclipse.gemini.naming</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.osgi</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>${equinox.version}</version>
+ <type>jar</type>
+ </dependency>
+
+
+
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <!--
+ this is the BND plugin which generates the actual OSGi bundle for
+ this project. You can find the documentation for this plugin at
+ http://is.gd/hL7p
+ -->
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Include-Resource>
+ {maven-resources}
+ </Include-Resource>
+ <obrRepository>NONE</obrRepository>
+ <Bundle-Name>
+ org.eclipse.gemini.naming.framework (Incubation)
+ </Bundle-Name>
+ <Bundle-SymbolicName>
+ org.eclipse.gemini.naming.framework
+ </Bundle-SymbolicName>
+ <Bundle-Vendor>Oracle</Bundle-Vendor>
+ <Bundle-Version>1.0</Bundle-Version>
+ <Bundle-ManifestVersion>2</Bundle-ManifestVersion>
+ <Bundle-Activator>org.eclipse.gemini.naming.Activator</Bundle-Activator>
+ <Bundle-Description>
+ Gemini Naming framework bundle (Incubation)
+ </Bundle-Description>
+ <Bundle-Category>jndi</Bundle-Category>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+
+
+</project>
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/Activator.java b/framework/src/main/java/org/eclipse/gemini/naming/Activator.java
new file mode 100644
index 0000000..7e5b243
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/Activator.java
@@ -0,0 +1,232 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactoryBuilder;
+import javax.naming.spi.NamingManager;
+import javax.naming.spi.ObjectFactory;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.jndi.JNDIConstants;
+import org.osgi.service.jndi.JNDIContextManager;
+import org.osgi.service.jndi.JNDIProviderAdmin;
+
+/**
+ * Activator implementation for the Gemini Naming Bundle.
+ *
+ * This activator's main purpose is to register the JNDI Builder singleton
+ * implementations that allow the Factory Manager to override the default JNDI
+ * framework.
+ *
+ *
+ */
+public class Activator implements BundleActivator {
+
+ private static final String OSGI_URL_SCHEME = "osgi";
+
+ private static Logger logger = Logger.getLogger(Activator.class.getName());
+
+ private BundleContext m_bundleContext = null;
+ private final List m_listOfServiceRegistrations = new LinkedList();
+
+ private CloseableProviderAdmin m_providerAdminService;
+ private ContextManagerServiceFactoryImpl m_contextManagerServiceFactory;
+
+ /*
+ * Create the Factory Manager's builder implementation, and register it with
+ * the JNDI NamingManager.
+ *
+ * @see
+ * org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext
+ * )
+ */
+ public void start(BundleContext context) throws Exception {
+ logger.info("Initializing Gemini Naming Factory Manager Bundle");
+
+ m_bundleContext = context;
+
+ // register static singletons with the JNDI framework
+ logger.info("Installing Static Singletons");
+ registerInitialContextFactoryBuilderSingleton();
+ registerObjectFactoryBuilderSingleton();
+
+ logger.info("Registering URL Context Factory for 'osgi' URL scheme");
+ registerOSGiURLContextFactory();
+
+ logger.info("Registering Default Runtime Builder for JRE-provided factories");
+ registerDefaultRuntimeBuilder();
+
+ logger.info("Registering ContextManager service");
+ // register the JNDIContextManager service once all Factory
+ // Manager initialization is complete
+ registerContextManager();
+
+ logger.info("Registering ProviderAdmin service");
+ // register the JNDIProviderAdmin interface, used by OSGi-aware
+ // context implementations to resolve JNDI references
+ registerProviderAdmin();
+ }
+
+
+ /*
+ * Allow the Builder implementation to clean up any
+ * ServiceListener/ServiceTracker instances.
+ *
+ * @see
+ * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ logger.info("Shutting down Gemini Naming Factory Manager Bundle");
+
+ // close all known Contexts associated with the JNDIContextManager service
+ m_contextManagerServiceFactory.closeAll();
+
+ // close the JNDIProviderAdmin service
+ m_providerAdminService.close();
+
+ // unregister all the JNDI services registered by this Activator
+ Iterator iterator = m_listOfServiceRegistrations.iterator();
+ while(iterator.hasNext()) {
+ ServiceRegistration serviceRegistration =
+ (ServiceRegistration)iterator.next();
+ serviceRegistration.unregister();
+ }
+ }
+
+
+ /**
+ * Registers the InitialContextFactoryBuilder static singleton
+ * @throws NamingException on any error that occurs during the setting
+ * of the builder.
+ */
+ private static void registerInitialContextFactoryBuilderSingleton() throws NamingException {
+ try {
+ NamingManager.setInitialContextFactoryBuilder(new TraditionalInitialContextFactoryBuilder());
+ }
+ catch (IllegalStateException illegalStateException) {
+ logger.log(Level.SEVERE,
+ "Gemini Naming Implementation cannot set the InitialContextFactoryBuilder - another builder was already installed",
+ illegalStateException);
+ NamingException namingException =
+ new NamingException("Error occurred while attempting to set the IntialContextFactoryBuilder.");
+ namingException.setRootCause(illegalStateException);
+ }
+ catch(SecurityException securityException) {
+ logger.log(Level.SEVERE,
+ "Gemini Naming Implementation did not have the proper security permissions to install the InitialContextFactoryBuilder",
+ securityException);
+ NamingException namingException =
+ new NamingException("Error occurred while attempting to set the IntialContextFactoryBuilder.");
+ namingException.setRootCause(securityException);
+ }
+ }
+
+
+ /**
+ * Registers the ObjectFactoryBuilder static singleton
+ * @throws NamingException on any error that occurs during the setting
+ * of the builder.
+ */
+ private static void registerObjectFactoryBuilderSingleton() throws NamingException {
+ try {
+ NamingManager.setObjectFactoryBuilder(new TraditionalObjectFactoryBuilder());
+ }
+ catch (IllegalStateException illegalStateException) {
+ logger.log(Level.SEVERE,
+ "Gemini Naming Implementation cannot set the ObjectFactoryBuilder - another builder was already installed",
+ illegalStateException);
+ NamingException namingException =
+ new NamingException("Error occurred while attempting to set the ObjectFactoryBuilder.");
+ namingException.setRootCause(illegalStateException);
+ }
+ catch(SecurityException securityException) {
+ logger.log(Level.SEVERE,
+ "Gemini Naming Implementation did not have the proper security permissions to install the ObjectFactoryBuilder",
+ securityException);
+ NamingException namingException =
+ new NamingException("Error occurred while attempting to set the ObjectFactoryBuilder.");
+ namingException.setRootCause(securityException);
+ }
+ }
+
+
+
+
+ /**
+ * Registers the OSGi URL Context Factory.
+ *
+ */
+ private void registerOSGiURLContextFactory() {
+ Hashtable serviceProperties = new Hashtable();
+ serviceProperties.put(JNDIConstants.JNDI_URLSCHEME, OSGI_URL_SCHEME);
+
+ ServiceRegistration serviceRegistration =
+ m_bundleContext.registerService(ObjectFactory.class.getName(),
+ new OSGiURLContextFactoryServiceFactory(),
+ serviceProperties);
+ m_listOfServiceRegistrations.add(serviceRegistration);
+ }
+
+
+ /**
+ * Registers the InitialContextFactoryBuilder implementation that
+ * is responsible for loading the JDK-defined providers that must be
+ * loaded from the boot classpath.
+ *
+ */
+ private void registerDefaultRuntimeBuilder() {
+ ServiceRegistration serviceRegistration =
+ m_bundleContext.registerService(InitialContextFactoryBuilder.class.getName(),
+ new DefaultRuntimeInitialContextFactoryBuilder(),
+ null);
+ m_listOfServiceRegistrations.add(serviceRegistration);
+ }
+
+
+ private void registerContextManager() {
+ m_contextManagerServiceFactory =
+ new ContextManagerServiceFactoryImpl(m_bundleContext);
+ ServiceRegistration serviceRegistration =
+ m_bundleContext.registerService(JNDIContextManager.class.getName(),
+ m_contextManagerServiceFactory,
+ null);
+ m_listOfServiceRegistrations.add(serviceRegistration);
+ }
+
+
+ private void registerProviderAdmin() {
+ m_providerAdminService =
+ new SecurityAwareProviderAdminImpl(new ProviderAdminImpl(m_bundleContext));
+
+
+ ServiceRegistration serviceRegistration =
+ m_bundleContext.registerService(JNDIProviderAdmin.class.getName(),
+ m_providerAdminService,
+ null);
+ m_listOfServiceRegistrations.add(serviceRegistration);
+ }
+
+} \ No newline at end of file
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/BuilderSupportedInitialContextFactory.java b/framework/src/main/java/org/eclipse/gemini/naming/BuilderSupportedInitialContextFactory.java
new file mode 100644
index 0000000..ce2e146
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/BuilderSupportedInitialContextFactory.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+
+public interface BuilderSupportedInitialContextFactory extends InitialContextFactory {
+
+ /**
+ * Returns the InitialContextFactoryBuilder service used to
+ * create this InitialContextFactory.
+ *
+ * @return the InitialContextFactoryBuilder that was used to
+ * create this InitialContextFactory.
+ */
+ public InitialContextFactoryBuilder getBuilder();
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/BuilderUtils.java b/framework/src/main/java/org/eclipse/gemini/naming/BuilderUtils.java
new file mode 100644
index 0000000..40ae2c6
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/BuilderUtils.java
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.security.PrivilegedExceptionAction;
+import java.util.Hashtable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+import org.osgi.service.jndi.JNDIConstants;
+
+/**
+ * Utility methods for the "traditional" JNDI builder implementations.
+ *
+ *
+ * @version $Revision$
+ */
+class BuilderUtils {
+
+ private static Logger logger = Logger.getLogger(BuilderUtils.class.getName());
+
+ /* private constructor, static utility class */
+ private BuilderUtils() {}
+
+ /**
+ * Array of strategies to use, in priority order, when
+ * attempting to find the caller's BundleContext.
+ */
+ private static final GetBundleContextStrategy[] getBundleContextStrategies =
+ { new EnvironmentPropertyStrategyImpl(),
+ new ThreadContextStrategyImpl(),
+ new CallStackStrategyImpl() };
+
+
+ /**
+ * This utility method implements the process for obtaining the
+ * JNDI client's BundleContext. This method should only be used within
+ * the "traditional" method of JNDI support.
+ *
+ * This method will try the following methods to obtain the BundleContext:
+ * 1. check for the "osgi.service.jndi.bundleContext" environment property
+ * 2. check the thread context ClassLoader to see if it supports BundleReference. If so, it uses
+ * this ClassLoader to obtain the caller's BundleContext.
+ * 3. checks the current call stack to find the code that is invoking the naming function. The BundleContext
+ * that is associated with this code is returned.
+ *
+ * @param environment the JNDI environment
+ * @param namingClassType the class name of the type to be used to walk the call stack. Typically,
+ * this value will be one of the following values:
+ * "javax.naming.InitialContext" - to detect Context creation
+ * "javax.naming.spi.NamingManager" - to detect Object resolution
+ * "javax.naming.spi.DirectoryManager" - to detect Object resolution for directories
+ *
+ * @return the BundleContext associated with the JNDI client, or
+ * null if no BundleContext could be found.
+ */
+ static BundleContext getBundleContext(Hashtable environment, String namingClassType) {
+ // iterate over the existing strategies to attempt to find a BundleContext
+ // for the calling Bundle
+ for(int i = 0; i < getBundleContextStrategies.length; i++) {
+ BundleContext clientBundleContext =
+ getBundleContextStrategies[i].getBundleContext(environment, namingClassType);
+ if(clientBundleContext != null) {
+ return clientBundleContext;
+ }
+ }
+
+ // if a BundleContext isn't found at this point, return null
+ return null;
+ }
+
+
+
+
+ /**
+ * Internal interface used to abstract the process of obtaining
+ * the caller's BundleContext.
+ *
+ */
+ private interface GetBundleContextStrategy {
+ /**
+ * Obtain the caller's BundleContext.
+ *
+ * @param environment the JNDI environment properties
+ * @param namingClassType the name of the javax.naming class to use when
+ * searching for the calling Bundle.
+ * @return the caller's BundleContext, or
+ * null if none found.
+ */
+ public BundleContext getBundleContext(Hashtable environment, String namingClassType);
+ }
+
+ /**
+ * Strategy implementation that attempts to find the caller's
+ * BundleContext in the JNDI environment.
+ *
+ */
+ private static class EnvironmentPropertyStrategyImpl implements GetBundleContextStrategy {
+ public BundleContext getBundleContext(Hashtable environment, String namingClassType) {
+ if((environment != null) && (environment.containsKey(JNDIConstants.BUNDLE_CONTEXT))) {
+ Object result =
+ environment.get(JNDIConstants.BUNDLE_CONTEXT);
+ if(result instanceof BundleContext) {
+ return (BundleContext)result;
+ }
+ }
+
+ return null;
+ }
+ }
+
+
+ /**
+ * Strategy implementation that attempts to find the
+ * caller's BundleContext on the ThreadContext ClassLoader.
+ *
+ */
+ private static class ThreadContextStrategyImpl implements GetBundleContextStrategy {
+ public BundleContext getBundleContext(Hashtable environment, String namingClassType) {
+ ClassLoader threadContextClassloader = null;
+ try {
+ // this code must run in a doPrivileged() block
+ threadContextClassloader = (ClassLoader)SecurityUtils.invokePrivilegedAction(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+ });
+ } catch (Exception e) {
+ logger.log(Level.FINE, "Exception occurred while trying to obtain the ThreadContextClassloader.", e);
+ }
+
+ if ((threadContextClassloader != null)
+ && (threadContextClassloader instanceof BundleReference)) {
+ BundleContext result = getBundleContextFromClassLoader(threadContextClassloader);
+ if(result != null) {
+ return result;
+ }
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * Strategy implementation that attempts to find the caller's
+ * BundleContext on the call stack.
+ *
+ */
+ private static class CallStackStrategyImpl implements GetBundleContextStrategy {
+ public BundleContext getBundleContext(Hashtable environment, String namingClassType) {
+ Class[] callStack = null;
+ try {
+ // creation of SecurityManager must take place in a doPrivileged() block,
+ // since JNDI clients should not have to include this permission in
+ // order to use JNDI services.
+ callStack = (Class[])SecurityUtils.invokePrivilegedAction(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ return new CallStackSecurityManager().getClientCallStack();
+ }
+
+ });
+ } catch (Exception e) {
+ logger.log(Level.FINE, "Exception occurred while attempting to traverse client call stack to find caller's BundleContext.",
+ e);
+ }
+
+
+
+ int indexOfConstructor = -1;
+ for(int i = 0; i < callStack.length; i++) {
+ if(callStack[i].getName().equals(namingClassType)) {
+ indexOfConstructor = i;
+ }
+ }
+
+ // the next stack frame should include the caller of the InitialContext constructor
+ if ((indexOfConstructor >= 0)
+ && ((indexOfConstructor + 1) < callStack.length)) {
+ final Class clientClass = callStack[indexOfConstructor + 1];
+ ClassLoader clientClassLoader = null;
+ try {
+ clientClassLoader =
+ (ClassLoader)SecurityUtils.invokePrivilegedAction(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ return clientClass.getClassLoader();
+ }
+ });
+ } catch (Exception e) {
+ logger.log(Level.FINE, "Exception occurred while trying to obtain the client classloader.",
+ e);
+ }
+
+ if(clientClassLoader instanceof BundleReference) {
+ return getBundleContextFromClassLoader(clientClassLoader);
+ }
+ }
+
+ return null;
+ }
+
+ private static class CallStackSecurityManager extends SecurityManager {
+ public Class[] getClientCallStack() {
+ return getClassContext();
+ }
+ }
+ }
+
+
+ /**
+ * Attempts to obtain the client's BundleContext from the
+ * ClassLoader specified in the method call.
+ *
+ * If the ClassLoader supports BundleReference, this loader
+ * represents a client bundle making a request for an OSGi service.
+ *
+ * @param classLoader
+ * @return BundleContext associated with this ClassLoader, or
+ * null if no BundleContext was associated with this ClassLoaer
+ */
+ private static BundleContext getBundleContextFromClassLoader(ClassLoader classLoader) {
+ BundleReference bundleRef = (BundleReference) classLoader;
+ if (bundleRef.getBundle() != null) {
+ return bundleRef.getBundle().getBundleContext();
+ }
+
+ return null;
+ }
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/CloseableContextManager.java b/framework/src/main/java/org/eclipse/gemini/naming/CloseableContextManager.java
new file mode 100644
index 0000000..800e49e
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/CloseableContextManager.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import org.osgi.service.jndi.JNDIContextManager;
+
+/**
+ * Closeable extension of the JNDIContextManager interface, to be
+ * used internally by the Gemini Naming implementation.
+ *
+ *
+ * @version $Revision$
+ */
+interface CloseableContextManager extends JNDIContextManager {
+ public void close();
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/CloseableProviderAdmin.java b/framework/src/main/java/org/eclipse/gemini/naming/CloseableProviderAdmin.java
new file mode 100644
index 0000000..ab61d02
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/CloseableProviderAdmin.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import org.osgi.service.jndi.JNDIProviderAdmin;
+
+/**
+ * Closeable extension of the JNDIProviderAdmin interface, to be
+ * used internally by the Gemini Naming implementation.
+ *
+ *
+ * @version $Revision$
+ */
+interface CloseableProviderAdmin extends JNDIProviderAdmin {
+ public void close();
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ContextManagerImpl.java b/framework/src/main/java/org/eclipse/gemini/naming/ContextManagerImpl.java
new file mode 100644
index 0000000..4ee27b5
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ContextManagerImpl.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.directory.DirContext;
+import javax.naming.spi.InitialContextFactory;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+class ContextManagerImpl implements CloseableContextManager {
+
+ private static final Logger logger = Logger.getLogger(ContextManagerImpl.class.getName());
+
+ private final OSGiInitialContextFactoryBuilder m_builder;
+
+ /* list of Context implementations */
+ private final List m_listOfContexts =
+ Collections.synchronizedList(new LinkedList());
+
+ ContextManagerImpl(Bundle callingBundle, BundleContext implBundleContext) {
+ // create a new builder for each client bundle
+ // since the JNDI services (factories) should be accessed
+ // by the JNDIContextManager service on behalf of the calling bundle
+ m_builder = new OSGiInitialContextFactoryBuilder(callingBundle.getBundleContext(), implBundleContext);
+ }
+
+
+ public Context newInitialContext() throws NamingException {
+ synchronized (m_builder) {
+ final Context initialContext = createNewInitialContext(new Hashtable());
+ m_listOfContexts.add(initialContext);
+ return initialContext;
+ }
+ }
+
+ public Context newInitialContext(Map environment)
+ throws NamingException {
+ synchronized (m_builder) {
+ final Context initialContext = createNewInitialContext(environment);
+ m_listOfContexts.add(initialContext);
+ return initialContext;
+ }
+ }
+
+ public DirContext newInitialDirContext() throws NamingException {
+ synchronized (m_builder) {
+ Context contextToReturn = createNewInitialContext(new Hashtable());
+ if (contextToReturn instanceof DirContext) {
+ m_listOfContexts.add(contextToReturn);
+ return (DirContext) contextToReturn;
+ }
+ }
+
+ throw new NoInitialContextException("DirContext could not be created. The matching InitialContextFactory did not create a matching type.");
+ }
+
+ public DirContext newInitialDirContext(Map environment) throws NamingException {
+ synchronized (m_builder) {
+ Context context = createNewInitialContext(environment);
+ if (context instanceof DirContext) {
+ m_listOfContexts.add(context);
+ return (DirContext) context;
+ }
+ }
+
+ throw new NoInitialContextException("DirContext could not be created. The matching InitialContextFactory did not create a matching type.");
+ }
+
+ /**
+ * Closes all the known context implementations that have
+ * been provided by this service.
+ */
+ public void close() {
+ // close known Context implementations
+ synchronized (m_listOfContexts) {
+ Iterator iterator = m_listOfContexts.iterator();
+ // call close() on all known contexts
+ while (iterator.hasNext()) {
+ Context context = (Context) iterator.next();
+ try {
+ context.close();
+ }
+ catch (NamingException e) {
+ logger.log(Level.INFO,
+ "NamingException occurred while trying to close an existing JNDI Context",
+ e);
+ }
+ }
+ }
+
+ m_listOfContexts.clear();
+
+ synchronized (m_builder) {
+ // close the Builder implementation
+ m_builder.close();
+ }
+ }
+
+ private Context createNewInitialContext(final Map environment)
+ throws NamingException {
+ final Hashtable jndiEnvironment = new Hashtable(environment);
+ InitialContextFactory factory =
+ m_builder.createInitialContextFactory(jndiEnvironment);
+ return factory.getInitialContext(jndiEnvironment);
+ }
+
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ContextManagerServiceFactoryImpl.java b/framework/src/main/java/org/eclipse/gemini/naming/ContextManagerServiceFactoryImpl.java
new file mode 100644
index 0000000..34b6813
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ContextManagerServiceFactoryImpl.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.SynchronousBundleListener;
+
+class ContextManagerServiceFactoryImpl implements ServiceFactory {
+
+ // map of bundles to context managers (CloseableContextManager)
+ private Map m_mapOfManagers =
+ Collections.synchronizedMap(new HashMap());
+
+ /* BundleContext for the Gemini Naming Implementation Bundle */
+ private final BundleContext m_implBundleContext;
+
+ ContextManagerServiceFactoryImpl(BundleContext implBundleContext) {
+ m_implBundleContext = implBundleContext;
+ }
+
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
+ CloseableContextManager contextManager =
+ createContextManager(bundle, m_implBundleContext);
+ m_mapOfManagers.put(bundle, contextManager);
+ bundle.getBundleContext().addBundleListener(new ContextManagerBundleListener());
+ return contextManager;
+ }
+
+
+
+ public void ungetService(Bundle bundle, ServiceRegistration registration, Object service) {
+ closeContextManager(bundle);
+ }
+
+ protected void closeAll() {
+ synchronized(m_mapOfManagers) {
+ Iterator iterator = m_mapOfManagers.keySet().iterator();
+ while(iterator.hasNext()) {
+ Bundle bundleKey = (Bundle)iterator.next();
+ closeContextManager(bundleKey);
+ }
+ }
+ }
+
+ private void closeContextManager(Bundle bundle) {
+ CloseableContextManager contextManager =
+ (CloseableContextManager)m_mapOfManagers.get(bundle);
+ if(contextManager != null) {
+ contextManager.close();
+ m_mapOfManagers.remove(bundle);
+ }
+ }
+
+
+ private class ContextManagerBundleListener implements SynchronousBundleListener {
+ public void bundleChanged(BundleEvent event) {
+ if(event.getType() == BundleEvent.STOPPED) {
+ if(m_mapOfManagers.containsKey(event.getBundle())) {
+ closeContextManager(event.getBundle());
+ }
+ }
+ }
+
+ }
+
+
+ /**
+ * Convenience factory method for creating a CloseableContextManager
+ * instance.
+ * @param bundle the Bundle associated with this context manager
+ * @return a CloseableContextManager that will handle requests for
+ * the given Bundle.
+ */
+ private static CloseableContextManager createContextManager(Bundle bundle, BundleContext implBundleContext) {
+ return new SecurityAwareContextManagerImpl(new ContextManagerImpl(bundle, implBundleContext));
+ }
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ContextWrapperImpl.java b/framework/src/main/java/org/eclipse/gemini/naming/ContextWrapperImpl.java
new file mode 100644
index 0000000..af2683e
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ContextWrapperImpl.java
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import javax.naming.*;
+import javax.naming.spi.ObjectFactory;
+
+import java.security.PrivilegedExceptionAction;
+import java.util.Hashtable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A Decorated Context class that will allow the Gemini Naming Framework to handle
+ * requests for URL context factory lookups.
+ *
+ */
+class ContextWrapperImpl implements Context {
+
+ private static Logger logger = Logger.getLogger(ContextWrapperImpl.class.getName());
+
+ private final Context m_context;
+ private final FactoryManager m_factoryManager;
+
+ public ContextWrapperImpl(Context context, FactoryManager factoryManager) {
+ m_context = context;
+ m_factoryManager = factoryManager;
+ }
+
+
+ public Object lookup(Name name) throws NamingException {
+ return m_context.lookup(name);
+ }
+
+ public Object lookup(String name) throws NamingException {
+ if (isURLRequest(name)) {
+ // attempt to find a URL Context Factory to satisfy this lookup
+ // request
+ ObjectFactory objectFactory = null;
+ try {
+ // obtain URL Context Factory in a doPrivilieged() block
+ objectFactory = (ObjectFactory)SecurityUtils.invokePrivilegedAction(new GetObjectFactoryAction(m_factoryManager, name));
+ } catch (Exception e) {
+ logger.log(Level.FINE,
+ "Exception occurred while trying to obtain a reference to a URL Context Factory.",
+ e);
+ }
+
+ if (objectFactory == null) {
+ throw new NameNotFoundException(
+ "Name: "
+ + name
+ + " was not found. A URL Context Factory was not registered to handle "
+ + "this URL scheme");
+ }
+
+ try {
+ Context context =
+ (Context) objectFactory.getObjectInstance(null, null,
+ null, m_context.getEnvironment());
+ if (context != null) {
+ return context.lookup(name);
+ }
+ else {
+ throw new NamingException("Name = " + name
+ + "was not found using the URL Context factory.");
+ }
+ }
+ catch (Exception e) {
+ if (e instanceof NamingException) {
+ // re-throw naming exceptions
+ throw (NamingException) e;
+ }
+
+ NamingException namingException =
+ new NameNotFoundException("Exception occurred during URL Context Factory Resolution for name = "
+ + name);
+ namingException.initCause(e);
+ throw namingException;
+ }
+ }
+ else {
+ // treat this lookup as a normal lookup
+ return m_context.lookup(name);
+ }
+
+ }
+
+
+
+
+ public void bind(Name name, Object obj) throws NamingException {
+ m_context.bind(name, obj);
+ }
+
+ public void bind(String name, Object obj) throws NamingException {
+ m_context.bind(name, obj);
+ }
+
+ public void rebind(Name name, Object obj) throws NamingException {
+ m_context.rebind(name, obj);
+ }
+
+ public void rebind(String name, Object obj) throws NamingException {
+ m_context.rebind(name, obj);
+ }
+
+ public void unbind(Name name) throws NamingException {
+ m_context.unbind(name);
+ }
+
+ public void unbind(String name) throws NamingException {
+ m_context.unbind(name);
+ }
+
+ public void rename(Name oldName, Name newName) throws NamingException {
+ m_context.rename(oldName, newName);
+ }
+
+ public void rename(String oldName, String newName) throws NamingException {
+ m_context.rename(oldName, newName);
+ }
+
+ public NamingEnumeration list(Name name) throws NamingException {
+ return m_context.list(name);
+ }
+
+ public NamingEnumeration list(String name) throws NamingException {
+ return m_context.list(name);
+ }
+
+ public NamingEnumeration listBindings(Name name) throws NamingException {
+ return m_context.listBindings(name);
+ }
+
+ public NamingEnumeration listBindings(String name) throws NamingException {
+ return m_context.listBindings(name);
+ }
+
+ public void destroySubcontext(Name name) throws NamingException {
+ m_context.destroySubcontext(name);
+ }
+
+ public void destroySubcontext(String name) throws NamingException {
+ m_context.destroySubcontext(name);
+ }
+
+ public Context createSubcontext(Name name) throws NamingException {
+ return m_context.createSubcontext(name);
+ }
+
+ public Context createSubcontext(String name) throws NamingException {
+ return m_context.createSubcontext(name);
+ }
+
+ public Object lookupLink(Name name) throws NamingException {
+ return m_context.lookupLink(name);
+ }
+
+ public Object lookupLink(String name) throws NamingException {
+ return m_context.lookupLink(name);
+ }
+
+ public NameParser getNameParser(Name name) throws NamingException {
+ return m_context.getNameParser(name);
+ }
+
+ public NameParser getNameParser(String name) throws NamingException {
+ return m_context.getNameParser(name);
+ }
+
+ public Name composeName(Name name, Name prefix) throws NamingException {
+ return m_context.composeName(name, prefix);
+ }
+
+ public String composeName(String name, String prefix)
+ throws NamingException {
+ return m_context.composeName(name, prefix);
+ }
+
+ public Object addToEnvironment(String propName, Object propVal)
+ throws NamingException {
+ return m_context.addToEnvironment(propName, propVal);
+ }
+
+ public Object removeFromEnvironment(String propName) throws NamingException {
+ return m_context.removeFromEnvironment(propName);
+ }
+
+ public Hashtable getEnvironment() throws NamingException {
+ return m_context.getEnvironment();
+ }
+
+ public void close() throws NamingException {
+ m_context.close();
+ }
+
+ public String getNameInNamespace() throws NamingException {
+ return m_context.getNameInNamespace();
+ }
+
+ private static boolean isURLRequest(String name) {
+ int indexOfColon = name.indexOf(":");
+ return (indexOfColon != -1);
+ }
+
+ private static String getScheme(String name) {
+ int indexOfColon = name.indexOf(":");
+ if (indexOfColon != -1) {
+ return name.substring(0, indexOfColon);
+ }
+
+ return null;
+ }
+
+ private static class GetObjectFactoryAction implements PrivilegedExceptionAction {
+ private final FactoryManager m_factoryManager;
+ private final String m_name;
+
+ GetObjectFactoryAction(FactoryManager factoryManager, String name) {
+ m_factoryManager = factoryManager;
+ m_name = name;
+ }
+
+ public Object run() throws Exception {
+ return obtainObjectFactory(m_name);
+ }
+
+ private ObjectFactory obtainObjectFactory(String name) {
+ ObjectFactory objectFactory;
+ synchronized (m_factoryManager) {
+ objectFactory = m_factoryManager.getURLContextFactory(getScheme(name));
+ }
+ return objectFactory;
+ }
+ }
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/DefaultInitialContextFactory.java b/framework/src/main/java/org/eclipse/gemini/naming/DefaultInitialContextFactory.java
new file mode 100644
index 0000000..47ff735
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/DefaultInitialContextFactory.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.spi.InitialContextFactory;
+
+/**
+ * This class implements a default InitialContextFactory.
+ *
+ * The Context implementation created by this factory is a no-op
+ * implementation of javax.naming.Context.
+ *
+ *
+ * @version $Revision$
+ */
+class DefaultInitialContextFactory implements InitialContextFactory {
+
+ public Context getInitialContext(Hashtable environment) throws NamingException {
+ return (Context) Proxy.newProxyInstance(this.getClass().getClassLoader(),
+ new Class[] {Context.class},
+ new DefaultContextInvocationHandler());
+ }
+
+
+ /**
+ * InvocationHandler for the default Context. Except for close() and getEnvironment(),
+ * all Context method invocations should throw a NoInitialContextFactory exception.
+ *
+ *
+ * @version $Revision$
+ */
+ private static class DefaultContextInvocationHandler implements InvocationHandler {
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ // special case for close() invocation
+ if(method.getName().equals("close")) {
+ return null;
+ }
+
+ // special case for getEnvironment(), return empty Hashtable
+ if(method.getName().equals("getEnvironment")) {
+ return new Hashtable();
+ }
+
+ throw new NoInitialContextException("No InitialContext service available to handle this request");
+ }
+ }
+} \ No newline at end of file
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/DefaultRuntimeInitialContextFactoryBuilder.java b/framework/src/main/java/org/eclipse/gemini/naming/DefaultRuntimeInitialContextFactoryBuilder.java
new file mode 100644
index 0000000..b51e4c8
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/DefaultRuntimeInitialContextFactoryBuilder.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Hashtable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+
+/**
+ * An InitialContextFactoryBuilder that is responsible for providing access to
+ * the JNDI implementations made available by the JDK/JRE. These implementations
+ * include LDAP, DNS, RMI, etc.
+ *
+ * This Builder interface must be registered as a service by the JNDI
+ * implementation.
+ *
+ * @version $Revision$
+ */
+class DefaultRuntimeInitialContextFactoryBuilder implements
+ InitialContextFactoryBuilder {
+
+ private static final Logger logger =
+ Logger.getLogger(DefaultRuntimeInitialContextFactoryBuilder.class.getName());
+
+ public InitialContextFactory createInitialContextFactory(Hashtable environment) throws NamingException {
+
+ if (environment.get(Context.INITIAL_CONTEXT_FACTORY) != null) {
+ final String initialContextFactoryName =
+ (String) environment.get(Context.INITIAL_CONTEXT_FACTORY);
+
+ // attempt to load this provider from the system classpath
+ try {
+ Class clazz =
+ getClass().getClassLoader().loadClass(initialContextFactoryName);
+ return (InitialContextFactory) clazz.newInstance();
+ }
+ catch (Exception e) {
+ logger.log(Level.FINEST,
+ "Error while trying to load system-level JNDI provider",
+ e);
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/DirContextWrapperImpl.java b/framework/src/main/java/org/eclipse/gemini/naming/DirContextWrapperImpl.java
new file mode 100644
index 0000000..1c124e3
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/DirContextWrapperImpl.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+
+class DirContextWrapperImpl extends ContextWrapperImpl implements DirContext {
+
+ private final DirContext m_dirContext;
+
+ DirContextWrapperImpl(DirContext dirContext, FactoryManager factoryManager) {
+ super(dirContext, factoryManager);
+ m_dirContext = dirContext;
+ }
+
+ public void bind(String name, Object obj, Attributes attributes)
+ throws NamingException {
+ m_dirContext.bind(name, obj, attributes);
+
+ }
+
+ public void bind(Name name, Object obj, Attributes attributes)
+ throws NamingException {
+ m_dirContext.bind(name, obj, attributes);
+ }
+
+ public DirContext createSubcontext(String name, Attributes attributes)
+ throws NamingException {
+ return m_dirContext.createSubcontext(name, attributes);
+ }
+
+ public DirContext createSubcontext(Name name, Attributes attributes)
+ throws NamingException {
+ return m_dirContext.createSubcontext(name, attributes);
+ }
+
+ public Attributes getAttributes(String name) throws NamingException {
+ return m_dirContext.getAttributes(name);
+ }
+
+ public Attributes getAttributes(Name name) throws NamingException {
+ return m_dirContext.getAttributes(name);
+ }
+
+ public Attributes getAttributes(String name, String[] values)
+ throws NamingException {
+ return m_dirContext.getAttributes(name, values);
+ }
+
+ public Attributes getAttributes(Name name, String[] values)
+ throws NamingException {
+ return m_dirContext.getAttributes(name, values);
+ }
+
+ public DirContext getSchema(String name) throws NamingException {
+ return m_dirContext.getSchema(name);
+ }
+
+ public DirContext getSchema(Name name) throws NamingException {
+ return m_dirContext.getSchema(name);
+ }
+
+ public DirContext getSchemaClassDefinition(String name)
+ throws NamingException {
+ return m_dirContext.getSchemaClassDefinition(name);
+ }
+
+ public DirContext getSchemaClassDefinition(Name name)
+ throws NamingException {
+ return m_dirContext.getSchemaClassDefinition(name);
+ }
+
+ public void modifyAttributes(String name, ModificationItem[] values)
+ throws NamingException {
+ m_dirContext.modifyAttributes(name, values);
+ }
+
+ public void modifyAttributes(Name name, ModificationItem[] values)
+ throws NamingException {
+ m_dirContext.modifyAttributes(name, values);
+ }
+
+ public void modifyAttributes(String name, int index, Attributes attributes)
+ throws NamingException {
+ m_dirContext.modifyAttributes(name, index, attributes);
+ }
+
+ public void modifyAttributes(Name name, int index, Attributes attributes)
+ throws NamingException {
+ m_dirContext.modifyAttributes(name, index, attributes);
+ }
+
+ public void rebind(String name, Object obj, Attributes attributes)
+ throws NamingException {
+ m_dirContext.rebind(name, obj, attributes);
+ }
+
+ public void rebind(Name name, Object obj, Attributes attributes)
+ throws NamingException {
+ m_dirContext.rebind(name, obj, attributes);
+ }
+
+ public NamingEnumeration search(String name, Attributes attributes)
+ throws NamingException {
+ return m_dirContext.search(name, attributes);
+ }
+
+ public NamingEnumeration search(Name name, Attributes attributes)
+ throws NamingException {
+ return m_dirContext.search(name, attributes);
+ }
+
+ public NamingEnumeration search(String name, String filter, SearchControls searchControls) throws NamingException {
+ return m_dirContext.search(name, filter, searchControls);
+ }
+
+ public NamingEnumeration search(String name, Attributes attributes, String[] attributesToReturn)
+ throws NamingException {
+ return m_dirContext.search(name, attributes, attributesToReturn);
+ }
+
+ public NamingEnumeration search(Name name, String filter, SearchControls searchControls)
+ throws NamingException {
+ return m_dirContext.search(name, filter, searchControls);
+ }
+
+ public NamingEnumeration search(Name name, Attributes attributes, String[] attributesToReturn) throws NamingException {
+ return m_dirContext.search(name, attributes, attributesToReturn);
+ }
+
+ public NamingEnumeration search(String name, String filter, Object[] filterArgs, SearchControls searchControls) throws NamingException {
+ return m_dirContext.search(name, filter, filterArgs, searchControls);
+ }
+
+ public NamingEnumeration search(Name name, String filter, Object[] filterArgs, SearchControls searchControls) throws NamingException {
+ return m_dirContext.search(name, filter, filterArgs, searchControls);
+ }
+
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/FactoryManager.java b/framework/src/main/java/org/eclipse/gemini/naming/FactoryManager.java
new file mode 100644
index 0000000..4c15443
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/FactoryManager.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import javax.naming.Context;
+import javax.naming.spi.InitialContextFactoryBuilder;
+import javax.naming.spi.ObjectFactory;
+
+
+/**
+ * Interface that defines the basic usage of the Factory Manager in Gemini Naming.
+ *
+ * The FactoryManager interface can be used to abstract the details of OSGi
+ * service access from certain portions of the implementation.
+ *
+ */
+public interface FactoryManager extends InitialContextFactoryBuilder {
+
+ /**
+ * Returns a javax.naming.spi.ObjectFactory that is published in the OSGi
+ * service registry. The ObjectFactory returned must support the specified
+ * urlScheme.
+ *
+ * @param urlScheme the requested URL scheme
+ * @return a javax.naming.spi.ObjectFactory that supports the given URL
+ * scheme
+ */
+ public ObjectFactory getURLContextFactory(String urlScheme);
+
+ /**
+ * Associates a given OSGi JNDI Factory service to a Context that
+ * was created with the given service.
+ *
+ * @param factory the JNDI factory service used to create the Context
+ * @param createdContext the Context created with this factory service
+ */
+ public void associateFactoryService(Object factory, Context createdContext);
+
+
+ /**
+ * Checks to see if a given OSGi JNDI Factory Service is still active in
+ * the service registry.
+ * @param factory the JNDI Factory service
+ * @return true if the service is still available
+ * false if the service is no longer available
+ */
+ public boolean isFactoryServiceActive(Object factory);
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/InitialContextFactoryWrapper.java b/framework/src/main/java/org/eclipse/gemini/naming/InitialContextFactoryWrapper.java
new file mode 100644
index 0000000..4ea2a29
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/InitialContextFactoryWrapper.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.DirContext;
+import javax.naming.spi.InitialContextFactory;
+import java.util.Hashtable;
+
+/**
+ * A Wrapper implementation of InitialContextFactory, used to support URL
+ * context factories in Gemini Naming.
+ *
+ */
+class InitialContextFactoryWrapper implements InitialContextFactory {
+ private final InitialContextFactory m_initialContextFactory;
+ private final FactoryManager m_factoryManager;
+
+ public InitialContextFactoryWrapper(InitialContextFactory initialContextFactory, FactoryManager factoryManager) {
+ m_initialContextFactory = initialContextFactory;
+ m_factoryManager = factoryManager;
+ }
+
+ public Context getInitialContext(Hashtable environment) throws NamingException {
+ final Context contextToReturn =
+ m_initialContextFactory.getInitialContext(environment);
+
+ if(contextToReturn instanceof DirContext) {
+ final DirContextWrapperImpl dirContextWrapper = new DirContextWrapperImpl((DirContext)contextToReturn, m_factoryManager);
+ setupFactoryAssociation(dirContextWrapper);
+ return ServiceAwareContextFactory.createServiceAwareDirContextWrapper(m_initialContextFactory, dirContextWrapper, m_factoryManager);
+ } else {
+ final ContextWrapperImpl contextWrapper = new ContextWrapperImpl(contextToReturn, m_factoryManager);
+ setupFactoryAssociation(contextWrapper);
+ return ServiceAwareContextFactory.createServiceAwareContextWrapper(m_initialContextFactory, contextWrapper, m_factoryManager);
+ }
+
+
+ }
+
+ private void setupFactoryAssociation(final Context contextWrapper) {
+ if(m_initialContextFactory instanceof BuilderSupportedInitialContextFactory) {
+ BuilderSupportedInitialContextFactory builderFactory =
+ (BuilderSupportedInitialContextFactory)m_initialContextFactory;
+ // this Context is backed by an InitialContextFactoryBuilder service
+ m_factoryManager.associateFactoryService(builderFactory.getBuilder(), contextWrapper);
+ } else {
+ // this Context is backed by an InitialContextFactory service
+ m_factoryManager.associateFactoryService(m_initialContextFactory, contextWrapper);
+ }
+ }
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/InvocationHandlerFactory.java b/framework/src/main/java/org/eclipse/gemini/naming/InvocationHandlerFactory.java
new file mode 100644
index 0000000..9638316
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/InvocationHandlerFactory.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.InvocationHandler;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Factory interface for creating InvocationHandler instances
+ * for the purpose of proxying OSGi services.
+ *
+ *
+ * @version $Revision$
+ */
+interface InvocationHandlerFactory {
+ /**
+ * Create an InvocationHandler for the specified OSGi service.
+ *
+ * @param bundleContext the BundleContext used to obtain the OSGi service
+ * @param serviceReference the ServiceReference that represents the service
+ * @param urlParser the OSGiURLParser associated with this service request
+ * @param osgiService the initial OSGi service to be proxied.
+ *
+ * @return an InvocationHandler that can be associated with a dynamic proxy
+ * for the specified service.
+ */
+ InvocationHandler create(BundleContext bundleContext, ServiceReference serviceReference, OSGiURLParser urlParser, Object osgiService);
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/NotSupportedContext.java b/framework/src/main/java/org/eclipse/gemini/naming/NotSupportedContext.java
new file mode 100644
index 0000000..8543c89
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/NotSupportedContext.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+
+/**
+ * This class implements an adapter for use in creating JNDI Context
+ * implementations.
+ *
+ * This implementation throws the OperationNotSupportedException in each
+ * method implementation for Context. This allows subclasses to only override
+ * the behavior that should be supported.
+ *
+ * @version $Revision$
+ */
+class NotSupportedContext implements Context {
+
+ private final String m_exceptionMessage;
+
+ public NotSupportedContext(String exceptionMessage) {
+ m_exceptionMessage = exceptionMessage;
+ }
+
+ public Object addToEnvironment(String var0, Object var1) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public void bind(String var0, Object var1) throws NamingException {
+ operationNotSupported();
+ }
+
+ public void bind(Name var0, Object var1) throws NamingException {
+ operationNotSupported();
+ }
+
+ public void close() throws NamingException {
+ operationNotSupported();
+ }
+
+ public String composeName(String var0, String var1) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public Name composeName(Name var0, Name var1) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public Context createSubcontext(String var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public Context createSubcontext(Name var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public void destroySubcontext(String var0) throws NamingException {
+ operationNotSupported();
+ }
+
+ public void destroySubcontext(Name var0) throws NamingException {
+ operationNotSupported();
+ }
+
+ public Hashtable getEnvironment() throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public String getNameInNamespace() throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public NameParser getNameParser(String var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public NameParser getNameParser(Name var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public NamingEnumeration list(String var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public NamingEnumeration list(Name var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public NamingEnumeration listBindings(String var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public NamingEnumeration listBindings(Name var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public Object lookup(String var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public Object lookup(Name var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public Object lookupLink(String var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public Object lookupLink(Name var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public void rebind(String var0, Object var1) throws NamingException {
+ operationNotSupported();
+ }
+
+ public void rebind(Name var0, Object var1) throws NamingException {
+ operationNotSupported();
+ }
+
+ public Object removeFromEnvironment(String var0) throws NamingException {
+ operationNotSupported();
+ return null;
+ }
+
+ public void rename(String var0, String var1) throws NamingException {
+ operationNotSupported();
+ }
+
+ public void rename(Name var0, Name var1) throws NamingException {
+ operationNotSupported();
+ }
+
+ public void unbind(String var0) throws NamingException {
+ operationNotSupported();
+ }
+
+ public void unbind(Name var0) throws NamingException {
+ operationNotSupported();
+ }
+
+ private void operationNotSupported() throws OperationNotSupportedException {
+ throw new OperationNotSupportedException(m_exceptionMessage);
+ }
+
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/OSGiInitialContextFactoryBuilder.java b/framework/src/main/java/org/eclipse/gemini/naming/OSGiInitialContextFactoryBuilder.java
new file mode 100644
index 0000000..1d88f81
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/OSGiInitialContextFactoryBuilder.java
@@ -0,0 +1,1086 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.security.PrivilegedExceptionAction;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.RefAddr;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.StringRefAddr;
+import javax.naming.directory.Attributes;
+import javax.naming.spi.DirObjectFactory;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+import javax.naming.spi.ObjectFactory;
+import javax.naming.spi.ObjectFactoryBuilder;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.jndi.JNDIConstants;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * This class represents the main integration point between the JNDI framework
+ * provided by the JDK and OSGi.
+ *
+ * This builder class is responsible for providing instances of
+ * InitialContextFactory and ObjectFactory to the JDK's NamingManager upon
+ * request. The builder uses the OSGi service registry to locate JNDI providers.
+ *
+ */
+class OSGiInitialContextFactoryBuilder implements
+ InitialContextFactoryBuilder, ObjectFactoryBuilder, FactoryManager {
+
+ private static Logger logger =
+ Logger.getLogger(OSGiInitialContextFactoryBuilder.class.getName());
+
+
+ private static final String JNDI_PROPERTIES_FILE_NAME = "jndi.properties";
+
+ private final static String NO_CONTEXT_FACTORIES_MSG = "No JNDI implementations available";
+
+ /* calling JNDI Client's BundleContext */
+ private final BundleContext m_callerBundleContext;
+
+ /* JNDI implementation bundle's BundleContext */
+ private final BundleContext m_implBundleContext;
+
+ private ServiceTracker m_contextFactoryServiceTracker = null;
+ private ServiceTracker m_contextFactoryBuilderServiceTracker = null;
+ private ServiceTracker m_objectFactoryServiceTracker = null;
+ private ServiceTracker m_objectFactoryBuilderServiceTracker = null;
+ private ServiceTracker m_urlContextFactoryServiceTracker = null;
+ private ServiceTracker m_dirObjectFactoryServiceTracker = null;
+
+
+ /*
+ * Map of OSGi services to a List of Contexts created by that service.
+ * Each service services as a key to a list of Context implementations.
+ */
+ private final Map m_mapOfServicesToContexts = Collections.synchronizedMap(new HashMap());
+
+
+ public OSGiInitialContextFactoryBuilder(BundleContext callerBundleContext, BundleContext implBundleContext) {
+ m_callerBundleContext = callerBundleContext;
+ m_implBundleContext = implBundleContext;
+
+ try {
+ // create the service trackers inside a doPrivileged() block
+ // since this code is the only interaction with a BundleContext
+ // context not covered by the security-aware wrapper interfaces
+ SecurityUtils.invokePrivilegedActionNoReturn(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ createServiceTrackers(m_implBundleContext);
+ return null;
+ }
+ });
+ } catch (Exception e) {
+ logger.log(Level.FINE,
+ "Exception occurred while creating ServiceTracker implementations for JNDI Provider Services",
+ e);
+ }
+ }
+
+ /**
+ * This builder implementation uses the OSGi service registry to find
+ * matching JNDI service providers.
+ */
+ public InitialContextFactory createInitialContextFactory(Hashtable environment) throws NamingException {
+ // check for valid tracker setup
+ if (m_contextFactoryServiceTracker == null) {
+ throw new NoInitialContextException(NO_CONTEXT_FACTORIES_MSG);
+ }
+
+ return getInitialContextFactoryInternal(getCombinedEnvironment(environment));
+ }
+
+ private InitialContextFactory getInitialContextFactoryInternal(Hashtable environment) throws NoInitialContextException {
+ if (environment.get(Context.INITIAL_CONTEXT_FACTORY) != null) {
+ final String initialContextFactoryName =
+ (String) environment.get(Context.INITIAL_CONTEXT_FACTORY);
+ Object factory =
+ obtainFactoryService(initialContextFactoryName, m_contextFactoryServiceTracker);
+ if (factory != null) {
+ return new InitialContextFactoryWrapper(
+ (InitialContextFactory) factory, this);
+ }
+ else {
+ // query known builders to see if any can support the
+ // given environment
+ InitialContextFactory contextFactory = getContextFactoryFromBuilder(environment);
+ if (contextFactory != null) {
+ return new InitialContextFactoryWrapper(contextFactory,
+ this);
+ }
+ }
+
+ throw new NoInitialContextException(NO_CONTEXT_FACTORIES_MSG);
+ }
+ else {
+ // query known builders to see if any can support
+ // the given environment
+ InitialContextFactory contextFactory = getContextFactoryFromBuilder(environment);
+ if (contextFactory != null) {
+ return new InitialContextFactoryWrapper(contextFactory, this);
+ }
+
+ // return the first valid context factory if one exists
+ try {
+ InitialContextFactory defaultContextFactory = getDefaultInitialContextFactory(environment);
+ if (defaultContextFactory == null) {
+ // return a wrapper to support URL-based lookups only
+ return new InitialContextFactoryWrapper(new DefaultInitialContextFactory(), this);
+ }
+ else {
+ return new InitialContextFactoryWrapper(defaultContextFactory, this);
+ }
+ }
+ catch (NamingException namingException) {
+ NoInitialContextException noInitialContextException =
+ new NoInitialContextException("Exception occured while iterating over the default InitialContextFactory services");
+ noInitialContextException.setRootCause(namingException);
+ throw noInitialContextException;
+ }
+
+
+ }
+ }
+
+
+ /**
+ * This Builder implementation uses the OSGi Service registry to find
+ * matching JNDI service providers for resolving references.
+ *
+ */
+ public ObjectFactory createObjectFactory(Object obj, Hashtable environment) throws NamingException {
+ if (m_objectFactoryServiceTracker == null) {
+ throw new NoInitialContextException("No Object factories available");
+ }
+
+ return new ReturnReferenceInfoObjectFactory(createInnerObjectFactory(obj));
+ }
+
+ public DirObjectFactory getDirObjectFactory(Object obj, Hashtable environment) throws NamingException {
+ if (m_dirObjectFactoryServiceTracker == null) {
+ throw new NamingException("No DirObjectFactories available");
+ }
+
+ return new ReturnReferenceInfoDirObjectFactory(createInnerDirObjectFactory(obj)) ;
+ }
+
+
+
+
+ /**
+ * Returns a URL Context Factory implementation that is published to support
+ * the provided URL scheme.
+ *
+ * @param urlScheme the URL scheme that the URL context factory must support
+ * @return a javax.naming.spi.ObjectFactory instance that supports the
+ * requested URL scheme, or null if no matching factory was found
+ */
+ public ObjectFactory getURLContextFactory(String urlScheme) {
+ if (m_urlContextFactoryServiceTracker.getServiceReferences() != null) {
+ ServiceReference[] serviceReferences = ServiceUtils.sortServiceReferences(m_urlContextFactoryServiceTracker);
+ for (int i = 0; i < serviceReferences.length; i++) {
+ ServiceReference serviceReference = serviceReferences[i];
+ if (serviceReference.getProperty(JNDIConstants.JNDI_URLSCHEME).equals(urlScheme)) {
+ return (ObjectFactory) m_callerBundleContext.getService(serviceReference);
+ }
+ }
+ }
+ return null;
+ }
+
+ public void associateFactoryService(Object factory, Context createdContext) {
+ if(m_mapOfServicesToContexts.containsKey(factory)) {
+ List listOfContexts =
+ (List) m_mapOfServicesToContexts.get(factory);
+ listOfContexts.add(createdContext);
+ m_mapOfServicesToContexts.put(factory, listOfContexts);
+ } else {
+ List listOfContexts = new LinkedList();
+ listOfContexts.add(createdContext);
+ m_mapOfServicesToContexts.put(factory, listOfContexts);
+ }
+
+ }
+
+ public boolean isFactoryServiceActive(Object factory) {
+ return m_mapOfServicesToContexts.containsKey(factory);
+ }
+
+
+
+ /**
+ * Simple close method to close the ServiceTracker objects currently in use
+ * by the FactoryManager.
+ */
+ protected void close() {
+ m_contextFactoryBuilderServiceTracker.close();
+ m_contextFactoryServiceTracker.close();
+ m_objectFactoryServiceTracker.close();
+ m_objectFactoryBuilderServiceTracker.close();
+ m_urlContextFactoryServiceTracker.close();
+ m_dirObjectFactoryServiceTracker.close();
+
+ }
+
+
+ private final void createServiceTrackers(BundleContext bundleContext) {
+ // create trackers
+ m_contextFactoryServiceTracker =
+ new ContextFactoryServiceTracker(bundleContext, InitialContextFactory.class.getName());
+
+ m_contextFactoryBuilderServiceTracker =
+ new ContextFactoryServiceTracker(bundleContext, InitialContextFactoryBuilder.class.getName());
+
+ m_objectFactoryServiceTracker =
+ new ObjectFactoryServiceTracker(bundleContext, ObjectFactory.class.getName());
+
+ m_dirObjectFactoryServiceTracker =
+ new ObjectFactoryServiceTracker(bundleContext, DirObjectFactory.class.getName());
+
+ m_objectFactoryBuilderServiceTracker =
+ createServiceTracker(bundleContext, ObjectFactoryBuilder.class.getName());
+
+ m_urlContextFactoryServiceTracker =
+ new URLContextFactoryServiceTracker(bundleContext, ObjectFactory.class.getName());
+
+
+ // open trackers
+ m_contextFactoryServiceTracker.open();
+ m_contextFactoryBuilderServiceTracker.open();
+ m_objectFactoryServiceTracker.open();
+ m_objectFactoryBuilderServiceTracker.open();
+ m_dirObjectFactoryServiceTracker.open();
+ m_urlContextFactoryServiceTracker.open();
+ }
+
+ private Object obtainFactoryService(String factoryServiceInterface,
+ ServiceTracker serviceTracker) {
+ ServiceReference[] serviceReferences = ServiceUtils.sortServiceReferences(serviceTracker);
+ for (int i = 0; i < serviceReferences.length; i++) {
+ ServiceReference serviceReference = serviceReferences[i];
+ String[] serviceInterfaces = (String[]) serviceReference
+ .getProperty(Constants.OBJECTCLASS);
+ List interfaceList = Arrays.asList(serviceInterfaces);
+ if (interfaceList.contains(factoryServiceInterface)) {
+ return m_callerBundleContext.getService(serviceReference);
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Convenience method to query each known InitialContextFactoryBuilder, and to return
+ * the first non-null factory produced by a builder.
+ *
+ * The first builder to return a non-null result is
+ * given precedence as per Section 5.2.1.1 of RFC 142.
+ *
+ * @param environment the JNDI environment
+ * @return an InitialContextFactory instance that can support this request
+ * or null if no match can be found.
+ */
+ private InitialContextFactory getContextFactoryFromBuilder(Hashtable environment) {
+ if (m_contextFactoryBuilderServiceTracker.getServiceReferences() != null) {
+ final ServiceReference[] serviceReferences = ServiceUtils.sortServiceReferences(m_contextFactoryBuilderServiceTracker);
+ for (int i = 0; i < serviceReferences.length; i++) {
+ ServiceReference serviceReference = serviceReferences[i];
+ InitialContextFactoryBuilder builder =
+ (InitialContextFactoryBuilder) m_callerBundleContext.getService(serviceReference);
+ try {
+ // if builder is null, then service is not available
+ if (builder != null) {
+ InitialContextFactory contextFactory = builder
+ .createInitialContextFactory(environment);
+ // the first builder to return a non-null result is
+ // given precedence as per Section 5.2.1.1 of RFC
+ // 142
+ if (contextFactory != null) {
+ return new DefaultBuilderSupportedInitialContextFactory(
+ contextFactory, builder);
+ }
+ }
+ }
+ catch (NamingException namingException) {
+ // catch exception, allow iteration to continue
+ logger.log(Level.FINE,
+ "NamingException occurred while invoking on an InitialContextFactoryBuilder",
+ namingException);
+ }
+ }
+
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Convenience method for obtaining the "default" InitialContextFactory.
+ * This method takes the list of known InitialContextFactory implementations,
+ * in service ranking order, and attempts to use each to create a JNDI Context
+ * given the environment passed in. The first service to return a non-null
+ * result is returned.
+ *
+ * @param environment the JNDI environment to use when creating the Context
+ * @return the first InitialContextFactory service that can support this environment,
+ * or null if no matching service was found.
+ * @throws NamingException any NamingException thrown by an InitialContextFactory
+ * service is thrown back to the caller.
+ */
+ private InitialContextFactory getDefaultInitialContextFactory(Hashtable environment) throws NamingException {
+ if (m_contextFactoryServiceTracker.getServiceReferences() != null) {
+ ServiceReference[] serviceReferences = ServiceUtils.sortServiceReferences(m_contextFactoryServiceTracker);
+ for (int i = 0; i < serviceReferences.length; i++) {
+ ServiceReference serviceReference = serviceReferences[i];
+ InitialContextFactory factoryService =
+ (InitialContextFactory) m_callerBundleContext.getService(serviceReference);
+ if(factoryService.getInitialContext(environment) != null) {
+ return factoryService;
+ } else {
+ m_callerBundleContext.ungetService(serviceReference);
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Convenience method to query each known ObjectFactoryBuilder, and to return
+ * the first non-null factory produced by a builder.
+ *
+ * The first builder to return a non-null result is
+ * given precedence as per Section 5.2.2.1 of RFC 142.
+ *
+ * @param environment the JNDI environment
+ * @param refInfo the Object to resolve
+ * @return an ObjectFactory instance that matches this Reference,
+ * or null if no match can be found.
+ */
+ private ObjectFactory getObjectFactoryFromBuilder(Hashtable environment, Object refInfo) {
+ if (m_objectFactoryBuilderServiceTracker.getServiceReferences() != null) {
+ final ServiceReference[] serviceReferences = ServiceUtils.sortServiceReferences(m_objectFactoryBuilderServiceTracker);
+ for (int i = 0; i < serviceReferences.length; i++) {
+ ServiceReference serviceReference = serviceReferences[i];
+ ObjectFactoryBuilder builder = (ObjectFactoryBuilder) m_callerBundleContext
+ .getService(serviceReference);
+ try {
+ ObjectFactory factory =
+ builder.createObjectFactory(refInfo, environment);
+
+ if (factory != null) {
+ return factory;
+ }
+ }
+ catch (NamingException namingException) {
+ // catch exception, allow iteration to continue
+ logger.log(Level.FINE,
+ "NamingException occurred while invoking on an ObjectFactoryBuilder",
+ namingException);
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Examines a Reference to determine if a StringRefAddr of type
+ * 'URL' is associated with the Reference. If so, the Factory Manager
+ * will attempt to locate a URL context factory that can be used to
+ * resolve the reference.
+ *
+ * @param reference to be resolved
+ * @return an object resolved from a URL Context Factory, or null if no URL
+ * Context Factory could resolve the reference.
+ */
+ private Object getObjectFromURLContextFactoryFromReference(final Reference reference, Hashtable environment) {
+ Enumeration refAddresses = reference.getAll();
+ while(refAddresses.hasMoreElements()) {
+ RefAddr address = (RefAddr)refAddresses.nextElement();
+ if((address instanceof StringRefAddr) && (address.getType().equals("URL"))) {
+ String urlContent = (String)address.getContent();
+ try {
+ URI uri = new URI(urlContent);
+ ObjectFactory objectFactory =
+ getURLContextFactory(uri.getScheme());
+ if(objectFactory != null) {
+ Object objToReturn = objectFactory.getObjectInstance(urlContent, null, null, environment);
+ if(objToReturn != null) {
+ // return the first object that is constructed from a URL string reference address
+ return objToReturn;
+ }
+ }
+ }
+ catch (URISyntaxException e) {
+ logger.log(Level.FINEST,
+ "Exception thrown while parsing URL. This URL reference address will be skipped.",
+ e);
+
+ }
+ catch (Exception e) {
+ logger.log(Level.FINEST,
+ "Exception thrown while parsing URL. This URL reference address will be skipped.",
+ e);
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ private Object getObjectToResolve(Object obj) throws NamingException {
+ Object objToResolve;
+ if(obj instanceof Referenceable) {
+ // obtain the Reference before proceeding
+ Referenceable referenceable = (Referenceable)obj;
+ objToResolve = referenceable.getReference();
+ } else {
+ // this object is either a Reference or another type
+ objToResolve = obj;
+ }
+ return objToResolve;
+ }
+
+
+ private ObjectFactory createInnerObjectFactory(Object obj) throws NamingException {
+ final Object objToResolve = getObjectToResolve(obj);
+ if (objToResolve instanceof Reference) {
+ final Reference reference = (Reference) objToResolve;
+ if (reference.getFactoryClassName() != null) {
+ return new FactoryNameSpecifiedObjectFactory();
+ }
+ else {
+ return new NoFactoryNameSpecifiedObjectFactory();
+ }
+ }
+ else {
+ return new NoReferenceObjectFactory();
+ }
+ }
+
+
+ private DirObjectFactory createInnerDirObjectFactory(Object obj) throws NamingException {
+ final Object objToResolve = getObjectToResolve(obj);
+ if (objToResolve instanceof Reference) {
+ final Reference reference = (Reference) objToResolve;
+ if (reference.getFactoryClassName() != null) {
+ return new FactoryNameSpecifiedDirObjectFactory();
+ }
+ else {
+ return new NoFactoryNameSpecifiedDirObjectFactory();
+ }
+ }
+ else {
+ return new NoReferenceDirObjectFactory();
+ }
+ }
+
+
+ /**
+ * Utility method for creating the set of environment properties from the
+ * following sources (in order of priority):
+ *
+ * 1. User-defined properties
+ * 2. Properties defined in a jndi.properties file in the caller's archive (if it exists)
+ *
+ *
+ * @param userEnvironment original environment passed in by the caller
+ * @return a Hashtable representing the combined JNDI environment for this context
+ */
+ private Hashtable getCombinedEnvironment(Hashtable userEnvironment) {
+ // create a copy of the user-defined environment settings
+ Hashtable combinedEnvironment = new Hashtable();
+ combinedEnvironment.putAll(userEnvironment);
+
+ // obtain environment properties defined in the calling bundle's archive
+ Properties fileDefinedEnvironment =
+ getFileDefinedJndiProperties(m_callerBundleContext);
+ if(fileDefinedEnvironment != null) {
+ Enumeration keyEnum = fileDefinedEnvironment.keys();
+ while(keyEnum.hasMoreElements()) {
+ final String key = (String) keyEnum.nextElement();
+ if(!combinedEnvironment.containsKey(key)) {
+ // add the file-defined property to the combined environment
+ // only add keys that do not exist, since the user-defined
+ // environment takes precedence over the file-defined
+ combinedEnvironment.put(key, fileDefinedEnvironment.get(key));
+ }
+ }
+ }
+
+ return combinedEnvironment;
+ }
+
+
+
+ private Object resolveObjectUsingBuilders(Object objectToResolve, Name name, Context context,
+ Hashtable environment)
+ throws Exception {
+ ObjectFactory objectFactory =
+ getObjectFactoryFromBuilder(environment, objectToResolve);
+ if(objectFactory != null) {
+ Object resolvedObject = objectFactory.getObjectInstance(objectToResolve, name, context, environment);
+ if(resolvedObject != null) {
+ return resolvedObject;
+ }
+ }
+
+ return null;
+ }
+
+ private Object resolveObjectUsingObjectFactories(Object objectToResolve, Name name, Context context, Hashtable environment) throws NamingException {
+ if (m_objectFactoryServiceTracker.getServiceReferences() != null) {
+ final ServiceReference[] serviceReferences = ServiceUtils.sortServiceReferences(m_objectFactoryServiceTracker);
+ for (int i = 0; i < serviceReferences.length; i++) {
+ ServiceReference serviceReference = serviceReferences[i];
+ ObjectFactory factory =
+ (ObjectFactory) m_callerBundleContext.getService(serviceReference);
+ try {
+ Object result =
+ factory.getObjectInstance(objectToResolve, name, context, environment);
+
+ // release the service for this factory
+ m_callerBundleContext.ungetService(serviceReference);
+
+ if (result != null) {
+ // return resolved object
+ return result;
+ }
+ }
+ catch (Exception exception) {
+ NamingException namingException = new NamingException("Exception occurred while trying to resolve object using ObjectFactory search");
+ namingException.setRootCause(exception);
+ throw namingException;
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ private Object resolveObjectUsingDirObjectFactories(Object objectToResolve, Name name, Context context, Hashtable environment, Attributes attributes) throws NamingException {
+ if (m_dirObjectFactoryServiceTracker.getServiceReferences() != null) {
+ final ServiceReference[] serviceReferences = ServiceUtils.sortServiceReferences(m_dirObjectFactoryServiceTracker);
+ for (int i = 0; i < serviceReferences.length; i++) {
+ ServiceReference serviceReference = serviceReferences[i];
+ DirObjectFactory factory =
+ (DirObjectFactory) m_callerBundleContext.getService(serviceReference);
+ try {
+ Object result =
+ factory.getObjectInstance(objectToResolve, name, context, environment, attributes);
+
+ // release the service reference
+ m_callerBundleContext.ungetService(serviceReference);
+
+ if (result != null) {
+ // return the resolved object
+ return result;
+ }
+ }
+ catch (Exception exception) {
+ NamingException namingException = new NamingException("Exception occurred while trying to resolve object using ObjectFactory search");
+ namingException.setRootCause(exception);
+ throw namingException;
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+ private Object resolveDirObjectUsingBuilders(Object objectToResolve, Name name, Context context, Hashtable environment, Attributes attributes)
+ throws Exception {
+ ObjectFactory objectFactory =
+ getObjectFactoryFromBuilder(environment, objectToResolve);
+ if((objectFactory != null) && (objectFactory instanceof DirObjectFactory)) {
+ DirObjectFactory dirObjectFactory = (DirObjectFactory)objectFactory;
+ Object resolvedObject = dirObjectFactory.getObjectInstance(objectToResolve, name, context, environment, attributes);
+ if(resolvedObject != null) {
+ return resolvedObject;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Checks the calling Bundle in order to search for a
+ * jndi.properties file.
+ *
+ * Check the client's bundle for a jndi.properties file in the archive
+ *
+ * @return a Properties instance that contains the properties defined in
+ * a jndi.properties file for the caller's archive, or null if none exists
+ */
+ private static Properties getFileDefinedJndiProperties(BundleContext callerBundleContext) {
+ if (callerBundleContext.getBundle() != null) {
+ Bundle bundle = callerBundleContext.getBundle();
+ try {
+ URL propertiesURL = bundle.getResource(JNDI_PROPERTIES_FILE_NAME);
+ if (propertiesURL != null) {
+ File jndiPropertiesFile = (File) propertiesURL.getContent();
+ try {
+ FileInputStream userDefinedPropertiesStream =
+ new FileInputStream(jndiPropertiesFile);
+ Properties fileDefinedJndiProperties = new Properties();
+ fileDefinedJndiProperties.load(userDefinedPropertiesStream);
+ return fileDefinedJndiProperties;
+ }
+ catch (FileNotFoundException e) {
+ // this exception should never occur, since the File has
+ // already been tested to be available
+ logger.log(Level.FINEST, "Exception encountered while trying to locate a jndi.properties file.", e);
+ }
+ }
+ }
+ catch (IOException e) {
+ logger.log(Level.FINEST,
+ "Exception encounted while trying to load a jndi.properties file",
+ e);
+ }
+ }
+
+
+ return null;
+ }
+
+
+
+ /**
+ * Convenience method for creating ServiceTracker instances.
+ *
+ * This method only creates tracker instances for a single interface type,
+ * and does not support customizing the tracker.
+ *
+ * @param bundleContext the BundleContext to use to create the tracker
+ * @param serviceInterface the service interface name to use for this
+ * tracker
+ *
+ * @return a ServiceTracker instance for the given interface
+ */
+ private static ServiceTracker createServiceTracker(BundleContext bundleContext, String serviceInterface) {
+ return new ServiceTracker(bundleContext, serviceInterface, null);
+ }
+
+
+ private static final class URLContextFactoryServiceTracker extends ServiceTracker {
+ private URLContextFactoryServiceTracker(BundleContext context, String clazz) {
+ super(context, clazz, null);
+ }
+
+ public Object addingService(ServiceReference serviceReference) {
+ if (serviceReference.getProperty(JNDIConstants.JNDI_URLSCHEME) != null) {
+ return super.addingService(serviceReference);
+ }
+
+ return null;
+ }
+ }
+
+
+
+ private static final class ObjectFactoryServiceTracker extends ServiceTracker {
+ private ObjectFactoryServiceTracker(BundleContext context, String clazz) {
+ super(context, clazz, null);
+ }
+
+ public Object addingService(ServiceReference serviceReference) {
+ if (serviceReference.getProperty(JNDIConstants.JNDI_URLSCHEME) == null) {
+ return super.addingService(serviceReference);
+ }
+
+ return null;
+ }
+ }
+
+
+
+ private final class ContextFactoryServiceTracker extends ServiceTracker {
+ private ContextFactoryServiceTracker(BundleContext context, String clazz) {
+ super(context, clazz, null);
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ handleRemovedService(reference, service);
+ }
+
+ public Object addingService(ServiceReference reference) {
+ return handleAddingService(reference);
+ }
+
+ private void handleRemovedService(ServiceReference reference, Object service) {
+ super.removedService(reference, service);
+ m_mapOfServicesToContexts.remove(service);
+ }
+
+ private Object handleAddingService(ServiceReference reference) {
+ return super.addingService(reference);
+ }
+ }
+
+
+
+ /**
+ * Query the inner ObjectFactory instance to see if that factory
+ * can resolve the object.
+ *
+ * If no matching ObjectFactory services exist that can resolve the object,
+ * return a specialized ObjectFactory implementation that
+ * merely returns the reference passed in. This allows the Factory
+ * Manager to more closely comply with the behavior specified in the
+ * javadoc for NamingManger.getObjectInstance()
+ *
+ *
+ * @version $Revision: 9053 $
+ */
+ private static class ReturnReferenceInfoObjectFactory implements ObjectFactory {
+ private final ObjectFactory m_objectFactory;
+
+
+ public ReturnReferenceInfoObjectFactory(ObjectFactory objectFactory) {
+ m_objectFactory = objectFactory;
+ }
+
+ public Object getObjectInstance(Object refInfo, Name name,
+ Context context, Hashtable environment) throws Exception {
+
+ if (m_objectFactory != null) {
+ Object resolvedObject =
+ m_objectFactory.getObjectInstance(refInfo, name,
+ context, environment);
+ if (resolvedObject != null) {
+ return resolvedObject;
+ }
+ }
+
+ // in all other cases return refInfo
+ return refInfo;
+ }
+ }
+
+
+
+ /**
+ * Query the inner DirObjectFactory instance to see if that factory
+ * can resolve the object.
+ *
+ * If no matching DirObjectFactory services exist that can resolve the object,
+ * return a specialized ObjectFactory implementation that
+ * merely returns the reference passed in. This allows the Factory
+ * Manager to more closely comply with the behavior specified in the
+ * javadoc for DirectoryManger.getObjectInstance()
+ *
+ *
+ * @version $Revision: 9053 $
+ */
+ private static final class ReturnReferenceInfoDirObjectFactory extends ReturnReferenceInfoObjectFactory implements DirObjectFactory {
+ private final DirObjectFactory m_dirObjectFactory;
+
+
+ public ReturnReferenceInfoDirObjectFactory(DirObjectFactory dirObjectFactory) {
+ super(dirObjectFactory);
+ m_dirObjectFactory = dirObjectFactory;
+ }
+
+
+ public Object getObjectInstance(Object refInfo, Name name,
+ Context context, Hashtable environment, Attributes attributes) throws Exception {
+ if (m_dirObjectFactory != null) {
+ Object resolvedObject =
+ m_dirObjectFactory.getObjectInstance(refInfo, name,
+ context, environment, attributes);
+ if (resolvedObject != null) {
+ return resolvedObject;
+ }
+ }
+
+ // in all other cases return refInfo
+ return refInfo;
+ }
+ }
+
+
+
+
+
+ /**
+ * Inner ObjectFactory implementation used to handle cases where a Reference
+ * is specified, but the Reference does not indicate which ObjectFactory should be used
+ * to resolve the object.
+ *
+ * This factory will dynamically attempt to use a URL context factory to
+ * resolve the object (if a Reference Address of type "URL" is detected),
+ * and will also consult the known ObjectFactoryBuilder services if no other
+ * way to resolve the reference exists.
+ *
+ *
+ * @version $Revision: 9053 $
+ */
+ private final class NoFactoryNameSpecifiedObjectFactory implements ObjectFactory {
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment) throws Exception {
+ if(refInfo == null) {
+ return null;
+ }
+
+ Object objectToResolve = getObjectToResolve(refInfo);
+ if(objectToResolve instanceof Reference) {
+ Reference reference = (Reference)objectToResolve;
+ Object resultFromURLContextFactories =
+ getObjectFromURLContextFactoryFromReference(reference, environment);
+ if (resultFromURLContextFactories != null) {
+ return resultFromURLContextFactories;
+ }
+
+ Object resultFromBuilders = resolveObjectUsingBuilders(objectToResolve, name, context, environment);
+ if(resultFromBuilders != null) {
+ return resultFromBuilders;
+ }
+
+ Object resultFromObjectFactories =
+ resolveObjectUsingObjectFactories(objectToResolve, name, context, environment);
+
+ if(resultFromObjectFactories != null) {
+ return resultFromObjectFactories;
+ }
+
+ }
+
+ return null;
+ }
+
+ }
+
+ private final class NoFactoryNameSpecifiedDirObjectFactory implements DirObjectFactory {
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment, Attributes attributes) throws Exception {
+ if(refInfo == null) {
+ return null;
+ }
+
+ Object objectToResolve = getObjectToResolve(refInfo);
+ if(objectToResolve instanceof Reference) {
+ Reference reference = (Reference)objectToResolve;
+ Object resultFromURLContextFactories =
+ getObjectFromURLContextFactoryFromReference(reference, environment);
+ if (resultFromURLContextFactories != null) {
+ return resultFromURLContextFactories;
+ }
+
+ Object resultFromBuilders = resolveDirObjectUsingBuilders(objectToResolve, name, context, environment, attributes);
+ if(resultFromBuilders != null) {
+ return resultFromBuilders;
+ }
+
+ Object resultFromDirObjectFactories =
+ resolveObjectUsingDirObjectFactories(objectToResolve, name, context, environment, attributes);
+ if(resultFromDirObjectFactories != null) {
+ return resultFromDirObjectFactories;
+ }
+ }
+
+ return null;
+ }
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment) throws Exception {
+ // no-op for this DirObjectFactory
+ return null;
+ }
+
+ }
+
+
+
+ /**
+ * Inner ObjectFactory implementation used to handle cases where a Reference
+ * is specified, and the Reference indicates which ObjectFactory should be used
+ * to resolve the object.
+ *
+ * This factory will dynamically attempt to use locate the specified
+ * factory in the OSGi service registry, and will also consult the known
+ * ObjectFactoryBuilder services if no other way to resolve the reference
+ * exists.
+ *
+ *
+ * @version $Revision: 9053 $
+ */
+ private final class FactoryNameSpecifiedObjectFactory implements ObjectFactory {
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment) throws Exception {
+ Object objectToResolve = getObjectToResolve(refInfo);
+ if(objectToResolve instanceof Reference) {
+ // if a factory class name is specified, look through the list
+ // of known ObjectFactories, and try to find a service published
+ // that also supports the custom interface.
+ Reference reference = (Reference)objectToResolve;
+ Object factory =
+ obtainFactoryService(reference.getFactoryClassName(), m_objectFactoryServiceTracker);
+ if (factory != null) {
+ ObjectFactory objectFactory = (ObjectFactory)factory;
+ Object resolvedObject =
+ objectFactory.getObjectInstance(objectToResolve, name, context, environment);
+ if(resolvedObject != null) {
+ return resolvedObject;
+ }
+ } else {
+ return resolveObjectUsingBuilders(objectToResolve, name, context, environment);
+ }
+ }
+
+ return null;
+ }
+
+ }
+
+ private final class FactoryNameSpecifiedDirObjectFactory implements DirObjectFactory {
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment, Attributes attributes) throws Exception {
+ Object objectToResolve = getObjectToResolve(refInfo);
+ if(objectToResolve instanceof Reference) {
+ // if a factory class name is specified, look through the list
+ // of known ObjectFactories, and try to find a service published
+ // that also supports the custom interface.
+ Reference reference = (Reference)objectToResolve;
+ Object factory =
+ obtainFactoryService(reference.getFactoryClassName(), m_dirObjectFactoryServiceTracker);
+ if (factory != null) {
+ DirObjectFactory dirObjectFactory = (DirObjectFactory)factory;
+ Object resolvedObject =
+ dirObjectFactory.getObjectInstance(objectToResolve, name, context, environment, attributes);
+ if(resolvedObject != null) {
+ return resolvedObject;
+ }
+ } else {
+ return resolveDirObjectUsingBuilders(objectToResolve, name, context, environment, attributes);
+ }
+ }
+
+ return null;
+ }
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment) throws Exception {
+ // always return null, since this DirObjectFactory is a wrapper type
+ return null;
+ }
+
+ }
+
+
+ private class NoReferenceObjectFactory implements ObjectFactory {
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment) throws Exception {
+ // first query all known ObjectFactoryBuilder services to resolve this reference
+ Object resultFromBuilders =
+ resolveObjectUsingBuilders(refInfo, name, context, environment);
+
+ if(resultFromBuilders != null) {
+ return resultFromBuilders;
+ }
+
+ // as a last resort, query all known ObjectFactory services to attempt to resolve this reference
+ Object resultFromObjectFactories =
+ resolveObjectUsingObjectFactories(refInfo, name, context, environment);
+
+ if(resultFromObjectFactories != null) {
+ return resultFromObjectFactories;
+ }
+
+ return null;
+ }
+
+ }
+
+ private class NoReferenceDirObjectFactory implements DirObjectFactory {
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment, Attributes attributes) throws Exception {
+ final Object resultFromBuilders = resolveDirObjectUsingBuilders(refInfo, name, context, environment, attributes);
+ if(resultFromBuilders != null) {
+ return resultFromBuilders;
+ }
+
+ Object resultFromDirObjectFactories =
+ resolveObjectUsingDirObjectFactories(refInfo, name, context, environment, attributes);
+ if(resultFromDirObjectFactories != null) {
+ return resultFromDirObjectFactories;
+ }
+
+ return null;
+ }
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment) throws Exception {
+ // no-op for this DirObjectFactory
+ return null;
+ }
+
+ }
+
+ private static class DefaultBuilderSupportedInitialContextFactory implements BuilderSupportedInitialContextFactory {
+
+ private final InitialContextFactory m_factory;
+ private final InitialContextFactoryBuilder m_builder;
+
+ DefaultBuilderSupportedInitialContextFactory(InitialContextFactory factory, InitialContextFactoryBuilder builder) {
+ m_factory = factory;
+ m_builder = builder;
+ }
+
+ public InitialContextFactoryBuilder getBuilder() {
+ return m_builder;
+ }
+
+ public Context getInitialContext(Hashtable environment) throws NamingException {
+ return m_factory.getInitialContext(environment);
+ }
+ }
+
+
+
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/OSGiServiceListContext.java b/framework/src/main/java/org/eclipse/gemini/naming/OSGiServiceListContext.java
new file mode 100644
index 0000000..325ecd4
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/OSGiServiceListContext.java
@@ -0,0 +1,238 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.InvocationHandler;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.Binding;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+class OSGiServiceListContext extends NotSupportedContext {
+
+ private static Logger logger =
+ Logger.getLogger(OSGiServiceListContext.class.getName());
+
+ private final BundleContext m_bundleContext;
+
+ private final ServiceReference[] m_serviceReferences;
+
+ private final OSGiURLParser m_urlParser;
+
+ /* map of service ids (Long) to ServiceReferences */
+ private final Map m_mapOfServices = new HashMap();
+
+ OSGiServiceListContext(BundleContext bundleContext, ServiceReference[] serviceReferences, OSGiURLParser urlParser) {
+ super("This operation is not supported in an osgi:servicelist context");
+ m_bundleContext = bundleContext;
+ m_serviceReferences = serviceReferences;
+ m_urlParser = urlParser;
+ buildMapOfServices(m_mapOfServices, m_serviceReferences);
+ }
+
+
+ public void close() throws NamingException {
+ // this operation is a no-op
+ }
+
+
+ public NamingEnumeration list(String name) throws NamingException {
+ if(name.equals("")) {
+ return new ListNamingEnumeration(m_bundleContext,
+ m_serviceReferences, m_urlParser.getServiceInterface());
+ }
+
+ throw new OperationNotSupportedException("This NamingEnumeration cannot support list() operations for anything other than the empty string");
+ }
+
+
+ public NamingEnumeration listBindings(String name) throws NamingException {
+ if(name.equals("")) {
+ return new ListBindingsNamingEnumeration(m_bundleContext,
+ m_serviceReferences,
+ m_urlParser);
+ }
+
+ throw new OperationNotSupportedException("This NamingEnumeration cannot support list() operations for anything other than the empty string");
+ }
+
+
+ public Object lookup(String name) throws NamingException {
+ Long serviceId = new Long(name);
+ if(serviceId == null) {
+ throw new NameNotFoundException("Service with the name = " + name + " does not exist in this context");
+ } else {
+ if(m_mapOfServices.containsKey(serviceId)) {
+ ServiceReference serviceReference = (ServiceReference)m_mapOfServices.get(serviceId);
+ // create a proxy for this service, and return the proxy to handle
+ // service dynamics
+ ServiceProxyInfo proxyInfo =
+ createNoRetryProxiedService(m_bundleContext, m_urlParser, serviceReference);
+
+ if(!proxyInfo.isProxied()) {
+ logger.log(Level.WARNING,
+ "The service returned could not be proxied, OSGi lifecycle maintenance will not be handled by the Context Manager service");
+ }
+
+ return proxyInfo.getService();
+ } else {
+ throw new NameNotFoundException("Service with the name = " + name + " does not exist in this context");
+ }
+ }
+ }
+
+
+ private static ServiceProxyInfo createNoRetryProxiedService(BundleContext bundleContext, OSGiURLParser urlParser, final ServiceReference serviceReference) {
+ return ReflectionUtils.getProxyForSingleService(bundleContext,
+ urlParser,
+ serviceReference,
+ new NoRetryInvocationHandlerFactory());
+ }
+
+
+ /**
+ * Convenience method for building a lookup map of service id's to services.
+ * @param mapOfServices
+ * @param serviceReferences
+ */
+ private static void buildMapOfServices(Map mapOfServices, ServiceReference[] serviceReferences) {
+ for(int i = 0; i < serviceReferences.length; i++) {
+ Long serviceId = (Long)serviceReferences[i].getProperty("service.id");
+ mapOfServices.put(serviceId, serviceReferences[i]);
+ }
+ }
+
+
+ /**
+ * NamingEnumeration that allows for iteration over a list of
+ * NameClassPair structures. This enumeration should be used
+ * from the Context.list() operation.
+ *
+ *
+ * @version $Revision$
+ */
+ private static class ListNamingEnumeration extends ServiceBasedNamingEnumeration {
+
+ ListNamingEnumeration(BundleContext bundleContext, ServiceReference[] serviceReferences, String interfaceName) {
+ super(bundleContext, serviceReferences, interfaceName);
+
+ // create the NameClassPair structure
+ m_nameClassPairs = new NameClassPair[m_serviceReferences.length];
+ for(int i = 0; i < m_serviceReferences.length; i++) {
+ Long serviceId = (Long)m_serviceReferences[i].getProperty(Constants.SERVICE_ID);
+ m_nameClassPairs[i] =
+ new NameClassPair(serviceId.toString(), m_interfaceName);
+ }
+ }
+ }
+
+
+ /**
+ * NamingEnumeration that supports calls to Context.listBinding()
+ *
+ * This enumeration will contain a collection of javax.naming.Binding
+ * objects.
+ *
+ * The Binding for each service reference will contain:
+ *
+ * 1. The service ID name
+ * 2. The service interface type (if specified)
+ * 3. The service object itself
+ *
+ * The responsibility for cleaning up the services obtained by
+ * this NamingEnumeration lies with the enumeration itself. The close()
+ * implementation must unget each service reference.
+ *
+ * The caller of the NamingEnumeration is responsible for calling close()
+ * when the caller is finished with the services in the enumeration.
+ *
+ *
+ * @version $Revision$
+ */
+ private static class ListBindingsNamingEnumeration extends ServiceBasedNamingEnumeration {
+
+ private final List m_listOfHandlers = new LinkedList();
+
+ ListBindingsNamingEnumeration(BundleContext bundleContext, ServiceReference[] serviceReferences, OSGiURLParser urlParser) {
+ super(bundleContext, serviceReferences, urlParser.getServiceInterface());
+
+ // setup a Binding object for each ServiceReference
+ m_nameClassPairs = new Binding[m_serviceReferences.length];
+ for(int i = 0; i < m_serviceReferences.length; i++) {
+ Long serviceId = (Long)m_serviceReferences[i].getProperty(Constants.SERVICE_ID);
+ final ServiceReference serviceReference = m_serviceReferences[i];
+ ServiceProxyInfo proxyInfo =
+ createNoRetryProxiedService(bundleContext, urlParser, serviceReference);
+ m_listOfHandlers.add(proxyInfo.getHandler());
+ m_nameClassPairs[i] =
+ new Binding(serviceId.toString(),
+ m_interfaceName,
+ proxyInfo.getService());
+ }
+ }
+
+ public void close() throws NamingException {
+ super.close();
+
+ for(int i = 0; i < m_serviceReferences.length; i++) {
+ m_bundleContext.ungetService(m_serviceReferences[i]);
+ }
+
+ Iterator iterator = m_listOfHandlers.iterator();
+ while(iterator.hasNext()) {
+ NoRetryServiceInvocationHandler handler =
+ (NoRetryServiceInvocationHandler)iterator.next();
+ handler.close();
+ }
+ }
+ }
+
+
+ private static class NoRetryServiceInvocationHandler extends ServiceInvocationHandler {
+ NoRetryServiceInvocationHandler(BundleContext callerBundleContext, ServiceReference serviceReference, OSGiURLParser urlParser, Object osgiService) {
+ super(callerBundleContext, serviceReference, urlParser, osgiService);
+ }
+
+
+ protected boolean obtainService() {
+ m_serviceTracker.close();
+ // always return false, since servicelist proxies must not rebind to a service
+ return false;
+ }
+ }
+
+ private static class NoRetryInvocationHandlerFactory implements InvocationHandlerFactory {
+ public InvocationHandler create(BundleContext bundleContext, ServiceReference serviceReference, OSGiURLParser urlParser, Object osgiService) {
+ return new NoRetryServiceInvocationHandler(bundleContext, serviceReference, urlParser, osgiService);
+ }
+
+ }
+
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/OSGiURLContextFactory.java b/framework/src/main/java/org/eclipse/gemini/naming/OSGiURLContextFactory.java
new file mode 100644
index 0000000..ba21493
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/OSGiURLContextFactory.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.util.Hashtable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+import javax.naming.spi.ObjectFactory;
+
+import org.osgi.framework.AdminPermission;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * A URL context factory that supports lookups of OSGi services.
+ *
+ *
+ */
+class OSGiURLContextFactory implements ObjectFactory {
+
+ private static final String OSGI_BUNDLE_CONTEXT_LOOKUP = "osgi:framework/bundleContext";
+
+ private static final Logger logger = Logger.getLogger(OSGiURLContextFactory.class.getName());
+
+ private final BundleContext m_bundleContext;
+
+ public OSGiURLContextFactory(BundleContext bundleContext) {
+ m_bundleContext = bundleContext;
+ }
+
+ public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
+ return new OSGiURLContext(m_bundleContext);
+ }
+
+ /**
+ * The OSGi URL Context that is handed back to the Gemini Naming Implementation.
+ * <p/>
+ * This URL Context only supports the Context.lookup(String) method.
+ * All other method invocations on this context will result in an
+ * OperationNotSupportedException being thrown.
+ */
+ private static class OSGiURLContext extends NotSupportedContext {
+
+ private final BundleContext m_bundleContext;
+
+ public OSGiURLContext(BundleContext bundleContext) {
+ super("This operation is not supported by the OSGi URL Context");
+ m_bundleContext = bundleContext;
+ }
+
+
+ public Object lookup(String name) throws NamingException {
+ String osgiURL = name;
+ try {
+ if(osgiURL.equals(OSGI_BUNDLE_CONTEXT_LOOKUP)) {
+ // return the caller's BundleContext
+ AdminPermission adminPermission =
+ new AdminPermission(m_bundleContext.getBundle(), AdminPermission.CONTEXT);
+
+ try {
+ AccessController.checkPermission(adminPermission);
+ return m_bundleContext;
+ } catch (AccessControlException accessControlException) {
+ NamingException namingException = new NameNotFoundException("BundleContext not available, caller does not have the correct permission.");
+ namingException.setRootCause(accessControlException);
+ throw namingException;
+ }
+
+ }
+
+ Object requestedService = obtainService(osgiURL);
+ if (requestedService != null) {
+ return requestedService;
+ }
+ }
+ catch (InvalidSyntaxException e) {
+ NamingException namingException = new NamingException(
+ "Error occurred while parsing the OSGi URL");
+ namingException.initCause(e);
+ throw namingException;
+ }
+
+ throw new NameNotFoundException(
+ "The OSGi service referred to by the URL = "
+ + osgiURL
+ + " could not be located in the OSGi Service Registry");
+ }
+
+
+ /**
+ * Obtain the service requested in the "osgi" URL. Currently, this
+ * method uses the Factory Manager's bundle context.
+ *
+ * @param osgiURL the URL for the OSGi service requested
+ * @return the OSGi Service requested, or null if the service cannot be
+ * found
+ * @throws InvalidSyntaxException if an error occurs while parsing the
+ * OSGi filer (if specified)
+ */
+ private Object obtainService(String osgiURL)
+ throws InvalidSyntaxException {
+ OSGiURLParser urlParser = new OSGiURLParser(osgiURL);
+ try {
+ urlParser.parse();
+ }
+ catch (IllegalStateException stateException) {
+ logger.log(Level.SEVERE, "An exception occurred while trying to parse this osgi URL", stateException);
+ return null;
+ }
+ if (urlParser.getServiceInterface() == null) {
+ return null;
+ }
+
+ return getService(m_bundleContext, urlParser);
+ }
+
+ private static Object getService(BundleContext bundleContext, OSGiURLParser urlParser) throws InvalidSyntaxException {
+ ServiceReference[] serviceReferences =
+ bundleContext.getServiceReferences(urlParser.getServiceInterface(),
+ urlParser.getFilter());
+ if (serviceReferences != null) {
+ final ServiceReference[] sortedServiceReferences =
+ ServiceUtils.sortServiceReferences(serviceReferences);
+ if (urlParser.isServiceListURL()) {
+ // return a Context that can handle service.id lookups
+ return new OSGiServiceListContext(bundleContext, sortedServiceReferences, urlParser);
+ }
+ else {
+ ServiceProxyInfo proxyInfo = ReflectionUtils.getProxyForSingleService(bundleContext, urlParser, sortedServiceReferences[0]);
+ return proxyInfo.getService();
+ }
+ }
+ else {
+ // service interface name may not map to a published name
+ // check the registry for a service that supports the
+ // osgi.jndi.serviceName property
+ ServiceReference[] serviceReferencesByName =
+ ServiceUtils.getServiceReferencesByServiceName(bundleContext, urlParser);
+ if (serviceReferencesByName != null) {
+ final ServiceReference[] sortedServiceReferences =
+ ServiceUtils.sortServiceReferences(serviceReferencesByName);
+ ServiceProxyInfo proxyInfo =
+ ReflectionUtils.getProxyForSingleService(bundleContext, urlParser, sortedServiceReferences[0]);
+ return proxyInfo.getService();
+ }
+ }
+
+ return null;
+ }
+
+ }
+
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/OSGiURLContextFactoryServiceFactory.java b/framework/src/main/java/org/eclipse/gemini/naming/OSGiURLContextFactoryServiceFactory.java
new file mode 100644
index 0000000..6e49f0c
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/OSGiURLContextFactoryServiceFactory.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+class OSGiURLContextFactoryServiceFactory implements ServiceFactory {
+
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
+ return new OSGiURLContextFactory(bundle.getBundleContext());
+ }
+
+ public void ungetService(Bundle bundle, ServiceRegistration registration,
+ Object service) {
+ }
+
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/OSGiURLParser.java b/framework/src/main/java/org/eclipse/gemini/naming/OSGiURLParser.java
new file mode 100644
index 0000000..3c8371e
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/OSGiURLParser.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+/**
+ * Utility Class to parse the "osgi:services" URL syntax
+ *
+ */
+class OSGiURLParser {
+
+ private static final String OSGI_SERVICE_PREFIX = "osgi:service/";
+
+ private static final String OSGI_SERVICE_LIST_PREFIX = "osgi:servicelist/";
+
+ private final String m_osgiURL;
+ private String m_serviceInterface = null;
+ private String m_filter = null;
+ private boolean m_parsingCompleted = false;
+ private boolean m_isServiceList = false;
+
+ public OSGiURLParser(String osgiURL) {
+ m_osgiURL = osgiURL;
+ }
+
+ public void parse() {
+ if (m_osgiURL.startsWith(OSGI_SERVICE_PREFIX)) {
+ parseURLData(OSGI_SERVICE_PREFIX);
+ }
+ else {
+ if (m_osgiURL.startsWith(OSGI_SERVICE_LIST_PREFIX)) {
+ parseURLData(OSGI_SERVICE_LIST_PREFIX);
+ m_isServiceList = true;
+ }
+ else {
+ throw new IllegalStateException(
+ "URL '" + m_osgiURL + "'" + "did not conform to the OSGi URL Syntax");
+ }
+
+ }
+ }
+
+
+ public String getServiceInterface() {
+ checkParserState();
+ return m_serviceInterface;
+ }
+
+ public String getFilter() {
+ checkParserState();
+ return m_filter;
+ }
+
+ public boolean hasFilter() {
+ checkParserState();
+ return getFilter() != null;
+ }
+
+ public boolean isServiceListURL() {
+ return m_isServiceList;
+ }
+
+ private void checkParserState() {
+ if (!m_parsingCompleted)
+ throw new IllegalStateException("OSGi URL has not been parsed");
+ }
+
+ private void parseURLData(final String prefix) {
+ String urlData = m_osgiURL.substring(prefix.length());
+ int indexOfSlash = urlData.indexOf("/");
+ if (indexOfSlash != -1) {
+ // interpret everything after the slash to be an OSGi filter
+ // string
+ m_serviceInterface = urlData.substring(0, indexOfSlash);
+ m_filter = urlData.substring(indexOfSlash + 1);
+ }
+ else {
+ m_serviceInterface = urlData;
+ }
+
+ if (m_serviceInterface.length() == 0) {
+ throw new IllegalStateException(
+ "URL did not conform to the OSGi URL Syntax - No Service Interface specified");
+ }
+
+ m_parsingCompleted = true;
+ }
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ProviderAdminImpl.java b/framework/src/main/java/org/eclipse/gemini/naming/ProviderAdminImpl.java
new file mode 100644
index 0000000..64c1f55
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ProviderAdminImpl.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.spi.DirObjectFactory;
+import javax.naming.spi.ObjectFactory;
+
+import org.osgi.framework.BundleContext;
+
+class ProviderAdminImpl implements CloseableProviderAdmin {
+
+ private final OSGiInitialContextFactoryBuilder m_objectFactoryBuilder;
+
+ ProviderAdminImpl(BundleContext bundleContext) {
+ m_objectFactoryBuilder =
+ new OSGiInitialContextFactoryBuilder(bundleContext, bundleContext);
+ }
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Map environment) throws NamingException {
+ synchronized (m_objectFactoryBuilder) {
+ Hashtable jndiEnvironment = new Hashtable();
+ if (environment != null) {
+ jndiEnvironment.putAll(environment);
+ }
+ ObjectFactory objectFactory =
+ m_objectFactoryBuilder.createObjectFactory(refInfo, jndiEnvironment);
+ try {
+ return objectFactory.getObjectInstance(refInfo, name, context, jndiEnvironment);
+ }
+ catch (Exception e) {
+ NamingException namingException = new NamingException(
+ "Error while attempting to resolve reference");
+ namingException.initCause(e);
+ throw namingException;
+ }
+ }
+ }
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Map environment, Attributes attributes) throws NamingException {
+ synchronized (m_objectFactoryBuilder) {
+ Hashtable jndiEnvironment = new Hashtable();
+ if (environment != null) {
+ jndiEnvironment.putAll(environment);
+ }
+ DirObjectFactory dirObjectFactory = m_objectFactoryBuilder
+ .getDirObjectFactory(refInfo, jndiEnvironment);
+ try {
+ return dirObjectFactory.getObjectInstance(refInfo, name,
+ context, jndiEnvironment, attributes);
+ }
+ catch (Exception e) {
+ NamingException namingException = new NamingException(
+ "Error while attempting to resolve reference");
+ namingException.initCause(e);
+ throw namingException;
+ }
+ }
+ }
+
+ public void close() {
+ synchronized (m_objectFactoryBuilder) {
+ m_objectFactoryBuilder.close();
+ }
+ }
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ReflectionUtils.java b/framework/src/main/java/org/eclipse/gemini/naming/ReflectionUtils.java
new file mode 100644
index 0000000..a56c2ec
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ReflectionUtils.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+import java.security.PrivilegedExceptionAction;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.Context;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Utility class for reflection calls made by the Gemini Naming implementation
+ *
+ *
+ * @version $Revision$
+ */
+class ReflectionUtils {
+
+ private static Logger logger = Logger.getLogger(ReflectionUtils.class.getName());
+
+ /**
+ * This method uses reflection to invoke the given Method
+ * on the passed in Context instance. This method also
+ * catches the InvocationTargeException, in order to always
+ * re-throw the original exception from the Method invocation.
+ *
+ * @param method the Method to invoke
+ * @param contextToInvokeOn the Context to invoke the Method on
+ * @param args the arguments to the Method
+ * @return an Object representing the result of the Method call
+ * @throws Throwable
+ */
+ static Object invokeMethodOnContext(Method method, Context contextToInvokeOn, Object[] args) throws Throwable {
+ return invokeMethodOnObject(method, contextToInvokeOn, args);
+ }
+
+
+
+ /**
+ * This method uses reflection to invoke the given Method
+ * on the passed in Object instance. This method also
+ * catches the InvocationTargeException, in order to always
+ * re-throw the original exception from the Method invocation.
+ *
+ * @param method the Method to invoke
+ * @param objectToInvokeOn the Object to invoke the Method on
+ * @param args the arguments to the Method
+ * @return an Object representing the result of the Method call
+ * @throws Throwable
+ */
+ static Object invokeMethodOnObject(Method method, Object objectToInvokeOn, Object[] args) throws IllegalAccessException, Throwable {
+ try {
+ return method.invoke(objectToInvokeOn, args);
+ } catch (InvocationTargetException invocationException) {
+ throw invocationException.getTargetException();
+ }
+ }
+
+
+
+ /**
+ * Creates a dynamic proxy for the given service. This method
+ * installs an InvocationHandler that will manage the dynamics of the
+ * underlying OSGi service (un-bind and re-bind).
+ *
+ * @param bundleContext the BundleContext used to obtain this service
+ * @param urlParser the OSGiURLParser used for this service
+ * @param serviceReference the ServiceReference for the service to proxy
+ * @return a ServiceProxyInfo instance, which includes the proxy or underlying service.
+ */
+ static ServiceProxyInfo getProxyForSingleService(BundleContext bundleContext, OSGiURLParser urlParser, ServiceReference serviceReference) {
+ return getProxyForSingleService(bundleContext,
+ urlParser,
+ serviceReference,
+ new RetryInvocationHandlerFactory());
+ }
+
+
+ /**
+ * Creates a dynamic proxy for the given service. This method
+ * calls on an InvocationHandlerFactory to create the handler associated
+ * with this proxy. This method allows callers to customize the type of
+ * InvocationHandler desired to be used with the proxy.
+ *
+ * @param bundleContext the BundleContext used to obtain this service
+ * @param urlParser the OSGiURLParser used for this service
+ * @param serviceReference the ServiceReference for the service to proxy
+ * @param handlerFactory a factory method for creating the InvocationHandler to be
+ * associated with this service proxy
+ * @return a ServiceProxyInfo instance, which includes the proxy or underlying service.
+ */
+ static ServiceProxyInfo getProxyForSingleService(BundleContext bundleContext, OSGiURLParser urlParser, ServiceReference serviceReference, InvocationHandlerFactory handlerFactory) {
+ final Object requestedService =
+ bundleContext.getService(serviceReference);
+ ClassLoader tempLoader = null;
+ try {
+ tempLoader = (ClassLoader)SecurityUtils.invokePrivilegedAction(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ return requestedService.getClass().getClassLoader();
+ }
+ });
+ } catch (Exception e) {
+ logger.log(Level.FINE,
+ "Exception occurred while trying to obtain OSGi service's ClassLoader",
+ e);
+ }
+
+ try {
+ Class clazz = Class.forName(urlParser.getServiceInterface(), true, tempLoader);
+ if (clazz.isInterface()) {
+ InvocationHandler handler =
+ handlerFactory.create(bundleContext, serviceReference, urlParser, requestedService);
+ final Object serviceProxy = Proxy.newProxyInstance(tempLoader, new Class[] {clazz}, handler);
+ return new ServiceProxyInfo(serviceProxy, handler, true);
+ }
+ else {
+ logger.log(Level.WARNING,
+ "The service type " + clazz.getName() +
+ " is not an interface. The Gemini Naming implementation cannot generate a proxy for this service.");
+ return new ServiceProxyInfo(requestedService, null, false);
+ }
+ }
+ catch (ClassNotFoundException classNotFoundException) {
+ tempLoader = requestedService.getClass().getClassLoader();
+ final Class[] interfaces = getInterfaces(serviceReference, bundleContext, tempLoader);
+ if (interfaces.length > 0) {
+ InvocationHandler handler =
+ handlerFactory.create(bundleContext, serviceReference,
+ urlParser, requestedService);
+ final Object serviceProxy = Proxy.newProxyInstance(tempLoader, interfaces, handler);
+ return new ServiceProxyInfo(serviceProxy, handler, true);
+ }
+ else {
+ logger.log(Level.WARNING,
+ "No compatible interfaces could be found for this OSGi service, type = " +
+ requestedService.getClass().getName() + ". The Gemini Naming implementation cannot generate a proxy for this service.");
+
+ throw new IllegalArgumentException("No compatible interfaces could be found for this OSGi service, type = " +
+ urlParser.getServiceInterface() + " (probably a JNDI Service Name)" + ". The Gemini Naming implementation cannot generate a proxy for this service.");
+ }
+ }
+ }
+
+
+ private static boolean isAssignable(ServiceReference serviceReference, BundleContext bundleContext, Class clazz) {
+ return serviceReference.isAssignableTo(bundleContext.getBundle(), clazz.getName());
+ }
+
+
+
+ private static boolean isInterfacePublic(Class clazz) {
+ return Modifier.isPublic(clazz.getModifiers());
+ }
+
+
+
+ private static Class[] getInterfaces(ServiceReference serviceReference, BundleContext bundleContext, ClassLoader classLoader) {
+ String[] objectClassValues = (String [])serviceReference.getProperty(Constants.OBJECTCLASS);
+ List listOfClasses = new LinkedList();
+ for(int i = 0; i < objectClassValues.length; i++) {
+ try {
+ Class clazz =
+ Class.forName(objectClassValues[i], true, classLoader);
+ if(clazz.isInterface()) {
+ if (isInterfacePublic(clazz)) {
+ if (isAssignable(serviceReference, bundleContext, clazz)) {
+ listOfClasses.add(clazz);
+ }
+ } else {
+ logger.warning("Unable to generate proxy for non-public interface: " +
+ clazz.getName() + ". This interface will not be available to clients");
+ }
+ }
+ }
+ catch (ClassNotFoundException e) {
+ // just continue
+ }
+
+ }
+
+ if(listOfClasses.isEmpty()) {
+ return new Class[0];
+ } else {
+ Class[] interfacesToReturn = new Class[listOfClasses.size()];
+ for(int i = 0; i < listOfClasses.size(); i++) {
+ interfacesToReturn[i] = (Class)listOfClasses.get(i);
+ }
+
+ return interfacesToReturn;
+ }
+ }
+
+ private static class RetryInvocationHandlerFactory implements InvocationHandlerFactory {
+ public InvocationHandler create(BundleContext bundleContext, ServiceReference serviceReference, OSGiURLParser urlParser, Object osgiService) {
+ return new ServiceInvocationHandler(bundleContext,
+ serviceReference,
+ urlParser,
+ osgiService);
+ }
+
+ }
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ReflectiveInvokeAction.java b/framework/src/main/java/org/eclipse/gemini/naming/ReflectiveInvokeAction.java
new file mode 100644
index 0000000..328ffb5
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ReflectiveInvokeAction.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.Method;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * This class represents a privileged action that involves
+ * invoking a method reflectively.
+ *
+ * This class does not make the reflective call. It provides
+ * common exception-handling mechanisms for sub-classes to rely upon.
+ *
+ * @version $Revision$
+ */
+abstract class ReflectiveInvokeAction implements PrivilegedExceptionAction {
+
+ private final Method m_method;
+ private final Object[] m_args;
+
+ ReflectiveInvokeAction(Method method, Object[] args) {
+ m_method = method;
+ m_args = args;
+ }
+
+ public Object run() throws Exception {
+ try {
+ return invokeMethod(m_method, m_args);
+ }
+ catch (Exception exception) {
+ // re-throw exception
+ throw exception;
+ }
+ catch (Throwable throwable) {
+ // the method that was invoked reflectively must have thrown a Throwable
+ // in this case, wrap the Throwable in an exception
+ throw new Exception("Exception occurred during method invocation", throwable);
+ }
+ }
+
+ public abstract Object invokeMethod(Method method, Object[] args) throws Throwable;
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/SecurityAwareContextManagerImpl.java b/framework/src/main/java/org/eclipse/gemini/naming/SecurityAwareContextManagerImpl.java
new file mode 100644
index 0000000..c4539f5
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/SecurityAwareContextManagerImpl.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.security.PrivilegedExceptionAction;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.directory.DirContext;
+
+
+/**
+ * Decorator for the CloseableContextManager that can handle invoking methods on the
+ * underlying context manager implementation in a doPrivileged() Action.
+ *
+ * @version $Revision$
+ */
+class SecurityAwareContextManagerImpl implements CloseableContextManager {
+
+ private static final Logger logger =
+ Logger.getLogger(SecurityAwareContextManagerImpl.class.getName());
+
+ private final CloseableContextManager m_contextManager;
+
+ public SecurityAwareContextManagerImpl(CloseableContextManager contextManager) {
+ m_contextManager = contextManager;
+ }
+
+
+ public Context newInitialContext() throws NamingException {
+ return (Context)invokePrivilegedAction(new NewInitialContextAction());
+ }
+
+
+ public Context newInitialContext(Map environment) throws NamingException {
+ return (Context)invokePrivilegedAction(new NewInitialContextWithEnvironmentAction(environment));
+ }
+
+
+ public DirContext newInitialDirContext() throws NamingException {
+ return (DirContext)invokePrivilegedAction(new NewInitialDirContextAction());
+ }
+
+
+ public DirContext newInitialDirContext(Map environment) throws NamingException {
+ return (DirContext)invokePrivilegedAction(new NewInitialDirContextWithEnvironmentAction(environment));
+ }
+
+ public void close() {
+ invokePrivilegedActionWithoutReturn(new CloseContextManagerAction());
+ }
+
+
+ private static Object invokePrivilegedAction(final PrivilegedExceptionAction action) throws NamingException {
+ try {
+ return SecurityUtils.invokePrivilegedAction(action);
+ } catch (Exception exception) {
+ if(exception instanceof NamingException) {
+ throw (NamingException)exception;
+ } else {
+ logExceptionFromPrivilegedAction(exception);
+
+ NamingException namingException =
+ new NoInitialContextException("Error occurred during a privileged operation");
+ namingException.setRootCause(exception);
+ throw namingException;
+ }
+ }
+ }
+
+ private static void invokePrivilegedActionWithoutReturn(final PrivilegedExceptionAction action) {
+ try {
+ SecurityUtils.invokePrivilegedActionNoReturn(action);
+ }
+ catch (Exception exception) {
+ logExceptionFromPrivilegedAction(exception);
+ }
+ }
+
+
+ private static void logExceptionFromPrivilegedAction(Exception e) {
+ logger.log(Level.FINE,
+ "Exception occurred while invoking a PrivilegedAction",
+ e);
+ }
+
+
+
+ // actions for each of the operations supported by the JNDIContextManager service
+ private class NewInitialContextAction implements PrivilegedExceptionAction {
+ public Object run() throws Exception {
+ return m_contextManager.newInitialContext();
+ }
+ }
+
+ private class NewInitialContextWithEnvironmentAction implements PrivilegedExceptionAction {
+
+ private final Map m_environment;
+
+ public NewInitialContextWithEnvironmentAction(Map environment) {
+ m_environment = environment;
+ }
+
+ public Object run() throws Exception {
+ return m_contextManager.newInitialContext(m_environment);
+ }
+ }
+
+
+ private class NewInitialDirContextAction implements PrivilegedExceptionAction {
+ public Object run() throws Exception {
+ return m_contextManager.newInitialDirContext();
+ }
+ }
+
+ private class NewInitialDirContextWithEnvironmentAction implements PrivilegedExceptionAction {
+ private final Map m_environment;
+
+ public NewInitialDirContextWithEnvironmentAction(Map environment) {
+ m_environment = environment;
+ }
+
+ public Object run() throws Exception {
+ return m_contextManager.newInitialDirContext(m_environment);
+ }
+ }
+
+ private class CloseContextManagerAction implements PrivilegedExceptionAction {
+ public Object run() throws Exception {
+ m_contextManager.close();
+ return null;
+ }
+
+ }
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/SecurityAwareProviderAdminImpl.java b/framework/src/main/java/org/eclipse/gemini/naming/SecurityAwareProviderAdminImpl.java
new file mode 100644
index 0000000..53b4519
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/SecurityAwareProviderAdminImpl.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.security.PrivilegedExceptionAction;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.directory.Attributes;
+
+
+/**
+ * Decorator for the CloseableProviderAdmin that can handle invoking methods on the
+ * underlying JNDIProviderAdmin implementation in a doPrivileged() Action.
+ *
+ *
+ * @version $Revision$
+ */
+class SecurityAwareProviderAdminImpl implements CloseableProviderAdmin {
+
+ private static final Logger logger =
+ Logger.getLogger(SecurityAwareProviderAdminImpl.class.getName());
+
+ private final CloseableProviderAdmin m_closeableProviderAdmin;
+
+ public SecurityAwareProviderAdminImpl(CloseableProviderAdmin closeableProviderAdmin) {
+ m_closeableProviderAdmin = closeableProviderAdmin;
+ }
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Map environment) throws Exception {
+ PrivilegedExceptionAction action =
+ new GetObjectInstanceAction(refInfo, name, context, environment);
+ return invokePrivilegedAction(action);
+ }
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Map environment, Attributes attributes) throws Exception {
+ PrivilegedExceptionAction action =
+ new GetObjectInstanceActionWithAttributes(refInfo, name, context, environment, attributes);
+ return invokePrivilegedAction(action);
+ }
+
+ public void close() {
+ try {
+ SecurityUtils.invokePrivilegedActionNoReturn(new CloseAction());
+ }
+ catch (Exception exception) {
+ logger.log(Level.FINE,
+ "Exception occurred while trying to close this JNDIProviderAdmin implementation",
+ exception);
+ }
+ }
+
+ private static Object invokePrivilegedAction(final PrivilegedExceptionAction action) throws Exception {
+ return SecurityUtils.invokePrivilegedAction(action);
+ }
+
+
+ private class GetObjectInstanceAction implements PrivilegedExceptionAction {
+ protected final Object m_refInfo;
+ protected final Name m_name;
+ protected final Context m_context;
+ protected final Map m_environment;
+
+ GetObjectInstanceAction(Object refInfo, Name name, Context context, Map environment) {
+ m_refInfo = refInfo;
+ m_name = name;
+ m_context = context;
+ m_environment = environment;
+ }
+
+ public Object run() throws Exception {
+ return m_closeableProviderAdmin.getObjectInstance(m_refInfo,
+ m_name,
+ m_context,
+ m_environment);
+ }
+
+ }
+
+ private class GetObjectInstanceActionWithAttributes extends GetObjectInstanceAction {
+ private final Attributes m_attributes;
+
+ GetObjectInstanceActionWithAttributes(Object refInfo, Name name, Context context, Map environment, Attributes attributes) {
+ super(refInfo, name, context, environment);
+ m_attributes = attributes;
+ }
+
+
+ public Object run() throws Exception {
+ return m_closeableProviderAdmin.getObjectInstance(m_refInfo,
+ m_name,
+ m_context,
+ m_environment,
+ m_attributes);
+ }
+
+ }
+
+
+ private class CloseAction implements PrivilegedExceptionAction {
+ public Object run() throws Exception {
+ m_closeableProviderAdmin.close();
+ return null;
+ }
+
+ }
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/SecurityUtils.java b/framework/src/main/java/org/eclipse/gemini/naming/SecurityUtils.java
new file mode 100644
index 0000000..afde5f3
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/SecurityUtils.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * Utility class for security-related operations in the Gemini Naming implementation.
+ *
+ *
+ * @version $Revision$
+ */
+class SecurityUtils {
+
+ private SecurityUtils() {
+ // construction of this object is not allowed
+ }
+
+
+ /**
+ * Invokes the specified action in a doPrivileged() block, and
+ * returns the result.
+ *
+ * @param action the PrivilegedExceptionAction to execute
+ * @return the resulting Object of the operation
+ * @throws Exception the exception thrown (if any) by the action itself
+ */
+ static Object invokePrivilegedAction(final PrivilegedExceptionAction action) throws Exception {
+ try {
+ return AccessController.doPrivileged(action);
+ }
+ catch (PrivilegedActionException e) {
+ throw e.getException();
+ }
+ }
+
+
+ /**
+ * Invokes the specified action, which does not require a return
+ * @param action the PrivilegedExceptionAction to execute
+ * @throws Exception the exception thrown (if any) by the action itself
+ */
+ static void invokePrivilegedActionNoReturn(final PrivilegedExceptionAction action) throws Exception {
+ try {
+ AccessController.doPrivileged(action);
+ }
+ catch (PrivilegedActionException e) {
+ throw e.getException();
+ }
+ }
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ServiceAwareContextFactory.java b/framework/src/main/java/org/eclipse/gemini/naming/ServiceAwareContextFactory.java
new file mode 100644
index 0000000..6921f71
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ServiceAwareContextFactory.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.security.PrivilegedExceptionAction;
+import java.util.Hashtable;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.directory.DirContext;
+import javax.naming.spi.InitialContextFactory;
+
+public class ServiceAwareContextFactory {
+
+ private static Logger logger = Logger.getLogger(ServiceAwareContextFactory.class.getName());
+
+ /* private constructor to disallow creation of this class */
+ private ServiceAwareContextFactory() {}
+
+ public static Context createServiceAwareContextWrapper(InitialContextFactory factory, Context internalContext, FactoryManager manager) {
+ return (Context) Proxy.newProxyInstance(ServiceAwareContextFactory.class.getClassLoader(),
+ new Class[] {Context.class},
+ new DefaultServiceAwareInvocationHandler(factory, internalContext, manager));
+ }
+
+ public static DirContext createServiceAwareDirContextWrapper(InitialContextFactory factory, DirContext internalContext, FactoryManager manager) {
+ return (DirContext) Proxy.newProxyInstance(ServiceAwareContextFactory.class.getClassLoader(),
+ new Class[] {DirContext.class},
+ new DefaultServiceAwareInvocationHandler(factory, internalContext, manager));
+ }
+
+ private static class DefaultServiceAwareInvocationHandler implements InvocationHandler {
+
+ private InitialContextFactory m_factory;
+ private Context m_context;
+ private final FactoryManager m_manager;
+ private boolean m_isOpen;
+
+ DefaultServiceAwareInvocationHandler(InitialContextFactory factory, Context context, FactoryManager manager) {
+ m_factory = factory;
+ m_context = context;
+ m_manager = manager;
+ m_isOpen = true;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ synchronized (this) {
+ synchronized (m_manager) {
+ try {
+ return invokeContextMethod(method, args);
+ }
+ catch (Exception exception) {
+ if(exception instanceof NamingException) {
+ throw (NamingException)exception;
+ }
+
+ logger.log(Level.FINE,
+ "Exception occurred during a doPrivileged call",
+ exception);
+ // if the cause was not a NamingException, wrap the
+ // cause in NamingException and throw back to caller
+ NamingException namingException = new NamingException("Exception occured during a Context method invocation");
+ namingException.setRootCause(exception);
+ throw namingException;
+ }
+ }
+ }
+ }
+
+ private Object invokeContextMethod(Method method, Object[] args) throws Throwable {
+ if (m_isOpen) {
+ if (isFactoryServiceActive()
+ || method.getName().equals("close")) {
+
+ if (method.getName().equals("close")) {
+ m_isOpen = false;
+ }
+
+ return ReflectionUtils.invokeMethodOnContext(method, m_context, args);
+ }
+ else {
+ return SecurityUtils.invokePrivilegedAction(new ObtainFactoryAndInvokeAction(method, args));
+ }
+ } else {
+ // if context is already closed, do not try to
+ // rebind the backing service
+ // simply forward the call to the underlying context implementation
+ return ReflectionUtils.invokeMethodOnContext(method, m_context, args);
+ }
+ }
+
+ private Object obtainNewFactoryAndInvoke(Method method, Object[] args) throws NamingException, Throwable, NoInitialContextException {
+ // make copy of existing context's environment
+ Hashtable newContextEnvironment = new Hashtable();
+ if (m_context.getEnvironment() != null) {
+ newContextEnvironment.putAll(m_context
+ .getEnvironment());
+ }
+ // attempt to recreate the required factory and context
+ try {
+ InitialContextFactory newFactory = m_manager
+ .createInitialContextFactory(newContextEnvironment);
+ if (newFactory != null) {
+ m_factory = newFactory;
+ Context newInternalContext = m_factory
+ .getInitialContext(newContextEnvironment);
+ if (newInternalContext != null) {
+ m_context = newInternalContext;
+ return ReflectionUtils.invokeMethodOnContext(method, m_context, args);
+ }
+ }
+ }
+ catch (NoInitialContextException noContextException) {
+ logger.log(Level.SEVERE,
+ "An exception occurred while attempting to rebind the JNDI Provider service for this Context",
+ noContextException);
+ }
+
+ // if no InitialContextFactory service can handle this request, throw exception
+ throw new NoInitialContextException(
+ "The service that created this JNDI Context is not available");
+ }
+
+
+ /**
+ * Query to see if the IntialContextFactory used
+ * to create this context is still active
+ *
+ * @return true if factory service is still active
+ * false if factory service is no longer active
+ */
+ private boolean isFactoryServiceActive() {
+ if(m_factory instanceof BuilderSupportedInitialContextFactory) {
+ return m_manager.isFactoryServiceActive(((BuilderSupportedInitialContextFactory)m_factory).getBuilder());
+ } else {
+ return m_manager.isFactoryServiceActive(m_factory);
+ }
+ }
+
+ private class ObtainFactoryAndInvokeAction implements PrivilegedExceptionAction {
+
+ private final Method m_method;
+ private final Object[] m_args;
+
+ ObtainFactoryAndInvokeAction(Method method, Object[] args) {
+ m_method = method;
+ m_args = args;
+ }
+
+ public Object run() throws Exception {
+ try {
+ return obtainNewFactoryAndInvoke(m_method, m_args);
+ } catch (Throwable e) {
+ if(e instanceof NamingException) {
+ throw (NamingException)e;
+ }
+
+ NamingException namingException = new NamingException("Error while attempting to obtain factory service on behalf of Context");
+ namingException.setRootCause(e);
+ throw namingException;
+ }
+ }
+
+ }
+
+ }
+}
+
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ServiceBasedNamingEnumeration.java b/framework/src/main/java/org/eclipse/gemini/naming/ServiceBasedNamingEnumeration.java
new file mode 100644
index 0000000..b0de740
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ServiceBasedNamingEnumeration.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.NoSuchElementException;
+
+import javax.naming.NameClassPair;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Abstract NamingEnumeration implementation that contains the
+ * basic logic for an enumeration over a set of NameClassPair objects.
+ *
+ *
+ *
+ *
+ * @version $Revision$
+ */
+abstract class ServiceBasedNamingEnumeration implements NamingEnumeration {
+
+ protected boolean m_isOpen = false;
+ protected int m_index = -1;
+ protected final BundleContext m_bundleContext;
+ protected final String m_interfaceName;
+ protected final ServiceReference[] m_serviceReferences;
+ protected NameClassPair[] m_nameClassPairs;
+
+ public ServiceBasedNamingEnumeration(BundleContext bundleContext, ServiceReference[] serviceReferences, String interfaceName) {
+ m_bundleContext = bundleContext;
+ if(interfaceName == null) {
+ m_interfaceName = "";
+ } else {
+ m_interfaceName = interfaceName;
+ }
+
+ m_serviceReferences = serviceReferences;
+ if(m_serviceReferences.length > 0) {
+ m_isOpen = true;
+ m_index = 0;
+ }
+ }
+
+ public void close() throws NamingException {
+ m_isOpen = false;
+ }
+
+ public boolean hasMore() throws NamingException {
+ checkIsOpen();
+ return (isIndexValid());
+ }
+
+ public Object next() throws NamingException {
+ checkIsOpen();
+ return internalNextElement();
+ }
+
+ public boolean hasMoreElements() {
+ if(!m_isOpen) {
+ return false;
+ } else {
+ return (isIndexValid());
+ }
+
+ }
+
+ public Object nextElement() {
+ return internalNextElement();
+ }
+
+ private void checkIsOpen() throws NamingException {
+ if (!m_isOpen) {
+ throw new NamingException("Operation cannot complete, since this NamingEnumeration has been closed");
+ }
+ }
+
+ private boolean isIndexValid() {
+ return m_index < m_nameClassPairs.length;
+ }
+
+ private Object internalNextElement() {
+ if(isIndexValid()) {
+ return internalNextClassPair();
+ } else {
+ throw new NoSuchElementException("No additional elements exist in this NamingEnumeration");
+ }
+ }
+
+ private NameClassPair internalNextClassPair() {
+ return m_nameClassPairs[m_index++];
+ }
+
+} \ No newline at end of file
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ServiceInvocationHandler.java b/framework/src/main/java/org/eclipse/gemini/naming/ServiceInvocationHandler.java
new file mode 100644
index 0000000..765991b
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ServiceInvocationHandler.java
@@ -0,0 +1,176 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+class ServiceInvocationHandler implements InvocationHandler {
+
+ private static final Logger logger = Logger.getLogger(ServiceInvocationHandler.class.getName());
+
+ private final BundleContext m_callerBundleContext;
+
+ /* backing OSGi service */
+ private Object m_osgiService;
+
+ /* service tracker for the backing service */
+ protected ServiceTracker m_serviceTracker;
+
+ /* ServiceReference for the backing service */
+ private ServiceReference m_serviceReference;
+
+ /* the URL information used to rebind the backing service if necessary */
+ private final OSGiURLParser m_urlParser;
+
+
+ ServiceInvocationHandler(BundleContext callerBundleContext, ServiceReference serviceReference, OSGiURLParser urlParser, Object osgiService) {
+ m_callerBundleContext = callerBundleContext;
+ // initialize backing service
+ m_osgiService = osgiService;
+ m_serviceReference = serviceReference;
+ m_urlParser = urlParser;
+
+ // open a tracker for just this service
+ m_serviceTracker =
+ new ServiceTracker(m_callerBundleContext, m_serviceReference, null);
+ m_serviceTracker.open();
+ }
+
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ return SecurityUtils.invokePrivilegedAction(new ServiceInvokeAction(method, args));
+ }
+
+
+ private Object handleMethodInvocation(Method method, Object[] args) throws Throwable {
+ if (isServiceAvailable()) {
+ return invokeMethodOnService(method, args);
+ } else {
+ // attempt to obtain another service reference to match this interface
+ if(obtainService()) {
+ return invokeMethodOnService(method, args);
+ }
+ }
+
+ throw new ServiceException("Backing service is not available for invocation",
+ ServiceException.UNREGISTERED);
+ }
+
+
+ private Object invokeMethodOnService(Method method, Object[] args) throws Throwable {
+ try {
+ return ReflectionUtils.invokeMethodOnObject(method, m_osgiService, args);
+ }
+ catch (IllegalAccessException illegalAccessException) {
+ throw new ServiceException("An error occurred while trying to invoke on this service, please verify that this service's interface is public", illegalAccessException);
+ }
+ }
+
+ protected void close() {
+ try {
+ m_callerBundleContext.ungetService(m_serviceReference);
+ }
+ catch (Throwable throwable) {
+ logger.log(Level.FINER,
+ "An Exception occurred while trying to unget the backing OSGi service",
+ throwable);
+ }
+
+ m_serviceTracker.close();
+ }
+
+
+
+ protected void finalize() throws Throwable {
+ close();
+ }
+
+
+ private boolean isServiceAvailable() {
+ return m_serviceTracker.size() == 1;
+ }
+
+ protected boolean obtainService() {
+ m_serviceTracker.close();
+ try {
+ ServiceReference[] serviceReferences =
+ m_callerBundleContext.getServiceReferences(m_urlParser.getServiceInterface(),
+ m_urlParser.getFilter());
+ if (serviceReferences != null) {
+ final ServiceReference[] sortedServiceReferences =
+ ServiceUtils.sortServiceReferences(serviceReferences);
+
+ // reset the tracker
+ return resetBackingService(sortedServiceReferences[0]);
+ } else {
+ // attempt to locate service using service name property
+ ServiceReference[] serviceReferencesByName =
+ ServiceUtils.getServiceReferencesByServiceName(m_callerBundleContext, m_urlParser);
+ if (serviceReferencesByName != null) {
+ ServiceReference[] sortedServiceReferences =
+ ServiceUtils.sortServiceReferences(serviceReferencesByName);
+ // reset the tracker
+ return resetBackingService(sortedServiceReferences[0]);
+ }
+
+ }
+ }
+ catch (InvalidSyntaxException invalidSyntaxException) {
+ logger.log(Level.SEVERE,
+ "An error in the filter syntax for this OSGi lookup has occurred.",
+ invalidSyntaxException);
+ }
+
+ return false;
+ }
+
+
+ private boolean resetBackingService(ServiceReference serviceReference) {
+ m_serviceTracker =
+ new ServiceTracker(m_callerBundleContext, serviceReference, null);
+ m_serviceTracker.open();
+
+ // reset the service
+ m_osgiService = m_serviceTracker.getService();
+ if(m_osgiService!= null) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ private class ServiceInvokeAction extends ReflectiveInvokeAction {
+
+ ServiceInvokeAction(Method method, Object[] args) {
+ super(method, args);
+ }
+
+ public Object invokeMethod(Method method, Object[] args) throws Throwable {
+ return handleMethodInvocation(method, args);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ServiceProxyInfo.java b/framework/src/main/java/org/eclipse/gemini/naming/ServiceProxyInfo.java
new file mode 100644
index 0000000..e4d32ac
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ServiceProxyInfo.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.InvocationHandler;
+
+/**
+ * Data class to hold the information on a dynamic proxy
+ * for a given OSGi service, including whether the proxy
+ * was actually created.
+ *
+ *
+ * @version $Revision$
+ */
+class ServiceProxyInfo {
+ final Object m_service;
+ final InvocationHandler m_handler;
+ final boolean m_isProxied;
+
+ ServiceProxyInfo(Object service, InvocationHandler handler, boolean isProxied) {
+ m_service = service;
+ m_handler = handler;
+ m_isProxied = isProxied;
+ }
+
+ Object getService() {
+ return m_service;
+ }
+
+ InvocationHandler getHandler() {
+ return m_handler;
+ }
+
+ boolean isProxied() {
+ return m_isProxied;
+ }
+} \ No newline at end of file
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/ServiceUtils.java b/framework/src/main/java/org/eclipse/gemini/naming/ServiceUtils.java
new file mode 100644
index 0000000..855324b
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/ServiceUtils.java
@@ -0,0 +1,105 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.jndi.JNDIConstants;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * This class holds utility methods for handling OSGi services/service references
+ *
+ *
+ *
+ * @version $Revision$
+ */
+class ServiceUtils {
+ /* private constructor, static utility class */
+ private ServiceUtils() {}
+
+ /**
+ * Utility method to sort an array of ServiceReferences using the service
+ * ranking (if specified).
+ *
+ * This utility should follow any service ranking rules already defined in
+ * the OSGi specification.
+ *
+ * @param serviceTracker tracker to use to provide the initial array to sort
+ * @return sorted array of ServiceReferences, or a zero-length array if no
+ * matching services were found
+ */
+ static ServiceReference[] sortServiceReferences(ServiceTracker serviceTracker) {
+ final ServiceReference[] serviceReferences = serviceTracker
+ .getServiceReferences();
+ if (serviceReferences == null) {
+ return new ServiceReference[0];
+ }
+
+ return sortServiceReferences(serviceReferences);
+ }
+
+
+ /**
+ * Utility method to sort an array of ServiceReferences using the OSGi
+ * service ranking.
+ *
+ * This utility should follow any service ranking rules already defined in
+ * the OSGi specification.
+ *
+ *
+ * @param serviceReferences an array of ServiceReferences to sort
+ * @return the array of ServiceReferences passed into this method, but sorted
+ * according to OSGi service ranking.
+ */
+ static ServiceReference[] sortServiceReferences(
+ final ServiceReference[] serviceReferences) {
+ Arrays.sort(serviceReferences, new Comparator() {
+ public int compare(Object objectOne, Object objectTwo) {
+ ServiceReference serviceReferenceOne = (ServiceReference) objectOne;
+ ServiceReference serviceReferenceTwo = (ServiceReference) objectTwo;
+ return serviceReferenceTwo.compareTo(serviceReferenceOne);
+ }
+ });
+
+ return serviceReferences;
+ }
+
+
+ /**
+ * Utility method to obtain the list of ServiceReferences that match
+ * a query using the JNDI "service name" service property.
+ *
+ * @param bundleContext the BundleContext to use to obtain services
+ * @param urlParser the parser associated with this request
+ * @return an array of ServiceReferences that match the given request
+ * @throws InvalidSyntaxException on filter parsing error
+ */
+ static ServiceReference[] getServiceReferencesByServiceName(BundleContext bundleContext, OSGiURLParser urlParser)
+ throws InvalidSyntaxException {
+ final String serviceNameFilter = "("
+ + JNDIConstants.JNDI_SERVICENAME + "="
+ + urlParser.getServiceInterface() + ")";
+ ServiceReference[] serviceReferencesByName =
+ bundleContext.getServiceReferences(null, serviceNameFilter);
+ return serviceReferencesByName;
+ }
+
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/TraditionalInitialContextFactoryBuilder.java b/framework/src/main/java/org/eclipse/gemini/naming/TraditionalInitialContextFactoryBuilder.java
new file mode 100644
index 0000000..29bbe67
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/TraditionalInitialContextFactoryBuilder.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.NoInitialContextException;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.jndi.JNDIContextManager;
+
+class TraditionalInitialContextFactoryBuilder implements InitialContextFactoryBuilder {
+
+ private static final String JNDI_CONTEXT_MANAGER_CLASS =
+ JNDIContextManager.class.getName();
+
+ private static final String INITIAL_CONTEXT_CLASSNAME =
+ InitialContext.class.getName();
+
+ private static final String INITIAL_DIR_CONTEXT_CLASSNAME =
+ InitialDirContext.class.getName();
+
+ public TraditionalInitialContextFactoryBuilder() {
+ }
+
+ public InitialContextFactory createInitialContextFactory(Hashtable environment) throws NamingException {
+ return new TraditionalInitialContextFactory();
+ }
+
+
+
+ /**
+ * An InitialContextFactory implementation that handles requests from
+ * "traditional" clients (non-OSGi clients).
+ *
+ * This factory first attempts to obtain the client's BundleContext. If this BundleContext
+ * cannot be located, a NoInitialContextException is thrown.
+ *
+ *
+ * @version $Revision$
+ */
+ private static class TraditionalInitialContextFactory implements InitialContextFactory {
+
+ public Context getInitialContext(Hashtable environment) throws NamingException {
+ // try to find BundleContext, assuming a call to the InitialContext constructor
+ BundleContext clientBundleContext =
+ BuilderUtils.getBundleContext(environment, INITIAL_CONTEXT_CLASSNAME);
+
+ if(clientBundleContext == null) {
+ // try to find BundleContext, assuming a call to the InitialDirContext constructor
+ clientBundleContext =
+ BuilderUtils.getBundleContext(environment, INITIAL_DIR_CONTEXT_CLASSNAME);
+ }
+
+
+ if(clientBundleContext == null) {
+ throw new NoInitialContextException("Client's BundleContext could not be located");
+ } else {
+ ServiceReference serviceRef =
+ clientBundleContext.getServiceReference(JNDI_CONTEXT_MANAGER_CLASS);
+
+ // if service not available, throw exception back to caller
+ if(serviceRef == null) {
+ throw new NamingException("JNDIContextManager service not available yet, cannot create a new context");
+ } else {
+ JNDIContextManager contextManager =
+ (JNDIContextManager)clientBundleContext.getService(serviceRef);
+ if(contextManager == null) {
+ throw new NamingException("JNDIContextManager service not available yet, cannot create a new context");
+ } else {
+ // install a dynamic proxy to trap calls to Context.close()
+ try {
+ final Context newInitialContext = contextManager.newInitialContext(environment);
+ final TraditionalContextInvocationHandler handler =
+ new TraditionalContextInvocationHandler(serviceRef, newInitialContext, clientBundleContext);
+ // create the correct proxy
+ if(newInitialContext instanceof DirContext) {
+ return (DirContext)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {DirContext.class}, handler);
+ } else {
+ return (Context)Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[] {Context.class}, handler);
+ }
+
+ }
+ catch (NamingException namingException) {
+ // clean up reference to JNDIContextManager service
+ clientBundleContext.ungetService(serviceRef);
+ // re-throw exception
+ throw namingException;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private static class TraditionalContextInvocationHandler implements InvocationHandler {
+
+ private final ServiceReference m_referenceToContextManager;
+ private final Context m_context;
+ private final BundleContext m_bundleContext;
+
+ TraditionalContextInvocationHandler(ServiceReference refToContextManager, Context context, BundleContext bundleContext) {
+ m_referenceToContextManager = refToContextManager;
+ m_context = context;
+ m_bundleContext = bundleContext;
+
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ if(method.getName().equals("close")) {
+ // clean up reference to JNDIContextManager
+ m_bundleContext.ungetService(m_referenceToContextManager);
+ }
+
+ return ReflectionUtils.invokeMethodOnContext(method, m_context, args);
+ }
+ }
+
+}
diff --git a/framework/src/main/java/org/eclipse/gemini/naming/TraditionalObjectFactoryBuilder.java b/framework/src/main/java/org/eclipse/gemini/naming/TraditionalObjectFactoryBuilder.java
new file mode 100644
index 0000000..3ed3af3
--- /dev/null
+++ b/framework/src/main/java/org/eclipse/gemini/naming/TraditionalObjectFactoryBuilder.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import javax.naming.spi.DirObjectFactory;
+import javax.naming.spi.DirectoryManager;
+import javax.naming.spi.NamingManager;
+import javax.naming.spi.ObjectFactory;
+import javax.naming.spi.ObjectFactoryBuilder;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.jndi.JNDIProviderAdmin;
+
+class TraditionalObjectFactoryBuilder implements ObjectFactoryBuilder {
+
+ private static final String JNDI_PROVIDER_ADMIN_INTERFACE =
+ JNDIProviderAdmin.class.getName();
+
+ private static final String NAMING_MANAGER_CLASSNAME =
+ NamingManager.class.getName();
+
+ private static final String DIRECTORY_MANAGER_CLASSNAME =
+ DirectoryManager.class.getName();
+
+
+ public TraditionalObjectFactoryBuilder() {
+ }
+
+ public ObjectFactory createObjectFactory(Object obj, Hashtable environment) throws NamingException {
+ // if the call came from NamingManager
+ BundleContext clientBundleContext =
+ BuilderUtils.getBundleContext(environment, NAMING_MANAGER_CLASSNAME);
+
+ // if the call came from DirectoryManager
+ if(clientBundleContext == null) {
+ clientBundleContext =
+ BuilderUtils.getBundleContext(environment, DIRECTORY_MANAGER_CLASSNAME);
+ }
+
+ return new TraditionalObjectFactory(clientBundleContext);
+ }
+
+ private class TraditionalObjectFactory implements DirObjectFactory {
+
+ private final BundleContext m_clientBundleContext;
+
+ TraditionalObjectFactory(BundleContext clientBundleContext) {
+ m_clientBundleContext = clientBundleContext;
+ }
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment) throws Exception {
+ ProviderAdminAction providerAdminAction =
+ new NamingManagerAction(refInfo, name, context, environment);
+ return resolveObjectWithProviderAdmin(providerAdminAction);
+ }
+
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context, Hashtable environment, Attributes attributes) throws Exception {
+ ProviderAdminAction providerAdminAction =
+ new DirectoryManagerAction(refInfo, name, context, environment, attributes);
+ return resolveObjectWithProviderAdmin(providerAdminAction);
+ }
+
+
+ /**
+ * Utility method used to keep the code for obtaining the JNDIProviderAdmin service in a common place. This allows
+ * for simpler managing of service references.
+ * @param providerAdminAction the action to perform on the JNDIProviderAdmin service
+ * @return the result Object of the call to the JNDIProviderAdmin service
+ * @throws Exception
+ */
+ private Object resolveObjectWithProviderAdmin(ProviderAdminAction providerAdminAction) throws Exception {
+ if(m_clientBundleContext == null) {
+ throw new NamingException("Error in obtaining client's BundleContext");
+ } else {
+ ServiceReference serviceReference =
+ m_clientBundleContext.getServiceReference(JNDI_PROVIDER_ADMIN_INTERFACE);
+ if(serviceReference == null) {
+ throw new NamingException("JNDIProviderAdmin service not available, cannot resolve object at this time");
+ } else {
+ JNDIProviderAdmin providerAdmin =
+ (JNDIProviderAdmin)m_clientBundleContext.getService(serviceReference);
+ if(providerAdmin == null) {
+ throw new NamingException("JNDIProviderAdmin service not available, cannot resolve object at this time");
+ } else {
+ final Object resolvedObject = providerAdminAction.runProviderAdminAction(providerAdmin);
+ // clean up reference to the provider admin service
+ m_clientBundleContext.ungetService(serviceReference);
+ // return result
+ return resolvedObject;
+ }
+ }
+ }
+ }
+
+
+ }
+
+ /**
+ * Internal interface meant to represent a generic action on the JNDIProviderAdmin service.
+ *
+ * @version $Revision$
+ */
+ private interface ProviderAdminAction {
+ Object runProviderAdminAction(JNDIProviderAdmin providerAdmin) throws Exception;
+ }
+
+ /**
+ * A ProviderAdminAction implementation that follows the behavior of
+ * NamingManager.getObjectInstance().
+ *
+ * @version $Revision$
+ */
+ private static class NamingManagerAction implements ProviderAdminAction {
+ protected final Object m_refInfo;
+ protected final Name m_name;
+ protected final Context m_context;
+ protected final Hashtable m_environment;
+
+ NamingManagerAction(Object refInfo, Name name, Context context, Hashtable environment) {
+ m_refInfo = refInfo;
+ m_name = name;
+ m_context = context;
+ m_environment = environment;
+ }
+
+ public Object runProviderAdminAction(JNDIProviderAdmin providerAdmin) throws Exception {
+ return providerAdmin.getObjectInstance(m_refInfo, m_name, m_context, m_environment);
+ }
+ }
+
+ /**
+ * A ProviderAdminAction implementation that follows the behavior of
+ * DirectoryManager.getObjectInstance().
+ *
+ * @version $Revision$
+ */
+ private static class DirectoryManagerAction extends NamingManagerAction {
+ private final Attributes m_attributes;
+
+ DirectoryManagerAction(Object refInfo, Name name, Context context, Hashtable environment, Attributes attributes) {
+ super(refInfo, name, context, environment);
+ m_attributes = attributes;
+ }
+
+ public Object runProviderAdminAction(JNDIProviderAdmin providerAdmin) throws Exception {
+ return providerAdmin.getObjectInstance(m_refInfo, m_name, m_context, m_environment, m_attributes);
+ }
+ }
+
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/ActivatorTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/ActivatorTestCase.java
new file mode 100644
index 0000000..da5b304
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/ActivatorTestCase.java
@@ -0,0 +1,309 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.Field;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import javax.naming.NamingException;
+import javax.naming.spi.DirObjectFactory;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+import javax.naming.spi.NamingManager;
+import javax.naming.spi.ObjectFactory;
+import javax.naming.spi.ObjectFactoryBuilder;
+
+import org.easymock.EasyMockSupport;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.jndi.JNDIConstants;
+import org.osgi.service.jndi.JNDIContextManager;
+import org.osgi.service.jndi.JNDIProviderAdmin;
+
+import static org.easymock.EasyMock.*;
+
+import junit.framework.TestCase;
+
+public class ActivatorTestCase extends TestCase {
+
+ public void setUp() {
+ setNamingManagerStaticFieldToNull("initctx_factory_builder");
+ setNamingManagerStaticFieldToNull("object_factory_builder");
+ }
+
+ public void tearDown() {
+ setNamingManagerStaticFieldToNull("initctx_factory_builder");
+ setNamingManagerStaticFieldToNull("object_factory_builder");
+ }
+
+
+ /**
+ * Verify the basic startup of the Gemini Naming Activator.
+ *
+ * This test method verifies that all the expected services are
+ * registered using the correct interface, actual type, and service
+ * properties.
+ */
+ public void testStart() throws Exception {
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+
+ setupBundleContextMock(mockSupport, bundleContextMock);
+ // expect OSGi URLContextFactory
+ Hashtable<String, Object> serviceProperties = new Hashtable<String, Object>();
+ serviceProperties.put(JNDIConstants.JNDI_URLSCHEME, "osgi");
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ ObjectFactory.class.getName(),
+ OSGiURLContextFactoryServiceFactory.class,
+ serviceProperties);
+
+ // expect the "default" InitialContextFactoryBuilder
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ InitialContextFactoryBuilder.class.getName(),
+ DefaultRuntimeInitialContextFactoryBuilder.class,
+ null);
+
+ // expect the JNDIContextManager service registration
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ JNDIContextManager.class.getName(),
+ ContextManagerServiceFactoryImpl.class,
+ null);
+ // expect the JNDIProviderAdmin service registration
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ JNDIProviderAdmin.class.getName(),
+ SecurityAwareProviderAdminImpl.class,
+ null);
+
+
+ mockSupport.replayAll();
+
+ // begin test
+ Activator activator = new Activator();
+ activator.start(bundleContextMock);
+
+ // verify that the static singletons are set as expected
+ assertTrue("Activator did not set the InitialContextFactoryBuilder singleton correctly",
+ getPrivateStaticField(NamingManager.class, "initctx_factory_builder") instanceof TraditionalInitialContextFactoryBuilder);
+ assertTrue("Activator did not set the ObjectFactoryBuilder singleton correctly",
+ getPrivateStaticField(NamingManager.class, "object_factory_builder") instanceof TraditionalObjectFactoryBuilder);
+
+ // stop() should complete without any exceptions
+ activator.stop(bundleContextMock);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testRegistrationOfContextBuilderError() throws Exception {
+ // setup test mocks
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ InitialContextFactoryBuilder builderMock =
+ mockSupport.createMock(InitialContextFactoryBuilder.class);
+ if(!NamingManager.hasInitialContextFactoryBuilder()) {
+ NamingManager.setInitialContextFactoryBuilder(builderMock);
+ }
+
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ setupBundleContextMock(mockSupport, bundleContextMock);
+ // expect OSGi URLContextFactory
+ Hashtable<String, Object> serviceProperties = new Hashtable<String, Object>();
+ serviceProperties.put(JNDIConstants.JNDI_URLSCHEME, "osgi");
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ ObjectFactory.class.getName(),
+ OSGiURLContextFactoryServiceFactory.class, serviceProperties);
+
+ // expect the "default" InitialContextFactoryBuilder
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ InitialContextFactoryBuilder.class.getName(),
+ DefaultRuntimeInitialContextFactoryBuilder.class,
+ null);
+
+ // expect the JNDIContextManager service registration
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ JNDIContextManager.class.getName(),
+ ContextManagerServiceFactoryImpl.class,
+ null);
+ // expect the JNDIProviderAdmin service registration
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ JNDIProviderAdmin.class.getName(),
+ SecurityAwareProviderAdminImpl.class,
+ null);
+
+
+ mockSupport.replayAll();
+
+ // begin test
+ Activator activator = new Activator();
+ try {
+ activator.start(bundleContextMock);
+ fail("NamingException should have been thrown");
+ } catch (NamingException namingException) {
+ // expected exception
+ }
+
+ mockSupport.verifyAll();
+
+ }
+
+
+ public void testRegistrationOfObjectFactoryBuilderError() throws Exception {
+ // setup test mocks
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ ObjectFactoryBuilder builderMock =
+ mockSupport.createMock(ObjectFactoryBuilder.class);
+
+ try {
+ // try to set builder, to guarantee
+ // that Activator's attempt to set this will fail
+ NamingManager.setObjectFactoryBuilder(builderMock);
+ } catch (Throwable throwable) {
+ // if already set, test can continue
+ }
+
+
+
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ setupBundleContextMock(mockSupport, bundleContextMock);
+ // expect OSGi URLContextFactory
+ Hashtable<String, Object> serviceProperties = new Hashtable<String, Object>();
+ serviceProperties.put(JNDIConstants.JNDI_URLSCHEME, "osgi");
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ ObjectFactory.class.getName(),
+ OSGiURLContextFactoryServiceFactory.class, serviceProperties);
+
+ // expect the "default" InitialContextFactoryBuilder
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ InitialContextFactoryBuilder.class.getName(),
+ DefaultRuntimeInitialContextFactoryBuilder.class,
+ null);
+
+ // expect the JNDIContextManager service registration
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ JNDIContextManager.class.getName(),
+ ContextManagerServiceFactoryImpl.class,
+ null);
+ // expect the JNDIProviderAdmin service registration
+ setServiceRegistrationExpectation(mockSupport, bundleContextMock,
+ JNDIProviderAdmin.class.getName(),
+ SecurityAwareProviderAdminImpl.class,
+ null);
+
+
+ mockSupport.replayAll();
+
+ // begin test
+ Activator activator = new Activator();
+ try {
+ activator.start(bundleContextMock);
+ fail("NamingException should have been thrown");
+ } catch (NamingException namingException) {
+ // expected exception
+ }
+
+ mockSupport.verifyAll();
+
+ }
+
+ /* test utility methods/classes */
+
+ private static void setupBundleContextMock(EasyMockSupport mockSupport, BundleContext bundleContextMock) throws InvalidSyntaxException {
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ expect(bundleContextMock.createFilter("(objectClass=" + InitialContextFactory.class.getName() + ")")).andReturn(filterMock);
+ expect(bundleContextMock.createFilter("(objectClass=" + InitialContextFactoryBuilder.class.getName() + ")")).andReturn(filterMock);
+ expect(bundleContextMock.createFilter("(objectClass=" + ObjectFactory.class.getName() + ")")).andReturn(filterMock).anyTimes();
+ expect(bundleContextMock.createFilter("(objectClass=" + DirObjectFactory.class.getName() + ")")).andReturn(filterMock);
+ expect(bundleContextMock.createFilter("(objectClass=" + ObjectFactoryBuilder.class.getName() + ")")).andReturn(filterMock);
+
+ bundleContextMock.addServiceListener(isA(ServiceListener.class), isA(String.class));
+ expectLastCall().anyTimes();
+
+ bundleContextMock.removeServiceListener(isA(ServiceListener.class));
+ expectLastCall().anyTimes();
+
+ expect(bundleContextMock.getServiceReferences(isA(String.class), isA(String.class))).andReturn(new ServiceReference[0]).anyTimes();
+ expect(bundleContextMock.getServiceReferences(isA(String.class), (String)isNull())).andReturn(new ServiceReference[0]).anyTimes();
+ }
+
+ private static <T> void setServiceRegistrationExpectation(EasyMockSupport mockSupport, BundleContext bundleContextMock, String serviceName, Class<T> serviceType, Dictionary<String, Object> serviceProperties) {
+ ServiceRegistration serviceRegistrationMock =
+ mockSupport.createMock(ServiceRegistration.class);
+ // required for stop() method
+ serviceRegistrationMock.unregister();
+ if(serviceProperties != null) {
+ expect(bundleContextMock.registerService(eq(serviceName),
+ isA(serviceType), eq(serviceProperties))).andReturn(serviceRegistrationMock);
+ } else {
+ expect(bundleContextMock.registerService(eq(serviceName),
+ isA(serviceType), (Dictionary)isNull())).andReturn(serviceRegistrationMock);
+ }
+
+ }
+
+ /**
+ * This method should be used only for unit testing the Gemini Naming Activator.
+ *
+ * This method sets the static singleton fields on the NamingManger class to null. This facilitates
+ * simpler unit-testing of the Activator, which attempts to set these singletons. The NamingManager usually
+ * throws and Exception on the set() methods for these singletons after they've been set once.
+ *
+ * This utility method is meant to make unit testing simpler, but should not be used in production code.
+ *
+ * This utility method will probably not work properly if a security manager is enabled.
+ *
+ * @param fieldName the name of the static field to set to null.
+ */
+ private static void setNamingManagerStaticFieldToNull(String fieldName) {
+ try {
+ final Field field = NamingManager.class.getDeclaredField(fieldName);
+ if(field != null) {
+ field.setAccessible(true);
+ // reset this static field to null
+ field.set(null, null);
+ }
+ } catch (Throwable throwable) {
+ throwable.printStackTrace();
+ }
+ }
+
+ /*
+ * Utility method used to access the private static singletons on the NamingManager class.
+ *
+ * This method should only be used for unit-testing the Gemini Naming code.
+ *
+ * This utility method will probably not work properly if a security manager is enabled.
+ *
+ * @param type the Class type that contains the field
+ * @param fieldName a String name that identifies the field
+ */
+ private static Object getPrivateStaticField(Class type, String fieldName) throws Exception {
+ Field field = type.getDeclaredField(fieldName);
+ if(field != null) {
+ field.setAccessible(true);
+ return field.get(null);
+ }
+
+ return null;
+ }
+
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/BuilderUtilsTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/BuilderUtilsTestCase.java
new file mode 100644
index 0000000..9bba825
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/BuilderUtilsTestCase.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Hashtable;
+
+import javax.naming.spi.NamingManager;
+
+import org.easymock.EasyMockSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+import org.osgi.service.jndi.JNDIConstants;
+
+import junit.framework.TestCase;
+
+import static org.easymock.EasyMock.*;
+
+public class BuilderUtilsTestCase extends TestCase {
+
+ public void testGetBundleContextDefault() throws Exception {
+ BundleContext result =
+ BuilderUtils.getBundleContext(null, NamingManager.class.getName());
+ assertNull("BuilderUtils incorrectly returned a BundleContext, should be null",
+ result);
+
+ BundleContext result2 =
+ BuilderUtils.getBundleContext(new Hashtable<String, Object>(), NamingManager.class.getName());
+ assertNull("BuilderUtils incorrect returned a BundleContext, should be null",
+ result2);
+ }
+
+ public void testGetBundleContextFromEnvironment() throws Exception {
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ BundleContext bundleContextFromEnvironmentMock =
+ mockSupport.createMock(BundleContext.class);
+
+ mockSupport.replayAll();
+
+ Hashtable<String, Object> environment = new Hashtable<String, Object>();
+ environment.put(JNDIConstants.BUNDLE_CONTEXT, bundleContextFromEnvironmentMock);
+ BundleContext result =
+ BuilderUtils.getBundleContext(environment, NamingManager.class.getName());
+
+ assertNotNull("BuilderUtils incorrectly returned a null BundleContext",
+ result);
+ assertSame("BuilderUtils did not return the expected BundleContext instance",
+ bundleContextFromEnvironmentMock, result);
+
+ mockSupport.verifyAll();
+ }
+
+
+ public void testGetBundleContextFromContextClassLoader() throws Exception {
+ ClassLoader oldContextClassLoader =
+ Thread.currentThread().getContextClassLoader();
+ try {
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Bundle bundleMock =
+ mockSupport.createMock(Bundle.class);
+ BundleContext bundleContextFromClassLoaderMock =
+ mockSupport.createMock(BundleContext.class);
+ expect(bundleMock.getBundleContext()).andReturn(bundleContextFromClassLoaderMock);
+
+ mockSupport.replayAll();
+
+ // set Thread Context ClassLoader to use stub TestClassLoader
+ Thread.currentThread().setContextClassLoader(new TestClassLoader(bundleMock));
+
+ BundleContext result =
+ BuilderUtils.getBundleContext(null, NamingManager.class.getName());
+
+ assertNotNull("BuilderUtils incorrectly returned a null BundleContext",
+ result);
+ assertSame("BuilderUtils did not return the expected BundleContext instance",
+ bundleContextFromClassLoaderMock, result);
+
+ mockSupport.verifyAll();
+ } finally {
+ if(oldContextClassLoader != null) {
+ // reset original Context ClassLoader
+ Thread.currentThread().setContextClassLoader(oldContextClassLoader);
+ }
+ }
+
+ }
+
+ /**
+ * Verifies that a BundleContext specified in an environment map will
+ * be used before a BundleContext specified on the Context ClassLoader.
+ *
+ * TODO, there might not be a way to easily unit test the CallStack strategy, so
+ * for now this test will only verify the first two strategies.
+ *
+ */
+ public void testGetBundleContextPriority() throws Exception {
+ ClassLoader oldContextClassLoader =
+ Thread.currentThread().getContextClassLoader();
+ try {
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Bundle bundleMock =
+ mockSupport.createMock(Bundle.class);
+ BundleContext bundleContextFromClassLoaderMock =
+ mockSupport.createMock(BundleContext.class);
+
+ BundleContext bundleContextFromEnvironmentMock =
+ mockSupport.createMock(BundleContext.class);
+
+ mockSupport.replayAll();
+
+ // set Thread Context ClassLoader to use stub TestClassLoader
+ Thread.currentThread().setContextClassLoader(new TestClassLoader(bundleMock));
+
+ Hashtable<String, Object> environment = new Hashtable<String, Object>();
+ environment.put(JNDIConstants.BUNDLE_CONTEXT, bundleContextFromEnvironmentMock);
+ // bundle context from environment should take precedence
+ BundleContext result =
+ BuilderUtils.getBundleContext(environment, NamingManager.class.getName());
+
+ assertNotNull("BuilderUtils incorrectly returned a null BundleContext",
+ result);
+ assertSame("BuilderUtils did not return the expected BundleContext instance",
+ bundleContextFromEnvironmentMock, result);
+
+ mockSupport.verifyAll();
+ } finally {
+ if(oldContextClassLoader != null) {
+ // reset original Context ClassLoader
+ Thread.currentThread().setContextClassLoader(oldContextClassLoader);
+ }
+ }
+ }
+
+ private static class TestClassLoader extends ClassLoader implements BundleReference {
+ private final Bundle m_bundle;
+
+ TestClassLoader(Bundle bundle) {
+ m_bundle = bundle;
+ }
+
+ public Bundle getBundle() {
+ return m_bundle;
+ }
+
+ }
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/ContextWrapperImplTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/ContextWrapperImplTestCase.java
new file mode 100644
index 0000000..d1e0fa9
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/ContextWrapperImplTestCase.java
@@ -0,0 +1,274 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Hashtable;
+
+import javax.naming.CompositeName;
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.spi.ObjectFactory;
+
+import org.easymock.EasyMockSupport;
+
+import junit.framework.TestCase;
+
+import static org.easymock.EasyMock.*;
+
+public class ContextWrapperImplTestCase extends TestCase {
+
+ public void testCreate() throws Exception {
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Context contextMock =
+ mockSupport.createMock(Context.class);
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+
+ mockSupport.replayAll();
+
+ new ContextWrapperImpl(contextMock, factoryManagerMock);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testDelegatedMethods() throws Exception {
+ final Name expectedCompositeName = new CompositeName();
+ final Name newCompositeName = new CompositeName();
+ final Object expectedBindingValue = new Object();
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Context contextMock =
+ mockSupport.createMock(Context.class);
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+ NamingEnumeration namingEnumerationMock =
+ mockSupport.createMock(NamingEnumeration.class);
+ Context subContextMock =
+ mockSupport.createMock(Context.class);
+
+ // expect every method of the Context interface to delegate to the
+ // internal Context implementation, except for the lookup(String) method
+ expect(contextMock.lookup(new CompositeName())).andReturn("test1");
+ contextMock.bind(expectedCompositeName, expectedBindingValue);
+ contextMock.bind("test-binding-one", "just a test");
+ contextMock.rebind(expectedCompositeName, "test2");
+ contextMock.rebind("test-rebind-one", "another value");
+ contextMock.unbind(expectedCompositeName);
+ contextMock.unbind("test-binding-one");
+ contextMock.rename(expectedCompositeName, newCompositeName);
+ contextMock.rename("test-binding-one", "test-binding-two");
+ expect(contextMock.list(expectedCompositeName)).andReturn(namingEnumerationMock);
+ expect(contextMock.list("test-list-one")).andReturn(namingEnumerationMock);
+ expect(contextMock.listBindings(expectedCompositeName)).andReturn(namingEnumerationMock);
+ expect(contextMock.listBindings("test-list-bindings-one")).andReturn(namingEnumerationMock);
+ contextMock.destroySubcontext(expectedCompositeName);
+ contextMock.destroySubcontext("test-destroy-sub-context-one");
+ expect(contextMock.createSubcontext(expectedCompositeName)).andReturn(subContextMock);
+ expect(contextMock.createSubcontext("test-create-sub-context-one")).andReturn(subContextMock);
+ expect(contextMock.lookupLink(expectedCompositeName)).andReturn("link value");
+ expect(contextMock.lookupLink("test-lookup-link")).andReturn("another link value");
+ expect(contextMock.getNameParser(expectedCompositeName)).andReturn(null);
+ expect(contextMock.getNameParser("test-get-name-parser")).andReturn(null);
+ expect(contextMock.composeName(expectedCompositeName, expectedCompositeName)).andReturn(null);
+ expect(contextMock.composeName("name", "prefix")).andReturn(null);
+ expect(contextMock.addToEnvironment("test-property-one", "add-environment-value")).andReturn(null);
+ expect(contextMock.removeFromEnvironment("test-remove-property")).andReturn(null);
+ expect(contextMock.getEnvironment()).andReturn(null);
+ contextMock.close();
+ expect(contextMock.getNameInNamespace()).andReturn("name-in-namespace");
+
+
+ mockSupport.replayAll();
+
+ // begin test
+ Context testContext =
+ new ContextWrapperImpl(contextMock, factoryManagerMock);
+
+ // exercise all Context methods (except lookup(String), and verify
+ // that the underlying context is used in each call
+ assertEquals("Context did not delegate to the proper Context implementation",
+ "test1", testContext.lookup(new CompositeName()));
+ testContext.bind(expectedCompositeName, expectedBindingValue);
+ testContext.bind("test-binding-one", "just a test");
+ testContext.rebind(expectedCompositeName, "test2");
+ testContext.rebind("test-rebind-one", "another value");
+ testContext.unbind(expectedCompositeName);
+ testContext.unbind("test-binding-one");
+ testContext.rename(expectedCompositeName, newCompositeName);
+ testContext.rename("test-binding-one", "test-binding-two");
+ assertNotNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.list(expectedCompositeName));
+ assertNotNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.list("test-list-one"));
+ assertNotNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.listBindings(expectedCompositeName));
+ assertNotNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.listBindings("test-list-bindings-one"));
+ testContext.destroySubcontext(expectedCompositeName);
+ testContext.destroySubcontext("test-destroy-sub-context-one");
+ assertNotNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.createSubcontext(expectedCompositeName));
+ assertNotNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.createSubcontext("test-create-sub-context-one"));
+ assertEquals("ContextWrapperImpl did not invoke on the internal context",
+ "link value", testContext.lookupLink(expectedCompositeName));
+ assertEquals("ContextWrapperImpl did not invoke on the internal context",
+ "another link value", testContext.lookupLink("test-lookup-link"));
+ assertNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.getNameParser(expectedCompositeName));
+ assertNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.getNameParser("test-get-name-parser"));
+ assertNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.composeName(expectedCompositeName, expectedCompositeName));
+ assertNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.composeName("name", "prefix"));
+ assertNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.addToEnvironment("test-property-one", "add-environment-value"));
+ assertNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.removeFromEnvironment("test-remove-property"));
+ assertNull("ContextWrapperImpl did not invoke on the internal context",
+ testContext.getEnvironment());
+ testContext.close();
+ assertEquals("ContextWrapperImpl did not invoke on the internal context",
+ "name-in-namespace", testContext.getNameInNamespace());
+
+ mockSupport.verifyAll();
+ }
+
+
+ /**
+ * Verify that the Context.lookup(String) method is intercepted by this wrapper in
+ * order to support URL Context Factories.
+ *
+ */
+ public void testURLLookup() throws Exception {
+ final String expectedURL = "testURL";
+ final String expectedLookupName = expectedURL + ":" + "basicLookupName";
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ ObjectFactory objectFactoryMock =
+ mockSupport.createMock(ObjectFactory.class);
+ Context contextMock =
+ mockSupport.createMock(Context.class);
+ Context urlContextMock =
+ mockSupport.createMock(Context.class);
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+ expect(contextMock.getEnvironment()).andReturn(new Hashtable());
+ expect(factoryManagerMock.getURLContextFactory(expectedURL)).andReturn(objectFactoryMock);
+ expect(objectFactoryMock.getObjectInstance(null, null, null, new Hashtable())).andReturn(urlContextMock);
+ expect(urlContextMock.lookup(expectedLookupName)).andReturn("just a url context factory test");
+
+ mockSupport.replayAll();
+
+ // begin test
+ Context testContext =
+ new ContextWrapperImpl(contextMock, factoryManagerMock);
+
+ testContext.lookup(expectedLookupName);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testNonURLLookup() throws Exception {
+ final String expectedNonURLName = "lookupOne";
+ final String expectedValue = "lookup result";
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Context contextMock =
+ mockSupport.createMock(Context.class);
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+ expect(contextMock.lookup(expectedNonURLName)).andReturn(expectedValue);
+
+ mockSupport.replayAll();
+
+ // begin test
+ Context testContext =
+ new ContextWrapperImpl(contextMock, factoryManagerMock);
+ assertEquals("ContextWrapperImpl did not handle non-url lookup correctly",
+ expectedValue, testContext.lookup(expectedNonURLName));
+
+ mockSupport.verifyAll();
+ }
+
+
+ public void testURLLookupWithNoObjectFactory() throws Exception {
+ final String expectedURL = "testURL";
+ final String expectedLookupName = expectedURL + ":" + "basicLookupName";
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Context contextMock =
+ mockSupport.createMock(Context.class);
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+ expect(factoryManagerMock.getURLContextFactory(expectedURL)).andReturn(null);
+
+ mockSupport.replayAll();
+
+ // begin test
+ Context testContext =
+ new ContextWrapperImpl(contextMock, factoryManagerMock);
+
+ try {
+ testContext.lookup(expectedLookupName);
+ fail("NameNotFoundException should have been thrown");
+ } catch (NameNotFoundException namingException) {
+ // expected exception
+ }
+
+
+ mockSupport.verifyAll();
+ }
+
+
+ public void testURLLookupWithNoURLContext() throws Exception {
+ final String expectedURL = "testURL";
+ final String expectedLookupName = expectedURL + ":" + "basicLookupName";
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ ObjectFactory objectFactoryMock =
+ mockSupport.createMock(ObjectFactory.class);
+ Context contextMock =
+ mockSupport.createMock(Context.class);
+
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+ expect(contextMock.getEnvironment()).andReturn(new Hashtable());
+ expect(factoryManagerMock.getURLContextFactory(expectedURL)).andReturn(objectFactoryMock);
+ expect(objectFactoryMock.getObjectInstance(null, null, null, new Hashtable())).andReturn(null);
+
+ mockSupport.replayAll();
+
+ // begin test
+ Context testContext =
+ new ContextWrapperImpl(contextMock, factoryManagerMock);
+
+ try {
+ testContext.lookup(expectedLookupName);
+ fail("NamingException should have been thrown");
+ } catch (NamingException namingException) {
+ // expected exception
+ }
+
+ mockSupport.verifyAll();
+ }
+
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/DefaultInitialContextFactoryTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/DefaultInitialContextFactoryTestCase.java
new file mode 100644
index 0000000..e37c868
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/DefaultInitialContextFactoryTestCase.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+
+import junit.framework.TestCase;
+
+public class DefaultInitialContextFactoryTestCase extends TestCase {
+
+ public void testCreate() throws Exception {
+ Context resultContext =
+ new DefaultInitialContextFactory().getInitialContext(null);
+ assertNotNull("Default Context not created", resultContext);
+
+ Context resultContextWithEnvironment =
+ new DefaultInitialContextFactory().getInitialContext(new Hashtable<String, Object>());
+ assertNotNull("Default Context not created", resultContextWithEnvironment);
+ }
+
+ public void testClose() throws Exception {
+ Context resultContext =
+ new DefaultInitialContextFactory().getInitialContext(null);
+
+ // close() should execute without any exceptions
+ resultContext.close();
+ }
+
+ public void testGetEnvironment() throws Exception {
+ Context resultContext =
+ new DefaultInitialContextFactory().getInitialContext(null);
+
+ Hashtable<?, ?> environment = resultContext.getEnvironment();
+ assertNotNull("Default Context did not properly handle the getEnvironment() call",
+ environment);
+ assertTrue("Default Context did not return the correct Hashtable",
+ environment.size() == 0);
+
+ Hashtable<?, ?> environment2 = resultContext.getEnvironment();
+ assertNotNull("Default Context did not properly handle the getEnvironment() call",
+ environment2);
+ assertNotSame("Default Context did not create a new Hashtable environment",
+ environment, environment2);
+ }
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/DefaultRuntimeInitialContextFactoryBuilderTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/DefaultRuntimeInitialContextFactoryBuilderTestCase.java
new file mode 100644
index 0000000..401ba8f
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/DefaultRuntimeInitialContextFactoryBuilderTestCase.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+
+import junit.framework.TestCase;
+
+public class DefaultRuntimeInitialContextFactoryBuilderTestCase extends TestCase {
+
+ public void testNullEnvironment() throws Exception {
+ InitialContextFactory factoryResult =
+ new DefaultRuntimeInitialContextFactoryBuilder().createInitialContextFactory(null);
+
+ assertNull("DefaultRuntime builder should have returned a null", factoryResult);
+ }
+
+ public void testEnvironmentWithNoFactorySet() throws Exception {
+ // create factory with empty environment
+ InitialContextFactory factoryResult =
+ new DefaultRuntimeInitialContextFactoryBuilder().createInitialContextFactory(new Hashtable<String, Object>());
+
+ assertNull("DefaultRuntime builder should have returned a null", factoryResult);
+ }
+
+ public void testEnvironmentWithFactorySet() throws Exception {
+ Hashtable<String, Object> environment = new Hashtable<String, Object>();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY, TestInitialContextFactory.class.getName());
+
+ InitialContextFactory factoryResult =
+ new DefaultRuntimeInitialContextFactoryBuilder().createInitialContextFactory(environment);
+
+ assertNotNull("DefaultRuntime builder did not return a factory", factoryResult);
+ assertTrue("DefaultRuntime builder did not return a factory of the expected type",
+ factoryResult instanceof TestInitialContextFactory);
+ }
+
+ public void testEnvironmentWithFactoryThatDoesNotExist() throws Exception {
+ Hashtable<String, Object> environment = new Hashtable<String, Object>();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY, "this.factory.does.not.exist");
+
+ InitialContextFactory factoryResult =
+ new DefaultRuntimeInitialContextFactoryBuilder().createInitialContextFactory(environment);
+
+ assertNull("DefaultRuntime builder should not have returned a factory",
+ factoryResult);
+ }
+
+ public void testFactoryThrowsException() throws Exception {
+ Hashtable<String, Object> environment = new Hashtable<String, Object>();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY, TestInitialContextFactoryThrowsException.class.getName());
+
+ InitialContextFactory factoryResult =
+ new DefaultRuntimeInitialContextFactoryBuilder().createInitialContextFactory(environment);
+
+ assertNull("DefaultRuntime builder should not have returned a factory",
+ factoryResult);
+ }
+
+ static class TestInitialContextFactory implements InitialContextFactory {
+ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
+ return null;
+ }
+ }
+
+ static class TestInitialContextFactoryThrowsException implements InitialContextFactory {
+
+ TestInitialContextFactoryThrowsException() {
+ // exception for unit test
+ throw new NullPointerException();
+ }
+
+ public Context getInitialContext(Hashtable<?, ?> environment) throws NamingException {
+ return null;
+ }
+
+ }
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/DirContextWrapperImplTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/DirContextWrapperImplTestCase.java
new file mode 100644
index 0000000..b89f187
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/DirContextWrapperImplTestCase.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import javax.naming.CompositeName;
+import javax.naming.Name;
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.ModificationItem;
+import javax.naming.directory.SearchControls;
+
+import org.easymock.EasyMockSupport;
+
+import junit.framework.TestCase;
+
+import static org.easymock.EasyMock.*;
+
+public class DirContextWrapperImplTestCase extends TestCase {
+
+ public void testCreate() throws Exception {
+ // setup mocks
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ DirContext dirContextMock =
+ mockSupport.createMock(DirContext.class);
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+
+ mockSupport.replayAll();
+ // begin test
+ new DirContextWrapperImpl(dirContextMock, factoryManagerMock);
+
+ mockSupport.verifyAll();
+ }
+
+
+ /**
+ * This test verifies that all of the methods on the wrapper for the DirContext interface
+ * will delegate to the internal DirContext implementation. The test also verifies that the
+ * parameters passed into the wrapper are passed unchanged to the internal
+ * implementation.
+ *
+ */
+ public void testDelegatedMethods() throws Exception {
+ final Name expectedCompositeName = new CompositeName();
+ final String[] expectedAttributeParameters = new String[] { "testOne", "testTwo" };
+ final ModificationItem[] expectedItems = new ModificationItem[0];
+ final Object expectedBindingValue = new Object();
+ final SearchControls expectedSearchControls = new SearchControls();
+ final Object[] expectedObjArray = new Object[0];
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ DirContext dirContextMock =
+ mockSupport.createMock(DirContext.class);
+ DirContext subContextMock =
+ mockSupport.createMock(DirContext.class);
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+ Attributes attributesMock =
+ mockSupport.createMock(Attributes.class);
+ NamingEnumeration namingEnumMock =
+ mockSupport.createMock(NamingEnumeration.class);
+ //setup of expected method calls on internal DirContext
+ dirContextMock.bind(expectedCompositeName, expectedBindingValue, attributesMock);
+ dirContextMock.bind("test-bind-one", expectedBindingValue, attributesMock);
+ expect(dirContextMock.createSubcontext(expectedCompositeName, attributesMock)).andReturn(subContextMock);
+ expect(dirContextMock.createSubcontext("create-subcontext-one", attributesMock)).andReturn(subContextMock);
+ expect(dirContextMock.getAttributes(expectedCompositeName)).andReturn(attributesMock);
+ expect(dirContextMock.getAttributes("get-attributes-one")).andReturn(attributesMock);
+ expect(dirContextMock.getAttributes(expectedCompositeName, expectedAttributeParameters)).andReturn(attributesMock);
+ expect(dirContextMock.getAttributes("get-attributes-with-params", expectedAttributeParameters)).andReturn(attributesMock);
+ expect(dirContextMock.getSchema(expectedCompositeName)).andReturn(subContextMock);
+ expect(dirContextMock.getSchema("get-schema")).andReturn(subContextMock);
+ expect(dirContextMock.getSchemaClassDefinition(expectedCompositeName)).andReturn(subContextMock);
+ expect(dirContextMock.getSchemaClassDefinition("get-schema-class-def")).andReturn(subContextMock);
+ dirContextMock.modifyAttributes(expectedCompositeName, expectedItems);
+ dirContextMock.modifyAttributes("modify-attributes", expectedItems);
+ dirContextMock.modifyAttributes(expectedCompositeName, 10, attributesMock);
+ dirContextMock.modifyAttributes("modify-attributes-two", 100, attributesMock);
+ dirContextMock.rebind(expectedCompositeName, expectedBindingValue, attributesMock);
+ dirContextMock.rebind("rebind-one", expectedBindingValue, attributesMock);
+ expect(dirContextMock.search(expectedCompositeName, attributesMock)).andReturn(namingEnumMock);
+ expect(dirContextMock.search("search-one", attributesMock)).andReturn(namingEnumMock);
+ expect(dirContextMock.search(expectedCompositeName, attributesMock, expectedAttributeParameters)).andReturn(namingEnumMock);
+ expect(dirContextMock.search(expectedCompositeName, "*", expectedSearchControls)).andReturn(namingEnumMock);
+ expect(dirContextMock.search("search-with-params", attributesMock, expectedAttributeParameters)).andReturn(namingEnumMock);
+ expect(dirContextMock.search("search-with-controls", "*", expectedSearchControls)).andReturn(namingEnumMock);
+ expect(dirContextMock.search(expectedCompositeName, "*", expectedObjArray, expectedSearchControls)).andReturn(namingEnumMock);
+ expect(dirContextMock.search("search-with-controls-and-filter", "*", expectedObjArray, expectedSearchControls)).andReturn(namingEnumMock);
+
+
+ mockSupport.replayAll();
+
+ // begin test
+ DirContext testDirContext =
+ new DirContextWrapperImpl(dirContextMock, factoryManagerMock);
+
+ testDirContext.bind(expectedCompositeName, expectedBindingValue, attributesMock);
+ testDirContext.bind("test-bind-one", expectedBindingValue, attributesMock);
+ assertSame("DirContextWrapperImpl did not return expected subContext",
+ subContextMock, testDirContext.createSubcontext(expectedCompositeName, attributesMock));
+ assertSame("DirContextWrapperImpl did not return expected subContext",
+ subContextMock, testDirContext.createSubcontext("create-subcontext-one", attributesMock));
+ assertSame("DirContextWrapperImpl did not return expected Attributes",
+ attributesMock, testDirContext.getAttributes(expectedCompositeName));
+ assertSame("DirContextWrapperImpl did not return expected Attributes",
+ attributesMock, testDirContext.getAttributes("get-attributes-one"));
+ assertSame("DirContextWrapperImpl did not return expected Attributes",
+ attributesMock, testDirContext.getAttributes(expectedCompositeName, expectedAttributeParameters));
+ assertSame("DirContextWrapperImpl did not return expected Attributes",
+ attributesMock, testDirContext.getAttributes("get-attributes-with-params", expectedAttributeParameters));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ subContextMock, testDirContext.getSchema(expectedCompositeName));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ subContextMock, testDirContext.getSchema("get-schema"));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ subContextMock, testDirContext.getSchemaClassDefinition(expectedCompositeName));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ subContextMock, testDirContext.getSchemaClassDefinition("get-schema-class-def"));
+ testDirContext.modifyAttributes(expectedCompositeName, expectedItems);
+ testDirContext.modifyAttributes("modify-attributes", expectedItems);
+ testDirContext.modifyAttributes(expectedCompositeName, 10, attributesMock);
+ testDirContext.modifyAttributes("modify-attributes-two", 100, attributesMock);
+ testDirContext.rebind(expectedCompositeName, expectedBindingValue, attributesMock);
+ testDirContext.rebind("rebind-one", expectedBindingValue, attributesMock);
+
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ namingEnumMock, testDirContext.search(expectedCompositeName, attributesMock));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ namingEnumMock, testDirContext.search("search-one", attributesMock));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ namingEnumMock, testDirContext.search(expectedCompositeName, attributesMock, expectedAttributeParameters));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ namingEnumMock, testDirContext.search(expectedCompositeName, "*", expectedSearchControls));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ namingEnumMock, testDirContext.search("search-with-params", attributesMock, expectedAttributeParameters));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ namingEnumMock, testDirContext.search("search-with-controls", "*", expectedSearchControls));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ namingEnumMock, testDirContext.search(expectedCompositeName, "*", expectedObjArray, expectedSearchControls));
+ assertSame("DirContextWrapperImpl did not properly call on internal DirContext impl",
+ namingEnumMock, testDirContext.search("search-with-controls-and-filter", "*", expectedObjArray, expectedSearchControls));
+
+ mockSupport.verifyAll();
+ }
+
+}
+
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/InitialContextFactoryWrapperTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/InitialContextFactoryWrapperTestCase.java
new file mode 100644
index 0000000..83cc8d4
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/InitialContextFactoryWrapperTestCase.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.directory.DirContext;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+
+import org.easymock.EasyMockSupport;
+
+import junit.framework.TestCase;
+
+import static org.easymock.EasyMock.*;
+
+
+
+public class InitialContextFactoryWrapperTestCase extends TestCase {
+
+ public void testCreateWrapper() throws Exception {
+ // setup mocks
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ InitialContextFactory factoryMock =
+ mockSupport.createMock(InitialContextFactory.class);
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+
+ mockSupport.replayAll();
+
+ // create wrapper
+ new InitialContextFactoryWrapper(factoryMock, factoryManagerMock);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testCreateContextDefault() throws Exception {
+ // setup mocks
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Context contextMock =
+ mockSupport.createMock(Context.class);
+
+ InitialContextFactory factoryMock =
+ mockSupport.createMock(InitialContextFactory.class);
+ expect(factoryMock.getInitialContext(new Hashtable<String, Object>())).andReturn(contextMock);
+
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+ factoryManagerMock.associateFactoryService(same(factoryMock), isA(Context.class));
+
+ mockSupport.replayAll();
+
+ // create wrapper
+ InitialContextFactoryWrapper wrapper =
+ new InitialContextFactoryWrapper(factoryMock, factoryManagerMock);
+
+ Context resultContext =
+ wrapper.getInitialContext(new Hashtable<String, Object>());
+ assertNotNull("Wrapper returned a null Context", resultContext);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testCreateDirContextDefault() throws Exception {
+ // setup mocks
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ DirContext dirContextMock =
+ mockSupport.createMock(DirContext.class);
+
+ InitialContextFactory factoryMock =
+ mockSupport.createMock(InitialContextFactory.class);
+ expect(factoryMock.getInitialContext(new Hashtable<String, Object>())).andReturn(dirContextMock);
+
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+ factoryManagerMock.associateFactoryService(same(factoryMock), isA(Context.class));
+
+ mockSupport.replayAll();
+
+ // create wrapper
+ InitialContextFactoryWrapper wrapper =
+ new InitialContextFactoryWrapper(factoryMock, factoryManagerMock);
+
+ DirContext resultContext =
+ (DirContext)wrapper.getInitialContext(new Hashtable<String, Object>());
+ assertNotNull("Wrapper returned a null Context", resultContext);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testCreateBuilderSupportedInitialContextFactory() throws Exception {
+ // setup mocks
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Context contextMock =
+ mockSupport.createMock(Context.class);
+
+ InitialContextFactoryBuilder builderMock =
+ mockSupport.createMock(InitialContextFactoryBuilder.class);
+
+ BuilderSupportedInitialContextFactory initialContextFactoryMock =
+ mockSupport.createMock(BuilderSupportedInitialContextFactory.class);
+ expect(initialContextFactoryMock.getInitialContext(new Hashtable<String, Object>())).andReturn(contextMock);
+ expect(initialContextFactoryMock.getBuilder()).andReturn(builderMock);
+
+ FactoryManager factoryManagerMock =
+ mockSupport.createMock(FactoryManager.class);
+ factoryManagerMock.associateFactoryService(same(builderMock), isA(Context.class));
+
+ mockSupport.replayAll();
+
+ // create wrapper
+ InitialContextFactoryWrapper wrapper =
+ new InitialContextFactoryWrapper(initialContextFactoryMock, factoryManagerMock);
+
+ Context resultContext =
+ wrapper.getInitialContext(new Hashtable<String, Object>());
+ assertNotNull("Wrapper returned a null Context", resultContext);
+
+ mockSupport.verifyAll();
+ }
+
+
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/NotSupportedContextTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/NotSupportedContextTestCase.java
new file mode 100644
index 0000000..afa3f36
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/NotSupportedContextTestCase.java
@@ -0,0 +1,299 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import javax.naming.CompositeName;
+import javax.naming.Context;
+import javax.naming.OperationNotSupportedException;
+
+import junit.framework.TestCase;
+
+public class NotSupportedContextTestCase extends TestCase {
+
+ public void testCreate() throws Exception {
+ new NotSupportedContext("just a test");
+ }
+
+ /**
+ * Verify that all Context methods supported by this class
+ * throw an OperationNotSupportedException.
+ */
+ public void testMethods() throws Exception {
+ final String expectedMessage = "just a test";
+ Context context = new NotSupportedContext(expectedMessage);
+
+ try {
+ context.addToEnvironment("test", "test1");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.bind(new CompositeName(), "bind test");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.bind("bind-name", "bind-value");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.close();
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.composeName(new CompositeName(), new CompositeName());
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.composeName("name", "prefix");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.createSubcontext(new CompositeName());
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.createSubcontext("name");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.destroySubcontext(new CompositeName());
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.destroySubcontext("name");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.getEnvironment();
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.getNameInNamespace();
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.getNameParser(new CompositeName());
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.getNameParser("name");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.list(new CompositeName());
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.list("name");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.listBindings(new CompositeName());
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.listBindings("name");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.lookup(new CompositeName());
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.lookup("name");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.lookupLink(new CompositeName());
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.lookupLink("name");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.rebind(new CompositeName(), "just a test");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.rebind("name", "just a rebind test");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.removeFromEnvironment("property-name");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.rename(new CompositeName(), new CompositeName());
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.rename("old-name", "new-name");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.unbind(new CompositeName());
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+
+ try {
+ context.unbind("unbind-name");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch(OperationNotSupportedException namingException) {
+ // expected exception
+ assertEquals("Context did not include expected message with exception",
+ expectedMessage, namingException.getMessage());
+ }
+ }
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/OSGiServiceListContextTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/OSGiServiceListContextTestCase.java
new file mode 100644
index 0000000..2f9a16a
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/OSGiServiceListContextTestCase.java
@@ -0,0 +1,402 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.io.Closeable;
+import java.util.NoSuchElementException;
+
+import javax.naming.Binding;
+import javax.naming.Context;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingEnumeration;
+import javax.naming.OperationNotSupportedException;
+
+import org.easymock.EasyMockSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+import junit.framework.TestCase;
+
+import static org.easymock.EasyMock.*;
+
+public class OSGiServiceListContextTestCase extends TestCase {
+
+ public void testBasicCreate() throws Exception {
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ // setup mocks and test fixtures
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+
+ mockSupport.replayAll();
+
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:servicelist/com.oracle.TestService");
+ new OSGiServiceListContext(bundleContextMock, new ServiceReference[0], urlParser);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testCreateWithServiceReferences() throws Exception {
+ // setup mocks and test fixtures
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Bundle bundleMock = mockSupport.createMock(Bundle.class);
+ // service reference
+ ServiceReference serviceRefMockOne =
+ createServiceReferenceMock(mockSupport, bundleMock, 1);
+
+ ServiceReference serviceRefMockTwo =
+ createServiceReferenceMock(mockSupport, bundleMock, 2);
+
+ // mock filter
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ // mock BundleContext
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ Closeable closeable1 = mockSupport.createMock(Closeable.class);
+ Closeable closeable2 = mockSupport.createMock(Closeable.class);
+ expect(bundleContextMock.getService(serviceRefMockOne)).andReturn(closeable1).anyTimes();
+ expect(bundleContextMock.getService(serviceRefMockTwo)).andReturn(closeable2).anyTimes();
+
+ expect(bundleContextMock.createFilter("(service.id=1)")).andReturn(filterMock).anyTimes();
+ expect(bundleContextMock.createFilter("(service.id=2)")).andReturn(filterMock).anyTimes();
+ bundleContextMock.addServiceListener(isA(ServiceListener.class), isA(String.class));
+ bundleContextMock.addServiceListener(isA(ServiceListener.class), isA(String.class));
+ expect(bundleContextMock.getBundle()).andReturn(bundleMock).anyTimes();
+
+ mockSupport.replayAll();
+
+ // begin test
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:servicelist/java.io.Closeable");
+ urlParser.parse();
+ Context context =
+ new OSGiServiceListContext(bundleContextMock,
+ new ServiceReference[]{serviceRefMockOne, serviceRefMockTwo},
+ urlParser);
+
+ // test service lookup using service.id
+ Object result = context.lookup("1");
+ assertNotNull("ServiceListContext incorrectly returned a null value",
+ result);
+ assertTrue("ServiceListContext returned incorrect type",
+ result instanceof Closeable);
+
+ Object result2 = context.lookup("2");
+ assertNotNull("ServiceListContext incorrectly returned a null value",
+ result2);
+ assertTrue("ServiceListContext returned incorrect type",
+ result2 instanceof Closeable);
+ assertNotSame("ServiceListContext incorrectly returned the same object",
+ result, result2);
+
+ try {
+ // verify that lookup of unknown service results in an exception
+ context.lookup("3");
+ fail("NameNotFoundException should have been thrown");
+ } catch (NameNotFoundException namingException) {
+ // expected exception
+ }
+
+ mockSupport.verifyAll();
+ }
+
+
+
+ public void testList() throws Exception {
+ // setup mocks and test fixtures
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Bundle bundleMock = mockSupport.createMock(Bundle.class);
+ // service reference
+ ServiceReference serviceRefMockOne =
+ createServiceReferenceMock(mockSupport, bundleMock, 1);
+
+ ServiceReference serviceRefMockTwo =
+ createServiceReferenceMock(mockSupport, bundleMock, 2);
+
+ // mock filter
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ // mock BundleContext
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ Closeable closeable1 = mockSupport.createMock(Closeable.class);
+ Closeable closeable2 = mockSupport.createMock(Closeable.class);
+ expect(bundleContextMock.getService(serviceRefMockOne)).andReturn(closeable1).anyTimes();
+ expect(bundleContextMock.getService(serviceRefMockTwo)).andReturn(closeable2).anyTimes();
+
+ expect(bundleContextMock.createFilter("(service.id=1)")).andReturn(filterMock).anyTimes();
+ expect(bundleContextMock.createFilter("(service.id=2)")).andReturn(filterMock).anyTimes();
+ expect(bundleContextMock.getBundle()).andReturn(bundleMock).anyTimes();
+
+ mockSupport.replayAll();
+
+ // begin test
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:servicelist/java.io.Closeable");
+ urlParser.parse();
+ Context context =
+ new OSGiServiceListContext(bundleContextMock,
+ new ServiceReference[]{serviceRefMockOne, serviceRefMockTwo},
+ urlParser);
+
+ // call Context.list("") on returned service list context
+ NamingEnumeration<NameClassPair> namingEnumeration = context.list("");
+ Object result = namingEnumeration.next();
+ // verify the contents of the NamingEnumeration returned
+ assertNotNull("NamingEnumeration did not contain the expected service",
+ result);
+ assertTrue("NamingEnumeration returned an unexpected type",
+ result instanceof NameClassPair);
+
+ NameClassPair nameClassPair = (NameClassPair)result;
+ assertEquals("NameClassPair did not contain the expected type",
+ Closeable.class.getName(),
+ nameClassPair.getClassName());
+ assertEquals("NameClassPair did not contain the expected ID",
+ "1", nameClassPair.getName());
+
+ assertTrue("NamingEnumeration should contain one more element",
+ namingEnumeration.hasMoreElements());
+
+ NameClassPair nameClassPairTwo = (NameClassPair)namingEnumeration.next();
+ assertEquals("NameClassPair did not contain the expected type",
+ Closeable.class.getName(),
+ nameClassPairTwo.getClassName());
+ assertEquals("NameClassPair did not contain the expected ID",
+ "2", nameClassPairTwo.getName());
+
+ assertFalse("NamingEnumeration should not contain any more elements",
+ namingEnumeration.hasMoreElements());
+
+ // verify exception handling
+ try {
+ namingEnumeration.nextElement();
+ fail("NoSuchElementException should have been thrown");
+ } catch (NoSuchElementException e) {
+ // expected exception
+ }
+
+ // verify exception handling
+ try {
+ namingEnumeration.next();
+ fail("NoSuchElementException should have been thrown");
+ } catch (NoSuchElementException e) {
+ // expected exception
+ }
+
+ mockSupport.verifyAll();
+ }
+
+ public void testListWithNonEmptyString() throws Exception {
+ //setup mocks and test fixtures
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Bundle bundleMock = mockSupport.createMock(Bundle.class);
+ // service reference
+ ServiceReference serviceRefMockOne =
+ createServiceReferenceMock(mockSupport, bundleMock, 1);
+
+ ServiceReference serviceRefMockTwo =
+ createServiceReferenceMock(mockSupport, bundleMock, 2);
+
+ // mock filter
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ // mock BundleContext
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ Closeable closeable1 = mockSupport.createMock(Closeable.class);
+ Closeable closeable2 = mockSupport.createMock(Closeable.class);
+ expect(bundleContextMock.getService(serviceRefMockOne)).andReturn(closeable1).anyTimes();
+ expect(bundleContextMock.getService(serviceRefMockTwo)).andReturn(closeable2).anyTimes();
+
+ expect(bundleContextMock.createFilter("(service.id=1)")).andReturn(filterMock).anyTimes();
+ expect(bundleContextMock.createFilter("(service.id=2)")).andReturn(filterMock).anyTimes();
+ expect(bundleContextMock.getBundle()).andReturn(bundleMock).anyTimes();
+
+ mockSupport.replayAll();
+
+ // begin test
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:servicelist/java.io.Closeable");
+ urlParser.parse();
+ Context context =
+ new OSGiServiceListContext(bundleContextMock,
+ new ServiceReference[]{serviceRefMockOne, serviceRefMockTwo},
+ urlParser);
+
+ // call Context.list("") on returned service list context
+ try {
+ context.list("this-string-is-not-valid");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch (OperationNotSupportedException namingException) {
+ // expected exception
+ }
+ }
+
+ public void testListBindings() throws Exception {
+ // setup mocks and test fixtures
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Bundle bundleMock = mockSupport.createMock(Bundle.class);
+ // service reference
+ ServiceReference serviceRefMockOne =
+ createServiceReferenceMock(mockSupport, bundleMock, 1);
+
+ ServiceReference serviceRefMockTwo =
+ createServiceReferenceMock(mockSupport, bundleMock, 2);
+
+ // mock filter
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ // mock BundleContext
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ Closeable closeable1 = mockSupport.createMock(Closeable.class);
+ Closeable closeable2 = mockSupport.createMock(Closeable.class);
+ expect(bundleContextMock.getService(serviceRefMockOne)).andReturn(closeable1).anyTimes();
+ expect(bundleContextMock.getService(serviceRefMockTwo)).andReturn(closeable2).anyTimes();
+
+ expect(bundleContextMock.createFilter("(service.id=1)")).andReturn(filterMock).anyTimes();
+ expect(bundleContextMock.createFilter("(service.id=2)")).andReturn(filterMock).anyTimes();
+ bundleContextMock.addServiceListener(isA(ServiceListener.class), isA(String.class));
+ bundleContextMock.addServiceListener(isA(ServiceListener.class), isA(String.class));
+ expect(bundleContextMock.getBundle()).andReturn(bundleMock).anyTimes();
+
+ mockSupport.replayAll();
+
+ // begin test
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:servicelist/java.io.Closeable");
+ urlParser.parse();
+ Context context =
+ new OSGiServiceListContext(bundleContextMock,
+ new ServiceReference[]{serviceRefMockOne, serviceRefMockTwo},
+ urlParser);
+
+ NamingEnumeration<Binding> namingEnumeration =
+ context.listBindings("");
+ assertTrue("NamingEnumeration did not contain any elements",
+ namingEnumeration.hasMoreElements());
+
+ Object result = namingEnumeration.next();
+ assertNotNull("NamingEnumeration did not contain the expected service",
+ result);
+ assertTrue("NamingEnumeration returned an unexpected type",
+ result instanceof Binding);
+
+ Binding bindingOne = (Binding)result;
+ assertEquals("Incorrect Binding type",
+ Closeable.class.getName(),
+ bindingOne.getClassName());
+ assertEquals("Binding's service ID was not expected",
+ "1", bindingOne.getName());
+ assertNotNull("Binding's service object was not included",
+ bindingOne.getObject());
+ assertTrue("Binding's service object was not the correct type",
+ bindingOne.getObject() instanceof Closeable);
+
+
+ assertTrue("NamingEnumeration should contain one more element",
+ namingEnumeration.hasMoreElements());
+
+ Binding bindingTwo = (Binding)namingEnumeration.next();
+ assertEquals("NameClassPair did not contain the expected type",
+ Closeable.class.getName(),
+ bindingTwo.getClassName());
+ assertEquals("NameClassPair did not contain an expected ID",
+ "2", bindingTwo.getName());
+ assertNotNull("Binding's service object was not included",
+ bindingTwo.getObject());
+ assertTrue("Binding's service object was not the correct type",
+ bindingTwo.getObject() instanceof Closeable);
+
+ assertFalse("NamingEnumeration should not contain any more elements",
+ namingEnumeration.hasMoreElements());
+
+ // verify exception handling
+ try {
+ namingEnumeration.nextElement();
+ fail("NoSuchElementException should have been thrown");
+ } catch (NoSuchElementException e) {
+ // expected exception
+ }
+
+ // verify exception handling
+ try {
+ namingEnumeration.next();
+ fail("NoSuchElementException should have been thrown");
+ } catch (NoSuchElementException e) {
+ // expected exception
+ }
+ }
+
+
+ public void testListBindingsWithNonEmptyString() throws Exception {
+ //setup mocks and test fixtures
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Bundle bundleMock = mockSupport.createMock(Bundle.class);
+ // service reference
+ ServiceReference serviceRefMockOne =
+ createServiceReferenceMock(mockSupport, bundleMock, 1);
+
+ ServiceReference serviceRefMockTwo =
+ createServiceReferenceMock(mockSupport, bundleMock, 2);
+
+ // mock filter
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ // mock BundleContext
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ Closeable closeable1 = mockSupport.createMock(Closeable.class);
+ Closeable closeable2 = mockSupport.createMock(Closeable.class);
+ expect(bundleContextMock.getService(serviceRefMockOne)).andReturn(closeable1).anyTimes();
+ expect(bundleContextMock.getService(serviceRefMockTwo)).andReturn(closeable2).anyTimes();
+
+ expect(bundleContextMock.createFilter("(service.id=1)")).andReturn(filterMock).anyTimes();
+ expect(bundleContextMock.createFilter("(service.id=2)")).andReturn(filterMock).anyTimes();
+ expect(bundleContextMock.getBundle()).andReturn(bundleMock).anyTimes();
+
+ mockSupport.replayAll();
+
+ // begin test
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:servicelist/java.io.Closeable");
+ urlParser.parse();
+ Context context =
+ new OSGiServiceListContext(bundleContextMock,
+ new ServiceReference[]{serviceRefMockOne, serviceRefMockTwo},
+ urlParser);
+
+ // call Context.list("") on returned service list context
+ try {
+ context.listBindings("this-string-is-not-valid");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch (OperationNotSupportedException namingException) {
+ // expected exception
+ }
+ }
+
+
+ /* private test utility methods */
+ private static ServiceReference createServiceReferenceMock(EasyMockSupport mockSupport, Bundle bundleMock, int serviceId) {
+ ServiceReference serviceRefMockOne =
+ mockSupport.createMock(ServiceReference.class);
+ expect(serviceRefMockOne.getProperty(Constants.SERVICE_ID)).andReturn(new Long(serviceId)).anyTimes();
+ expect(serviceRefMockOne.getBundle()).andReturn(bundleMock).anyTimes();
+ return serviceRefMockOne;
+ }
+
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/OSGiURLContextFactoryTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/OSGiURLContextFactoryTestCase.java
new file mode 100644
index 0000000..24ce1ad
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/OSGiURLContextFactoryTestCase.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import javax.naming.Context;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.spi.ObjectFactory;
+
+import org.easymock.EasyMockSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+import junit.framework.TestCase;
+
+import static org.easymock.EasyMock.*;
+
+public class OSGiURLContextFactoryTestCase extends TestCase {
+
+ public void testCreate() throws Exception {
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+
+ mockSupport.replayAll();
+ // begin test
+ new OSGiURLContextFactory(bundleContextMock);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testGetObjectInstance() throws Exception {
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+
+ mockSupport.replayAll();
+ // begin test
+ ObjectFactory testFactory =
+ new OSGiURLContextFactory(bundleContextMock);
+ Object result =
+ testFactory.getObjectInstance(null, null, null, null);
+ assertTrue("OSGiURLContextFactory returned an object that is not a Context",
+ result instanceof Context);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testLookupBundleContext() throws Exception {
+ // not sure if this is easily unit testable, since
+ // there is interaction with the AccessController
+
+ // mock setup
+// EasyMockSupport mockSupport = new EasyMockSupport();
+// BundleContext bundleContextMock =
+// mockSupport.createMock(BundleContext.class);
+// Bundle bundleMock =
+// mockSupport.createMock(Bundle.class);
+//
+// expect(bundleContextMock.getBundle()).andReturn(bundleMock);
+// expect(bundleMock.getBundleId()).andReturn(new Long(10));
+// expect(bundleMock.hasPermission(isA(Object.class))).andReturn(true);
+//
+// mockSupport.replayAll();
+// // begin test
+// ObjectFactory testFactory =
+// new OSGiURLContextFactory(bundleContextMock);
+// Object result =
+// testFactory.getObjectInstance(null, null, null, null);
+// assertTrue("OSGiURLContextFactory returned an object that is not a Context",
+// result instanceof Context);
+// Context context = (Context)result;
+//
+// assertSame("OSGiURLContextFactory did not return the expected BundleContext instance",
+// bundleContextMock, context.lookup("osgi:framework/bundleContext"));
+//
+//
+// mockSupport.verifyAll();
+ fail("test not implemented yet");
+ }
+
+ public void testLookupService() throws Exception {
+ final String expectedServiceInterface = TestService.class.getName();
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Bundle bundleMock =
+ mockSupport.createMock(Bundle.class);
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ ServiceReference serviceReferenceMock =
+ mockSupport.createMock(ServiceReference.class);
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ TestService serviceMock =
+ mockSupport.createMock(TestService.class);
+ expect(serviceReferenceMock.getProperty(Constants.SERVICE_ID)).andReturn("10");
+ expect(serviceReferenceMock.getBundle()).andReturn(bundleMock);
+ expect(bundleContextMock.getServiceReferences(expectedServiceInterface, null)).andReturn(new ServiceReference[] {serviceReferenceMock});
+ expect(bundleContextMock.getService(serviceReferenceMock)).andReturn(serviceMock).anyTimes();
+ expect(bundleContextMock.createFilter("(service.id=10)")).andReturn(filterMock);
+ bundleContextMock.addServiceListener(isA(ServiceListener.class), eq("(service.id=10)"));
+
+ mockSupport.replayAll();
+
+ ObjectFactory testFactory =
+ new OSGiURLContextFactory(bundleContextMock);
+ Object result =
+ testFactory.getObjectInstance(null, null, null, null);
+ assertTrue("OSGiURLContextFactory returned an object that is not a Context",
+ result instanceof Context);
+ Context context = (Context)result;
+
+ assertTrue("OSGiURLContextFactory did not return the correct Context type",
+ context instanceof NotSupportedContext);
+
+ TestService service = (TestService)context.lookup("osgi:service/" + expectedServiceInterface);
+ assertNotNull("OSGiURLContextFactory did not return the expected OSGi service",
+ service);
+
+ try {
+ context.bind("name", "value");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch (OperationNotSupportedException namingException) {
+ // expected exception
+ }
+
+
+ mockSupport.verifyAll();
+ }
+
+ interface TestService {
+ public String getData();
+ }
+
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/OSGiURLParserTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/OSGiURLParserTestCase.java
new file mode 100644
index 0000000..5b4c2f2
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/OSGiURLParserTestCase.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import junit.framework.TestCase;
+
+public class OSGiURLParserTestCase extends TestCase {
+
+ public void testCreate() throws Exception {
+ new OSGiURLParser("osgi:service/com.oracle.TestService");
+ }
+
+ public void testBasicParse() throws Exception {
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:service/com.oracle.TestService");
+ // should return without exception
+ urlParser.parse();
+ // verify correct information was parsed
+ assertEquals("Parser did not correctly return service interface",
+ "com.oracle.TestService", urlParser.getServiceInterface());
+ assertNull("Parser did not correctly return a null filter", urlParser.getFilter());
+ assertFalse("Parser did not correctly parse URL, no filter present",
+ urlParser.hasFilter());
+ assertFalse("Parser did not correctly interpret URL, no servicelist",
+ urlParser.isServiceListURL());
+
+
+ OSGiURLParser urlParserServiceList =
+ new OSGiURLParser("osgi:servicelist/com.oracle.AnotherTestService");
+ // should return without exception
+ urlParserServiceList.parse();
+ // verify correct information was parsed
+ assertEquals("Parser did not correctly return service interface",
+ "com.oracle.AnotherTestService", urlParserServiceList.getServiceInterface());
+ assertNull("Parser did not correctly return a null filter", urlParserServiceList.getFilter());
+ assertFalse("Parser did not correctly parse URL, no filter present",
+ urlParserServiceList.hasFilter());
+ assertTrue("Parser did not correctly interpret URL, servicelist",
+ urlParserServiceList.isServiceListURL());
+ }
+
+ public void testParseFilter() throws Exception {
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:service/com.oracle.TestService/testFilter");
+ // should return without exception
+ urlParser.parse();
+ // verify correct information was parsed
+ assertEquals("Parser did not correctly return service interface",
+ "com.oracle.TestService", urlParser.getServiceInterface());
+ assertEquals("Parser did not correctly return the expected filter",
+ "testFilter", urlParser.getFilter());
+ assertTrue("Parser did not correctly parse URL, filter present",
+ urlParser.hasFilter());
+ assertFalse("Parser did not correctly interpret URL, no servicelist",
+ urlParser.isServiceListURL());
+ }
+
+ public void testParseError() throws Exception {
+ // "testURL" is not a supported URL
+ OSGiURLParser urlParser = new OSGiURLParser("testURL:com.oracle.TestService");
+ try {
+ urlParser.parse();
+ fail("IllegalStateException should have been thrown");
+ } catch (IllegalStateException exception) {
+ // expected Exception
+ }
+
+ // zero-length service interface is an error
+ OSGiURLParser urlParser2 = new OSGiURLParser("osgi:service//testFilter");
+ try {
+ urlParser2.parse();
+ fail("IllegalStateException should have been thrown");
+ } catch (IllegalStateException exception) {
+ // expected Exception
+ }
+ }
+
+ public void testPreParseErrorChecks() throws Exception {
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:service/com.oracle.TestService");
+ // verify that all accessor methods throw an IllegalStateException
+ // prior to the parse() method being called
+ try {
+ urlParser.getServiceInterface();
+ fail("IllegalStateException should have been thrown");
+ } catch (IllegalStateException exception) {
+ // expected Exception
+ }
+
+ try {
+ urlParser.getFilter();
+ fail("IllegalStateException should have been thrown");
+ } catch (IllegalStateException exception) {
+ // expected Exception
+ }
+
+ try {
+ urlParser.hasFilter();
+ fail("IllegalStateException should have been thrown");
+ } catch (IllegalStateException exception) {
+ // expected Exception
+ }
+
+ try {
+ urlParser.isServiceListURL();
+ fail("IllegalStateException should have been thrown");
+ } catch (IllegalStateException exception) {
+ // expected Exception
+ }
+ }
+
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/ReflectionUtilsTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/ReflectionUtilsTestCase.java
new file mode 100644
index 0000000..803e70b
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/ReflectionUtilsTestCase.java
@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+import javax.naming.Context;
+
+import org.easymock.EasyMockSupport;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Filter;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+import junit.framework.TestCase;
+
+import static org.easymock.EasyMock.*;
+
+public class ReflectionUtilsTestCase extends TestCase {
+
+
+ public void testInvokeMethodOnContext() throws Throwable {
+ final String expectedName = "test-binding-name-one";
+ final String expectedValue = "invoke-method-on-context";
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Context contextMock =
+ mockSupport.createMock(Context.class);
+ expect(contextMock.lookup(expectedName)).andReturn(expectedValue);
+
+ mockSupport.replayAll();
+
+ // begin test
+ Method lookupMethod = Context.class.getMethod("lookup", String.class);
+ Object result = ReflectionUtils.invokeMethodOnContext(lookupMethod, contextMock, new Object[] {expectedName});
+ assertNotNull("ReflectionUtils returned null", result);
+ assertTrue("ReflectionUtils returned an incorrect type",
+ result instanceof String);
+ assertEquals("ReflectionUtils returned an incorrect string value",
+ expectedValue, result);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testInvokeMethodOnObject() throws Throwable {
+ final String expectedName = "test-binding-name-one";
+ final String expectedValue = "invoke-method-on-object";
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ Context contextMock =
+ mockSupport.createMock(Context.class);
+ expect(contextMock.lookup(expectedName)).andReturn(expectedValue);
+
+ mockSupport.replayAll();
+
+ // begin test
+ Method lookupMethod = Context.class.getMethod("lookup", String.class);
+ Object result = ReflectionUtils.invokeMethodOnObject(lookupMethod, contextMock, new Object[] {expectedName});
+ assertNotNull("ReflectionUtils returned null", result);
+ assertTrue("ReflectionUtils returned an incorrect type",
+ result instanceof String);
+ assertEquals("ReflectionUtils returned an incorrect string value",
+ expectedValue, result);
+
+ mockSupport.verifyAll();
+ }
+
+ public void testGetProxyForSingleService() throws Exception {
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ TestService serviceMock =
+ mockSupport.createMock(TestService.class);
+ expect(serviceMock.getValue()).andReturn("just a test");
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ Bundle bundleMock =
+ mockSupport.createMock(Bundle.class);
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:service/" + TestService.class.getName());
+ urlParser.parse();
+
+ ServiceReference serviceReferenceMock =
+ mockSupport.createMock(ServiceReference.class);
+ expect(serviceReferenceMock.getProperty(Constants.SERVICE_ID)).andReturn(new Long(1));
+ expect(serviceReferenceMock.getBundle()).andReturn(bundleMock).anyTimes();
+
+ expect(bundleContextMock.getService(serviceReferenceMock)).andReturn(serviceMock).times(2);
+ expect(bundleContextMock.createFilter("(service.id=1)")).andReturn(filterMock);
+ bundleContextMock.addServiceListener(isA(ServiceListener.class), isA(String.class));
+ expectLastCall().anyTimes();
+
+ mockSupport.replayAll();
+
+ // begin test
+ ServiceProxyInfo result =
+ ReflectionUtils.getProxyForSingleService(bundleContextMock, urlParser, serviceReferenceMock);
+ assertNotNull("ReflectionUtils did not return a service proxy info",
+ result);
+ assertTrue("ReflectionUtils did not proxy the object as expected",
+ result.isProxied());
+ assertNotSame("ReflectionUtils did not return the expected proxy",
+ result.getService(), serviceMock);
+ assertNotNull("ReflectionUtils did not set the InvocationHandler type",
+ result.getHandler());
+ assertEquals("ReflectionUtils returned a proxy for an unexpected object",
+ "just a test", ((TestService)result.getService()).getValue());
+
+
+ mockSupport.verifyAll();
+ }
+
+
+ public void testGetProxyForSingleServiceUsingJNDIServiceName() throws Exception {
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ TestService serviceMock =
+ mockSupport.createMock(TestService.class);
+ expect(serviceMock.getValue()).andReturn("just a test");
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ Bundle bundleMock =
+ mockSupport.createMock(Bundle.class);
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:service/" + "anotherName");
+
+ urlParser.parse();
+
+ ServiceReference serviceReferenceMock =
+ mockSupport.createMock(ServiceReference.class);
+ expect(serviceReferenceMock.getProperty(Constants.SERVICE_ID)).andReturn(new Long(1));
+ expect(serviceReferenceMock.getProperty(Constants.OBJECTCLASS)).andReturn(new String[] {TestService.class.getName()});
+ expect(serviceReferenceMock.getBundle()).andReturn(bundleMock).anyTimes();
+ expect(serviceReferenceMock.isAssignableTo(bundleMock, TestService.class.getName())).andReturn(true);
+
+ expect(bundleContextMock.getService(serviceReferenceMock)).andReturn(serviceMock).times(2);
+ expect(bundleContextMock.createFilter("(service.id=1)")).andReturn(filterMock);
+ expect(bundleContextMock.getBundle()).andReturn(bundleMock).anyTimes();
+ bundleContextMock.addServiceListener(isA(ServiceListener.class), isA(String.class));
+ expectLastCall().anyTimes();
+
+ mockSupport.replayAll();
+
+ // begin test
+ ServiceProxyInfo result =
+ ReflectionUtils.getProxyForSingleService(bundleContextMock, urlParser, serviceReferenceMock);
+ assertNotNull("ReflectionUtils did not return a service proxy info",
+ result);
+ assertTrue("ReflectionUtils did not proxy the object as expected",
+ result.isProxied());
+ assertNotSame("ReflectionUtils did not return the expected proxy",
+ result.getService(), serviceMock);
+ assertNotNull("ReflectionUtils did not set the InvocationHandler type",
+ result.getHandler());
+ assertEquals("ReflectionUtils returned a proxy for an unexpected object",
+ "just a test", ((TestService)result.getService()).getValue());
+
+
+ mockSupport.verifyAll();
+ }
+
+
+ public void testGetProxyForSingleServiceUsingJNDIServiceNameNoInterface() throws Exception {
+ final OSGiURLParser urlParser = new OSGiURLParser("osgi:service/" + "anotherName");
+ urlParser.parse();
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ TestService serviceMock =
+ mockSupport.createMock(TestService.class);
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ ServiceReference serviceReferenceMock =
+ mockSupport.createMock(ServiceReference.class);
+ // return a service class name that does not exist in the classpath
+ expect(serviceReferenceMock.getProperty(Constants.OBJECTCLASS)).andReturn(new String[] {"com.oracle.does.not.exist.TestService"});
+ expect(bundleContextMock.getService(serviceReferenceMock)).andReturn(serviceMock);
+
+ mockSupport.replayAll();
+
+ // begin test
+ try {
+ ReflectionUtils.getProxyForSingleService(bundleContextMock, urlParser, serviceReferenceMock);
+ fail("IllegalArgumentException should have been thrown");
+ } catch (IllegalArgumentException illegalArgumentException) {
+ // expected exception
+ }
+
+
+
+ mockSupport.verifyAll();
+ }
+
+ public void testGetProxyForSingleServiceWithInvocationHandlerFactory() throws Throwable {
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ TestService serviceMock =
+ mockSupport.createMock(TestService.class);
+ expect(serviceMock.getValue()).andReturn("just a test");
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ Bundle bundleMock =
+ mockSupport.createMock(Bundle.class);
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:service/" + TestService.class.getName());
+ urlParser.parse();
+
+ ServiceReference serviceReferenceMock =
+ mockSupport.createMock(ServiceReference.class);
+ expect(serviceReferenceMock.getProperty(Constants.SERVICE_ID)).andReturn(new Long(1));
+ expect(serviceReferenceMock.getBundle()).andReturn(bundleMock).anyTimes();
+
+ expect(bundleContextMock.getService(serviceReferenceMock)).andReturn(serviceMock).times(2);
+ expect(bundleContextMock.createFilter("(service.id=1)")).andReturn(filterMock);
+ bundleContextMock.addServiceListener(isA(ServiceListener.class), isA(String.class));
+ expectLastCall().anyTimes();
+
+ InvocationHandlerFactory handlerFactoryMock =
+ mockSupport.createMock(InvocationHandlerFactory.class);
+ InvocationHandler handlerMock =
+ mockSupport.createMock(InvocationHandler.class);
+
+ expect(handlerMock.invoke(isA(Object.class), isA(Method.class), (Object[])anyObject())).andReturn("just a test");
+ expect(handlerFactoryMock.create(bundleContextMock, serviceReferenceMock, urlParser, serviceMock)).andReturn(handlerMock);
+
+ mockSupport.replayAll();
+
+ // begin test
+ ServiceProxyInfo result =
+ ReflectionUtils.getProxyForSingleService(bundleContextMock,
+ urlParser,
+ serviceReferenceMock,
+ handlerFactoryMock);
+
+
+ assertNotNull("ReflectionUtils did not return a service proxy info",
+ result);
+ assertTrue("ReflectionUtils did not proxy the object as expected",
+ result.isProxied());
+ assertNotSame("ReflectionUtils did not return the expected proxy",
+ result.getService(), serviceMock);
+ assertNotNull("ReflectionUtils did not set the InvocationHandler type",
+ result.getHandler());
+ assertSame("ReflectionUtils did not return the expected InvocationHandler",
+ handlerMock, result.getHandler());
+ assertEquals("ReflectionUtils returned a proxy for an unexpected object",
+ "just a test", ((TestService)result.getService()).getValue());
+
+ }
+
+
+ public void testGetProxyForSingleServiceWithInvocationHandlerFactoryClassType() throws Throwable {
+ // mock setup
+ EasyMockSupport mockSupport = new EasyMockSupport();
+ TestAnotherService serviceStub =
+ new TestAnotherService("a value from a class");
+
+ Filter filterMock =
+ mockSupport.createMock(Filter.class);
+ Bundle bundleMock =
+ mockSupport.createMock(Bundle.class);
+ BundleContext bundleContextMock =
+ mockSupport.createMock(BundleContext.class);
+ OSGiURLParser urlParser = new OSGiURLParser("osgi:service/" + TestAnotherService.class.getName());
+ urlParser.parse();
+
+ ServiceReference serviceReferenceMock =
+ mockSupport.createMock(ServiceReference.class);
+ expect(serviceReferenceMock.getProperty(Constants.SERVICE_ID)).andReturn(new Long(1));
+ expect(serviceReferenceMock.getBundle()).andReturn(bundleMock).anyTimes();
+
+ expect(bundleContextMock.getService(serviceReferenceMock)).andReturn(serviceStub).times(2);
+ expect(bundleContextMock.createFilter("(service.id=1)")).andReturn(filterMock);
+ bundleContextMock.addServiceListener(isA(ServiceListener.class), isA(String.class));
+ expectLastCall().anyTimes();
+
+ InvocationHandlerFactory handlerFactoryMock =
+ mockSupport.createMock(InvocationHandlerFactory.class);
+ InvocationHandler handlerMock =
+ mockSupport.createMock(InvocationHandler.class);
+
+ expect(handlerMock.invoke(isA(Object.class), isA(Method.class), (Object[])anyObject())).andReturn("just a test");
+ expect(handlerFactoryMock.create(bundleContextMock, serviceReferenceMock, urlParser, serviceStub)).andReturn(handlerMock);
+
+ mockSupport.replayAll();
+
+ // begin test
+ ServiceProxyInfo result =
+ ReflectionUtils.getProxyForSingleService(bundleContextMock,
+ urlParser,
+ serviceReferenceMock,
+ handlerFactoryMock);
+
+
+ assertNotNull("ReflectionUtils did not return a service proxy info",
+ result);
+ assertFalse("ReflectionUtils should not have proxied this object (class type)",
+ result.isProxied());
+ assertSame("ReflectionUtils did not return the expected service",
+ result.getService(), serviceStub);
+ assertNull("ReflectionUtils incorrect set the InvocationHandler type",
+ result.getHandler());
+ assertEquals("ReflectionUtils returned a proxy for an unexpected object",
+ "a value from a class", ((TestAnotherService)result.getService()).getValue());
+
+ }
+
+ public interface TestService {
+ public String getValue();
+ }
+
+ public class TestAnotherService {
+ private final String m_value;
+
+ TestAnotherService(String value) {
+ m_value = value;
+ }
+
+ public String getValue() {
+ return m_value;
+ }
+ }
+}
diff --git a/framework/src/test/java/org/eclipse/gemini/naming/ServiceProxyInfoTestCase.java b/framework/src/test/java/org/eclipse/gemini/naming/ServiceProxyInfoTestCase.java
new file mode 100644
index 0000000..1d8069b
--- /dev/null
+++ b/framework/src/test/java/org/eclipse/gemini/naming/ServiceProxyInfoTestCase.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton (Oracle) - Initial Reference Implementation Unit Tests
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+import junit.framework.TestCase;
+
+public class ServiceProxyInfoTestCase extends TestCase {
+
+ /**
+ * Verifies basic creation of this datatype.
+ */
+ public void testCreate() throws Exception {
+ final Object testService = new Object();
+ final InvocationHandler testHandler = new InvocationHandler() {
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ return null;
+ }
+ };
+
+ ServiceProxyInfo proxyInfo =
+ new ServiceProxyInfo(testService, testHandler, true);
+
+ assertSame("ServiceProxyInfo did not return the correct service",
+ testService, proxyInfo.getService());
+ assertSame("ServiceProxyInfo did not return the correct handler",
+ testHandler, proxyInfo.getHandler());
+ assertTrue("ServiceProxyInfo did not return the correct proxy status",
+ proxyInfo.isProxied());
+
+ ServiceProxyInfo anotherProxyInfo =
+ new ServiceProxyInfo(testService, testHandler, false);
+ assertSame("ServiceProxyInfo did not return the correct service",
+ testService, anotherProxyInfo.getService());
+ assertSame("ServiceProxyInfo did not return the correct handler",
+ testHandler, anotherProxyInfo.getHandler());
+ assertFalse("ServiceProxyInfo did not return the correct proxy status",
+ anotherProxyInfo.isProxied());
+
+ }
+}
diff --git a/integration-testing/pom.xml b/integration-testing/pom.xml
new file mode 100644
index 0000000..347d2d5
--- /dev/null
+++ b/integration-testing/pom.xml
@@ -0,0 +1,90 @@
+<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.eclipse.gemini.naming</groupId>
+ <artifactId>org.eclipse.gemini.naming</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.eclipse.gemini.naming</groupId>
+ <artifactId>gemini-naming-integration-testing</artifactId>
+
+ <packaging>jar</packaging>
+ <name>Integration Tests for the Gemini Naming Implementation</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.eclipse.osgi</groupId>
+ <artifactId>org.eclipse.osgi</artifactId>
+ <version>${equinox.version}</version>
+ <type>jar</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>osgi_R4_compendium</artifactId>
+ <version>1.0</version>
+ <type>jar</type>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Dependency on the Gemini Naming Bundle -->
+ <dependency>
+ <groupId>org.eclipse.gemini.naming</groupId>
+ <artifactId>org.eclipse.gemini.naming.impl.bundle-Incubation</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <type>jar</type>
+ <scope>provided</scope>
+ </dependency>
+
+ <!--
+ dependency on the Spring OSGi Test Framework for integration testing
+ -->
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>org.springframework.osgi.test</artifactId>
+ <version>1.2.1</version>
+ </dependency>
+
+ <!--
+ The following dependencies seem to be required by the Spring OSGi
+ Test Framework
+ -->
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>log4j.osgi</artifactId>
+ <version>1.2.15-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>spring-osgi-annotation</artifactId>
+ <version>1.2.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.osgi</groupId>
+ <artifactId>spring-osgi-extender</artifactId>
+ <version>1.2.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>com.springsource.org.apache.commons.logging</artifactId>
+ <version>1.1.1</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.objectweb.asm</groupId>
+ <artifactId>com.springsource.org.objectweb.asm</artifactId>
+ <version>2.2.3</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
+
diff --git a/integration-testing/src/test/java/org/eclipse/gemini/naming/test/ContextAdminTestCase.java b/integration-testing/src/test/java/org/eclipse/gemini/naming/test/ContextAdminTestCase.java
new file mode 100644
index 0000000..ab37a8a
--- /dev/null
+++ b/integration-testing/src/test/java/org/eclipse/gemini/naming/test/ContextAdminTestCase.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton - Initial Developer tests for Reference Implementation
+ ******************************************************************************/
+
+/**
+ * Test Case to verify the behavior of the Gemini Naming
+ * implementation of the JNDIProviderAdmin interface.
+ */
+
+package org.eclipse.gemini.naming.test;
+
+
+import java.util.Hashtable;
+
+import javax.naming.Context;
+import javax.naming.Name;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.directory.Attributes;
+import javax.naming.spi.DirObjectFactory;
+import javax.naming.spi.ObjectFactory;
+import javax.naming.spi.ObjectFactoryBuilder;
+
+
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.jndi.JNDIProviderAdmin;
+
+
+public class ContextAdminTestCase extends NamingTestCase {
+
+ private static String VERSION = "1.0-SNAPSHOT";
+
+ protected String[] getTestBundlesNames() {
+ return new String[]{ "org.eclipse.gemini.naming, org.eclipse.gemini.naming.impl.bundle-Incubation," + VERSION,
+ "org.osgi.service.jndi,org.osgi.service.jndi,1.0",
+ };
+ }
+
+ /**
+ * Verifies that the JNDIProviderAdmin service is made
+ * available by the Gemini Naming implementation.
+ */
+ public void testServiceAvailable() throws Exception {
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIProviderAdmin");
+ assertNotNull("JNDIProviderAdmin service was not published as expected", serviceReference);
+
+ JNDIProviderAdmin contextAdmin =
+ (JNDIProviderAdmin) getContext().getService(serviceReference);
+ assertNotNull("JNDIProviderAdmin service not available via factory", contextAdmin);
+ }
+
+ /**
+ * Verifies basic behavior of the JNDIProviderAdmin.getObjectInstance() method.
+ */
+ public void testGetObjectInstance() throws Exception {
+ // test setup
+ final int expectedValue = 100;
+ // stub builder to be used in test
+ ObjectFactoryBuilder factoryBuilder = new ObjectFactoryBuilder() {
+ public ObjectFactory createObjectFactory(Object var0, Hashtable var1) throws NamingException {
+ return new ObjectFactory() {
+ public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
+ return new Integer(expectedValue);
+ }
+ };
+ }
+ };
+
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIProviderAdmin");
+ assertNotNull("JNDIProviderAdmin service was not published as expected", serviceReference);
+
+ JNDIProviderAdmin contextAdmin =
+ (JNDIProviderAdmin) getContext().getService(serviceReference);
+
+ // only register the builder implementation
+ registerService(ObjectFactoryBuilder.class.getName(), factoryBuilder, null);
+
+
+ // reference data does not matter, since we're testing that
+ // the factory manager can locate the only ObjectFactory registered.
+ Reference reference = new Reference("test", "com.test.factory.DoesNotExist", null);
+ // invoke getObjectInstance on the JNDIProviderAdmin service
+ Object result = contextAdmin.getObjectInstance(reference, null, null, new Hashtable());
+ assertEquals("JNDI Factory Manager did not locate the correct ObjectFactory",
+ new Integer(expectedValue), result);
+ }
+
+
+ /**
+ * Verifies the behavior of the JNDIProviderAdmin.getObjectInstance() method
+ * that takes an Attributes object as a parameter.
+ */
+ public void testGetObjectInstanceWithAttributes() throws Exception {
+ String[] serviceInterfaces = { DirObjectFactory.class.getName(),
+ TestDirObjectFactory.class.getName() };
+ ServiceRegistration serviceRegistration =
+ getContext().registerService(serviceInterfaces,
+ new TestDirObjectFactory(),
+ null);
+
+ try {
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIProviderAdmin");
+ assertNotNull("JNDIProviderAdmin service was not published as expected", serviceReference);
+
+ JNDIProviderAdmin contextAdmin =
+ (JNDIProviderAdmin) getContext().getService(serviceReference);
+
+ Reference reference = new Reference("test",
+ TestDirObjectFactory.class.getName(), null);
+ Object result = contextAdmin.getObjectInstance(reference, null, null, new Hashtable(), null);
+ assertNotNull("JNDIProviderAdmin did not properly consult the DirObjectFactory",
+ result);
+ assertTrue("JNDIProviderAdmin returned an incorrect type",
+ result instanceof Integer);
+ assertEquals("JNDIProviderAdmin returned an incorrect value",
+ new Integer(100), result);
+ }
+ finally {
+ serviceRegistration.unregister();
+ }
+ }
+
+ /**
+ * Verifies that the JNDIProviderAdmin.getObjectInstance() implementation
+ * will query on ObjectFactoryBuilder services first in an attempt to
+ * resolve an object.
+ */
+ public void testGetObjectInstanceWithAttributesUsingBuilder() throws Exception {
+ // setup test builder
+ final ObjectFactoryBuilder builder = new ObjectFactoryBuilder() {
+ public ObjectFactory createObjectFactory(Object refInfo, Hashtable environment) throws NamingException {
+ return new TestDirObjectFactory();
+ }
+ };
+
+ // should be ignored, since it only supports ObjectFactory
+ final ObjectFactoryBuilder builder2 = new ObjectFactoryBuilder() {
+ public ObjectFactory createObjectFactory(Object refInfo, Hashtable environment) throws NamingException {
+ return new ObjectFactory() {
+ public Object getObjectInstance(Object var0, Name var1,
+ Context var2, Hashtable var3)
+ throws Exception {
+ return null;
+ }
+
+ };
+ }
+ };
+
+ registerService(ObjectFactoryBuilder.class.getName(),
+ builder, null);
+
+ registerService(ObjectFactoryBuilder.class.getName(),
+ builder2, null);
+
+ // test should resolve reference with builder installed,
+ // since the DirObjectFactory is indirectly created by the builder
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIProviderAdmin");
+ assertNotNull("JNDIProviderAdmin service was not published as expected", serviceReference);
+
+ JNDIProviderAdmin contextAdmin =
+ (JNDIProviderAdmin) getContext().getService(serviceReference);
+
+ Reference reference = new Reference("test",
+ TestDirObjectFactory.class.getName(), null);
+ Object result = contextAdmin.getObjectInstance(reference, null, null, new Hashtable(), null);
+ assertNotNull("JNDIProviderAdmin did not properly consult the DirObjectFactory",
+ result);
+
+ assertFalse("JNDIProviderAdmin should not have returned reference",
+ result instanceof Reference);
+ assertTrue("JNDIProviderAdmin returned an incorrect type",
+ result instanceof Integer);
+
+ assertEquals("JNDIProviderAdmin returned an incorrect value",
+ new Integer(100), result);
+ }
+
+ /**
+ * Verifies that JNDIProviderAdmin.getObjectInstance() can support
+ * calls that pass in an Object to be resolved that is not a Reference.
+ */
+ public void testGetObjectInstanceWithAttributesUsingNonReference()
+ throws Exception {
+ // setup test builder
+ final ObjectFactoryBuilder builder = new ObjectFactoryBuilder() {
+ public ObjectFactory createObjectFactory(Object refInfo, Hashtable environment) throws NamingException {
+ return new TestDirObjectFactory();
+ }
+ };
+
+ registerService(ObjectFactoryBuilder.class.getName(), builder, null);
+
+ ServiceReference serviceReference =
+ getContext().getServiceReference(
+ "org.osgi.service.jndi.JNDIProviderAdmin");
+ assertNotNull("JNDIProviderAdmin service was not published as expected",
+ serviceReference);
+
+ JNDIProviderAdmin contextAdmin =
+ (JNDIProviderAdmin) getContext().getService(serviceReference);
+
+ Object result =
+ contextAdmin.getObjectInstance("This is only a test, and is not a Reference", null, null, new Hashtable(), null);
+ assertNotNull(
+ "JNDIProviderAdmin did not properly consult the DirObjectFactory",
+ result);
+ assertTrue("JNDIProviderAdmin returned an incorrect type",
+ result instanceof Integer);
+ assertEquals("JNDIProviderAdmin returned an incorrect value",
+ new Integer(100), result);
+
+
+ }
+
+
+ /* Test classes */
+ private static class TestDirObjectFactory implements DirObjectFactory {
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context,
+ Hashtable environment, Attributes attributes) throws Exception {
+ return new Integer(100);
+ }
+
+ public Object getObjectInstance(Object refInfo, Name name, Context context,
+ Hashtable environment) throws Exception {
+ return null;
+ }
+
+ }
+}
diff --git a/integration-testing/src/test/java/org/eclipse/gemini/naming/test/ContextManagerTestCase.java b/integration-testing/src/test/java/org/eclipse/gemini/naming/test/ContextManagerTestCase.java
new file mode 100644
index 0000000..a701c8c
--- /dev/null
+++ b/integration-testing/src/test/java/org/eclipse/gemini/naming/test/ContextManagerTestCase.java
@@ -0,0 +1,919 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton - Initial Developer tests for Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming.test;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+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.NoInitialContextException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.directory.DirContext;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.jndi.JNDIContextManager;
+
+
+/**
+ * Class used to verify the behavior of the JNDIContextManager service.
+ *
+ * @author Bob Nettleton
+ *
+ */
+public class ContextManagerTestCase extends NamingTestCase {
+
+ private static String VERSION = "1.0-SNAPSHOT";
+
+ protected String[] getTestBundlesNames() {
+ return new String[]{ "org.eclipse.gemini.naming, org.eclipse.gemini.naming.impl.bundle-Incubation," + VERSION,
+ "org.osgi.service.jndi,org.osgi.service.jndi,1.0",
+ };
+ }
+
+ /**
+ * Verifies that if a specific InitialContextFactory is requested by
+ * a client, and that factory is not available, the Factory Manager will query the
+ * list of known InitialContextFactoryBuilder implementations to try
+ * and create a suitable context.
+ *
+ * Please see section 5.2.1.1 of RFC 142 for more details.
+ *
+ * @throws Exception
+ */
+ public void testSpecificFactoryResolvedByBuilder() throws Exception {
+ final String expectedBindingName = "test-binding-one";
+ final String expectedBindingValue = "this is only a test";
+
+ // setup a test context
+ Context testContext = new FactoryResolutionTestCase.TestContext() {
+ public Object lookup(String name) throws NamingException {
+ if (name.equals(expectedBindingName)) {
+ return expectedBindingValue;
+ }
+
+ throw new NameNotFoundException("Error in JNDI test");
+ }
+
+ };
+
+ // register a builder service
+ registerService(InitialContextFactoryBuilder.class.getName(),
+ new FactoryResolutionTestCase.TestContextFactoryBuilder(testContext), null);
+
+ Hashtable environment = new Hashtable();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.test.factory.FactoryDoesNotExist");
+ environment.put("osgi.service.jndi.bundleContext", bundleContext);
+ // builder should provide an InitialContextFactory implementation
+ InitialContext initialContext = null;
+ try {
+ initialContext = new InitialContext(environment);
+ // verify that the expected value is returned
+ assertEquals("Factory Manager did not return the expected factory",
+ expectedBindingValue, initialContext.lookup(expectedBindingName));
+ } finally {
+ initialContext.close();
+ }
+
+ // attempt the same test from the context manager service
+
+ ServiceReference serviceRef =
+ getContext().getServiceReference(JNDIContextManager.class.getName());
+ JNDIContextManager contextManager =
+ (JNDIContextManager)getContext().getService(serviceRef);
+ assertNotNull("Context Manager service not available", contextManager);
+ Context serviceInitialContext = contextManager.newInitialContext(environment);
+ // verify that context returned from manager behaves the same
+ assertEquals("Factory Manager did not return the expected factory",
+ expectedBindingValue, serviceInitialContext.lookup(expectedBindingName));
+
+ getContext().ungetService(serviceRef);
+ }
+
+
+ /**
+ * Verifies that the Gemini Naming bundle provides an implementation
+ * of the JNDIContextManager service interface.
+ */
+ public void testJNDIContextManagerServiceAvailable() throws Exception {
+ ServiceReference serviceReference = null;
+ try {
+ serviceReference = getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ assertNotNull("JNDIContextManager was not published as expected", serviceReference);
+ } finally {
+ if(serviceReference != null) {
+ getContext().ungetService(serviceReference);
+ }
+ }
+ }
+
+ /**
+ * Verifies that the implementation of JNDIContextManager.newInitialContext() will
+ * query the available InitialContextFactoryBuilder services to create a "default" context,
+ * if the JNDI client has not specified which factory to use to create the Context.
+ */
+ public void testJNDIContextManagerCreateDefaultContextWithBuilder() throws Exception {
+ final String expectedName = "test-one";
+ final String expectedValue = "this is only a test";
+ // test setup
+ final Context testContext = new ExpectedValueTestContext(expectedName, expectedValue);
+ InitialContextFactoryBuilder builder =
+ new FactoryResolutionTestCase.TestContextFactoryBuilder(testContext);
+ registerService(InitialContextFactoryBuilder.class.getName(), builder, null);
+
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ // create a context with the default environment setup
+ Context initialContext = contextManager.newInitialContext();
+ assertNotNull("JNDIContextManager did not create a new default context", initialContext);
+ assertEquals("JNDIContextManager did not return the correct context",
+ expectedValue, initialContext.lookup(expectedName));
+ getContext().ungetService(serviceReference);
+ }
+
+
+ /**
+ * Verify that if a Builder service is un-registered, that the JNDI Context
+ * created by this Builder will throw the appropriate exception. If the service
+ * is re-registered, the Context should function properly as before the service
+ * was un-registered.
+ */
+ public void testJNDIContextManagerCreateDefaultContextWithBuilderThenRemoveBuilder() throws Exception {
+ final String expectedName = "test-one";
+ final String expectedValue = "this is only a test";
+ // test setup
+ final Context testContext = new ExpectedValueTestContext(expectedName, expectedValue);
+ InitialContextFactoryBuilder builder =
+ new FactoryResolutionTestCase.TestContextFactoryBuilder(testContext);
+ registerService(InitialContextFactoryBuilder.class.getName(), builder, null);
+
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ // create a context with the default environment setup
+ Context initialContext = contextManager.newInitialContext();
+ assertNotNull("JNDIContextManager did not create a new default context", initialContext);
+ assertEquals("JNDIContextManager did not return the correct context",
+ expectedValue, initialContext.lookup(expectedName));
+
+ unregisterService(builder);
+ // try lookup again, without builder being available
+ try {
+ initialContext.lookup(expectedName);
+ fail("NoInitialContextException should have been thrown");
+ } catch (NoInitialContextException e) {
+ // expected exception
+ }
+
+ // re-register Builder service
+ registerService(InitialContextFactoryBuilder.class.getName(),
+ builder, null);
+
+ assertEquals("JNDIContextManager did not return the correct context after re-bind of Builder service",
+ expectedValue, initialContext.lookup(expectedName));
+
+ getContext().ungetService(serviceReference);
+ }
+
+
+ /**
+ * Verify that when all references to the JNDIContextManager service
+ * are released (with an ungetService() call), the JNDIContextManager service
+ * implementation will call Context.close() on all Contexts created for the client
+ * by this service.
+ */
+ public void testJNDIContextManagerContextClose() throws Exception {
+ final String expectedName = "test-one";
+ final String expectedValue = "this is only a test";
+ // test setup
+ final ExpectedValueTestContext testContext =
+ new ExpectedValueTestContext(expectedName, expectedValue);
+ InitialContextFactoryBuilder builder =
+ new FactoryResolutionTestCase.TestContextFactoryBuilder(testContext);
+ registerService(InitialContextFactoryBuilder.class.getName(), builder, null);
+
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ try {
+ // create a context with the default environment setup
+ Context initialContext = contextManager.newInitialContext();
+ assertNotNull("JNDIContextManager did not create a new default context", initialContext);
+ assertEquals("JNDIContextManager did not return the correct context",
+ expectedValue, initialContext.lookup(expectedName));
+
+ // remove reference to service, this should trigger a close() call
+ // on the context instance.
+ assertEquals("JNDIContextManager service should not have closed the context yet",
+ 0, testContext.getNumCloseCalls());
+ getContext().ungetService(serviceReference);
+ assertEquals("JNDIContextManager service did not properly close the created context",
+ 1, testContext.getNumCloseCalls());
+ } finally {
+ getContext().ungetService(serviceReference);
+ }
+
+ }
+
+
+ /**
+ * Verify that if no factories or builders exist to create a Context, the
+ * "default" Context instance returned will not support bind() calls.
+ */
+ public void testJNDIContextManagerCreateDefaultContextWithoutBuilder() throws Exception {
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ // create a context with the default environment setup
+ try {
+ // this should fail
+ Context initialContext = contextManager.newInitialContext();
+ initialContext.bind("this is just a test", "test object one");
+ fail("NoInitialContextException should have been thrown");
+ }
+ catch (NoInitialContextException namingException) {
+ // expected exception
+ }
+
+ getContext().ungetService(serviceReference);
+ }
+
+
+
+ /**
+ * Verify basic creation of DirContexts.
+ */
+ public void testCreateDirContext() throws Exception {
+ // setup test InitialContextFactory service
+ String[] serviceInterfaceNames = {InitialContextFactory.class.getName(),
+ TestInitialDirContextFactory.class.getName()};
+ ServiceRegistration serviceRegistration =
+ getContext().registerService(serviceInterfaceNames,
+ new TestInitialDirContextFactory(), null);
+
+ try {
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ Hashtable environment = new Hashtable();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY,
+ TestInitialDirContextFactory.class.getName());
+
+ DirContext dirContext =
+ contextManager.newInitialDirContext(environment);
+ assertNotNull("JNDIContextManager did not create a DirContext as expected",
+ dirContext);
+
+ getContext().ungetService(serviceReference);
+ }
+ finally {
+ if(serviceRegistration != null) {
+ serviceRegistration.unregister();
+ }
+ }
+ }
+
+
+ /**
+ * Verify creation of DirContext using an InitialContextFactoryBuilder.
+ */
+ public void testJNDIContextManagerCreateDefaultDirContextWithBuilder() throws Exception {
+ // test setup
+ InitialContextFactoryBuilder builder =
+ new InitialContextFactoryBuilder() {
+ public InitialContextFactory createInitialContextFactory(
+ Hashtable var0) throws NamingException {
+ return new TestInitialDirContextFactory();
+ }
+ };
+
+ registerService(InitialContextFactoryBuilder.class.getName(),
+ builder, null);
+
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ // create a context with the default environment setup
+ DirContext initialDirContext = contextManager.newInitialDirContext();
+ assertNotNull("JNDIContextManager did not create a new default context", initialDirContext);
+
+ getContext().ungetService(serviceReference);
+ }
+
+
+ /**
+ * Verify that the methods to create a DirContext on the JNDIContextManager
+ * interface check the type of the created Context. If the object is not an
+ * instanceof DirContext, a NoInitialContextException should be thrown.
+ *
+ */
+ public void testJNDIContextManagerCreateDirContextWithBuilderWrongType() throws Exception {
+ // test setup
+ registerService(InitialContextFactoryBuilder.class.getName(),
+ new FactoryResolutionTestCase.TestContextFactoryBuilder(new FactoryResolutionTestCase.TestContext()), null);
+
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ // create a context with an environment config
+ try {
+ contextManager.newInitialDirContext(new Hashtable());
+ fail("NoInitialContextException should have been thrown");
+ }
+ catch (NoInitialContextException e) {
+ // expected exception
+ }
+
+ // create a context with the default environment config
+ try {
+ contextManager.newInitialDirContext();
+ fail("NoInitialContextException should have been thrown");
+ }
+ catch (NoInitialContextException e) {
+ // expected exception
+ }
+
+ getContext().ungetService(serviceReference);
+ }
+
+ /**
+ * Verify that if no builders or factories exist to create the DirContext,
+ * then a NoInitialContextException should be thrown.
+ *
+ */
+ public void testJNDIContextManagerCreateDefaultDirContextWithoutBuilder() throws Exception {
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ // create a context with the default environment setup
+ try {
+ // this should fail
+ contextManager.newInitialDirContext();
+ fail("NoInitialContextException should have been thrown");
+ }
+ catch (NoInitialContextException namingException) {
+ // expected exception
+ }
+
+ getContext().ungetService(serviceReference);
+ }
+
+
+ /**
+ * Verify the basic behavior of an "osgi:servicelist" lookup, including
+ * the basic operations of the NamingEnumeration associated with this type
+ * of lookup (Context.list()).
+ */
+ public void testJNDIServiceListNamingEnumeration() throws Exception {
+ final String expectedBindingName = "test-binding-one";
+ final String expectedBindingValue = "this is only a test";
+
+ // setup a test context
+ Context testContext =
+ new ExpectedValueTestContext(expectedBindingName, expectedBindingValue);
+
+ // register a builder service
+ registerService(InitialContextFactoryBuilder.class.getName(),
+ new FactoryResolutionTestCase.TestContextFactoryBuilder(testContext), null);
+
+ registerService(Closeable.class.getName(), new NoOpCloseable(), null);
+ registerService(Closeable.class.getName(), new NoOpCloseable(), null);
+
+ ServiceReference[] builderReferences =
+ getContext().getServiceReferences(Closeable.class.getName(), null);
+
+ final Set setOfIds = new HashSet();
+ for(int i = 0; i < builderReferences.length; i++) {
+ setOfIds.add(builderReferences[i].getProperty(Constants.SERVICE_ID).toString());
+ }
+
+ assertEquals("Initial set of services is not the expected number",
+ 2, setOfIds.size());
+
+
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+
+ try {
+ Context initialContext = contextManager.newInitialContext(new Hashtable());
+ Context serviceListContext = (Context)initialContext.lookup("osgi:servicelist/" + Closeable.class.getName());
+
+ final int originalNumberOfServicesInUse =
+ getContext().getBundle().getServicesInUse().length;
+
+ assertNotNull("JNDI implementation did not return the expected context type for a servicelist URL",
+ serviceListContext);
+ NamingEnumeration namingEnum = serviceListContext.list("");
+ assertTrue("NamingEnumeration did not contain any elements",
+ namingEnum.hasMoreElements());
+
+ Object result = namingEnum.next();
+ assertNotNull("NamingEnumeration did not contain the expected service",
+ result);
+ assertTrue("NamingEnumeration returned an unexpected type",
+ result instanceof NameClassPair);
+
+ NameClassPair nameClassPair = (NameClassPair)result;
+ assertEquals("NameClassPair did not contain the expected type",
+ Closeable.class.getName(),
+ nameClassPair.getClassName());
+ assertTrue("NameClassPair did not contain an expected ID",
+ setOfIds.contains(nameClassPair.getName()));
+
+ assertTrue("NamingEnumeration should contain one more element",
+ namingEnum.hasMoreElements());
+
+ NameClassPair nameClassPairTwo = (NameClassPair)namingEnum.next();
+ assertEquals("NameClassPair did not contain the expected type",
+ Closeable.class.getName(),
+ nameClassPairTwo.getClassName());
+ assertTrue("NameClassPair did not contain an expected ID",
+ setOfIds.contains(nameClassPairTwo.getName()));
+
+ assertFalse("NamingEnumeration should not contain any more elements",
+ namingEnum.hasMoreElements());
+
+ // verify exception handling
+ try {
+ namingEnum.nextElement();
+ fail("NoSuchElementException should have been thrown");
+ } catch (NoSuchElementException e) {
+ // expected exception
+ }
+
+ // verify exception handling
+ try {
+ namingEnum.next();
+ fail("NoSuchElementException should have been thrown");
+ } catch (NoSuchElementException e) {
+ // expected exception
+ }
+
+ assertEquals("NamingEnumeration returned from Context.list() call incorrectly increased the service count for this calling bundle",
+ originalNumberOfServicesInUse, getContext().getBundle().getServicesInUse().length);
+
+
+ NamingEnumeration namingEnumTwo =
+ serviceListContext.list("");
+ assertNotSame("ServiceList context should have returned a new enumeration",
+ namingEnum, namingEnumTwo);
+
+ // close first enumeration, verify that service count does not change
+ namingEnum.close();
+ assertEquals("NamingEnumeration returned from Context.list() call incorrectly decreased the service count for this calling bundle",
+ originalNumberOfServicesInUse, getContext().getBundle().getServicesInUse().length);
+
+
+ assertTrue("NamingEnum should have contained elements",
+ namingEnumTwo.hasMoreElements());
+ namingEnumTwo.close();
+
+ try {
+ namingEnumTwo.next();
+ fail("NamingException should have been thrown");
+ } catch (NamingException e) {
+ // expected exception
+ }
+
+ // verify that only empty string context lists are supported
+ try {
+ serviceListContext.list("someName");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch (OperationNotSupportedException e) {
+ // expected exception
+ }
+
+ } finally {
+ getContext().ungetService(serviceReference);
+ }
+ }
+
+ /**
+ * Verifies the behavior of the NamingEnumeration returned as the result
+ * of a Context.listBindings() call on a Context that supports the "osgi:servicelist"
+ * lookup.
+ */
+ public void testJNDIServiceListBindingsNamingEnumeration() throws Exception {
+ final String expectedBindingName = "test-binding-one";
+ final String expectedBindingValue = "this is only a test";
+
+ // setup a test context
+ Context testContext =
+ new ExpectedValueTestContext(expectedBindingName, expectedBindingValue);
+
+ // register a builder service
+ registerService(InitialContextFactoryBuilder.class.getName(),
+ new FactoryResolutionTestCase.TestContextFactoryBuilder(testContext), null);
+
+ registerService(Closeable.class.getName(), new NoOpCloseable(), null);
+
+ registerService(Closeable.class.getName(), new NoOpCloseable(), null);
+
+ ServiceReference[] builderReferences =
+ getContext().getServiceReferences(Closeable.class.getName(), null);
+
+ final Set setOfIds = new HashSet();
+ for(int i = 0; i < builderReferences.length; i++) {
+ setOfIds.add(builderReferences[i].getProperty(Constants.SERVICE_ID).toString());
+ }
+
+ assertEquals("Initial set of services is not the expected number",
+ 2, setOfIds.size());
+
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+
+ try {
+ Context initialContext = contextManager.newInitialContext(new Hashtable());
+ Context serviceListContext = (Context)initialContext.lookup("osgi:servicelist/" + Closeable.class.getName());
+
+ final int originalNumOfServices =
+ getContext().getBundle().getServicesInUse().length;
+
+ assertNotNull("JNDI implementation did not return the expected context type for a servicelist URL",
+ serviceListContext);
+
+ NamingEnumeration namingEnum = serviceListContext.listBindings("");
+
+ // verify that the number of services in use by this bundle
+ // has increased due to the call to listBindings
+ // this test verifies that the NamingEnumeration is using the
+ // caller's bundle context to obtain the services
+ assertEquals("Context.listBindings() call should have increased the service count for this bundle",
+ originalNumOfServices + setOfIds.size(), getContext().getBundle().getServicesInUse().length);
+
+ assertTrue("NamingEnumeration did not contain any elements",
+ namingEnum.hasMoreElements());
+
+ Object result = namingEnum.next();
+ assertNotNull("NamingEnumeration did not contain the expected service",
+ result);
+ assertTrue("NamingEnumeration returned an unexpected type",
+ result instanceof Binding);
+
+ Binding bindingOne = (Binding)result;
+ assertEquals("Incorrect Binding type",
+ Closeable.class.getName(),
+ bindingOne.getClassName());
+ assertTrue("Binding's service ID was not expected",
+ setOfIds.contains(bindingOne.getName()));
+ assertNotNull("Binding's service object was not included",
+ bindingOne.getObject());
+ assertTrue("Binding's service object was not the correct type",
+ bindingOne.getObject() instanceof Closeable);
+
+
+ assertTrue("NamingEnumeration should contain one more element",
+ namingEnum.hasMoreElements());
+
+ Binding bindingTwo = (Binding)namingEnum.next();
+ assertEquals("NameClassPair did not contain the expected type",
+ Closeable.class.getName(),
+ bindingTwo.getClassName());
+ assertTrue("NameClassPair did not contain an expected ID",
+ setOfIds.contains(bindingTwo.getName()));
+ assertNotNull("Binding's service object was not included",
+ bindingTwo.getObject());
+ assertTrue("Binding's service object was not the correct type",
+ bindingTwo.getObject() instanceof Closeable);
+
+ assertFalse("NamingEnumeration should not contain any more elements",
+ namingEnum.hasMoreElements());
+
+
+
+ NamingEnumeration namingEnumTwo =
+ serviceListContext.listBindings("");
+ assertNotSame("ServiceList context should have returned a new enumeration",
+ namingEnum, namingEnumTwo);
+
+ assertTrue("NamingEnum should have contained elements",
+ namingEnumTwo.hasMoreElements());
+ namingEnumTwo.close();
+
+ try {
+ namingEnumTwo.next();
+ fail("NamingException should have been thrown");
+ } catch (NamingException e) {
+ // expected exception
+ }
+
+
+ // verify exception handling
+ try {
+ namingEnum.nextElement();
+ fail("NoSuchElementException should have been thrown");
+ } catch (NoSuchElementException e) {
+ // expected exception
+ }
+
+ // verify exception handling
+ try {
+ namingEnum.next();
+ fail("NoSuchElementException should have been thrown");
+ } catch (NoSuchElementException e) {
+ // expected exception
+ }
+
+ // verify that only empty string context lists are supported
+ try {
+ serviceListContext.listBindings("someName");
+ fail("OperationNotSupportedException should have been thrown");
+ } catch (OperationNotSupportedException e) {
+ // expected exception
+ }
+
+ namingEnum.close();
+
+ assertEquals("namingEnum.close() call should have decreased the service count for this bundle",
+ originalNumOfServices, getContext().getBundle().getServicesInUse().length);
+
+ } finally {
+ getContext().ungetService(serviceReference);
+ }
+ }
+
+
+ /**
+ * Verify that an OSGi service returned from a JNDI lookup is proxied
+ * according to the requirements of the OSGi Enterprise Spec, JNDI Services
+ * Chapter.
+ */
+ public void testOSGiServiceProxyWithInterface() throws Exception {
+ // test setup
+ Hello testService = new Hello() {
+ public String sayHello(String name) {
+ return "Hello " + name;
+ }
+ };
+
+ registerService(Hello.class.getName(), testService, null);
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ try {
+ Context initialContext = contextManager.newInitialContext();
+ Hello helloService =
+ (Hello) initialContext.lookup("osgi:service/" + Hello.class.getName());
+ assertNotNull("OSGi URL Context did not return the expected service value", helloService);
+ assertEquals("OSGi URL Context did not return the correct service",
+ "Hello Bob", helloService.sayHello("Bob"));
+
+ // verify that service un-binds are handled correctly
+ unregisterService(testService);
+
+ try {
+ helloService.sayHello("OSGi");
+ fail("ServiceException should have been thrown");
+ } catch(ServiceException serviceUnavailable) {
+ // expected exception
+ assertEquals("ServiceException was thrown with incorrect type code",
+ ServiceException.UNREGISTERED, serviceUnavailable.getType());
+ }
+
+ // verify that service re-binds are handled correctly
+ registerService(Hello.class.getName(), testService, null);
+
+ assertEquals("OSGi URL Context did not return the correct service",
+ "Hello Todd", helloService.sayHello("Todd"));
+ } finally {
+ getContext().ungetService(serviceReference);
+ }
+
+ }
+
+
+ /**
+ * Verify that the Gemini Naming bundle properly handles the case of
+ * a private interface being used as an OSGi service interface. An exception
+ * should be thrown back to the JNDI client, indicating the error.
+ */
+ public void testOSGiServiceProxyWithPrivateInterface() throws Exception {
+ // test setup
+ Thanks testService = new Thanks() {
+ public String sayThankYou(String name) {
+ return "Thank You " + name;
+ }
+ };
+
+ registerService(Thanks.class.getName(), testService, null);
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ try {
+ Context initialContext = contextManager.newInitialContext();
+ Thanks thanksService =
+ (Thanks) initialContext.lookup("osgi:service/" + Thanks.class.getName());
+ assertNotNull("OSGi URL Context did not return the expected service value", thanksService);
+
+ try {
+ thanksService.sayThankYou("Connie");
+ fail("ServiceException should have been thrown");
+ }
+ catch (ServiceException serviceException) {
+ // expected exception
+ assertTrue("ServiceException did not contain expected cause",
+ serviceException.getCause() instanceof IllegalAccessException);
+ }
+ } finally {
+ getContext().ungetService(serviceReference);
+ }
+ }
+
+ /**
+ * Verify the behavior of service proxies that are returned
+ * as part of a NamingEnumeration from a Context.listBindings() call on
+ * a Context returned from an "osgi:servicelist/" lookup.
+ */
+ public void testServiceProxyWithListBindingsNamingEnumeration() throws Exception {
+ // test setup
+ Hello testService = new Hello() {
+ public String sayHello(String name) {
+ return "Hello " + name;
+ }
+ };
+
+ registerService(Hello.class.getName(), testService, null);
+ // obtain JNDIContextManager service
+ ServiceReference serviceReference =
+ getContext().getServiceReference("org.osgi.service.jndi.JNDIContextManager");
+ JNDIContextManager contextManager = (JNDIContextManager)
+ getContext().getService(serviceReference);
+
+ try {
+ final int originalNumberOfServices =
+ getContext().getBundle().getServicesInUse().length;
+
+ Context initialContext = contextManager.newInitialContext();
+ Context serviceListContext =
+ (Context) initialContext.lookup("osgi:servicelist/" + Hello.class.getName());
+ assertNotNull("JNDIContextManager did not return expected context", serviceListContext);
+
+ NamingEnumeration namingEnumeration =
+ serviceListContext.listBindings("");
+
+ Binding binding = (Binding)namingEnumeration.next();
+ Hello serviceFromEnum =
+ (Hello)binding.getObject();
+
+ assertNotNull("ServiceListContext did not return expected service in enum",
+ serviceFromEnum);
+ assertEquals("Returned service did not return correct result",
+ "Hello Bob", serviceFromEnum.sayHello("Bob"));
+
+ unregisterService(testService);
+ // verify that proxy handles un-bind correctly
+ try {
+ serviceFromEnum.sayHello("Joe");
+ fail("ServiceException should have been thrown");
+ } catch (ServiceException serviceException) {
+ // expected exception
+ assertEquals("ServiceException was thrown with incorrect type code",
+ ServiceException.UNREGISTERED, serviceException.getType());
+ }
+
+ registerService(Hello.class.getName(), testService, null);
+ // verify that proxy does not attempt to rebind the service
+ try {
+ serviceFromEnum.sayHello("Cole");
+ fail("ServiceException should have been thrown");
+ } catch (ServiceException serviceException) {
+ // expected exception
+ assertEquals("ServiceException was thrown with incorrect type code",
+ ServiceException.UNREGISTERED, serviceException.getType());
+ }
+
+ // clean up enumeration
+ namingEnumeration.close();
+ // verify service tracking
+ assertEquals("JNDI Implementation did not correctly manage service references",
+ originalNumberOfServices, getContext().getBundle().getServicesInUse().length);
+ } finally {
+ getContext().ungetService(serviceReference);
+ }
+
+ }
+
+ /* test classes */
+ private static final class ExpectedValueTestContext extends FactoryResolutionTestCase.TestContext {
+ private final String expectedValue;
+ private final String expectedName;
+
+ private ExpectedValueTestContext(String expectedName, String expectedValue) {
+ this.expectedName = expectedName;
+ this.expectedValue = expectedValue;
+ }
+
+ public Object lookup(String name) throws NamingException {
+ if(name.equals(expectedName)) {
+ return expectedValue;
+ }
+ throw new NameNotFoundException("name not found - test error");
+ }
+ }
+
+ private static final class NoOpCloseable implements Closeable {
+ public void close() throws IOException {
+ // no-op for testing
+ }
+ }
+
+ private static class TestInitialDirContextFactory implements InitialContextFactory {
+
+ public Context getInitialContext(Hashtable var0)
+ throws NamingException {
+
+ return (Context)Proxy.newProxyInstance(this.getClass().getClassLoader(),
+ new Class[] {DirContext.class},
+ new TestInvocationHandler());
+
+ }
+
+ private static class TestInvocationHandler implements InvocationHandler {
+
+ public Object invoke(Object var0, Method var1, Object[] var2)
+ throws Throwable {
+ return null;
+ }
+
+ }
+
+ }
+
+ public interface Hello {
+ String sayHello(String name);
+ }
+
+ private interface Thanks {
+ String sayThankYou(String name);
+ }
+
+}
diff --git a/integration-testing/src/test/java/org/eclipse/gemini/naming/test/FactoryResolutionTestCase.java b/integration-testing/src/test/java/org/eclipse/gemini/naming/test/FactoryResolutionTestCase.java
new file mode 100644
index 0000000..aa03703
--- /dev/null
+++ b/integration-testing/src/test/java/org/eclipse/gemini/naming/test/FactoryResolutionTestCase.java
@@ -0,0 +1,797 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton - Initial Developer tests for Reference Implementation
+ ******************************************************************************/
+
+package org.eclipse.gemini.naming.test;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ConnectException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.naming.CommunicationException;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+import javax.naming.StringRefAddr;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.InitialContextFactoryBuilder;
+import javax.naming.spi.NamingManager;
+import javax.naming.spi.ObjectFactory;
+import javax.naming.spi.ObjectFactoryBuilder;
+
+import org.osgi.framework.*;
+
+
+/**
+ * Test case used to verify the Factory resolution process
+ * in Gemini Naming.
+ *
+ */
+public class FactoryResolutionTestCase extends NamingTestCase {
+
+ private static String VERSION = "1.0-SNAPSHOT";
+
+ private ClassLoader m_oldClassLoader = null;
+
+ protected void onSetUp() throws Exception {
+ super.onSetUp();
+ m_oldClassLoader = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(new TestClassLoaderTwo());
+ }
+
+ protected String[] getTestBundlesNames() {
+ return new String[]{ "org.eclipse.gemini.naming, org.eclipse.gemini.naming.impl.bundle-Incubation," + VERSION,
+ "org.osgi.service.jndi,org.osgi.service.jndi,1.0",
+ };
+ }
+
+
+ protected void onTearDown() throws Exception {
+ super.onTearDown();
+ Thread.currentThread().setContextClassLoader(m_oldClassLoader);
+ }
+
+
+ /**
+ * Verifies that the Factory Manager allows access to the JNDI implementations
+ * provided by the JDK. This test will verify access to the RMI JNDI implementation as
+ * an example of how to test this.
+ *
+ * @TODO, add tests for the other factories provided by the JDK
+ * @throws Exception
+ */
+ public void testAccessToJDK_RMIContext() throws Exception {
+ Hashtable environment = new Hashtable();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY,
+ "com.sun.jndi.rmi.registry.RegistryContextFactory");
+ environment.put("osgi.service.jndi.bundleContext", bundleContext);
+
+ // verify that context can be created without any errors
+ Context context = null;
+ try {
+ context = new InitialContext(environment);
+ } finally {
+ context.close();
+ }
+ }
+
+ /**
+ * Verifies access to the LDAP context factory provided by the
+ * JDK. This test does not verify any LDAP connectivity, it merely
+ * ensures that the JDK-provided implementation is available in an OSGi
+ * environment.
+ *
+ * @throws Exception
+ */
+ public void testAccessToJDK_LDAPContext() throws Exception {
+ Hashtable environment = new Hashtable();
+ environment.put(Context.INITIAL_CONTEXT_FACTORY,
+ "com.sun.jndi.ldap.LdapCtxFactory");
+ environment.put("osgi.service.jndi.bundleContext", bundleContext);
+
+ DirContext dirContext = null;
+ try {
+ dirContext = new InitialDirContext(environment);
+ // verify that a communication exception is thrown,
+ // since this test does not include an LDAP server
+ // the intention of this test is to verify that the factory
+ // can be made available by the factory manager.
+ fail("CommunicationException should have been thrown");
+ }
+ catch (CommunicationException communicationException) {
+ // expected exception for this test
+ assertTrue("Did not receive expected root exception for this test",
+ communicationException.getCause() instanceof ConnectException);
+ } finally {
+ if (dirContext != null) {
+ dirContext.close();
+ }
+ }
+ }
+
+ /**
+ * Verify that if an ObjectFactory classname is specified in a Reference, and that
+ * ObjectFactory is not available to the Factory Manager, that the manager will
+ * query the existing ObjectFactoryBuilder services in order to attempt to
+ * find a matching ObjectFactory.
+ *
+ * Please see section 5.2.2.1 of RFC 142 for more details.
+ *
+ * @throws Exception
+ */
+ public void testSpecificObjectFactoryResolvedByBuilder() throws Exception {
+ final int expectedValue = 100;
+ // stub builder to be used in test
+ ObjectFactoryBuilder factoryBuilder = new ObjectFactoryBuilder() {
+ public ObjectFactory createObjectFactory(Object var0, Hashtable var1) throws NamingException {
+ return new ObjectFactory() {
+ public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
+ return new Integer(expectedValue);
+ }
+ };
+ }
+ };
+
+ // only register the builder implementation
+ registerService(ObjectFactoryBuilder.class.getName(), factoryBuilder, null);
+
+ // reference data does not matter, since we're testing that
+ // the factory manager can locate the only ObjectFactory registered.
+ Reference reference = new Reference("test", "com.test.factory.DoesNotExist", null);
+ Object result = NamingManager.getObjectInstance(reference, null, null, null);
+ assertEquals("JNDI Factory Manager did not locate the correct ObjectFactory",
+ new Integer(expectedValue), result);
+ }
+
+
+ /**
+ * Verify that the Factory Manager can resolve a reference that includes an
+ * address (StringRefAddr) of type "URL". This address can be used by the Factory
+ * Manager in order to locate a URL context factory that supports the given scheme.
+ *
+ * Please see section 5.2.2.1 of RFC 142 for more details.
+ *
+ * @throws Exception
+ */
+ public void testObjectFactoryResolvedUsingURLContextFactory() throws Exception {
+ final int expectedValue = 100;
+ ObjectFactory urlContextFactory = new ObjectFactory() {
+ public Object getObjectInstance(Object var0, Name var1,
+ Context var2, Hashtable var3) throws Exception {
+ return new Integer(expectedValue);
+ }
+
+ };
+
+ Hashtable serviceProperties = new Hashtable();
+ serviceProperties.put("osgi.jndi.url.scheme", "testURL");
+
+ registerService(ObjectFactory.class.getName(),
+ urlContextFactory,
+ serviceProperties);
+
+ // reference data does not matter, since we're testing that
+ // the factory manager can locate the URL context factory
+ // to support this URL scheme
+ Reference reference = new Reference("test", null, null);
+ // create a string reference address of type URL
+ // and add it to the reference
+ reference.add(new StringRefAddr("URL", "testURL://testOne"));
+
+ Object result = NamingManager.getObjectInstance(reference, null, null, null);
+ assertEquals("Incorrect type returned by URL context factory",
+ new Integer(expectedValue), result);
+ }
+
+
+ /**
+ * Verify that if no ObjectFactories are found to resolve the reference,
+ * then the Reference object itself is returned. This behavior complies with the
+ * behavior of the NamingManager.getObjectInstance() method. In this test case
+ * the Reference specifies a factory class that is not available.
+ *
+ */
+ public void testReturnValueWhenSpecifiedAndNoObjectFactoriesFound() throws Exception {
+ // no ObjectFactory services or builder services are registered for this test
+ Reference reference = new Reference("test", "com.test.factory.FactoryDoesNotExist", null);
+
+ Object result = NamingManager.getObjectInstance(reference, null, null, null);
+ assertSame("Factory Manager did not return the refInfo as expected",
+ reference, result);
+ }
+
+
+ /**
+ * Verify that if no ObjectFactories are found to resolve the reference,
+ * then the Reference object itself is returned. This behavior complies with the
+ * behavior of the NamingManager.getObjectInstance() method. In this test case
+ * the Reference does not specify a factory class.
+ *
+ */
+ public void testReturnValueWhenNotSpecifiedAndNoObjectFactoriesFound() throws Exception {
+ // no ObjectFactory services or builder services are registered for this test
+ Reference reference = new Reference("test", null, null);
+
+ Object result = NamingManager.getObjectInstance(reference, null, null, null);
+ assertSame("Factory Manager did not return the refInfo as expected",
+ reference, result);
+ }
+
+
+ /**
+ * Verify that an ObjectFactoryBuilder can be queried in the attempt
+ * to resolve a reference. Verify that this process works as expected
+ * when the NamingManager.getObjectInstance() method is called.
+ * @throws Exception
+ */
+ public void testReferenceableSupportWithBuilder() throws Exception {
+ final int expectedValue = 100;
+ // stub builder to be used in test
+ ObjectFactoryBuilder factoryBuilder = new ObjectFactoryBuilder() {
+ public ObjectFactory createObjectFactory(Object var0, Hashtable var1) throws NamingException {
+ return new ObjectFactory() {
+ public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
+ return new Integer(expectedValue);
+ }
+ };
+ }
+ };
+
+ // only register the builder implementation
+ registerService(ObjectFactoryBuilder.class.getName(), factoryBuilder, null);
+
+ // create implementation of Referenceable that can
+ // create a reference to resolve
+ Referenceable referenceable = new Referenceable() {
+ public Reference getReference() throws NamingException {
+ return new Reference("test", "com.test.factory.DoesNotExist", null);
+ }
+ };
+
+ Object result = NamingManager.getObjectInstance(referenceable, null, null, null);
+ assertEquals("JNDI Factory Manager did not locate the correct ObjectFactory",
+ new Integer(expectedValue), result);
+ }
+
+
+ /**
+ * Verify that the Gemini Naming bundle can support calls to resolve
+ * a reference from the NamingManager.getObjectInstance() method. This test
+ * verifies that an ObjectFactory registered as an OSGi service can be queried in
+ * the attempt to resolve the reference.
+ */
+ public void testReferenceableSupportWithObjectFactory() throws Exception {
+ final int expectedValue = 100;
+ // stub builder to be used in test
+ final ObjectFactory objectFactory = new ObjectFactory() {
+ public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) throws Exception {
+ return new Integer(expectedValue);
+ }
+ };
+
+
+ String[] serviceInterfaces = { ObjectFactory.class.getName(),
+ objectFactory.getClass().getName() };
+
+ ServiceRegistration serviceRegistration =
+ bundleContext.registerService(serviceInterfaces, objectFactory, null);
+
+ try {
+ // create implementation of Referenceable that can
+ // create a reference to resolve
+ Referenceable referenceable = new Referenceable() {
+ public Reference getReference() throws NamingException {
+ return new Reference("test", objectFactory.getClass().getName(), null);
+ }
+ };
+
+ Object result = NamingManager.getObjectInstance(referenceable, null, null, null);
+ assertEquals("JNDI Factory Manager did not locate the correct ObjectFactory",
+ new Integer(expectedValue), result);
+ }
+ finally {
+ serviceRegistration.unregister();
+ }
+ }
+
+
+ /**
+ * Verify that a "jndi.properties" file can be used in a Bundle to
+ * specify the desired InitialContextFactory implementation.
+ */
+ public void testJndiPropertiesFileFromArchive() throws Exception {
+ final String expectedLookupName = "test-binding-one";
+ final String expectedLookupValue = "this is only a test!";
+ // setup a stub context factory
+ Context testContext = new TestContext() {
+ public Object lookup(String name) throws NamingException {
+ if(name.equals(expectedLookupName)) {
+ return expectedLookupValue;
+ }
+
+ throw new NameNotFoundException("Error in test");
+ }
+
+ };
+
+ InitialContextFactory initialContextFactory = new TestContextFactory(testContext);
+ String[] interfaceNames = { InitialContextFactory.class.getName(), TestContextFactory.class.getName() };
+
+ // register context factory
+ ServiceRegistration serviceRegistration =
+ bundleContext.registerService(interfaceNames, initialContextFactory, null);
+
+ // create and setup a temp file for testing
+ File jndiPropertiesFile = File.createTempFile("jndi", "properties");
+ FileOutputStream outputStream = new FileOutputStream(jndiPropertiesFile);
+ Properties tempProperties = new Properties();
+ tempProperties.put(Context.INITIAL_CONTEXT_FACTORY, TestContextFactory.class.getName());
+ tempProperties.store(outputStream, "test properties file");
+
+ ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+ InitialContext context = null;
+ try {
+ URL testURL =
+ new URL("", "", -1, "", new TestURLStreamHandler(jndiPropertiesFile));
+
+ final TestClassLoader testClassLoader = new TestClassLoader(testURL);
+ // set context classloader that can provide the jndi.properties file
+ Thread.currentThread().setContextClassLoader(testClassLoader);
+
+ //System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "this.package.doesNotExist.Factory");
+ Hashtable environment = new Hashtable();
+ environment.put("osgi.service.jndi.bundleContext", bundleContext);
+ context = new InitialContext(environment);
+ assertEquals("Incorrect value returned by context factory",
+ expectedLookupValue, context.lookup(expectedLookupName));
+ } finally {
+ context.close();
+
+ serviceRegistration.unregister();
+
+ // clean up context classloader
+ Thread.currentThread().setContextClassLoader(oldClassLoader);
+
+ if (jndiPropertiesFile != null) {
+ // clean up temp file
+ jndiPropertiesFile.delete();
+ }
+
+ // clean up system property
+ Properties sysProperties = System.getProperties();
+ sysProperties.remove(Context.INITIAL_CONTEXT_FACTORY);
+ }
+ }
+
+ // Stub implementations of JNDI factories used for simpler unit testing
+ static class TestContextFactoryBuilder implements InitialContextFactoryBuilder {
+ private final Context m_context;
+
+ TestContextFactoryBuilder(Context context) {
+ m_context = context;
+ }
+
+
+ public InitialContextFactory createInitialContextFactory(Hashtable var0)
+ throws NamingException {
+ return new TestContextFactory(m_context);
+ }
+ }
+
+ private static class TestContextFactory implements InitialContextFactory {
+ private final Context m_context;
+
+ TestContextFactory(Context context) {
+ m_context = context;
+ }
+
+
+ public Context getInitialContext(Hashtable var0) throws NamingException {
+ return m_context;
+ }
+
+ }
+
+ static class TestContext implements Context {
+
+ private int m_numOfCloseCalls = 0;
+
+ int getNumCloseCalls() {
+ return m_numOfCloseCalls;
+ }
+
+ public Object addToEnvironment(String var0, Object var1)
+ throws NamingException {
+ return null;
+ }
+
+ public void bind(String var0, Object var1) throws NamingException {
+ }
+
+ public void bind(Name var0, Object var1) throws NamingException {
+ }
+
+ public void close() throws NamingException {
+ m_numOfCloseCalls++;
+ }
+
+ public String composeName(String var0, String var1)
+ throws NamingException {
+ return null;
+ }
+
+ public Name composeName(Name var0, Name var1) throws NamingException {
+ return null;
+ }
+
+ public Context createSubcontext(String var0) throws NamingException {
+ return null;
+ }
+
+ public Context createSubcontext(Name var0) throws NamingException {
+ return null;
+ }
+
+ public void destroySubcontext(String var0) throws NamingException {
+ }
+
+ public void destroySubcontext(Name var0) throws NamingException {
+ }
+
+ public Hashtable getEnvironment() throws NamingException {
+ return null;
+ }
+
+ public String getNameInNamespace() throws NamingException {
+ return null;
+ }
+
+ public NameParser getNameParser(String var0) throws NamingException {
+ return null;
+ }
+
+ public NameParser getNameParser(Name var0) throws NamingException {
+ return null;
+ }
+
+ public NamingEnumeration list(String var0) throws NamingException {
+ return null;
+ }
+
+ public NamingEnumeration list(Name var0) throws NamingException {
+ return null;
+ }
+
+ public NamingEnumeration listBindings(String var0)
+ throws NamingException {
+ return null;
+ }
+
+ public NamingEnumeration listBindings(Name var0) throws NamingException {
+ return null;
+ }
+
+ public Object lookup(String var0) throws NamingException {
+ return null;
+ }
+
+ public Object lookup(Name var0) throws NamingException {
+ return null;
+ }
+
+ public Object lookupLink(String var0) throws NamingException {
+ return null;
+ }
+
+ public Object lookupLink(Name var0) throws NamingException {
+ return null;
+ }
+
+ public void rebind(String var0, Object var1) throws NamingException {
+ }
+
+ public void rebind(Name var0, Object var1) throws NamingException {
+ }
+
+ public Object removeFromEnvironment(String var0) throws NamingException {
+ return null;
+ }
+
+ public void rename(String var0, String var1) throws NamingException {
+ }
+
+ public void rename(Name var0, Name var1) throws NamingException {
+ }
+
+ public void unbind(String var0) throws NamingException {
+ }
+
+ public void unbind(Name var0) throws NamingException {
+ }
+
+ }
+
+
+ private static class TestURLStreamHandler extends URLStreamHandler {
+ private final File m_propertiesFile;
+
+ TestURLStreamHandler(File propertiesFile) {
+ m_propertiesFile = propertiesFile;
+ }
+ protected URLConnection openConnection(URL var0) throws IOException {
+ return new URLConnection(null) {
+ public void connect() throws IOException {
+ // no-op
+ }
+
+ public Object getContent() throws IOException {
+ return m_propertiesFile;
+ }
+ };
+ }
+
+ }
+
+ private static class TestClassLoader extends ClassLoader implements BundleReference {
+
+ private final URL m_fileURL;
+
+ TestClassLoader(URL fileURL) {
+ m_fileURL = fileURL;
+ }
+
+ public Bundle getBundle() {
+ return new TestBundle() {
+ public URL getResource(String name) {
+ if(name.equals("jndi.properties")) {
+ return m_fileURL;
+ }
+
+ return null;
+ }
+
+ };
+ }
+
+ }
+
+ private static class TestBundle implements Bundle {
+
+ public Enumeration findEntries(String path, String filePattern,
+ boolean recurse) {
+ return null;
+ }
+
+ public BundleContext getBundleContext() {
+ return null;
+ }
+
+ public long getBundleId() {
+ return 0;
+ }
+
+ public URL getEntry(String path) {
+ return null;
+ }
+
+ public Enumeration getEntryPaths(String path) {
+ return null;
+ }
+
+ public Dictionary getHeaders() {
+ return null;
+ }
+
+ public Dictionary getHeaders(String locale) {
+ return null;
+ }
+
+ public long getLastModified() {
+ return 0;
+ }
+
+ public String getLocation() {
+ return null;
+ }
+
+ public ServiceReference[] getRegisteredServices() {
+ return null;
+ }
+
+ public URL getResource(String name) {
+ return null;
+ }
+
+ public Enumeration getResources(String name) throws IOException {
+ return null;
+ }
+
+ public ServiceReference[] getServicesInUse() {
+ return null;
+ }
+
+ public Map getSignerCertificates(int signersType) {
+ return null;
+ }
+
+ public int getState() {
+ return 0;
+ }
+
+ public String getSymbolicName() {
+ return null;
+ }
+
+ public Version getVersion() {
+ return null;
+ }
+
+ public boolean hasPermission(Object permission) {
+ return false;
+ }
+
+ public Class loadClass(String name) throws ClassNotFoundException {
+ return null;
+ }
+
+ public void start() throws BundleException {
+ }
+
+ public void start(int options) throws BundleException {
+ }
+
+ public void stop() throws BundleException {
+ }
+
+ public void stop(int options) throws BundleException {
+ }
+
+ public void uninstall() throws BundleException {
+ }
+
+ public void update() throws BundleException {
+ }
+
+ public void update(InputStream input) throws BundleException {
+ }
+
+ }
+
+
+ private class TestClassLoaderTwo extends ClassLoader implements BundleReference {
+
+ public Bundle getBundle() {
+ return new Bundle() {
+ public Enumeration findEntries(String path, String filePattern, boolean recurse) {
+ return null;
+ }
+
+ public BundleContext getBundleContext() {
+ return getContext();
+ }
+
+ public long getBundleId() {
+ return 0;
+ }
+
+ public URL getEntry(String path) {
+ return null;
+ }
+
+ public Enumeration getEntryPaths(String path) {
+ return null;
+ }
+
+ public Dictionary getHeaders() {
+ return null;
+ }
+
+ public Dictionary getHeaders(String locale) {
+ return null;
+ }
+
+ public long getLastModified() {
+ return 0;
+ }
+
+ public String getLocation() {
+ return null;
+ }
+
+ public ServiceReference[] getRegisteredServices() {
+ return null;
+ }
+
+ public URL getResource(String name) {
+ return null;
+ }
+
+ public Enumeration getResources(String name) throws IOException {
+ return null;
+ }
+
+ public ServiceReference[] getServicesInUse() {
+ return null;
+ }
+
+ public Map getSignerCertificates(int signersType) {
+ return null;
+ }
+
+ public int getState() {
+ return 0;
+ }
+
+ public String getSymbolicName() {
+ return null;
+ }
+
+ public Version getVersion() {
+ return null;
+ }
+
+ public boolean hasPermission(Object permission) {
+ return false;
+ }
+
+ public Class loadClass(String name) throws ClassNotFoundException {
+ return null;
+ }
+
+ public void start() throws BundleException {
+ }
+
+ public void start(int options) throws BundleException {
+ }
+
+ public void stop() throws BundleException {
+ }
+
+ public void stop(int options) throws BundleException {
+ }
+
+ public void uninstall() throws BundleException {
+ }
+
+ public void update() throws BundleException {
+ }
+
+ public void update(InputStream input) throws BundleException {
+ }
+
+ };
+ }
+
+ }
+
+
+}
diff --git a/integration-testing/src/test/java/org/eclipse/gemini/naming/test/NamingTestCase.java b/integration-testing/src/test/java/org/eclipse/gemini/naming/test/NamingTestCase.java
new file mode 100644
index 0000000..35c32da
--- /dev/null
+++ b/integration-testing/src/test/java/org/eclipse/gemini/naming/test/NamingTestCase.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2010 Oracle.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Bob Nettleton - Initial Developer tests for Reference Implementation
+ ******************************************************************************/
+
+
+/**
+ * This class is a common base class for the developer tests for the Gemini
+ * Naming project.
+ */
+
+package org.eclipse.gemini.naming.test;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.springframework.osgi.test.AbstractConfigurableBundleCreatorTests;
+
+public abstract class NamingTestCase extends AbstractConfigurableBundleCreatorTests {
+
+ private Map m_mapOfServicesToRegistrations =
+ new HashMap();
+
+ protected void onSetUp() throws Exception {
+ m_mapOfServicesToRegistrations = new HashMap();
+ }
+
+ protected void onTearDown() throws Exception {
+ super.onTearDown();
+ unregisterAllServices();
+ }
+
+ protected void registerService(String serviceType, Object service, Dictionary properties) {
+ ServiceRegistration registration =
+ bundleContext.registerService(serviceType, service, properties);
+ m_mapOfServicesToRegistrations.put(service, registration);
+
+ }
+
+ protected void unregisterService(Object service) {
+ if(m_mapOfServicesToRegistrations.containsKey(service)) {
+ ServiceRegistration registration =
+ (ServiceRegistration)m_mapOfServicesToRegistrations.get(service);
+ registration.unregister();
+ }
+ }
+
+ protected void unregisterAllServices() {
+ Set keySet = m_mapOfServicesToRegistrations.keySet();
+ Iterator iterator = keySet.iterator();
+ while(iterator.hasNext()) {
+ unregisterService(iterator.next());
+ }
+ }
+
+ protected BundleContext getContext() {
+ return bundleContext;
+ }
+
+}
diff --git a/lib/osgi.enterprise.jar b/lib/osgi.enterprise.jar
new file mode 100644
index 0000000..563f674
--- /dev/null
+++ b/lib/osgi.enterprise.jar
Binary files differ
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..76ab183
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,110 @@
+<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">
+
+ <properties>
+ <equinox.version>3.5.0.v20090520</equinox.version>
+ <spring.version>2.5.6.A</spring.version>
+ <spring.osgi.version>1.2.0</spring.osgi.version>
+ </properties>
+
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.eclipse.gemini.naming</groupId>
+ <artifactId>org.eclipse.gemini.naming</artifactId>
+ <packaging>pom</packaging>
+ <version>1.0-SNAPSHOT</version>
+ <name>org.eclipse.gemini.naming</name>
+ <url>http://maven.apache.org</url>
+
+ <modules>
+ <module>framework</module>
+ <module>integration-testing</module>
+ </modules>
+
+ <repositories>
+ <repository>
+ <id>com.springsource.repository.bundles.release</id>
+ <name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</name>
+ <url>http://repository.springsource.com/maven/bundles/release</url>
+ </repository>
+
+ <repository>
+ <id>com.springsource.repository.bundles.external</id>
+ <name>SpringSource Enterprise Bundle Repository - External Bundle Releases</name>
+ <url>http://repository.springsource.com/maven/bundles/external</url>
+ </repository>
+
+ <repository>
+ <id>maven.springframework.org.release</id>
+ <name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</name>
+ <url>http://maven.springframework.org/release</url>
+ </repository>
+ <repository>
+ <id>maven.springframework.org.osgi</id>
+ <name>SpringSource Enterprise Bundle Repository - SpringSource Bundle OSGi</name>
+ <url>http://maven.springframework.org/osgi
+ </url>
+ </repository>
+ <repository>
+ <id>com.springsource.repository.bundles.release</id>
+ <name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</name>
+ <url>http://repository.springsource.com/maven/bundles/release</url>
+ </repository>
+ <repository>
+ <id>com.springsource.repository.bundles.external
+ </id>
+ <name>SpringSource Enterprise Bundle Repository - External Bundle Releases</name>
+ <url>http://repository.springsource.com/maven/bundles/external</url>
+ </repository>
+ <repository>
+ <id>com.springsource.repository.bundles.snapshot</id>
+ <name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Snapshots</name>
+ <url>http://repository.springsource.com/maven/bundles/snapshot</url>
+ </repository>
+ </repositories>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>3.8.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <!-- NEW DEPENDENCY ADDED AFTER CQ for unit testing -->
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>com.springsource.org.easymock</artifactId>
+ <version>2.5.2</version>
+ <scope>test</scope>
+ </dependency>
+ <!-- END OF NEW DEPENDENDIES AFTER CQ -->
+
+ <!-- temporary workaround until the correct way to handle the standard JNDI OSGi interfaces has been determined -->
+ <dependency>
+ <groupId>org.osgi.service.jndi</groupId>
+ <artifactId>org.osgi.service.jndi</artifactId>
+ <version>2.0</version>
+ <scope>system</scope>
+ <systemPath>${env.GEMINI_NAMING_HOME}/lib/osgi.enterprise.jar</systemPath>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!-- NEW PLUGIN DEPENDENCY ADDED AFTER initial CQ -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ </plugins>
+
+ </build>
+</project>

Back to the top