Package org.objectweb.joram.mom.messages

Source Code of org.objectweb.joram.mom.messages.Message

/*
* JORAM: Java(TM) Open Reliable Asynchronous Messaging
* Copyright (C) 2006 - 2008 ScalAgent Distributed Technologies
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
* USA.
*
* Initial developer(s): ScalAgent Distributed Technologies
* Contributor(s):
*/
package org.objectweb.joram.mom.messages;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

import fr.dyade.aaa.agent.AgentServer;
import fr.dyade.aaa.common.Debug;
import fr.dyade.aaa.common.stream.StreamUtil;
import fr.dyade.aaa.util.Transaction;

/**
* The <code>Message</code> class actually provides the transport facility
* for the data exchanged during MOM operations.
* <p>
* A message content is always wrapped as a bytes array, it is characterized
* by properties and "header" fields.
*/
public final class Message implements Serializable, MessageView {
  /** define serialVersionUID for interoperability */
  private static final long serialVersionUID = 2L;

  /** logger */
  public static Logger logger = Debug.getLogger(Message.class.getName());

  /** Arrival position of this message on its queue or proxy. */
  transient public long order;

  /**
   * The number of acknowledgements a message still expects from its
   * subscribers before having been fully consumed by them (field used
   * by JMS proxies).
   * Be careful, this field is not saved but set to 0 during message
   * loading then calculated during the proxy initialization.
   */
  public transient int acksCounter;

  /**
   * The number of acknowledgements a message still expects from its
   * durable subscribers before having been fully consumed by them (field used
   * by JMS proxies).
   * Be careful, this field is not saved but set to 0 during message
   * loading then calculated during the proxy initialization.
   */
  public transient int durableAcksCounter;

  /**
   * Reference to the MOM message.
   */
  private transient org.objectweb.joram.shared.messages.Message msg;

  /** SoftReference to the body of the MOM message. */
  private transient SoftReference bodySoftRef = null;

  /** <code>true</code> if soft reference is used for the message. */
  private transient boolean soft;

  /**
   *  Defines if the swapping mechanism is globally activated for messages
   * in this server.
   * <p>
   *  Default value is false.
   * <p>
   *  Note: the message swapping can be finely configured using the
   * <code>JMS_JORAM_SWAPALLOWED</code> property of the JMS message.
   * <p>
   *  Theses properties can be fixed either from <code>java</code> launching
   * command, or in <code>a3servers.xml</code> configuration file.
   */
  private static final boolean globalUseSoftRef =
    AgentServer.getBoolean("org.objectweb.joram.mom.messages.SWAPALLOWED");

  /**
   * Constructs a <code>Message</code> instance.
   */
  public Message(org.objectweb.joram.shared.messages.Message msg) {
    this.msg = msg;
    // Soft reference can be used only if message is persistent and has a body.
    Boolean msgUseSoftRef = (Boolean) msg.getProperty("JMS_JORAM_SWAPALLOWED");
    if (msgUseSoftRef != null) {
      this.soft = msgUseSoftRef.booleanValue() && msg.persistent && msg.body != null;
    } else {
      this.soft = globalUseSoftRef && msg.persistent && msg.body != null;
    }
  }

