You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ta...@apache.org on 2014/09/23 20:20:47 UTC

[23/27] Initial drop of donated AMQP Client Code.

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIStorable.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIStorable.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIStorable.java
new file mode 100644
index 0000000..1dfd0b3
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JNDIStorable.java
@@ -0,0 +1,119 @@
+/**
+ * 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.jms.jndi;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.naming.NamingException;
+import javax.naming.Reference;
+import javax.naming.Referenceable;
+
+/**
+ * Facilitates objects to be stored in JNDI as properties
+ *
+ * @since 1.0
+ */
+public abstract class JNDIStorable implements Referenceable, Externalizable {
+
+    private Map<String, String> properties;
+
+    /**
+     * Set the properties that will represent the instance in JNDI
+     *
+     * @param props
+     */
+    protected abstract void buildFromProperties(Map<String, String> props);
+
+    /**
+     * Initialize the instance from properties stored in JNDI
+     *
+     * @param props
+     */
+    protected abstract void populateProperties(Map<String, String> props);
+
+    /**
+     * set the properties for this instance as retrieved from JNDI
+     *
+     * @param props
+     */
+    public synchronized void setProperties(Map<String, String> props) {
+        this.properties = props;
+        buildFromProperties(props);
+    }
+
+    /**
+     * Get the properties from this instance for storing in JNDI
+     *
+     * @return the properties
+     */
+    public synchronized Map<String, String> getProperties() {
+        if (this.properties == null) {
+            this.properties = new HashMap<String, String>();
+        }
+        populateProperties(this.properties);
+        return this.properties;
+    }
+
+    /**
+     * Retrieve a Reference for this instance to store in JNDI
+     *
+     * @return the built Reference
+     * @throws NamingException
+     *         if error on building Reference
+     */
+    @Override
+    public Reference getReference() throws NamingException {
+        return JNDIReferenceFactory.createReference(this.getClass().getName(), this);
+    }
+
+    /**
+     * @param in
+     * @throws IOException
+     * @throws ClassNotFoundException
+     * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
+     */
+    @Override
+    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+        Map<String, String> props = (Map<String, String>) in.readObject();
+        if (props != null) {
+            setProperties(props);
+        }
+    }
+
+    /**
+     * @param out
+     * @throws IOException
+     * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
+     */
+    @Override
+    public void writeExternal(ObjectOutput out) throws IOException {
+        out.writeObject(getProperties());
+    }
+
+    protected String getProperty(Map<String, String> map, String key, String defaultValue) {
+        String value = map.get(key);
+        if (value != null) {
+            return value;
+        }
+        return defaultValue;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JmsInitialContextFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JmsInitialContextFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JmsInitialContextFactory.java
new file mode 100644
index 0000000..8ad7b32
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/JmsInitialContextFactory.java
@@ -0,0 +1,197 @@
+/**
+ * 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.jms.jndi;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.jms.Queue;
+import javax.jms.Topic;
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.spi.InitialContextFactory;
+
+import org.apache.qpid.jms.JmsConnectionFactory;
+import org.apache.qpid.jms.JmsQueue;
+import org.apache.qpid.jms.JmsTopic;
+
+/**
+ * A factory of the StompJms InitialContext which contains
+ * {@link javax.jms.ConnectionFactory} instances as well as a child context
+ * called <i>destinations</i> which contain all of the current active
+ * destinations, in child context depending on the QoS such as transient or
+ * durable and queue or topic.
+ *
+ * @since 1.0
+ */
+public class JmsInitialContextFactory implements InitialContextFactory {
+
+    private static final String[] DEFAULT_CONNECTION_FACTORY_NAMES = {
+        "ConnectionFactory", "QueueConnectionFactory", "TopicConnectionFactory" };
+
+    private String connectionPrefix = "";
+
+    String queuePrefix = "/queue/";
+    String topicPrefix = "/topic/";
+
+    @Override
+    public Context getInitialContext(Hashtable environment) throws NamingException {
+
+        queuePrefix = getValue(environment, "queuePrefix", queuePrefix);
+        topicPrefix = getValue(environment, "topicPrefix", topicPrefix);
+
+        // lets create a factory
+        Map<String, Object> data = new ConcurrentHashMap<String, Object>();
+        String[] names = getConnectionFactoryNames(environment);
+        for (int i = 0; i < names.length; i++) {
+            JmsConnectionFactory factory = null;
+            String name = names[i];
+
+            try {
+                factory = createConnectionFactory(name, environment);
+            } catch (Exception e) {
+                throw new NamingException("Invalid broker URL");
+
+            }
+
+            data.put(name, factory);
+        }
+
+        data.put("queue", new LazyCreateContext() {
+            private static final long serialVersionUID = 6503881346214855588L;
+
+            @Override
+            protected Object createEntry(String name) {
+                return new JmsQueue(name);
+            }
+        });
+
+        data.put("topic", new LazyCreateContext() {
+            private static final long serialVersionUID = 2019166796234979615L;
+
+            @Override
+            protected Object createEntry(String name) {
+                return new JmsTopic(name);
+            }
+        });
+
+        return createContext(environment, data);
+    }
+
+    static private String getValue(Hashtable environment, String key, String defaultValue) {
+        Object o = environment.get(key);
+        if (o != null && o instanceof String) {
+            return (String) o;
+        } else {
+            return defaultValue;
+        }
+    }
+
+    // Implementation methods
+    // -------------------------------------------------------------------------
+
+    protected ReadOnlyContext createContext(Hashtable environment, Map<String, Object> data) {
+        return new ReadOnlyContext(environment, data);
+    }
+
+    protected JmsConnectionFactory createConnectionFactory(String name, Hashtable environment) throws URISyntaxException {
+        Hashtable temp = new Hashtable(environment);
+        String prefix = connectionPrefix + name + ".";
+        for (Iterator iter = environment.entrySet().iterator(); iter.hasNext();) {
+            Map.Entry entry = (Map.Entry) iter.next();
+            String key = (String) entry.getKey();
+            if (key.startsWith(prefix)) {
+                // Rename the key...
+                temp.remove(key);
+                key = key.substring(prefix.length());
+                temp.put(key, entry.getValue());
+            }
+        }
+        return createConnectionFactory(temp);
+    }
+
+    protected String[] getConnectionFactoryNames(Map environment) {
+        String factoryNames = (String) environment.get("factories");
+        if (factoryNames != null) {
+            List<String> list = new ArrayList<String>();
+            for (StringTokenizer enumeration = new StringTokenizer(factoryNames, ","); enumeration.hasMoreTokens();) {
+                list.add(enumeration.nextToken().trim());
+            }
+            int size = list.size();
+            if (size > 0) {
+                String[] answer = new String[size];
+                list.toArray(answer);
+                return answer;
+            }
+        }
+        return DEFAULT_CONNECTION_FACTORY_NAMES;
+    }
+
+    /**
+     * Factory method to create new Queue instances
+     */
+    protected Queue createQueue(String name) {
+        return new JmsQueue(name);
+    }
+
+    /**
+     * Factory method to create new Topic instances
+     */
+    protected Topic createTopic(String name) {
+        return new JmsTopic(name);
+    }
+
+    /**
+     * Factory method to create a new connection factory from the given
+     * environment
+     */
+    protected JmsConnectionFactory createConnectionFactory(Hashtable environment) throws URISyntaxException {
+        JmsConnectionFactory answer = new JmsConnectionFactory();
+        Properties properties = new Properties();
+        environment.remove("java.naming.factory.initial");
+        Object o = environment.remove("java.naming.provider.url");
+        if (o != null) {
+            answer.setBrokerURI(o.toString());
+        }
+        o = environment.remove("java.naming.security.principal");
+        if (o != null) {
+            answer.setUsername(o.toString());
+        }
+        o = environment.remove("java.naming.security.credentials");
+        if (o != null) {
+            answer.setPassword(o.toString());
+        }
+        properties.putAll(environment);
+        answer.setProperties(properties);
+        return answer;
+    }
+
+    public String getConnectionPrefix() {
+        return connectionPrefix;
+    }
+
+    public void setConnectionPrefix(String connectionPrefix) {
+        this.connectionPrefix = connectionPrefix;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/LazyCreateContext.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/LazyCreateContext.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/LazyCreateContext.java
new file mode 100644
index 0000000..11b52fe
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/LazyCreateContext.java
@@ -0,0 +1,46 @@
+/**
+ * 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.jms.jndi;
+
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+/**
+ * Allows users to dynamically create items
+ *
+ * @since 1.0
+ */
+public abstract class LazyCreateContext extends ReadOnlyContext {
+
+    private static final long serialVersionUID = 5131341840091473967L;
+
+    @Override
+    public Object lookup(String name) throws NamingException {
+        try {
+            return super.lookup(name);
+        } catch (NameNotFoundException e) {
+            Object answer = createEntry(name);
+            if (answer == null) {
+                throw e;
+            }
+            internalBind(name, answer);
+            return answer;
+        }
+    }
+
+    protected abstract Object createEntry(String name);
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/NameParserImpl.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/NameParserImpl.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/NameParserImpl.java
new file mode 100644
index 0000000..abdd4a2
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/NameParserImpl.java
@@ -0,0 +1,35 @@
+/**
+ * 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.jms.jndi;
+
+import javax.naming.CompositeName;
+import javax.naming.Name;
+import javax.naming.NameParser;
+import javax.naming.NamingException;
+
+/**
+ * A default implementation of {@link NameParser}
+ *
+ * @since 1.0
+ */
+public class NameParserImpl implements NameParser {
+
+    @Override
+    public Name parse(String name) throws NamingException {
+        return new CompositeName(name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/ReadOnlyContext.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/ReadOnlyContext.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/ReadOnlyContext.java
new file mode 100644
index 0000000..60181d1
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/jndi/ReadOnlyContext.java
@@ -0,0 +1,465 @@
+/**
+ * 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.jms.jndi;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.naming.Binding;
+import javax.naming.CompositeName;
+import javax.naming.Context;
+import javax.naming.LinkRef;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.NotContextException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.Reference;
+import javax.naming.spi.NamingManager;
+
+/**
+ * A read-only Context
+ * <p/>
+ * This version assumes it and all its sub-context 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 optimize the performance of lookup.
+ * </p>
+ * <p>
+ * This implementation is intended to optimize 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>
+ */
+@SuppressWarnings("unchecked")
+public class ReadOnlyContext implements Context, Serializable {
+
+    public static final String SEPARATOR = "/";
+    protected static final NameParser NAME_PARSER = new NameParserImpl();
+    private static final long serialVersionUID = -5754338187296859149L;
+
+    protected final Hashtable<String, Object> environment; // environment for this context
+    protected final Map<String, Object> bindings; // bindings at my level
+    protected final Map<String, Object> treeBindings; // all bindings under me
+
+    private boolean frozen;
+    private String nameInNamespace = "";
+
+    public ReadOnlyContext() {
+        environment = new Hashtable<String, Object>();
+        bindings = new HashMap<String, Object>();
+        treeBindings = new HashMap<String, Object>();
+    }
+
+    public ReadOnlyContext(Hashtable env) {
+        if (env == null) {
+            this.environment = new Hashtable<String, Object>();
+        } else {
+            this.environment = new Hashtable<String, Object>(env);
+        }
+        this.bindings = Collections.EMPTY_MAP;
+        this.treeBindings = Collections.EMPTY_MAP;
+    }
+
+    public ReadOnlyContext(Hashtable environment, Map<String, Object> bindings) {
+        if (environment == null) {
+            this.environment = new Hashtable<String, Object>();
+        } else {
+            this.environment = new Hashtable<String, Object>(environment);
+        }
+        this.bindings = new HashMap<String, Object>();
+        treeBindings = new HashMap<String, Object>();
+        if (bindings != null) {
+            for (Map.Entry<String, Object> binding : bindings.entrySet()) {
+                try {
+                    internalBind(binding.getKey(), binding.getValue());
+                } catch (Throwable e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        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<String, Object>(env);
+    }
+
+    protected ReadOnlyContext(ReadOnlyContext clone, Hashtable<String, Object> 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 super-classes. 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<String, Object> internalBind(String name, Object value) throws NamingException {
+        assert name != null && name.length() > 0;
+        assert !frozen;
+
+        Map<String, Object> newBindings = new HashMap<String, Object>();
+        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<String, Object> 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();
+    }
+
+    @Override
+    public Object addToEnvironment(String propName, Object propVal) throws NamingException {
+        return environment.put(propName, propVal);
+    }
+
+    @Override
+    public Hashtable<String, Object> getEnvironment() throws NamingException {
+        return (Hashtable<String, Object>) environment.clone();
+    }
+
+    @Override
+    public Object removeFromEnvironment(String propName) throws NamingException {
+        return environment.remove(propName);
+    }
+
+    @Override
+    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;
+    }
+
+    @Override
+    public Object lookup(Name name) throws NamingException {
+        return lookup(name.toString());
+    }
+
+    @Override
+    public Object lookupLink(String name) throws NamingException {
+        return lookup(name);
+    }
+
+    @Override
+    public Name composeName(Name name, Name prefix) throws NamingException {
+        Name result = (Name) prefix.clone();
+        result.addAll(name);
+        return result;
+    }
+
+    @Override
+    public String composeName(String name, String prefix) throws NamingException {
+        CompositeName result = new CompositeName(prefix);
+        result.addAll(new CompositeName(name));
+        return result.toString();
+    }
+
+    @Override
+    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();
+        }
+    }
+
+    @Override
+    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();
+        }
+    }
+
+    @Override
+    public Object lookupLink(Name name) throws NamingException {
+        return lookupLink(name.toString());
+    }
+
+    @Override
+    public NamingEnumeration list(Name name) throws NamingException {
+        return list(name.toString());
+    }
+
+    @Override
+    public NamingEnumeration listBindings(Name name) throws NamingException {
+        return listBindings(name.toString());
+    }
+
+    @Override
+    public void bind(Name name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void bind(String name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void close() throws NamingException {
+        // ignore
+    }
+
+    @Override
+    public Context createSubcontext(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public Context createSubcontext(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void destroySubcontext(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void destroySubcontext(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public String getNameInNamespace() throws NamingException {
+        return nameInNamespace;
+    }
+
+    @Override
+    public NameParser getNameParser(Name name) throws NamingException {
+        return NAME_PARSER;
+    }
+
+    @Override
+    public NameParser getNameParser(String name) throws NamingException {
+        return NAME_PARSER;
+    }
+
+    @Override
+    public void rebind(Name name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void rebind(String name, Object obj) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void rename(Name oldName, Name newName) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void rename(String oldName, String newName) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void unbind(Name name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    @Override
+    public void unbind(String name) throws NamingException {
+        throw new OperationNotSupportedException();
+    }
+
+    private abstract class LocalNamingEnumeration implements NamingEnumeration {
+        private final Iterator i = bindings.entrySet().iterator();
+
+        @Override
+        public boolean hasMore() throws NamingException {
+            return i.hasNext();
+        }
+
+        @Override
+        public boolean hasMoreElements() {
+            return i.hasNext();
+        }
+
+        protected Map.Entry getNext() {
+            return (Map.Entry) i.next();
+        }
+
+        @Override
+        public void close() throws NamingException {
+        }
+    }
+
+    private class ListEnumeration extends LocalNamingEnumeration {
+        ListEnumeration() {
+        }
+
+        @Override
+        public Object next() throws NamingException {
+            return nextElement();
+        }
+
+        @Override
+        public Object nextElement() {
+            Map.Entry entry = getNext();
+            return new NameClassPair((String) entry.getKey(), entry.getValue().getClass().getName());
+        }
+    }
+
+    private class ListBindingEnumeration extends LocalNamingEnumeration {
+        ListBindingEnumeration() {
+        }
+
+        @Override
+        public Object next() throws NamingException {
+            return nextElement();
+        }
+
+        @Override
+        public Object nextElement() {
+            Map.Entry entry = getNext();
+            return new Binding((String) entry.getKey(), entry.getValue());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsBytesMessage.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsBytesMessage.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsBytesMessage.java
new file mode 100644
index 0000000..2383768
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsBytesMessage.java
@@ -0,0 +1,831 @@
+/**
+ * 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.jms.message;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+import javax.jms.MessageEOFException;
+import javax.jms.MessageFormatException;
+import javax.jms.MessageNotReadableException;
+import javax.jms.MessageNotWriteableException;
+
+import org.apache.qpid.jms.exceptions.JmsExceptionSupport;
+import org.apache.qpid.jms.message.facade.JmsBytesMessageFacade;
+import org.fusesource.hawtbuf.Buffer;
+import org.fusesource.hawtbuf.ByteArrayInputStream;
+import org.fusesource.hawtbuf.DataByteArrayOutputStream;
+
+/**
+ * A <CODE>BytesMessage</CODE> object is used to send a message containing a
+ * stream of uninterpreted bytes. It inherits from the <CODE>Message</CODE>
+ * interface and adds a bytes message body. The receiver of the message supplies
+ * the interpretation of the bytes.
+ * <p/>
+ * The <CODE>BytesMessage</CODE> methods are based largely on those found in
+ * <CODE>java.io.DataInputStream</CODE> and
+ * <CODE>java.io.DataOutputStream</CODE>.
+ * <p/>
+ * This message type is for client encoding of existing message formats. If
+ * possible, one of the other self-defining message types should be used
+ * instead.
+ * <p/>
+ * Although the JMS API allows the use of message properties with byte messages,
+ * they are typically not used, since the inclusion of properties may affect the
+ * format.
+ * <p/>
+ * The primitive types can be written explicitly using methods for each type.
+ * They may also be written generically as objects. For instance, a call to
+ * <CODE>BytesMessage.writeInt(6)</CODE> is equivalent to
+ * <CODE> BytesMessage.writeObject(new Integer(6))</CODE>. Both forms are
+ * provided, because the explicit form is convenient for static programming, and
+ * the object form is needed when types are not known at compile time.
+ * <p/>
+ * When the message is first created, and when <CODE>clearBody</CODE> is
+ * called, the body of the message is in write-only mode. After the first call
+ * to <CODE>reset</CODE> has been made, the message body is in read-only mode.
+ * After a message has been sent, the client that sent it can retain and modify
+ * it without affecting the message that has been sent. The same message object
+ * can be sent multiple times. When a message has been received, the provider
+ * has called <CODE>reset</CODE> so that the message body is in read-only mode
+ * for the client.
+ * <p/>
+ * If <CODE>clearBody</CODE> is called on a message in read-only mode, the
+ * message body is cleared and the message is in write-only mode.
+ * <p/>
+ * If a client attempts to read a message in write-only mode, a
+ * <CODE>MessageNotReadableException</CODE> is thrown.
+ * <p/>
+ * If a client attempts to write a message in read-only mode, a
+ * <CODE>MessageNotWriteableException</CODE> is thrown.
+ *
+ * @see javax.jms.Session#createBytesMessage()
+ * @see javax.jms.MapMessage
+ * @see javax.jms.Message
+ * @see javax.jms.ObjectMessage
+ * @see javax.jms.StreamMessage
+ * @see javax.jms.TextMessage
+ */
+public class JmsBytesMessage extends JmsMessage implements BytesMessage {
+
+    protected transient DataByteArrayOutputStream bytesOut;
+    protected transient DataInputStream dataIn;
+    protected transient int length;
+
+    private final JmsBytesMessageFacade facade;
+
+    public JmsBytesMessage(JmsBytesMessageFacade facade) {
+        super(facade);
+        this.facade = facade;
+    }
+
+    @Override
+    public JmsBytesMessage copy() throws JMSException {
+        storeContent();
+        JmsBytesMessage other = new JmsBytesMessage(facade.copy());
+        other.copy(this);
+        return other;
+    }
+
+    private void copy(JmsBytesMessage other) throws JMSException {
+        super.copy(other);
+        this.bytesOut = null;
+        this.dataIn = null;
+    }
+
+    @Override
+    public void onSend() throws JMSException {
+        this.storeContent();
+        super.onSend();
+    }
+
+    /**
+     * Clears out the message body. Clearing a message's body does not clear its
+     * header values or property entries.
+     * <p/>
+     * If this message body was read-only, calling this method leaves the
+     * message body in the same state as an empty body in a newly created
+     * message.
+     *
+     * @throws JMSException if the JMS provider fails to clear the message body
+     *                      due to some internal error.
+     */
+    @Override
+    public void clearBody() throws JMSException {
+        super.clearBody();
+        this.dataIn = null;
+        this.bytesOut = null;
+    }
+
+    /**
+     * Gets the number of bytes of the message body when the message is in
+     * read-only mode. The value returned can be used to allocate a byte array.
+     * The value returned is the entire length of the message body, regardless
+     * of where the pointer for reading the message is currently located.
+     *
+     * @return number of bytes in the message
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     * @since 1.1
+     */
+
+    @Override
+    public long getBodyLength() throws JMSException {
+        initializeReading();
+        return length;
+    }
+
+    /**
+     * Reads a <code>boolean</code> from the bytes message stream.
+     *
+     * @return the <code>boolean</code> value read
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public boolean readBoolean() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readBoolean();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a signed 8-bit value from the bytes message stream.
+     *
+     * @return the next byte from the bytes message stream as a signed 8-bit
+     *         <code>byte</code>
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public byte readByte() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readByte();
+        } catch (EOFException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.create(e);
+        }
+    }
+
+    /**
+     * Reads an unsigned 8-bit number from the bytes message stream.
+     *
+     * @return the next byte from the bytes message stream, interpreted as an
+     *         unsigned 8-bit number
+     * @throws JMSException                  if the JMS provider fails to read the message due to
+     *                                       some internal error.
+     * @throws javax.jms.MessageEOFException if unexpected end of bytes stream has been
+     *                                       reached.
+     * @throws MessageNotReadableException   if the message is in write-only mode.
+     */
+    @Override
+    public int readUnsignedByte() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readUnsignedByte();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a signed 16-bit number from the bytes message stream.
+     *
+     * @return the next two bytes from the bytes message stream, interpreted as
+     *         a signed 16-bit number
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public short readShort() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readShort();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads an unsigned 16-bit number from the bytes message stream.
+     *
+     * @return the next two bytes from the bytes message stream, interpreted as
+     *         an unsigned 16-bit integer
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public int readUnsignedShort() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readUnsignedShort();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a Unicode character value from the bytes message stream.
+     *
+     * @return the next two bytes from the bytes message stream as a Unicode
+     *         character
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public char readChar() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readChar();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a signed 32-bit integer from the bytes message stream.
+     *
+     * @return the next four bytes from the bytes message stream, interpreted as
+     *         an <code>int</code>
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public int readInt() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readInt();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a signed 64-bit integer from the bytes message stream.
+     *
+     * @return the next eight bytes from the bytes message stream, interpreted
+     *         as a <code>long</code>
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public long readLong() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readLong();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a <code>float</code> from the bytes message stream.
+     *
+     * @return the next four bytes from the bytes message stream, interpreted as
+     *         a <code>float</code>
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public float readFloat() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readFloat();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a <code>double</code> from the bytes message stream.
+     *
+     * @return the next eight bytes from the bytes message stream, interpreted
+     *         as a <code>double</code>
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public double readDouble() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readDouble();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a string that has been encoded using a modified UTF-8 format from
+     * the bytes message stream.
+     * <p/>
+     * For more information on the UTF-8 format, see "File System Safe UCS
+     * Transformation Format (FSS_UTF)", X/Open Preliminary Specification,
+     * X/Open Company Ltd., Document Number: P316. This information also appears
+     * in ISO/IEC 10646, Annex P.
+     *
+     * @return a Unicode string from the bytes message stream
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageEOFException         if unexpected end of bytes stream has been
+     *                                     reached.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public String readUTF() throws JMSException {
+        initializeReading();
+        try {
+            return this.dataIn.readUTF();
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Reads a byte array from the bytes message stream.
+     * <p/>
+     * If the length of array <code>value</code> is less than the number of
+     * bytes remaining to be read from the stream, the array should be filled. A
+     * subsequent call reads the next increment, and so on.
+     * <p/>
+     * If the number of bytes remaining in the stream is less than the length of
+     * array <code>value</code>, the bytes should be read into the array. The
+     * return value of the total number of bytes read will be less than the
+     * length of the array, indicating that there are no more bytes left to be
+     * read from the stream. The next read of the stream returns -1.
+     *
+     * @param value the buffer into which the data is read
+     * @return the total number of bytes read into the buffer, or -1 if there is
+     *         no more data because the end of the stream has been reached
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public int readBytes(byte[] value) throws JMSException {
+        return readBytes(value, value.length);
+    }
+
+    /**
+     * Reads a portion of the bytes message stream.
+     * <p/>
+     * If the length of array <code>value</code> is less than the number of
+     * bytes remaining to be read from the stream, the array should be filled. A
+     * subsequent call reads the next increment, and so on.
+     * <p/>
+     * If the number of bytes remaining in the stream is less than the length of
+     * array <code>value</code>, the bytes should be read into the array. The
+     * return value of the total number of bytes read will be less than the
+     * length of the array, indicating that there are no more bytes left to be
+     * read from the stream. The next read of the stream returns -1. <p/> If
+     * <code>length</code> is negative, or <code>length</code> is greater
+     * than the length of the array <code>value</code>, then an
+     * <code>IndexOutOfBoundsException</code> is thrown. No bytes will be read
+     * from the stream for this exception case.
+     *
+     * @param value  the buffer into which the data is read
+     * @param length the number of bytes to read; must be less than or equal to
+     *               <code>value.length</code>
+     * @return the total number of bytes read into the buffer, or -1 if there is
+     *         no more data because the end of the stream has been reached
+     * @throws JMSException                if the JMS provider fails to read the message due to
+     *                                     some internal error.
+     * @throws MessageNotReadableException if the message is in write-only mode.
+     */
+    @Override
+    public int readBytes(byte[] value, int length) throws JMSException {
+        initializeReading();
+
+        if (length < 0 || value.length < length) {
+            throw new IndexOutOfBoundsException(
+                "length must not be negative or larger than the size of the provided array");
+        }
+
+        try {
+            int n = 0;
+            while (n < length) {
+                int count = this.dataIn.read(value, n, length - n);
+                if (count < 0) {
+                    break;
+                }
+                n += count;
+            }
+            if (n == 0 && length > 0) {
+                n = -1;
+            }
+            return n;
+        } catch (ArrayIndexOutOfBoundsException e) {
+            throw JmsExceptionSupport.createMessageEOFException(e);
+        } catch (Throwable e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a <code>boolean</code> to the bytes message stream as a 1-byte
+     * value. The value <code>true</code> is written as the value
+     * <code>(byte)1</code>; the value <code>false</code> is written as the
+     * value <code>(byte)0</code>.
+     *
+     * @param value the <code>boolean</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeBoolean(boolean value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeBoolean(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a <code>byte</code> to the bytes message stream as a 1-byte
+     * value.
+     *
+     * @param value the <code>byte</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeByte(byte value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeByte(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a <code>short</code> to the bytes message stream as two bytes,
+     * high byte first.
+     *
+     * @param value the <code>short</code> to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeShort(short value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeShort(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a <code>char</code> to the bytes message stream as a 2-byte
+     * value, high byte first.
+     *
+     * @param value the <code>char</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeChar(char value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeChar(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes an <code>int</code> to the bytes message stream as four bytes,
+     * high byte first.
+     *
+     * @param value the <code>int</code> to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeInt(int value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeInt(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a <code>long</code> to the bytes message stream as eight bytes,
+     * high byte first.
+     *
+     * @param value the <code>long</code> to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeLong(long value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeLong(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Converts the <code>float</code> argument to an <code>int</code> using
+     * the <code>floatToIntBits</code> method in class <code>Float</code>,
+     * and then writes that <code>int</code> value to the bytes message stream
+     * as a 4-byte quantity, high byte first.
+     *
+     * @param value the <code>float</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeFloat(float value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeFloat(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Converts the <code>double</code> argument to a <code>long</code>
+     * using the <code>doubleToLongBits</code> method in class
+     * <code>Double</code>, and then writes that <code>long</code> value to
+     * the bytes message stream as an 8-byte quantity, high byte first.
+     *
+     * @param value the <code>double</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeDouble(double value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeDouble(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a string to the bytes message stream using UTF-8 encoding in a
+     * machine-independent manner.
+     * <p/>
+     * For more information on the UTF-8 format, see "File System Safe UCS
+     * Transformation Format (FSS_UTF)", X/Open Preliminary Specification,
+     * X/Open Company Ltd., Document Number: P316. This information also appears
+     * in ISO/IEC 10646, Annex P.
+     *
+     * @param value the <code>String</code> value to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeUTF(String value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.writeUTF(value);
+        } catch (IOException ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+
+    /**
+     * Writes a byte array to the bytes message stream.
+     *
+     * @param value the byte array to be written
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeBytes(byte[] value) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.write(value);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes a portion of a byte array to the bytes message stream.
+     *
+     * @param value  the byte array value to be written
+     * @param offset the initial offset within the byte array
+     * @param length the number of bytes to use
+     * @throws JMSException                 if the JMS provider fails to write the message due
+     *                                      to some internal error.
+     * @throws MessageNotWriteableException if the message is in read-only mode.
+     */
+    @Override
+    public void writeBytes(byte[] value, int offset, int length) throws JMSException {
+        initializeWriting();
+        try {
+            this.bytesOut.write(value, offset, length);
+        } catch (IOException e) {
+            throw JmsExceptionSupport.createMessageFormatException(e);
+        }
+    }
+
+    /**
+     * Writes an object to the bytes message stream.
+     * <p/>
+     * This method works only for the objectified primitive object types (<code>Integer</code>,<code>Double</code>,
+     * <code>Long</code> &nbsp;...), <code>String</code> objects, and byte
+     * arrays.
+     *
+     * @param value the object in the Java programming language ("Java object")
+     *              to be written; it must not be null
+     * @throws JMSException                   if the JMS provider fails to write the message due
+     *                                        to some internal error.
+     * @throws MessageFormatException         if the object is of an invalid type.
+     * @throws MessageNotWriteableException   if the message is in read-only mode.
+     * @throws java.lang.NullPointerException if the parameter
+     *                                        <code>value</code> is null.
+     */
+    @Override
+    public void writeObject(Object value) throws JMSException {
+        if (value == null) {
+            throw new NullPointerException();
+        }
+        initializeWriting();
+        if (value instanceof Boolean) {
+            writeBoolean(((Boolean) value).booleanValue());
+        } else if (value instanceof Character) {
+            writeChar(((Character) value).charValue());
+        } else if (value instanceof Byte) {
+            writeByte(((Byte) value).byteValue());
+        } else if (value instanceof Short) {
+            writeShort(((Short) value).shortValue());
+        } else if (value instanceof Integer) {
+            writeInt(((Integer) value).intValue());
+        } else if (value instanceof Long) {
+            writeLong(((Long) value).longValue());
+        } else if (value instanceof Float) {
+            writeFloat(((Float) value).floatValue());
+        } else if (value instanceof Double) {
+            writeDouble(((Double) value).doubleValue());
+        } else if (value instanceof String) {
+            writeUTF(value.toString());
+        } else if (value instanceof byte[]) {
+            writeBytes((byte[]) value);
+        } else {
+            throw new MessageFormatException("Cannot write non-primitive type:" + value.getClass());
+        }
+    }
+
+    /**
+     * Puts the message body in read-only mode and repositions the stream of
+     * bytes to the beginning.
+     *
+     * @throws JMSException if an internal error occurs
+     */
+    @Override
+    public void reset() throws JMSException {
+        storeContent();
+        this.bytesOut = null;
+        this.dataIn = null;
+        setReadOnlyBody(true);
+    }
+
+    @Override
+    public void setObjectProperty(String name, Object value) throws JMSException {
+        initializeWriting();
+        super.setObjectProperty(name, value);
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " JmsBytesMessage{ " + "bytesOut = " + bytesOut + ", dataIn = " + dataIn + " }";
+    }
+
+    /**
+     * Direct view of the underlying message contents.
+     *
+     * @return a Buffer holding the bytes contained in this message.
+     */
+    public Buffer getContent() {
+        return this.facade.getContent();
+    }
+
+    /**
+     * A direct write method to the underlying message content buffer.
+     *
+     * @param content
+     *        the new content to assign to this message.
+     */
+    public void setContent(Buffer content) {
+        this.facade.setContent(content);
+    }
+
+    private void initializeWriting() throws JMSException {
+        checkReadOnlyBody();
+        if (this.bytesOut == null) {
+            this.bytesOut = new DataByteArrayOutputStream();
+        }
+    }
+
+    private void initializeReading() throws JMSException {
+        checkWriteOnlyBody();
+        if (dataIn == null) {
+            Buffer buffer = facade.getContent();
+            if (buffer == null) {
+                buffer = new Buffer(0);
+            }
+            dataIn = new DataInputStream(new ByteArrayInputStream(buffer));
+            this.length = buffer.getLength();
+        }
+    }
+
+    private void storeContent() throws JMSException {
+        try {
+            if (bytesOut != null) {
+                bytesOut.close();
+                Buffer bs = bytesOut.toBuffer();
+                facade.setContent(bs);
+                bytesOut = null;
+            }
+        } catch (IOException ioe) {
+            throw JmsExceptionSupport.create(ioe);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsDefaultMessageFactory.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsDefaultMessageFactory.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsDefaultMessageFactory.java
new file mode 100644
index 0000000..c909f2d
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsDefaultMessageFactory.java
@@ -0,0 +1,94 @@
+/**
+ * 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.jms.message;
+
+import java.io.Serializable;
+
+import javax.jms.JMSException;
+
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultBytesMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultMapMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultObjectMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultStreamMessageFacade;
+import org.apache.qpid.jms.message.facade.defaults.JmsDefaultTextMessageFacade;
+
+/**
+ * Default implementation of the ProviderMessageFactory that create simple
+ * generic javax.jms.Message types that can be sent to any Provider instance.
+ *
+ * TODO: Once the AMQP Message Facade stuff is done we should move this factory
+ *       and the default JmsMessageFacade implementations into the test package
+ *       since their primary use will be to test the JMS spec compliance of the
+ *       JmsMessage classes.
+ */
+public class JmsDefaultMessageFactory implements JmsMessageFactory {
+
+    @Override
+    public JmsMessage createMessage() throws UnsupportedOperationException {
+        return new JmsMessage(new JmsDefaultMessageFacade());
+    }
+
+    @Override
+    public JmsTextMessage createTextMessage() throws UnsupportedOperationException {
+        return createTextMessage(null);
+    }
+
+    @Override
+    public JmsTextMessage createTextMessage(String payload) throws UnsupportedOperationException {
+        JmsTextMessage result = new JmsTextMessage(new JmsDefaultTextMessageFacade());
+        if (payload != null) {
+            try {
+                result.setText(payload);
+            } catch (JMSException e) {
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public JmsBytesMessage createBytesMessage() throws UnsupportedOperationException {
+        return new JmsBytesMessage(new JmsDefaultBytesMessageFacade());
+    }
+
+    @Override
+    public JmsMapMessage createMapMessage() throws UnsupportedOperationException {
+        return new JmsMapMessage(new JmsDefaultMapMessageFacade());
+    }
+
+    @Override
+    public JmsStreamMessage createStreamMessage() throws UnsupportedOperationException {
+        return new JmsStreamMessage(new JmsDefaultStreamMessageFacade());
+    }
+
+    @Override
+    public JmsObjectMessage createObjectMessage() throws UnsupportedOperationException {
+        return createObjectMessage(null);
+    }
+
+    @Override
+    public JmsObjectMessage createObjectMessage(Serializable payload) throws UnsupportedOperationException {
+        JmsObjectMessage result = new JmsObjectMessage(new JmsDefaultObjectMessageFacade());
+        if (payload != null) {
+            try {
+                result.setObject(payload);
+            } catch (Exception e) {
+            }
+        }
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsInboundMessageDispatch.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsInboundMessageDispatch.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsInboundMessageDispatch.java
new file mode 100644
index 0000000..e651060
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsInboundMessageDispatch.java
@@ -0,0 +1,57 @@
+/**
+ * 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.jms.message;
+
+import org.apache.qpid.jms.meta.JmsConsumerId;
+
+/**
+ * Envelope used to deliver incoming messages to their targeted consumer.
+ */
+public class JmsInboundMessageDispatch {
+
+    private JmsConsumerId consumerId;
+    private JmsMessage message;
+    private Object providerHint;
+
+    public JmsMessage getMessage() {
+        return message;
+    }
+
+    public void setMessage(JmsMessage message) {
+        this.message = message;
+    }
+
+    public JmsConsumerId getConsumerId() {
+        return consumerId;
+    }
+
+    public void setConsumerId(JmsConsumerId consumerId) {
+        this.consumerId = consumerId;
+    }
+
+    public Object getProviderHint() {
+        return this.providerHint;
+    }
+
+    public void setProviderHint(Object hint) {
+        this.providerHint = hint;
+    }
+
+    public void onMessageRedelivered() {
+        this.message.incrementRedeliveryCount();
+    }
+}

http://git-wip-us.apache.org/repos/asf/qpid-jms/blob/e4decdc1/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMapMessage.java
----------------------------------------------------------------------
diff --git a/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMapMessage.java b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMapMessage.java
new file mode 100644
index 0000000..9414eca
--- /dev/null
+++ b/qpid-jms-client/src/main/java/org/apache/qpid/jms/message/JmsMapMessage.java
@@ -0,0 +1,320 @@
+/**
+ * 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.jms.message;
+
+import java.util.Enumeration;
+
+import javax.jms.JMSException;
+import javax.jms.MapMessage;
+import javax.jms.MessageFormatException;
+
+import org.apache.qpid.jms.message.facade.JmsMapMessageFacade;
+
+/**
+ * Implementation of the JMS MapMessage.
+ */
+public class JmsMapMessage extends JmsMessage implements MapMessage {
+
+    JmsMapMessageFacade facade;
+
+    public JmsMapMessage(JmsMapMessageFacade facade) {
+        super(facade);
+        this.facade = facade;
+    }
+
+    @Override
+    public JmsMapMessage copy() throws JMSException {
+        JmsMapMessage other = new JmsMapMessage(facade.copy());
+        other.copy(this);
+        return other;
+    }
+
+    @Override
+    public void clearBody() throws JMSException {
+        super.clearBody();
+        facade.clearBody();
+    }
+
+    @Override
+    public boolean getBoolean(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Boolean) {
+            return ((Boolean) value).booleanValue();
+        } else if (value instanceof String || value == null) {
+            return Boolean.valueOf((String) value).booleanValue();
+        } else {
+            throw new MessageFormatException("Cannot read a boolean from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public byte getByte(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Byte) {
+            return ((Byte) value).byteValue();
+        } else if (value instanceof String || value == null) {
+            return Byte.valueOf((String) value).byteValue();
+        } else {
+            throw new MessageFormatException("Cannot read a byte from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public short getShort(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Short) {
+            return ((Short) value).shortValue();
+        } else if (value instanceof Byte) {
+            return ((Byte) value).shortValue();
+        } else if (value instanceof String || value == null) {
+            return Short.valueOf((String) value).shortValue();
+        } else {
+            throw new MessageFormatException("Cannot read a short from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public char getChar(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value == null) {
+            throw new NullPointerException();
+        } else if (value instanceof Character) {
+            return ((Character) value).charValue();
+        } else {
+            throw new MessageFormatException("Cannot read a short from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public int getInt(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Integer) {
+            return ((Integer) value).intValue();
+        } else if (value instanceof Short) {
+            return ((Short) value).intValue();
+        } else if (value instanceof Byte) {
+            return ((Byte) value).intValue();
+        } else if (value instanceof String || value == null) {
+            return Integer.valueOf((String) value).intValue();
+        } else {
+            throw new MessageFormatException("Cannot read an int from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public long getLong(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Long) {
+            return ((Long) value).longValue();
+        } else if (value instanceof Integer) {
+            return ((Integer) value).longValue();
+        } else if (value instanceof Short) {
+            return ((Short) value).longValue();
+        } else if (value instanceof Byte) {
+            return ((Byte) value).longValue();
+        } else if (value instanceof String || value == null) {
+            return Long.valueOf((String) value).longValue();
+        } else {
+            throw new MessageFormatException("Cannot read a long from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public float getFloat(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Float) {
+            return ((Float) value).floatValue();
+        } else if (value instanceof String || value == null) {
+            return Float.valueOf((String) value).floatValue();
+        } else {
+            throw new MessageFormatException("Cannot read a float from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public double getDouble(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value instanceof Double) {
+            return ((Double) value).doubleValue();
+        } else if (value instanceof Float) {
+            return ((Float) value).floatValue();
+        } else if (value instanceof String || value == null) {
+            return Double.valueOf((String) value).doubleValue();
+        } else {
+            throw new MessageFormatException("Cannot read a double from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public String getString(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value == null) {
+            return null;
+        } else if (value instanceof byte[]) {
+            throw new MessageFormatException("Use getBytes to read a byte array");
+        } else {
+            return value.toString();
+        }
+    }
+
+    @Override
+    public byte[] getBytes(String name) throws JMSException {
+        Object value = getObject(name);
+
+        if (value == null) {
+            return (byte[]) value;
+        } else if (value instanceof byte[]) {
+            byte[] original = (byte[]) value;
+            byte[] clone = new byte[original.length];
+            System.arraycopy(original, 0, clone, 0, original.length);
+            return clone;
+        } else {
+            throw new MessageFormatException("Cannot read a byte[] from " + value.getClass().getSimpleName());
+        }
+    }
+
+    @Override
+    public Object getObject(String name) throws JMSException {
+        checkKeyNameIsValid(name);
+        return facade.get(name);
+    }
+
+    @Override
+    public Enumeration<String> getMapNames() throws JMSException {
+        return facade.getMapNames();
+    }
+
+    @Override
+    public void setBoolean(String name, boolean value) throws JMSException {
+        put(name, value ? Boolean.TRUE : Boolean.FALSE);
+    }
+
+    @Override
+    public void setByte(String name, byte value) throws JMSException {
+        put(name, Byte.valueOf(value));
+    }
+
+    @Override
+    public void setShort(String name, short value) throws JMSException {
+        put(name, Short.valueOf(value));
+    }
+
+    @Override
+    public void setChar(String name, char value) throws JMSException {
+        put(name, Character.valueOf(value));
+    }
+
+    @Override
+    public void setInt(String name, int value) throws JMSException {
+        put(name, Integer.valueOf(value));
+    }
+
+    @Override
+    public void setLong(String name, long value) throws JMSException {
+        put(name, Long.valueOf(value));
+    }
+
+    @Override
+    public void setFloat(String name, float value) throws JMSException {
+        checkReadOnlyBody();
+        put(name, new Float(value));
+    }
+
+    @Override
+    public void setDouble(String name, double value) throws JMSException {
+        put(name, new Double(value));
+    }
+
+    @Override
+    public void setString(String name, String value) throws JMSException {
+        put(name, value);
+    }
+
+    @Override
+    public void setBytes(String name, byte[] value) throws JMSException {
+        setBytes(name, value, 0, (value != null ? value.length : 0));
+    }
+
+    @Override
+    public void setBytes(String name, byte[] value, int offset, int length) throws JMSException {
+        // Fail early to avoid unnecessary array copy.
+        checkReadOnlyBody();
+        checkKeyNameIsValid(name);
+
+        byte[] clone = null;
+        if (value != null) {
+            clone = new byte[length];
+            System.arraycopy(value, offset, clone, 0, length);
+        }
+
+        put(name, clone);
+    }
+
+    @Override
+    public void setObject(String name, Object value) throws JMSException {
+        // byte[] not allowed on properties so cover that here.
+        if (!(value instanceof byte[])) {
+            checkValidObject(value);
+        }
+
+        put(name, value);
+    }
+
+    /**
+     * Indicates whether an item exists in this <CODE>MapMessage</CODE> object.
+     *
+     * @param name
+     *        the name of the item to test
+     * @return true if the item exists
+     * @throws JMSException
+     *         if the JMS provider fails to determine if the item exists due to
+     *         some internal error.
+     */
+    @Override
+    public boolean itemExists(String name) throws JMSException {
+        return facade.itemExists(name);
+    }
+
+    @Override
+    public String toString() {
+        // TODO - better toString implementation.
+        return "JmsMapMessage{ }";
+    }
+
+    private void put(String name, Object value) throws JMSException {
+        checkReadOnlyBody();
+        checkKeyNameIsValid(name);
+        facade.put(name, value);
+    }
+
+    private void checkKeyNameIsValid(String name) throws IllegalArgumentException {
+        if (name == null) {
+            throw new IllegalArgumentException("Map key name must not be null");
+        } else if (name.length() == 0) {
+            throw new IllegalArgumentException("Map key name must not be the empty string");
+        }
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org