You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ri...@apache.org on 2006/10/20 13:46:58 UTC

svn commit: r466076 - in /incubator/qpid/trunk/qpid/java/client: src/org/apache/qpid/client/ src/org/apache/qpid/jndi/ test/src/org/apache/qpid/test/ test/src/org/apache/qpid/test/unit/ test/src/org/apache/qpid/test/unit/jndi/

Author: ritchiem
Date: Fri Oct 20 04:46:56 2006
New Revision: 466076

URL: http://svn.apache.org/viewvc?view=rev&rev=466076
Log:
Resolution to QPID-23

Added Simple JNDI SPI Class that uses a PropertiesFile to create a ContextFactory for use with in JNDI.

Added a unit test to test using properties file to get correct objects from JNDI lookup.

Modifed AMQHeadersExchange.java to allow creation from a BindingURL.

Added:
    incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/
    incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/Example.properties   (with props)
    incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/NameParserImpl.java   (with props)
    incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java   (with props)
    incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/ReadOnlyContext.java   (with props)
    incubator/qpid/trunk/qpid/java/client/test/src/org/apache/qpid/test/
    incubator/qpid/trunk/qpid/java/client/test/src/org/apache/qpid/test/unit/
    incubator/qpid/trunk/qpid/java/client/test/src/org/apache/qpid/test/unit/jndi/
    incubator/qpid/trunk/qpid/java/client/test/src/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java   (with props)
Modified:
    incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/client/AMQHeadersExchange.java