  /**
   * Returns the contained message eventually without the body.
   *
   * @return The contained message.
   */
  public org.objectweb.joram.shared.messages.Message getHeaderMessage() {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "MessagePersistenceModule.getHeaderMessage() -> " + msg);
    return msg;
  }

  /**
   * Returns the contained message with body.
   * If needed the body is loaded from repository.
   *
   * @return The contained message.
   */
  public org.objectweb.joram.shared.messages.Message getFullMessage() {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "MessagePersistenceModule.getFullMessage() " + txname);
    // The message can be soft but releaseFullMessage has not been called !
    if (!soft || msg.body != null)
      return msg;

    if (bodySoftRef != null) {
      msg.body = (byte[]) bodySoftRef.get();
      bodySoftRef = null;
      if (msg.body != null) {
        return msg;
      }
    }

    // Try to load the body from repository
    try {
      msg.body = AgentServer.getTransaction().loadByteArray(txname + "B");
      if (logger.isLoggable(BasicLevel.DEBUG))
        logger.log(BasicLevel.DEBUG, "Body loaded.");
      bodySoftRef = null;
    } catch (Exception exc) {
      logger.log(BasicLevel.ERROR,
                 "Body of message named [" + txname + "] could not be loaded", exc);
    }
    return msg;
  }

  /**
   * Creates a soft reference instead of a hard one linking to the body of the
   * contained message. The message must have been saved previously.
   */
  public void releaseFullMessage() {
    if (soft) {
      bodySoftRef = new SoftReference(msg.body);
      msg.body = null;
    }
  }

  /** Returns the message type. */
  public int getType() {
    return msg.type;
  }

  /** Returns the message identifier. */
  public String getIdentifier() {
    return msg.id;
  }

  /** Sets the message identifier. */
  public void setIdentifier(String id) {
    msg.id = id;
  }

  /** Returns <code>true</code> if the message is persistent. */
  public boolean isPersistent() {
    return msg.persistent;
  }

  /** Sets the message persistence mode. */
  public void setPersistent(boolean persistent) {
    msg.persistent = persistent;
  }

  /** Returns the message priority. */
  public int getPriority() {
    return msg.priority;
  }

  /**
   * Sets the message priority.
   *
   * @param priority  Priority value: 0 the lowest, 9 the highest, 4 normal.
   */
  public void setPriority(int priority) {
    if (priority >= 0 && priority <= 9)
      msg.priority = priority;
  }

  /** Returns the message expiration time. */
  public long getExpiration() {
    return msg.expiration;
  }

  /**
   * Sets the message expiration.
   *
   * @param expiration  The expiration time.
   */
  public void setExpiration(long expiration) {
    if (expiration >= 0)
      msg.expiration = expiration;
  }

  /** Returns the message time stamp. */
  public long getTimestamp() {
    return msg.timestamp;
  }

  /** Sets the message time stamp. */
  public void setTimestamp(long timestamp) {
    msg.timestamp = timestamp;
  }

  /** Returns the message correlation identifier. */
  public final String getCorrelationId() {
    return msg.correlationId;
  }

  /** Sets the message correlation identifier. */
  public void setCorrelationId(String correlationId) {
    msg.correlationId = correlationId;
  }

  /** Returns the message delivery count.*/
  public int getDeliveryCount() {
    return msg.deliveryCount;
  }

  /** Sets the message delivery count. */
  public void setDeliveryCount(int deliveryCount) {
    msg.deliveryCount = deliveryCount;
  }

  /** Increments the message delivery count. */
  public void incDeliveryCount() {
    msg.deliveryCount += 1;
  }

  /** Sets the message redelivered flag. */
  public void setRedelivered() {
    msg.redelivered = true;
  }

  /**
   * Sets a property value.
   * If the value is not a Java primitive object its string representation is used.
   *
   * @param name  The property name.
   * @param value  The property value.
   *
   * @throws MessageException          Specified by the JMS API.
   * @throws IllegalArgumentException  If the key name is illegal (null or empty string).
   */
  public void setObjectProperty(String name, Object value) {
    msg.setProperty(name, value);
  }

  //   /**
  //    * Sets an object as the body of the message.
  //    * AF: Used to wrap administration message !!
  //    *
  //    * @exception IOException  In case of an error while setting the object.
  //    */
  //   public void setObject(Object object) throws IOException {
  //     msg.type = Message.OBJECT;

  //     if (object == null) {
  //       msg.body = null;
  //     } else {
  //       ByteArrayOutputStream baos = new ByteArrayOutputStream();
  //       ObjectOutputStream oos = new ObjectOutputStream(baos);
  //       oos.writeObject(object);
  //       oos.flush();
  //       msg.body = baos.toByteArray();
  //       oos.close();
  //       baos.close();
  //     }
  //   }

  //   /**
  //    * Returns the object body of the message.
  //    * AF: Used to wrap administration message !!
  //    *
  //    * @exception IOException  In case of an error while getting the object.
  //    * @exception ClassNotFoundException  If the object class is unknown.
  //    */
  //   public Object getObject() throws Exception {
  //     // AF: May be, we should verify that it is an Object message!!
  //     if (msg.body == null) return null;

  //     ByteArrayInputStream bais = new ByteArrayInputStream(msg.body);
  //     ObjectInputStream ois = new ObjectInputStream(bais);
  //     Object obj = ois.readObject();
  //     ois.close();

  //     return obj;
  //   }

  /**
   * Returns <code>true</code> if the message is valid. The message is valid if
   * not expired.
   *
   * @param currentTime  The current time to verify the expiration time.
   */
  public boolean isValid(long currentTime) {
    return (msg.expiration <= 0) || (msg.expiration > currentTime);
  }

  /** Name used to store the message */
  transient String txname = null;

  public void setTxName(String txname) {
    this.txname = txname;
  }

  public String getTxName() {
    return txname;
  }

  public static Message load(String txname) throws IOException, ClassNotFoundException {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "Message.load:" + txname);
    Message msg = (Message) AgentServer.getTransaction().load(txname);
    msg.txname = txname;
    return msg;
  }

  public void save() {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "Message.save:" + txname);

    if (!isPersistent()) return;
   
    if (soft) {
      byte[] body = msg.body;
      // sets the body to null to save it in an other file
      msg.body = null;
      try {
        AgentServer.getTransaction().create(this, txname);
      } catch (IOException exc) {
        logger.log(BasicLevel.ERROR, "Message named [" + txname + "] could not be saved", exc);
      }
      // save the body
      try {
        // The body is RO do not copy it.
        AgentServer.getTransaction().saveByteArray(body, null, txname + "B", false, true);
      } catch (IOException exc) {
        logger.log(BasicLevel.ERROR, "Message named [" + txname + "] could not be saved", exc);
      }
      msg.body = body;
    } else {
      try {
        AgentServer.getTransaction().create(this, txname);
      } catch (IOException exc) {
        logger.log(BasicLevel.ERROR, "Message named [" + txname + "] could not be saved", exc);
      }
    }
  }

  public void saveHeader() {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "Message.saveHeader:" + txname);

    if (!isPersistent())
      return;
    if (soft) {
      byte[] body = msg.body;
      // sets the body to null to not save it
      msg.body = null;
      try {
        AgentServer.getTransaction().create(this, txname);
      } catch (IOException exc) {
        logger.log(BasicLevel.ERROR, "Message named [" + txname + "] could not be saved", exc);
      }
      msg.body = body;
    } else {
      save();
    }
  }

  public void delete() {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "Message.delete:" + txname);

    if (!isPersistent())
      return;
    AgentServer.getTransaction().delete(txname);
    if (soft) {
      AgentServer.getTransaction().delete(txname + "B");
    }
  }

  /** Loads all persisted messages. */
  public static Vector loadAll(String msgTxname) {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "MessagePersistenceModule.loadAll() " + msgTxname);

    Vector messages = new Vector();

    // Retrieving the names of the persistence message previously saved.
    Transaction tx = AgentServer.getTransaction();
    String[] names = tx.getList(msgTxname);

    // Retrieving the messages individually persisted.
    for (int i = 0; i < names.length; i++) {
      if (names[i].charAt(names[i].length() - 1) != 'B') {
        try {
          Message msg = (Message) tx.load(names[i]);
          msg.txname = names[i];

          if (logger.isLoggable(BasicLevel.DEBUG))
            logger.log(BasicLevel.DEBUG, "loadAll: names[" + i + "] = " + msg);
          messages.add(msg);
        } catch (Exception exc) {
          logger.log(BasicLevel.ERROR, "Message named [" + names[i] + "] could not be loaded", exc);
        }
      }
    }
    return messages;
  }

  /** Deletes all persisted objects. */
  public static void deleteAll(String msgTxname) {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "MessagePersistenceModule.deleteAll() " + msgTxname);

    Transaction tx = AgentServer.getTransaction();

    // Retrieving the names of the persistence message previously saved.
    String[] names = tx.getList(msgTxname);

    // Deleting the message.
    for (int i = 0; i < names.length; i++) {
      tx.delete(names[i]);
      tx.delete(names[i] + "B");
    }
  }

  /* ***** ***** ***** ***** ***** ***** ***** *****
   * Serializable interface
   * ***** ***** ***** ***** ***** ***** ***** ***** */
  private void writeObject(ObjectOutputStream out) throws IOException {
    out.writeLong(order);
    out.writeBoolean(soft);

    msg.writeHeaderTo(out);
    StreamUtil.writeTo(msg.body, out);
  }

  /**
   * @throws ClassNotFoundException 
   */
  private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    order = in.readLong();
    soft = in.readBoolean();

    acksCounter = 0;
    durableAcksCounter = 0;

    msg = new org.objectweb.joram.shared.messages.Message();
    msg.readHeaderFrom(in);
    msg.body = StreamUtil.readByteArrayFrom(in);
  }

  public String getId() {
    return msg.id;
  }

  public String getText() {
    return msg.getText();
  }

  public boolean isRedelivered() {
    return msg.redelivered;
  }

  public Map getProperties() {
    Map props = new HashMap();
    if (msg.properties == null) {
      return null;
    }
    msg.properties.copyInto(props);
    return props;
  }
}
TOP

Related Classes of org.objectweb.joram.mom.messages.Message

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.