All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.oss.pulsar.jms.messages.PulsarMapMessage Maven / Gradle / Ivy

There is a newer version: 7.0.2
Show newest version
/*
 * Copyright DataStax, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.datastax.oss.pulsar.jms.messages;

import com.datastax.oss.pulsar.jms.PulsarMessage;
import com.datastax.oss.pulsar.jms.Utils;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.jms.JMSException;
import jakarta.jms.MapMessage;
import jakarta.jms.MessageFormatException;
import jakarta.jms.MessageNotWriteableException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import org.apache.pulsar.client.api.TypedMessageBuilder;

@SuppressFBWarnings({"EI_EXPOSE_REP2", "EI_EXPOSE_REP"})
public final class PulsarMapMessage extends PulsarMessage implements MapMessage {

  private final Map map = new HashMap<>();

  public PulsarMapMessage() {
    writable = true;
  }

  public PulsarMapMessage(Map body) throws MessageFormatException {
    this(body, true);
  }

  public PulsarMapMessage(Map body, boolean validate)
      throws MessageFormatException {
    this();
    if (body != null) {
      map.putAll(body);
      if (validate) {
        for (Object value : body.values()) {
          validateWritableObject(value);
        }
      }
    }
  }

  @Override
  protected String messageType() {
    return "map";
  }

  public PulsarMapMessage(byte[] payload) throws JMSException {
    writable = false;
    if (payload != null) {
      try {
        ByteArrayInputStream in = new ByteArrayInputStream(payload);
        ObjectInputStream input = new ObjectInputStream(in);
        int size = input.readInt();
        for (int i = 0; i < size; i++) {
          String key = input.readUTF();
          Object value = input.readUnshared();
          map.put(key, value);
        }
      } catch (Exception err) {
        throw handleExceptionAccordingToMessageSpecs(err);
      }
    }
  }

  @Override
  public void clearBody() throws JMSException {
    writable = true;
    map.clear();
  }

  @Override
  public  T getBody(Class c) throws JMSException {
    if (c == Map.class) {
      return (T) map;
    }
    throw new MessageFormatException("only java.util.Map is supported");
  }

  @Override
  public boolean isBodyAssignableTo(Class c) throws JMSException {
    return c == Map.class;
  }

  @Override
  protected void prepareForSend(TypedMessageBuilder producer) throws JMSException {
    if (map.isEmpty()) {
      producer.value(null);
      return;
    }
    try {
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      ObjectOutputStream oo = new ObjectOutputStream(out);
      oo.writeInt(map.size());
      for (Map.Entry entry : map.entrySet()) {
        oo.writeUTF(entry.getKey()); // already not null and not empty
        oo.writeUnshared(entry.getValue());
      }
      oo.flush();
      oo.close();
      producer.value(out.toByteArray());
    } catch (Exception err) {
      throw handleExceptionAccordingToMessageSpecs(err);
    }
  }

  /**
   * Returns the {@code boolean} value with the specified name.
   *
   * @param name the name of the {@code boolean}
   * @return the {@code boolean} value with the specified name
   * @throws JMSException if the JMS provider fails to read the message due to some internal error.
   * @throws MessageFormatException if this type conversion is invalid.
   */
  @Override
  public boolean getBoolean(String name) throws JMSException {
    Object value = map.get(name);
    if (value == null) {
      throw new NullPointerException("Invalid null value (" + map + ")");
    }
    if (value instanceof Boolean) {
      return (Boolean) value;
    }
    allowOnlyStrings(value);
    try {
      return Boolean.parseBoolean(value.toString());
    } catch (Exception err) {
      throw handleExceptionAccordingToMessageSpecs(err);
    }
  }

  /**
   * Returns the {@code byte} value with the specified name.
   *
   * @param name the name of the {@code byte}
   * @return the {@code byte} value with the specified name
   * @throws JMSException if the JMS provider fails to read the message due to some internal error.
   * @throws MessageFormatException if this type conversion is invalid.
   */
  @Override
  public byte getByte(String name) throws JMSException {
    Object value = map.get(name);
    if (value == null) {
      throw new NullPointerException("Invalid null value");
    }
    if (value instanceof Byte) {
      return (Byte) value;
    }
    allowOnlyStrings(value);
    try {
      return Byte.parseByte(value.toString());
    } catch (Exception err) {
      throw handleExceptionAccordingToMessageSpecs(err);
    }
  }

  /**
   * Returns the {@code short} value with the specified name.
   *
   * @param name the name of the {@code short}
   * @return the {@code short} value with the specified name
   * @throws JMSException if the JMS provider fails to read the message due to some internal error.
   * @throws MessageFormatException if this type conversion is invalid.
   */
  @Override
  public short getShort(String name) throws JMSException {
    Object value = map.get(name);
    if (value == null) {
      throw new NullPointerException("Invalid null value");
    }
    if ((value instanceof Byte) || (value instanceof Short)) {
      return ((Number) value).shortValue();
    }
    allowOnlyStrings(value);
    try {
      return Short.parseShort(value.toString());
    } catch (Exception err) {
      throw handleExceptionAccordingToMessageSpecs(err);
    }
  }

  /**
   * Returns the Unicode character value with the specified name.
   *
   * @param name the name of the Unicode character
   * @return the Unicode character value with the specified name
   * @throws JMSException if the JMS provider fails to read the message due to some internal error.
   * @throws MessageFormatException if this type conversion is invalid.
   */
  @Override
  public char getChar(String name) throws JMSException {
    return Utils.invoke(() -> (Character) map.get(name));
  }

  /**
   * Returns the {@code int} value with the specified name.
   *
   * @param name the name of the {@code int}
   * @return the {@code int} value with the specified name
   * @throws JMSException if the JMS provider fails to read the message due to some internal error.
   * @throws MessageFormatException if this type conversion is invalid.
   */
  @Override
  public int getInt(String name) throws JMSException {
    Object value = map.get(name);
    if (value == null) {
      throw new NullPointerException("Invalid null value");
    }
    if ((value instanceof Integer) || (value instanceof Short) || (value instanceof Byte)) {
      return ((Number) value).intValue();
    }
    allowOnlyStrings(value);
    try {
      return Integer.parseInt(value.toString());
    } catch (Exception err) {
      throw handleExceptionAccordingToMessageSpecs(err);
    }
  }

  /**
   * Returns the {@code long} value with the specified name.
   *
   * @param name the name of the {@code long}
   * @return the {@code long} value with the specified name
   * @throws JMSException if the JMS provider fails to read the message due to some internal error.
   * @throws MessageFormatException if this type conversion is invalid.
   */
  @Override
  public long getLong(String name) throws JMSException {
    Object value = map.get(name);
    if (value == null) {
      throw new NullPointerException("Invalid null value");
    }
    if ((value instanceof Integer)
        || (value instanceof Short)
        || (value instanceof Byte)
        || (value instanceof Long)) {
      return ((Number) value).longValue();
    }
    allowOnlyStrings(value);
    try {
      return Long.parseLong(value.toString());
    } catch (Exception err) {
      throw handleExceptionAccordingToMessageSpecs(err);
    }
  }

  /**
   * Returns the {@code float} value with the specified name.
   *
   * @param name the name of the {@code float}
   * @return the {@code float} value with the specified name
   * @throws JMSException if the JMS provider fails to read the message due to some internal error.
   * @throws MessageFormatException if this type conversion is invalid.
   */
  @Override
  public float getFloat(String name) throws JMSException {
    Object value = map.get(name);
    if (value == null) {
      throw new NullPointerException("Invalid null value");
    }
    if (value instanceof Float) {
      return (Float) value;
    }
    allowOnlyStrings(value);
    try {
      return Float.parseFloat(value.toString());
    } catch (Exception err) {
      throw handleExceptionAccordingToMessageSpecs(err);
    }
  }

  /**
   * Returns the {@code double} value with the specified name.
   *
   * @param name the name of the {@code double}
   * @return the {@code double} value with the specified name
   * @throws JMSException if the JMS provider fails to read the message due to some internal error.
   * @throws MessageFormatException if this type conversion is invalid.
   */
  @Override
  public double getDouble(String name) throws JMSException {
    Object value = map.get(name);
    if (value == null) {
      throw new NullPointerException("Invalid null value");
    }
    if ((value instanceof Double) || (value instanceof Float)) {
      return ((Number) value).doubleValue();
    }
    allowOnlyStrings(value);
    try {
      return Double.parseDouble(value.toString());
    } catch (Exception err) {
      throw handleExceptionAccordingToMessageSpecs(err);
    }
  }

  private void allowOnlyStrings(Object value) throws MessageFormatException {
    if (!(value instanceof String)) {
      throw new MessageFormatException("Invalid conversion");
    }
  }

  /**
   * Returns the {@code String} value with the specified name.
   *
   * @param name the name of the {@code String}
   * @return the {@code String} value with the specified name; 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.
   * @throws MessageFormatException if this type conversion is invalid.
   */
  @Override
  public String getString(String name) throws JMSException {
    Object value = map.get(name);
    if (value == null) {
      return null;
    }
    if (value instanceof String) {
      return (String) value;
    }
    if ((value instanceof Number) || (value instanceof Boolean) || (value instanceof Character)) {
      return value.toString();
    }
    throw new MessageFormatException("Unsupported conversion");
  }

  /**
   * Returns the byte array value with the specified name.
   *
   * @param name the name of the byte array
   * @return a copy of the byte array value with the specified name; 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.
   * @throws MessageFormatException if this type conversion is invalid.
   */
  @Override
  public byte[] getBytes(String name) throws JMSException {
    return Utils.invoke(() -> (byte[]) map.get(name));
  }

  /**
   * Returns the value of the object with the specified name.
   *
   * 

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} * method call, or its equivalent primitive settype method. * *

Note that byte values are returned as {@code byte[]}, not {@code Byte[]}. * * @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}, an {@code Integer} 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. */ @Override public Object getObject(String name) throws JMSException { return Utils.invoke(() -> map.get(name)); } /** * Returns an {@code Enumeration} of all the names in the {@code MapMessage} object. * * @return an enumeration of all the names in this {@code MapMessage} * @throws JMSException if the JMS provider fails to read the message due to some internal error. */ @Override public Enumeration getMapNames() throws JMSException { return Collections.enumeration(map.keySet()); } /** * Sets a {@code boolean} value with the specified name into the Map. * * @param name the name of the {@code boolean} * @param value the {@code boolean} 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 MessageNotWriteableException if the message is in read-only mode. */ @Override public void setBoolean(String name, boolean value) throws JMSException { checkWritableProperty(name); map.put(name, value); } /** * Sets a {@code byte} value with the specified name into the Map. * * @param name the name of the {@code byte} * @param value the {@code byte} 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 MessageNotWriteableException if the message is in read-only mode. */ @Override public void setByte(String name, byte value) throws JMSException { checkWritableProperty(name); map.put(name, value); } /** * Sets a {@code short} value with the specified name into the Map. * * @param name the name of the {@code short} * @param value the {@code short} 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 MessageNotWriteableException if the message is in read-only mode. */ @Override public void setShort(String name, short value) throws JMSException { checkWritableProperty(name); map.put(name, value); } /** * Sets a Unicode character value with the specified name into the Map. * * @param name the name of the Unicode character * @param value the Unicode character 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 MessageNotWriteableException if the message is in read-only mode. */ @Override public void setChar(String name, char value) throws JMSException { checkWritableProperty(name); map.put(name, value); } /** * Sets an {@code int} value with the specified name into the Map. * * @param name the name of the {@code int} * @param value the {@code int} 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 MessageNotWriteableException if the message is in read-only mode. */ @Override public void setInt(String name, int value) throws JMSException { checkWritableProperty(name); map.put(name, value); } /** * Sets a {@code long} value with the specified name into the Map. * * @param name the name of the {@code long} * @param value the {@code long} 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 MessageNotWriteableException if the message is in read-only mode. */ @Override public void setLong(String name, long value) throws JMSException { checkWritableProperty(name); map.put(name, value); } /** * Sets a {@code float} value with the specified name into the Map. * * @param name the name of the {@code float} * @param value the {@code float} 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 MessageNotWriteableException if the message is in read-only mode. */ @Override public void setFloat(String name, float value) throws JMSException { checkWritableProperty(name); map.put(name, value); } /** * Sets a {@code double} value with the specified name into the Map. * * @param name the name of the {@code double} * @param value the {@code double} 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 MessageNotWriteableException if the message is in read-only mode. */ @Override public void setDouble(String name, double value) throws JMSException { checkWritableProperty(name); map.put(name, value); } /** * Sets a {@code String} value with the specified name into the Map. * * @param name the name of the {@code String} * @param value the {@code String} 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 MessageNotWriteableException if the message is in read-only mode. */ @Override public void setString(String name, String value) throws JMSException { checkWritableProperty(name); map.put(name, value); } /** * Sets a byte array value with the specified name into the Map. * * @param name the name of the byte array * @param value the byte array value to set in the Map; the array is copied so that the value for * {@code name} will not be altered by future modifications * @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 MessageNotWriteableException if the message is in read-only mode. */ @Override public void setBytes(String name, byte[] value) throws JMSException { checkWritableProperty(name); map.put(name, value); } /** * Sets a portion of the byte array value with the specified name into the Map. * * @param name the name of the byte array * @param value the byte array value to set in the Map * @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 IllegalArgumentException if the name is null or if the name is an empty string. * @throws MessageNotWriteableException if the message is in read-only mode. */ @Override public void setBytes(String name, byte[] value, int offset, int length) throws JMSException { checkWritableProperty(name); if (offset == 0 && length == value.length) { map.put(name, value); } else { byte[] copy = new byte[length]; System.arraycopy(value, offset, copy, 0, length); map.put(name, copy); } } /** * Sets an object value with the specified name into the Map. * *

This method works only for the objectified primitive object types ({@code Integer}, {@code * Double}, {@code Long} ...), {@code String} 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. * @throws MessageNotWriteableException if the message is in read-only mode. */ @Override public void setObject(String name, Object value) throws JMSException { checkWritableProperty(name); validateWritableObject(value); map.put(name, value); } /** * Indicates whether an item exists in this {@code MapMessage} 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 map.containsKey(name); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy