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); + } +}