Modified: incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/client/AMQHeadersExchange.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/client/AMQHeadersExchange.java?view=diff&rev=466076&r1=466075&r2=466076
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/client/AMQHeadersExchange.java (original)
+++ incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/client/AMQHeadersExchange.java Fri Oct 20 04:46:56 2006
@@ -18,12 +18,18 @@
 package org.apache.qpid.client;
 
 import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.url.BindingURL;
 
 /**
  * A destination backed by a headers exchange
  */
 public class AMQHeadersExchange extends AMQDestination
 {
+    public AMQHeadersExchange(BindingURL binding)
+    {
+        this(binding.getExchangeName());
+    }
+
     public AMQHeadersExchange(String queueName)
     {
         super(queueName, ExchangeDefaults.HEADERS_EXCHANGE_CLASS, queueName, true, true, null);

Added: incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/Example.properties
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/Example.properties?view=auto&rev=466076
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/Example.properties (added)
+++ incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/Example.properties Fri Oct 20 04:46:56 2006
@@ -0,0 +1,21 @@
+java.naming.factory.initial = org.apache.qpid.jndi.PropertiesFileInitialConextFactory
+
+# use the following property to configure the default connector
+#java.naming.provider.url - ignored.
+
+# register some connection factories
+# connectionfactory.[jndiname] = [ConnectionURL]
+connectionfactory.local = amqp://guest:guest@clientid/testpath?brokerlist='vm://:1'
+
+# register some queues in JNDI using the form
+# queue.[jndiName] = [physicalName]
+queue.MyQueue = example.MyQueue
+
+# register some topics in JNDI using the form
+# topic.[jndiName] = [physicalName]
+topic.ibmStocks = stocks.nyse.ibm
+
+# Register an AMQP destination in JNDI
+#   NOTE: Qpid currently only supports direct,topics and headers
+# destination.[jniName] = [BindingURL]
+destination.direct = direct://amq.direct//directQueue

Propchange: incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/Example.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/NameParserImpl.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/NameParserImpl.java?view=auto&rev=466076
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/NameParserImpl.java (added)
+++ incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/NameParserImpl.java Fri Oct 20 04:46:56 2006
@@ -0,0 +1,37 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.jndi;
+
+import javax.naming.CompositeName;
+import javax.naming.Name;
+import javax.naming.NameParser;
+import javax.naming.NamingException;
+
+/**
+ * A default implementation of {@link NameParser}
+ * <p/>
+ * Based on class from ActiveMQ.
+ */
+public class NameParserImpl implements NameParser
+{
+    public Name parse(String name) throws NamingException
+    {
+        return new CompositeName(name);
+    }
+}

Propchange: incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/NameParserImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java?view=auto&rev=466076
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java (added)
+++ incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java Fri Oct 20 04:46:56 2006
@@ -0,0 +1,289 @@
+/*
+ *
+ * Copyright (c) 2006 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.qpid.jndi;
+
+import org.apache.log4j.Logger;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQHeadersExchange;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQTopic;
+import org.apache.qpid.exchange.ExchangeDefaults;
+import org.apache.qpid.url.AMQBindingURL;
+import org.apache.qpid.url.BindingURL;
+import org.apache.qpid.url.URLSyntaxException;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Queue;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class PropertiesFileInitialContextFactory implements InitialContextFactory
+{
+    protected final Logger _logger = Logger.getLogger(getClass());
+
+    private String CONNECTION_FACTORY_PREFIX = "connectionfactory.";
+    private String DESTINATION_PREFIX = "destination.";
+    private String QUEUE_PREFIX = "queue.";
+    private String TOPIC_PREFIX = "topic.";
+
+    public Context getInitialContext(Hashtable environment) throws NamingException
+    {
+        Map data = new ConcurrentHashMap();
+
+        createConnectionFactories(data, environment);
+
+        createDestinations(data, environment);
+
+        createQueues(data, environment);
+
+        createTopics(data, environment);
+
+        return createContext(data, environment);
+    }
+
+    // Implementation methods
+    //-------------------------------------------------------------------------
+    protected ReadOnlyContext createContext(Map data, Hashtable environment)
+    {
+        return new ReadOnlyContext(environment, data);
+    }
+
+    protected void createConnectionFactories(Map data, Hashtable environment)
+    {
+        for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();)
+        {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String key = entry.getKey().toString();
+            if (key.startsWith(CONNECTION_FACTORY_PREFIX))
+            {
+                String jndiName = key.substring(CONNECTION_FACTORY_PREFIX.length());
+                ConnectionFactory cf = createFactory(entry.getValue().toString());
+                if (cf != null)
+                {
+                    data.put(jndiName, cf);
+                }
+            }
+        }
+    }
+
+    protected void createDestinations(Map data, Hashtable environment)
+    {
+        for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();)
+        {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String key = entry.getKey().toString();
+            if (key.startsWith(DESTINATION_PREFIX))
+            {
+                String jndiName = key.substring(DESTINATION_PREFIX.length());
+                Destination dest = createDestination(entry.getValue().toString());
+                if (dest != null)
+                {
+                    data.put(jndiName, dest);
+                }
+            }
+        }
+    }
+
+    protected void createQueues(Map data, Hashtable environment)
+    {
+        for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();)
+        {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String key = entry.getKey().toString();
+            if (key.startsWith(QUEUE_PREFIX))
+            {
+                String jndiName = key.substring(QUEUE_PREFIX.length());
+                Queue q = createQueue(entry.getValue().toString());
+                if (q != null)
+                {
+                    data.put(jndiName, q);
+                }
+            }
+        }
+    }
+
+    protected void createTopics(Map data, Hashtable environment)
+    {
+        for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();)
+        {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String key = entry.getKey().toString();
+            if (key.startsWith(TOPIC_PREFIX))
+            {
+                String jndiName = key.substring(TOPIC_PREFIX.length());
+                Topic t = createTopic(entry.getValue().toString());
+                if (t != null)
+                {
+                    data.put(jndiName, t);
+                }
+            }
+        }
+    }
+
+    /**
+     * Factory method to create new Connection Factory instances
+     */
+    protected ConnectionFactory createFactory(String url)
+    {
+        try
+        {
+            return new AMQConnectionFactory(url);
+        }
+        catch (URLSyntaxException urlse)
+        {
+            _logger.warn("Unable to createFactories:" + urlse);
+        }
+        return null;
+    }
+
+    /**
+     * Factory method to create new Destination instances from an AMQP BindingURL
+     */
+    protected Destination createDestination(String bindingURL)
+    {
+        AMQBindingURL binding;
+        try
+        {
+            binding = new AMQBindingURL(bindingURL);
+        }
+        catch (URLSyntaxException urlse)
+        {
+            _logger.warn("Unable to destination:" + urlse);
+            return null;
+        }
+
+        if (binding.getExchangeClass().equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
+        {
+            return createTopic(binding);
+        }
+        else if (binding.getExchangeClass().equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
+        {
+            return createQueue(binding);
+        }
+        else if (binding.getExchangeClass().equals(ExchangeDefaults.HEADERS_EXCHANGE_CLASS))
+        {
+            return createHeaderExchange(binding);
+        }
+
+        _logger.warn("Binding: '" + binding + "' not supported");
+        return null;
+    }
+
+    /**
+     * Factory method to create new Queue instances
+     */
+    protected Queue createQueue(Object value)
+    {
+        if (value instanceof String)
+
+        {
+            return new AMQQueue((String) value);
+        }
+        else if (value instanceof BindingURL)
+
+        {
+            return new AMQQueue((BindingURL) value);
+        }
+
+        return null;
+    }
+
+    /**
+     * Factory method to create new Topic instances
+     */
+    protected Topic createTopic(Object value)
+    {
+        if (value instanceof String)
+        {
+            return new AMQTopic((String) value);
+        }
+        else if (value instanceof BindingURL)
+
+        {
+            return new AMQTopic((BindingURL) value);
+        }
+
+        return null;
+    }
+
+    /**
+     * Factory method to create new HeaderExcahnge instances
+     */
+    protected Destination createHeaderExchange(Object value)
+    {
+        if (value instanceof String)
+        {
+            return new AMQHeadersExchange((String) value);
+        }
+        else if (value instanceof BindingURL)
+        {
+            return new AMQHeadersExchange((BindingURL) value);
+        }
+
+        return null;
+    }
+
+    // Properties
+    //-------------------------------------------------------------------------
+    public String getConnectionPrefix()
+    {
+        return CONNECTION_FACTORY_PREFIX;
+    }
+
+    public void setConnectionPrefix(String connectionPrefix)
+    {
+        this.CONNECTION_FACTORY_PREFIX = connectionPrefix;
+    }
+
+    public String getDestinationPrefix()
+    {
+        return DESTINATION_PREFIX;
+    }
+
+    public void setDestinationPrefix(String destinationPrefix)
+    {
+        this.DESTINATION_PREFIX = destinationPrefix;
+    }
+
+    public String getQueuePrefix()
+    {
+        return QUEUE_PREFIX;
+    }
+
+    public void setQueuePrefix(String queuePrefix)
+    {
+        this.QUEUE_PREFIX = queuePrefix;
+    }
+
+    public String getTopicPrefix()
+    {
+        return TOPIC_PREFIX;
+    }
+
+    public void setTopicPrefix(String topicPrefix)
+    {
+        this.TOPIC_PREFIX = topicPrefix;
+    }
+}

Propchange: incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/PropertiesFileInitialContextFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/ReadOnlyContext.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/ReadOnlyContext.java?view=auto&rev=466076
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/ReadOnlyContext.java (added)
+++ incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/ReadOnlyContext.java Fri Oct 20 04:46:56 2006
@@ -0,0 +1,497 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.qpid.jndi;
+
+import javax.naming.*;
+import javax.naming.spi.NamingManager;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Based on class from ActiveMQ.
+ * A read-only Context
+ * <p/>
+ * This version assumes it and all its subcontext are read-only and any attempt
+ * to modify (e.g. through bind) will result in an OperationNotSupportedException.
+ * Each Context in the tree builds a cache of the entries in all sub-contexts
+ * to optimise the performance of lookup.
+ * </p>
+ * <p>This implementation is intended to optimise the performance of lookup(String)
+ * to about the level of a HashMap get. It has been observed that the scheme
+ * resolution phase performed by the JVM takes considerably longer, so for
+ * optimum performance lookups should be coded like:</p>
+ * <code>
+ * Context componentContext = (Context)new InitialContext().lookup("java:comp");
+ * String envEntry = (String) componentContext.lookup("env/myEntry");
+ * String envEntry2 = (String) componentContext.lookup("env/myEntry2");
+ * </code>
+ *
+ * @version $Revision: 1.2 $ $Date: 2005/08/27 03:52:39 $
+ */
+public class ReadOnlyContext implements Context, Serializable
+{
+    private static final long serialVersionUID = -5754338187296859149L;
+    protected static final NameParser nameParser = new NameParserImpl();
+
+    protected final Hashtable environment;        // environment for this context
+    protected final Map bindings;         // bindings at my level
+    protected final Map treeBindings;     // all bindings under me
+
+    private boolean frozen = false;
+    private String nameInNamespace = "";
+    public static final String SEPARATOR = "/";
+
+    public ReadOnlyContext()
+    {
+        environment = new Hashtable();
+        bindings = new HashMap();
+        treeBindings = new HashMap();
+    }
+
+    public ReadOnlyContext(Hashtable env)
+    {
+        if (env == null)
+        {
+            this.environment = new Hashtable();
+        }
+        else
+        {
+            this.environment = new Hashtable(env);
+        }
+        this.bindings = Collections.EMPTY_MAP;
+        this.treeBindings = Collections.EMPTY_MAP;
+    }
+
+    public ReadOnlyContext(Hashtable environment, Map bindings)
+    {
+        if (environment == null)
+        {
+            this.environment = new Hashtable();
+        }
+        else
+        {
+            this.environment = new Hashtable(environment);
+        }
+        this.bindings = bindings;
+        treeBindings = new HashMap();
+        frozen = true;
+    }
+
+    public ReadOnlyContext(Hashtable environment, Map bindings, String nameInNamespace)
+    {
+        this(environment, bindings);
+        this.nameInNamespace = nameInNamespace;
+    }
+
+    protected ReadOnlyContext(ReadOnlyContext clone, Hashtable env)
+    {
+        this.bindings = clone.bindings;
+        this.treeBindings = clone.treeBindings;
+        this.environment = new Hashtable(env);
+    }
+
+    protected ReadOnlyContext(ReadOnlyContext clone, Hashtable env, String nameInNamespace)
+    {
+        this(clone, env);
+        this.nameInNamespace = nameInNamespace;
+    }
+
+    public void freeze()
+    {
+        frozen = true;
+    }
+
+    boolean isFrozen()
+    {
+        return frozen;
+    }
+
+    /**
+     * internalBind is intended for use only during setup or possibly by suitably synchronized superclasses.
+     * It binds every possible lookup into a map in each context.  To do this, each context
+     * strips off one name segment and if necessary creates a new context for it. Then it asks that context
+     * to bind the remaining name.  It returns a map containing all the bindings from the next context, plus
+     * the context it just created (if it in fact created it). (the names are suitably extended by the segment
+     * originally lopped off).
+     *
+     * @param name
+     * @param value
+     * @return
+     * @throws javax.naming.NamingException
+     */
+    protected Map internalBind(String name, Object value) throws NamingException
+    {
+        assert name != null && name.length() > 0;
+        assert!frozen;
+
+        Map newBindings = new HashMap();
+        int pos = name.indexOf('/');
+        if (pos == -1)
+        {
+            if (treeBindings.put(name, value) != null)
+            {
+                throw new NamingException("Something already bound at " + name);
+            }
+            bindings.put(name, value);
+            newBindings.put(name, value);
+        }
+        else
+        {
+            String segment = name.substring(0, pos);
+            assert segment != null;
+            assert!segment.equals("");
+            Object o = treeBindings.get(segment);
+            if (o == null)
+            {
+                o = newContext();
+                treeBindings.put(segment, o);
+                bindings.put(segment, o);
+                newBindings.put(segment, o);
+            }
+            else if (!(o instanceof ReadOnlyContext))
+            {
+                throw new NamingException("Something already bound where a subcontext should go");
+            }
+            ReadOnlyContext readOnlyContext = (ReadOnlyContext) o;
+            String remainder = name.substring(pos + 1);
+            Map subBindings = readOnlyContext.internalBind(remainder, value);
+            for (Iterator iterator = subBindings.entrySet().iterator(); iterator.hasNext();)
+            {
+                Map.Entry entry = (Map.Entry) iterator.next();
+                String subName = segment + "/" + (String) entry.getKey();
+                Object bound = entry.getValue();
+                treeBindings.put(subName, bound);
+                newBindings.put(subName, bound);
+            }
+        }
+        return newBindings;
+    }
+
+    protected ReadOnlyContext newContext()
+    {
+        return new ReadOnlyContext();
+    }
+
+    public Object addToEnvironment(String propName, Object propVal) throws NamingException
+    {
+        return environment.put(propName, propVal);
+    }
+
+    public Hashtable getEnvironment() throws NamingException
+    {
+        return (Hashtable) environment.clone();
+    }
+
+    public Object removeFromEnvironment(String propName) throws NamingException
+    {
+        return environment.remove(propName);
+    }
+
+    public Object lookup(String name) throws NamingException
+    {
+        if (name.length() == 0)
+        {
+            return this;
+        }
+        Object result = treeBindings.get(name);
+        if (result == null)
+        {
+            result = bindings.get(name);
+        }
+        if (result == null)
+        {
+            int pos = name.indexOf(':');
+            if (pos > 0)
+            {
+                String scheme = name.substring(0, pos);
+                Context ctx = NamingManager.getURLContext(scheme, environment);
+                if (ctx == null)
+                {
+                    throw new NamingException("scheme " + scheme + " not recognized");
+                }
+                return ctx.lookup(name);
+            }
+            else
+            {
+                // Split out the first name of the path
+                // and look for it in the bindings map.
+                CompositeName path = new CompositeName(name);
+
+                if (path.size() == 0)
+                {
+                    return this;
+                }
+                else
+                {
+                    String first = path.get(0);
+                    Object obj = bindings.get(first);
+                    if (obj == null)
+                    {
+                        throw new NameNotFoundException(name);
+                    }
+                    else if (obj instanceof Context && path.size() > 1)
+                    {
+                        Context subContext = (Context) obj;
+                        obj = subContext.lookup(path.getSuffix(1));
+                    }
+                    return obj;
+                }
+            }
+        }
+        if (result instanceof LinkRef)
+        {
+            LinkRef ref = (LinkRef) result;
+            result = lookup(ref.getLinkName());
+        }
+        if (result instanceof Reference)
+        {
+            try
+            {
+                result = NamingManager.getObjectInstance(result, null, null, this.environment);
+            }
+            catch (NamingException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw(NamingException) new NamingException("could not look up : " + name).initCause(e);
+            }
+        }
+        if (result instanceof ReadOnlyContext)
+        {
+            String prefix = getNameInNamespace();
+            if (prefix.length() > 0)
+            {
+                prefix = prefix + SEPARATOR;
+            }
+            result = new ReadOnlyContext((ReadOnlyContext) result, environment, prefix + name);
+        }
+        return result;
+    }
+
+    public Object lookup(Name name) throws NamingException
+    {
+        return lookup(name.toString());
+    }
+
+    public Object lookupLink(String name) throws NamingException
+    {
+        return lookup(name);
+    }
+
+    public Name composeName(Name name, Name prefix) throws NamingException
+    {
+        Name result = (Name) prefix.clone();
+        result.addAll(name);
+        return result;
+    }
+
+    public String composeName(String name, String prefix) throws NamingException
+    {
+        CompositeName result = new CompositeName(prefix);
+        result.addAll(new CompositeName(name));
+        return result.toString();
+    }
+
+    public NamingEnumeration list(String name) throws NamingException
+    {
+        Object o = lookup(name);
+        if (o == this)
+        {
+            return new ListEnumeration();
+        }
+        else if (o instanceof Context)
+        {
+            return ((Context) o).list("");
+        }
+        else
+        {
+            throw new NotContextException();
+        }
+    }
+
+    public NamingEnumeration listBindings(String name) throws NamingException
+    {
+        Object o = lookup(name);
+        if (o == this)
+        {
+            return new ListBindingEnumeration();
+        }
+        else if (o instanceof Context)
+        {
+            return ((Context) o).listBindings("");
+        }
+        else
+        {
+            throw new NotContextException();
+        }
+    }
+
+    public Object lookupLink(Name name) throws NamingException
+    {
+        return lookupLink(name.toString());
+    }
+
+    public NamingEnumeration list(Name name) throws NamingException
+    {
+        return list(name.toString());
+    }
+
+    public NamingEnumeration listBindings(Name name) throws NamingException
+    {
+        return listBindings(name.toString());
+    }
+
+    public void bind(Name name, Object obj) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public void bind(String name, Object obj) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public void close() throws NamingException
+    {
+        // ignore
+    }
+
+    public Context createSubcontext(Name name) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public Context createSubcontext(String name) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public void destroySubcontext(Name name) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public void destroySubcontext(String name) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public String getNameInNamespace() throws NamingException
+    {
+        return nameInNamespace;
+    }
+
+    public NameParser getNameParser(Name name) throws NamingException
+    {
+        return nameParser;
+    }
+
+    public NameParser getNameParser(String name) throws NamingException
+    {
+        return nameParser;
+    }
+
+    public void rebind(Name name, Object obj) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public void rebind(String name, Object obj) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public void rename(Name oldName, Name newName) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public void rename(String oldName, String newName) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public void unbind(Name name) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    public void unbind(String name) throws NamingException
+    {
+        throw new OperationNotSupportedException();
+    }
+
+    private abstract class LocalNamingEnumeration implements NamingEnumeration
+    {
+        private Iterator i = bindings.entrySet().iterator();
+
+        public boolean hasMore() throws NamingException
+        {
+            return i.hasNext();
+        }
+
+        public boolean hasMoreElements()
+        {
+            return i.hasNext();
+        }
+
+        protected Map.Entry getNext()
+        {
+            return (Map.Entry) i.next();
+        }
+
+        public void close() throws NamingException
+        {
+        }
+    }
+
+    private class ListEnumeration extends LocalNamingEnumeration
+    {
+        public Object next() throws NamingException
+        {
+            return nextElement();
+        }
+
+        public Object nextElement()
+        {
+            Map.Entry entry = getNext();
+            return new NameClassPair((String) entry.getKey(), entry.getValue().getClass().getName());
+        }
+    }
+
+    private class ListBindingEnumeration extends LocalNamingEnumeration
+    {
+        public Object next() throws NamingException
+        {
+            return nextElement();
+        }
+
+        public Object nextElement()
+        {
+            Map.Entry entry = getNext();
+            return new Binding((String) entry.getKey(), entry.getValue());
+        }
+    }
+}

Propchange: incubator/qpid/trunk/qpid/java/client/src/org/apache/qpid/jndi/ReadOnlyContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/qpid/trunk/qpid/java/client/test/src/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java
URL: http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/java/client/test/src/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java?view=auto&rev=466076
==============================================================================
--- incubator/qpid/trunk/qpid/java/client/test/src/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java (added)
+++ incubator/qpid/trunk/qpid/java/client/test/src/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java Fri Oct 20 04:46:56 2006
@@ -0,0 +1,110 @@
+/*
+ *
+ * Copyright (c) 2006 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.qpid.test.unit.jndi;
+
+import junit.framework.JUnit4TestAdapter;
+import org.apache.qpid.client.AMQConnectionFactory;
+import org.apache.qpid.client.AMQQueue;
+import org.apache.qpid.client.AMQTopic;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+import java.util.Properties;
+
+public class PropertiesFileInitialContextFactoryTest
+{
+    InitialContextFactory contextFactory;
+    Properties _properties;
+
+    @Before
+    public void setupProperties()
+    {
+        _properties = new Properties();
+        _properties.put("java.naming.factory.initial", "org.apache.qpid.jndi.PropertiesFileInitialContextFactory");
+        _properties.put("connectionfactory.local", "amqp://guest:guest@clientid/testpath?brokerlist='vm://:1'");
+        _properties.put("queue.MyQueue", "example.MyQueue");
+        _properties.put("topic.ibmStocks", "stocks.nyse.ibm");
+        _properties.put("destination.direct", "direct://amq.direct//directQueue");
+    }
+
+    @Test
+    public void test()
+    {
+        Context ctx = null;
+        try
+        {
+            ctx = new InitialContext(_properties);
+        }
+        catch (NamingException ne)
+        {
+            Assert.fail("Error loading context:" + ne);
+        }
+
+        try
+        {
+            AMQConnectionFactory cf = (AMQConnectionFactory) ctx.lookup("local");
+            Assert.assertEquals("amqp://guest:guest@clientid/testpath?brokerlist='vm://:1'", cf.getConnectionURL().toString());
+        }
+        catch (NamingException ne)
+        {
+            Assert.fail("Unable to create Connection Factory:" + ne);
+        }
+
+        try
+        {
+            AMQQueue queue = (AMQQueue) ctx.lookup("MyQueue");
+            Assert.assertEquals("example.MyQueue", queue.getRoutingKey());
+        }
+        catch (NamingException ne)
+        {
+            Assert.fail("Unable to create queue:" + ne);
+        }
+
+        try
+        {
+            AMQTopic topic = (AMQTopic) ctx.lookup("ibmStocks");
+            Assert.assertEquals("stocks.nyse.ibm", topic.getTopicName());
+        }
+        catch (Exception ne)
+        {
+            Assert.fail("Unable to create topic:" + ne);
+        }
+
+        try
+        {
+            AMQQueue direct = (AMQQueue) ctx.lookup("direct");
+            Assert.assertEquals("directQueue", direct.getRoutingKey());
+        }
+        catch (NamingException ne)
+        {
+            Assert.fail("Unable to create direct destination:" + ne);
+        }
+
+
+    }
+
+    public static junit.framework.Test suite()
+    {
+        return new JUnit4TestAdapter(PropertiesFileInitialContextFactoryTest.class);
+    }
+}

Propchange: incubator/qpid/trunk/qpid/java/client/test/src/org/apache/qpid/test/unit/jndi/PropertiesFileInitialContextFactoryTest.java
------------------------------------------------------------------------------
    svn:eol-style = native