blob: fbc5fa5e6c8ab55216ab7e34d318fe4e2e9d2961 [file] [log] [blame]
/**
* 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.activemq.openwire.commands;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectStreamException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import org.apache.activemq.openwire.annotations.OpenWireExtension;
import org.apache.activemq.openwire.annotations.OpenWireType;
import org.apache.activemq.openwire.codec.OpenWireFormat;
import org.apache.activemq.openwire.utils.IOExceptionSupport;
import org.apache.activemq.openwire.utils.OpenWireMarshallingSupport;
import org.fusesource.hawtbuf.Buffer;
import org.fusesource.hawtbuf.ByteArrayInputStream;
import org.fusesource.hawtbuf.ByteArrayOutputStream;
import org.fusesource.hawtbuf.UTF8Buffer;
/**
* openwire:marshaller code="25"
*/
@OpenWireType(typeCode = 25)
public class OpenWireMapMessage extends OpenWireMessage {
public static final byte DATA_STRUCTURE_TYPE = CommandTypes.OPENWIRE_MAP_MESSAGE;
@OpenWireExtension
protected transient Map<String, Object> map = new HashMap<String, Object>();
private Object readResolve() throws ObjectStreamException {
if (this.map == null) {
this.map = new HashMap<String, Object>();
}
return this;
}
@Override
public OpenWireMapMessage copy() {
OpenWireMapMessage copy = new OpenWireMapMessage();
copy(copy);
return copy;
}
private void copy(OpenWireMapMessage copy) {
storeContent();
super.copy(copy);
}
// We only need to marshal the content if we are hitting the wire.
@Override
public void beforeMarshall(OpenWireFormat wireFormat) throws IOException {
super.beforeMarshall(wireFormat);
storeContent();
}
@Override
public void clearMarshalledState() throws IOException {
super.clearMarshalledState();
map.clear();
}
@Override
public void storeContentAndClear() {
storeContent();
map.clear();
}
@Override
public void storeContent() {
try {
if (getContent() == null && !map.isEmpty()) {
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
OutputStream os = bytesOut;
if (isUseCompression()) {
compressed = true;
os = new DeflaterOutputStream(os);
}
DataOutputStream dataOut = new DataOutputStream(os);
OpenWireMarshallingSupport.marshalPrimitiveMap(map, dataOut);
dataOut.close();
setContent(bytesOut.toBuffer());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Builds the message body from data
*
* @throws IOException
*/
private void loadContent() throws IOException {
try {
if (getContent() != null && map.isEmpty()) {
Buffer content = getContent();
InputStream is = new ByteArrayInputStream(content);
if (isCompressed()) {
is = new InflaterInputStream(is);
}
DataInputStream dataIn = new DataInputStream(is);
map = OpenWireMarshallingSupport.unmarshalPrimitiveMap(dataIn);
dataIn.close();
}
} catch (Exception e) {
throw IOExceptionSupport.create(e);
}
}
@Override
public byte getDataStructureType() {
return DATA_STRUCTURE_TYPE;
}
@Override
public String getMimeType() {
return "jms/map-message";
}
/**
* 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.
*/
@Override
public void clearBody() throws IOException {
super.clearBody();
map.clear();
}
/**
* Returns the value of the object with the specified name.
* <P>
* This method can be used to return, in objectified format, an object in
* the Java programming language ("Java object") that had been stored in the
* Map with the equivalent <CODE>setObject</CODE> method call, or its
* equivalent primitive <CODE>set <I>type </I></CODE> method.
* <P>
* Note that byte values are returned as <CODE>byte[]</CODE>, not
* <CODE>Byte[]</CODE>.
*
* @param name
* the name of the Java object
*
* @return a copy of the Java object value with the specified name, in
* objectified format (for example, if the object was set as an
* <CODE>int</CODE>, an <CODE>Integer</CODE> is returned); if
* there is no item by this name, a null value is returned
* @throws JMSException if the JMS provider fails to read the message due to
* some internal error.
*/
public Object getObject(String name) throws IOException {
initializeReading();
Object result = getContentMap().get(name);
if (result instanceof UTF8Buffer) {
result = result.toString();
}
return result;
}
/**
* Sets an object value with the specified name into the Map.
* <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 name
* the name of the Java object
* @param value
* the Java object value to set in the Map
* @throws JMSException if the JMS provider fails to write the message due
* to some internal error.
* @throws IllegalArgumentException if the name is null or if the name is an
* empty string.
* @throws MessageFormatException if the object is invalid.
*/
public void setObject(String name, Object value) throws IOException {
initializeWriting();
if (value != null) {
// byte[] not allowed on properties
if (!(value instanceof byte[])) {
checkValidObject(value);
}
put(name, value);
} else {
put(name, null);
}
}
/**
* Removes an object value with the specified name into the Map.
*
* @param name
* the name of the Java object
*
* @throws JMSException if the JMS provider fails to write the message due
* to some internal error.
* @throws IllegalArgumentException if the name is null or if the name is an
* empty string.
*/
public void removeObject(String name) throws IOException {
initializeWriting();
if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("map element name cannot be null or empty.");
}
this.map.remove(name);
}
/**
* Returns an <CODE>Enumeration</CODE> of all the names in the
* <CODE>MapMessage</CODE> object.
*
* @return an enumeration of all the names in this <CODE>MapMessage</CODE>
* @throws JMSException
*/
public Enumeration<String> getMapNames() throws IOException {
return Collections.enumeration(getContentMap().keySet());
}
/**
* 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.
*/
public boolean itemExists(String name) throws IOException {
return getContentMap().containsKey(name);
}
private void initializeReading() throws IOException {
loadContent();
}
private void initializeWriting() throws IOException {
setContent(null);
}
@Override
public void compress() throws IOException {
storeContent();
super.compress();
}
@Override
public String toString() {
return super.toString() + " OpenWireMapMessage{ " + "theTable = " + map + " }";
}
protected Map<String, Object> getContentMap() throws IOException {
initializeReading();
return map;
}
protected void put(String name, Object value) throws IOException {
if (name == null) {
throw new IllegalArgumentException("The name of the property cannot be null.");
}
if (name.length() == 0) {
throw new IllegalArgumentException("The name of the property cannot be an emprty string.");
}
map.put(name, value);
}
}