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> ...), <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