Index: framework/src/java/jndi.properties
===================================================================
RCS file: framework/src/java/jndi.properties
diff -N framework/src/java/jndi.properties
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ framework/src/java/jndi.properties 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,1 @@
+java.naming.factory.url.pkgs = org.apache.hivemind.impl.naming
Index: framework/src/java/org/apache/hivemind/impl/naming/ContextAdapter.java
===================================================================
RCS file: framework/src/java/org/apache/hivemind/impl/naming/ContextAdapter.java
diff -N framework/src/java/org/apache/hivemind/impl/naming/ContextAdapter.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ framework/src/java/org/apache/hivemind/impl/naming/ContextAdapter.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,181 @@
+//Copyright 2004 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.hivemind.impl.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;
+
+/**
+ * Abstract adapter class for {@link javax.naming.Context}. The methods in this
+ * class throw OperationNotSupportedException. This class exists as
+ * a convenience for creating context objects.
+ *
+ * @author Naresh Sikha
+ */
+public abstract class ContextAdapter implements Context {
+
+ //
+ public void close() throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public String getNameInNamespace() throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public void destroySubcontext(String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public void unbind(String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public Hashtable getEnvironment() throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public void destroySubcontext(Name name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public void unbind(Name name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public Object lookup(String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public Object lookupLink(String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public Object removeFromEnvironment(String propName) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public void bind(String name, Object obj) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public void rebind(String name, Object obj) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public Object lookup(Name name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public Object lookupLink(Name name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public void bind(Name name, Object obj) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public void rebind(Name name, Object obj) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public void rename(String oldName, String newName) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public Context createSubcontext(String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public Context createSubcontext(Name name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public void rename(Name oldName, Name newName) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public NameParser getNameParser(String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public NameParser getNameParser(Name name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public NamingEnumeration list(String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public NamingEnumeration listBindings(String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public NamingEnumeration list(Name name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public NamingEnumeration listBindings(Name name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public Object addToEnvironment(String propName, Object propVal)
+ throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public String composeName(String name, String prefix)
+ throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ //
+ public Name composeName(Name name, Name prefix) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+}
Index: framework/src/java/org/apache/hivemind/impl/naming/RegistryContext.java
===================================================================
RCS file: framework/src/java/org/apache/hivemind/impl/naming/RegistryContext.java
diff -N framework/src/java/org/apache/hivemind/impl/naming/RegistryContext.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ framework/src/java/org/apache/hivemind/impl/naming/RegistryContext.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,143 @@
+//Copyright 2004 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.hivemind.impl.naming;
+
+import java.util.Map;
+import java.util.WeakHashMap;
+
+import javax.naming.CompositeName;
+import javax.naming.Name;
+import javax.naming.NamingException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hivemind.Registry;
+import org.apache.hivemind.impl.RegistryBuilder;
+
+/**
+ * Superclass for Registry related JNDI Contexts. Provides a default
+ * implementation of {@link #lookup(String)}that treats the String as a
+ * CompositeName.
+ *
+ * This class also caches a default Registry once per context class loader.
+ *
+ * The intent is that all Configuration and Service names are composite names.
+ * See http://java.sun.com/products/jndi/tutorial/beyond/names/composite.html
+ * for details on the use of composite names.
+ *
+ * @see org.apache.hivemind.impl.naming.configuration.ConfigurationContext
+ * @see org.apache.hivemind.impl.naming.service.ServiceContext
+ *
+ * @author Naresh Sikha
+ */
+public class RegistryContext extends ContextAdapter {
+
+ /**
+ * A cache that keys on context class loader. Class loader refernces are
+ * weak references so they may be safely garbage collected.
+ */
+ private static final class RegistryCache {
+
+ /**
+ * A mutex.
+ */
+ private final Object _lock = new Object();
+
+ /**
+ * The cache.
+ */
+ private final Map _map = new WeakHashMap(11);
+
+ /**
+ * @return The cached reference to a default Registry that is keyed on
+ * the current context class loader
+ */
+ public Registry get() {
+ // Alternatives to double checked locking
+ // algorithm are welcome.
+ ClassLoader k = Thread.currentThread().getContextClassLoader();
+ Object v = _map.get(k);
+ if (null == v) {
+ synchronized (_lock) {
+ v = _map.get(k);
+ if (null == v) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(k.getClass().getName());
+ sb.append("@");
+ sb.append(System.identityHashCode(k));
+
+ LOG.info("##### Registry is starting for ClassLoader: "
+ + sb);
+
+ v = RegistryBuilder.constructDefaultRegistry();
+
+ LOG.info("##### Registry is started for ClassLoader: "
+ + sb);
+
+ _map.put(k, v);
+ }
+ }
+ }
+ return ((Registry) v);
+ }
+ }
+
+ /**
+ * The primoridal cache reference.
+ */
+ private static final RegistryCache CACHE = new RegistryCache();
+
+ private static final Log LOG = LogFactory.getLog(RegistryContext.class);
+
+ /**
+ * Returns the cached default Registry. The reference will be unique per
+ * context class loader and will be safely garbage collected whenever the
+ * keyed context class loader is dropped - ostensibly on J2EE application
+ * restarts.
+ *
+ * @return The context class loader unique instance to the default Registry
+ */
+ protected Registry getRegistry() {
+ return (CACHE.get());
+ }
+
+ /**
+ * Convenience method to wrap an exception in a NamingException.
+ *
+ * @param e
+ * The exeption to wrap
+ * @throws NamingException
+ * that wraps the specified exception
+ */
+ protected void handleException(Exception e) throws NamingException {
+ NamingException nex = new NamingException();
+ nex.setRootCause(e);
+ throw nex;
+ }
+
+ /**
+ * Implements lookup(String) by converting it to a CompositeName and
+ * delegating to {@link #lookup(Name)}. Subclasses merely need to implement
+ * their business logic in {@link #lookup(Name)}.
+ *
+ * @param name
+ * The composite name as a String
+ * @return an Object from the default Registry
+ * @throws NamingException
+ * if an error condition is encountered
+ */
+ public Object lookup(String name) throws NamingException {
+ return lookup(new CompositeName(name));
+ }
+}
Index: framework/src/java/org/apache/hivemind/impl/naming/configuration/ConfigurationContext.java
===================================================================
RCS file: framework/src/java/org/apache/hivemind/impl/naming/configuration/ConfigurationContext.java
diff -N framework/src/java/org/apache/hivemind/impl/naming/configuration/ConfigurationContext.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ framework/src/java/org/apache/hivemind/impl/naming/configuration/ConfigurationContext.java 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,55 @@
+//Copyright 2004 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.hivemind.impl.naming.configuration;
+
+import javax.naming.Name;
+import javax.naming.NamingException;
+
+import org.apache.hivemind.ApplicationRuntimeException;
+import org.apache.hivemind.impl.naming.RegistryContext;
+
+/**
+ * JNDI Context implementation to locate Configurations.
+ *
+ * Configuration names are composite names with the first
+ * component being configuration: and the second
+ * component being the Configuration Point id. For example:
+ *
+ *
+ * configuration:/hivemind.FactoryDefaults + *+ * + * @author Naresh Sikha + */ +public class ConfigurationContext extends RegistryContext { + + // + public Object lookup(Name name) throws NamingException { + String serviceId = null; + try { + serviceId = name.get(1); + } catch (ArrayIndexOutOfBoundsException e) { + handleException(e); + } + + Object o = null; + try { + o = getRegistry().getConfiguration(serviceId); + } catch (ApplicationRuntimeException e) { + handleException(e); + } + + return o; + } +} Index: framework/src/java/org/apache/hivemind/impl/naming/configuration/configurationURLContextFactory.java =================================================================== RCS file: framework/src/java/org/apache/hivemind/impl/naming/configuration/configurationURLContextFactory.java diff -N framework/src/java/org/apache/hivemind/impl/naming/configuration/configurationURLContextFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ framework/src/java/org/apache/hivemind/impl/naming/configuration/configurationURLContextFactory.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,41 @@ +//Copyright 2004 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package org.apache.hivemind.impl.naming.configuration; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.spi.ObjectFactory; + +/** + * Implementation of {@link javax.naming.spi.ObjectFactory}to lookup HiveMind + * Configurations. + * + * Note: the name of this class follows JNDI SPI naming + * conventions, not Java best practices. + * + * @author Naresh Sikha + */ +public class configurationURLContextFactory implements ObjectFactory { + + private static final ConfigurationContext _context = new ConfigurationContext(); + + // + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) throws Exception { + return _context; + } + +} Index: framework/src/java/org/apache/hivemind/impl/naming/service/ServiceContext.java =================================================================== RCS file: framework/src/java/org/apache/hivemind/impl/naming/service/ServiceContext.java diff -N framework/src/java/org/apache/hivemind/impl/naming/service/ServiceContext.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ framework/src/java/org/apache/hivemind/impl/naming/service/ServiceContext.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,103 @@ +//Copyright 2004 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package org.apache.hivemind.impl.naming.service; + +import javax.naming.Name; +import javax.naming.NamingException; + +import org.apache.hivemind.ApplicationRuntimeException; +import org.apache.hivemind.Registry; +import org.apache.hivemind.impl.naming.RegistryContext; +import org.apache.hivemind.internal.RegistryInfrastructure; + +/** + * JNDI Context implementation to locate Services. + * + * Configuration names are composite names with the first + * component being
service:. the second
+ * component being the Service interface name, and the
+ * third component being the Service Point id. For example:
+ *
+ * + * service:/org.apache.hivemind.service.ThreadLocalStorage/hivemind.ThreadLocalStorage + *+ * + * If the Service Interface Name is specified, then the + * Service Point Id is optional. For example: + * + *
+ * service:/org.apache.hivemind.service.ThreadLocalStorage + *+ * + * If the Service Point Id is specified, then the Service + * Interface Name is optional. In this case, an empty second + * component name must be specified. For example: + * + *
+ * service://hivemind.ThreadLocalStorage + *+ * + * @author Naresh Sikha + */ +public class ServiceContext extends RegistryContext { + + // + public Object lookup(Name name) throws NamingException { + String serviceInterfaceName = null; + try { + serviceInterfaceName = (String) name.get(1); + } catch (ArrayIndexOutOfBoundsException e) { + handleException(e); + } + + // Registry should be a service + if (Registry.class.getName().equals(serviceInterfaceName)) { + return getRegistry(); + } + if (RegistryInfrastructure.class.getName().equals(serviceInterfaceName)) { + return getRegistry(); + } + + Class serviceInterface = null; + if (0 == serviceInterfaceName.trim().length()) { + serviceInterface = Object.class; + } else { + try { + serviceInterface = Thread.currentThread() + .getContextClassLoader() + .loadClass(serviceInterfaceName); + } catch (ClassNotFoundException e) { + handleException(e); + } + } + + String serviceId = null; + if (3 == name.size()) { + serviceId = name.get(2); + } + + Object o = null; + try { + if (null == serviceId) { + o = getRegistry().getService(serviceInterface); + } else { + o = getRegistry().getService(serviceId, serviceInterface); + } + } catch (ApplicationRuntimeException e) { + handleException(e); + } + + return o; + } +} Index: framework/src/java/org/apache/hivemind/impl/naming/service/serviceURLContextFactory.java =================================================================== RCS file: framework/src/java/org/apache/hivemind/impl/naming/service/serviceURLContextFactory.java diff -N framework/src/java/org/apache/hivemind/impl/naming/service/serviceURLContextFactory.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ framework/src/java/org/apache/hivemind/impl/naming/service/serviceURLContextFactory.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,41 @@ +//Copyright 2004 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package org.apache.hivemind.impl.naming.service; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.spi.ObjectFactory; + +/** + * Implementation of {@link javax.naming.spi.ObjectFactory}to lookup HiveMind + * Services. + * + * Note: the name of this class follows JNDI SPI naming + * conventions, not Java best practices. + * + * @author Naresh Sikha + */ +public class serviceURLContextFactory implements ObjectFactory { + + private static final ServiceContext _context = new ServiceContext(); + + // + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) throws Exception { + return _context; + } + +} Index: framework/src/test/hivemind/test/naming/NamingTest.java =================================================================== RCS file: framework/src/test/hivemind/test/naming/NamingTest.java diff -N framework/src/test/hivemind/test/naming/NamingTest.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ framework/src/test/hivemind/test/naming/NamingTest.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,131 @@ +//Copyright 2004 The Apache Software Foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package hivemind.test.naming; + +import javax.naming.CompositeName; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NamingException; + +import junit.framework.TestCase; + +import org.apache.hivemind.Registry; +import org.apache.hivemind.internal.RegistryInfrastructure; +import org.apache.hivemind.service.ThreadLocalStorage; + +/** + * @author Naresh Sikha + */ +public class NamingTest extends TestCase { + + // + private Context _context; + + // + protected void executeLookup(final boolean f, final String ns) { + Object o = null; + try { + o = _context.lookup(ns); + } catch (NamingException e) { + if (f) { + assertNull(e.toString(), e); + } + } + try { + executeLookup(f, new CompositeName(ns)); + } catch (InvalidNameException e) { + assertNull(e.toString(), e); + } + } + + // + protected void executeLookup(final boolean f, final Name n) { + Object o = null; + try { + o = _context.lookup(n); + } catch (NamingException e) { + if (f) { + assertNull(e.toString(), e); + } + } + } + + // + protected void setUp() throws Exception { + _context = new InitialContext(); + } + + // + protected void tearDown() throws Exception { + _context = null; + } + + public void testConfigurationLookup() { + executeLookup(true, "configuration:/hivemind.FactoryDefaults"); + executeLookup(false, "configuration:/DOES_NOT_EXIST"); + executeLookup(false, "configuration:///"); + executeLookup(false, "configuration://"); + executeLookup(false, "configuration:/"); + executeLookup(false, "configuration:"); + } + + public void testServiceLookupName() { + executeLookup( + true, + "service:/org.apache.hivemind.service.ThreadLocalStorage/hivemind.ThreadLocalStorage"); + executeLookup(true, + "service:/org.apache.hivemind.service.ThreadLocalStorage"); + executeLookup(true, "service://hivemind.ThreadLocalStorage"); + executeLookup(false, "service:/DOES_NOT_EXIST"); + executeLookup(false, "service:///"); + executeLookup(false, "service://"); + executeLookup(false, "service:/"); + executeLookup(false, "service:"); + + CompositeName n = null; + try { + n = new CompositeName(); + n.add("service:"); + n.add(ThreadLocalStorage.class.getName()); + } catch (InvalidNameException e) { + assertNull(e.toString(), e); + } + assertNotNull(n); + executeLookup(true, n); + + n = null; + try { + n = new CompositeName(); + n.add("service:"); + n.add(Registry.class.getName()); + } catch (InvalidNameException e) { + assertNull(e.toString(), e); + } + assertNotNull(n); + executeLookup(true, n); + + n = null; + try { + n = new CompositeName(); + n.add("service:"); + n.add(RegistryInfrastructure.class.getName()); + } catch (InvalidNameException e) { + assertNull(e.toString(), e); + } + assertNotNull(n); + executeLookup(true, n); + } +}