summaryrefslogtreecommitdiff
path: root/qpid/java/client/src/main/java/org/apache/qpid/naming/ReadOnlyContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/java/client/src/main/java/org/apache/qpid/naming/ReadOnlyContext.java')
-rw-r--r--qpid/java/client/src/main/java/org/apache/qpid/naming/ReadOnlyContext.java509
1 files changed, 509 insertions, 0 deletions
diff --git a/qpid/java/client/src/main/java/org/apache/qpid/naming/ReadOnlyContext.java b/qpid/java/client/src/main/java/org/apache/qpid/naming/ReadOnlyContext.java
new file mode 100644
index 0000000000..59ec4cfba7
--- /dev/null
+++ b/qpid/java/client/src/main/java/org/apache/qpid/naming/ReadOnlyContext.java
@@ -0,0 +1,509 @@
+/* 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.naming;
+
+import org.apache.qpid.jndi.NameParserImpl;
+
+import javax.naming.*;
+import javax.naming.spi.NamingManager;
+import java.io.Serializable;
+import java.util.*;
+
+/**
+ * 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>
+ */
+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 ReadOnlyContext.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 ReadOnlyContext.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 ReadOnlyContext.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 ReadOnlyContext.LocalNamingEnumeration
+ {
+ public Object next() throws NamingException
+ {
+ return nextElement();
+ }
+
+ public Object nextElement()
+ {
+ Map.Entry entry = getNext();
+
+ return new Binding((String) entry.getKey(), entry.getValue());
+ }
+ }
+}