Package org.xmlBlaster.util.queuemsg

Source Code of org.xmlBlaster.util.queuemsg.MsgQueueEntry

/*------------------------------------------------------------------------------
Name:      MsgQueueEntry.java
Project:   xmlBlaster.org
Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
------------------------------------------------------------------------------*/
package org.xmlBlaster.util.queuemsg;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.xmlBlaster.util.Global;
import org.xmlBlaster.util.MsgUnit;
import org.xmlBlaster.util.SessionName;
import org.xmlBlaster.util.Timestamp;
import org.xmlBlaster.util.XmlBlasterException;
import org.xmlBlaster.util.def.MethodName;
import org.xmlBlaster.util.def.PriorityEnum;
import org.xmlBlaster.util.queue.I_QueueEntry;
import org.xmlBlaster.util.queue.StorageId;
import org.xmlBlaster.util.queue.jdbc.XBMeat;
import org.xmlBlaster.util.queue.jdbc.XBRef;


/**
* Base class to enter xmlBlaster method invocations (messages) into an ordered queue.
* @author xmlBlaster@marcelruff.info
* @author michele@laghi.eu
*/
public abstract class MsgQueueEntry implements I_QueueEntry, Cloneable
{
   private final static String ME = "MsgQueueEntry";

   protected transient Global glob;
   private static Logger log = Logger.getLogger(MsgQueueEntry.class.getName());

   // Three helpers to transport the return value back to the caller
   protected transient boolean wantReturnObj = true;
   protected transient Object returnObj;
   protected transient MsgQueueEntry refToCloneOrigin;

   private String logId;

   /** The queue to which this entry belongs (set in the constructors) */
   protected StorageId storageId;

   /** How often the entry was tried to send but failed */
   protected int redeliverCounter = 0;

   /** The unique creation timestamp (unique in a Global of a virtual machine) */
   protected final Timestamp uniqueIdTimestamp;

   /** The message priority, see Constants.java */
   protected final PriorityEnum priority;

   /** the flag telling if a message is persistent (opposite to transient) */
   protected boolean persistent;

   /** Which method we invoke, e.g. "update" or "publish" */
   protected final String entryType;

   private transient boolean stored = false;
   //private transient boolean swapped = false;

   /** The queue to which this entry belongs (set in the constructors) */
   protected final String uniqueIdString;

   /**
    * @param methodName use methodName as entryType
    */
   public MsgQueueEntry(Global glob, MethodName methodName, PriorityEnum priority, StorageId storageId, boolean persistent) {
      this(glob, methodName.toString(), priority, (Timestamp)null, storageId, persistent);
   }

   /**
    * Creates a new queue entry object.
    * @param priority The message priority
    * @param storageId The queue i belong to
    * @see org.xmlBlaster.util.Timestamp
    */
   public MsgQueueEntry(Global glob, String entryType, PriorityEnum priority, StorageId storageId, boolean persistent) {
      this(glob, entryType, priority, (Timestamp)null, storageId, persistent);
   }

   /**
    * This constructor is for internal creation from persistence only.
    *
    * @param timestamp The unique nano timestamp as from org.xmlBlaster.util.Timestamp or null to create one now
    */
   public MsgQueueEntry(Global glob, String entryType, PriorityEnum priority, Timestamp timestamp, StorageId storageId, boolean persistent) {
      this.uniqueIdTimestamp = (timestamp == null) ? new Timestamp() : timestamp;
      this.uniqueIdString = "" + this.uniqueIdTimestamp.getTimestamp();

      if (entryType == null || priority == null || glob == null || storageId ==null) {
         log.severe("Invalid constructor parameter");
         Thread.dumpStack();
         throw new IllegalArgumentException(ME + ": Invalid constructor parameter");
      }

      this.glob = glob;

      this.entryType = entryType;
      this.priority = priority;
      this.storageId = storageId;
      this.persistent = persistent;
   }

   public final void setGlobal(Global global) {
      this.glob = global;

   }


   public void finalize() {
      try {
         super.finalize();
         if (log != null && log.isLoggable(Level.FINE)) log.fine("finalize - garbage collect");
      }
      catch (Throwable e) {
         e.printStackTrace();
      }
   }

   /**
    * Enforced by I_QueueEntry
    * @return The priority of this message as int (see PriorityEnum.java)
    */
   public int getPriority() {
      return this.priority.getInt();
   }

   /**
    * @return The priority of this message
    */
   public final PriorityEnum getPriorityEnum() {
      return this.priority;
   }

   /**
    * @return The persistent flag of this message
    */
   public boolean isPersistent() {
      return this.persistent;
   }

   public void setPersistent(boolean persistent) {
      this.persistent = persistent;
   }

   /**
    * The unique creation timestamp (unique in a Global of a virtual machine)
    * Enforced by I_QueueEntry
    * @param nano seconds
    */
   public long getUniqueId() {
      return this.uniqueIdTimestamp.getTimestamp();
   }

   /**
    * The unique creation timestamp (unique in a Global of a virtual machine)
    * @param nano seconds
    */
   public Long getUniqueIdLong() {
      return this.uniqueIdTimestamp.getTimestampLong();
   }

   /**
    * Flag which marks the entry as outdated
    */
   public abstract boolean isExpired();

   /**
    * Flag which marks the entry as destroyed, you should take it from queue and ignore/discard it
    */
   public abstract boolean isDestroyed();

   /**
    * @return If it is an internal message (oid starting with "_").
    */
   public abstract boolean isInternal();

   /**
    * @return The name of the sender (data source) or null
    */
   public abstract SessionName getSender();

   /**
    * @return The name of the receiver (data sink) or null
    */
   public abstract SessionName getReceiver();

   /**
    * @return The message key oid or null
    */
   public abstract String getKeyOid();

   /**
    * To which queue do i belong
    */
   public final StorageId getStorageId() {
      return this.storageId;
   }

   /**
    * Increment the counter if message delivery fails (exception during sending)
    * We don't know if other side has processed it completely or not
    */
   public final void incrRedeliverCounter() {
      this.redeliverCounter++;
   }

   /**
    * How often we tried to redeliver the message.
    * <p>
    * Note: Depending on the derived class implementation this information
    * is lost on server crash (the redeliver counter
    * is not persistent). Only MsgQueueUpdateEntry persists it.
    * </p>
    * @return Number of failed tries
    */
   public final int getRedeliverCounter() {
      return this.redeliverCounter;
   }

   /**
    * Try to find out the approximate memory consumption of this message in RAM.
    * <p />
    * NOTE: The derived classes need to add their data amount to this value.
    * @return the approximate size in bytes of this object which contributes to a QueueEntry memory consumption
    */
   public long getSizeInBytes() {
      return 100; // a totally intuitive number for the object creation itself
   }

   /**
    * Needed for sorting the queue.
    * Comparing the longs directly is 20% faster than having a
    * String compound key
    * <br /><br />
    * Sorts the messages
    * <ol>
    *   <li>Priority</li>
    *   <li>Timestamp</li>
    * </ol>
    * <p>
    * The sorting order is priority,timestamp:
    * </p>
    * <pre>
    *   ->    5,100 - 5,98 - 5,50 - 9,3000 - 9,2500   ->
    * </pre>
    * <p>
    * As 9 is highest priority it is the first to be taken out.<br />
    * As we need to maintain the timely sequence and
    * id is a timestamp in (more or less) nano seconds elapsed since 1970)
    * the id 2500 (it is older) has precedence to the id 3000
    * </p>
    */
   public final int compare(I_QueueEntry m2) {
      //log.info(ME, "Entering compare A=" + getUniqueId() + " B=" + m2.getUniqueId());
      int diff = m2.getPriority() - getPriority();
      if (diff != 0) // The higher prio wins
         return diff;

      long dif = m2.getUniqueId() - getUniqueId();
      if (dif < 0L)
         return 1// The older message wins
      else if (dif > 0L)
         return -1;
      return 0;

      //System.out.println("Comparing " + getSortKey() + " : " + d2.getSortKey());
      // return getSortKey().compareTo(d2.getSortKey());
   }

   /**
    * Needed for sorting in queue
    */
   public final boolean equals(I_QueueEntry m2) {
      return (getPriority() == m2.getPriority() && getUniqueId() == m2.getUniqueId());
   }

   /**
    * Dump state of this object into XML.
    * <br>
    * @return XML state of MsgQueueEntry
    */
   public String toXml() {
      return toXml((String)null);
   }

   /**
    * Dump state of this object into XML.
    * <br>
    * @param extraOffset indenting of tags
    * @return XML state of MsgQueueEntry
    */
   public String toXml(String extraOffset) {
      StringBuffer sb = new StringBuffer(200);
      String offset = "\n   ";
      if (extraOffset != null) offset += extraOffset;

      sb.append(offset).append("<MsgQueueEntry type='").append(entryType).append("'>");
      sb.append(offset).append("   <priority>").append(getPriority()).append("</priority>");
      sb.append(offset).append("   <persistent>").append(isPersistent()).append("</persistent>");
      sb.append(offset).append("   <uniqueId>").append(getUniqueId()).append("</uniqueId>");
      sb.append(offset).append("   <sender>").append(getSender()).append("</sender>");
      sb.append(offset).append("   <receiver>").append(getReceiver()).append("</receiver>");
      sb.append(offset).append("   <expired>").append(isExpired()).append("</expired>");
      sb.append(offset).append("   <isInternal>").append(isInternal()).append("</isInternal>");
      sb.append(offset).append("</MsgQueueEntry>\n");
      return sb.toString();
   }

   /**
    * Nice for logging
    * @see #getLogId()
    */
   public String toString() {
      return getLogId();
      /*
      StringBuffer sb = new StringBuffer(200);
      sb.append("MsgQueueEntry sender=").append(getSender());
      sb.append(" receiver=").append(getReceiver());
      sb.append(" priority=").append(getPriority());
      sb.append(" uniqueId=").append(getUniqueId());
      sb.append(" expired=").append(isExpired());
      return sb.toString();
      */
   }

   /**
    * @see I_QueueEntry.getEmbeddedObject()
    */
   //public Object getEmbeddedObject() {
   //   return this.getMsgUnit();
   //}


   /**
    * @return MethodName.xxx
    */
   public String getEmbeddedType() {
      return entryType;
   }

   /**
    * Notification if this entry is added to queue
    * @see org.xmlBlaster.util.queue.I_Entry#added(StorageId)
    */
   public void added(StorageId storageId) {
      log.info(getLogId() + " is added to queue: REFERENCE COUNTER IMPL MISSING");
   }

   /**
    * Notification if this entry is removed from queue
    * @see org.xmlBlaster.util.queue.I_Entry#removed(StorageId)
    */
   public void removed(StorageId storageId) {
      log.info(getLogId() + " is removed from queue: REFERENCE COUNTER IMPL MISSING");
   }

   /**
    * @return e.g. MethodName.PUBLISH
    * @see #getEmbeddedType()
    */
   public MethodName getMethodName() {
      return MethodName.toMethodName(this.entryType);
   }

   /**
    * @return true if the dispatcher framework shall provide a return object
    */
   public boolean wantReturnObj() {
      return this.wantReturnObj;
   }

   /**
    * sets the 'wantReturnObj' flag to what you specify (overwrites the default for
    * the implementing class).
    * @param wantReturnObj
    */
   public void setWantReturnObject(boolean wantReturnObj) {
      this.wantReturnObj = wantReturnObj;
   }

   /**
    * If this instance is a clone we can remember who cloned us.
    */
   void setRefToCloneOrigin(MsgQueueEntry origEntry) {
      this.refToCloneOrigin = origEntry;
   }

   /**
    * @return returnObj The carried object used as return QoS in sync or async I_Queue.put() mode, can be null.
    */
   public Object getReturnObj() {
      return this.returnObj;
   }

   /**
    * Set the object to be carried as return value.
    * NOTE: This can be used only once as the first call to this method
    * destroys the reference to the clone original instance.
    */
   public void setReturnObj(Object returnObj) {
      if (this.refToCloneOrigin != null) {
         this.refToCloneOrigin.setReturnObj(returnObj);
         this.refToCloneOrigin = null; // free reference so that GC can remove it if swapped
      }
      this.returnObj = returnObj;
   }

   /**
    * Returns a shallow clone.
    * Is done by DispatchManager.prepareMsgsFromQueue() so that it can later encrypt
    * the message without touching the original
    */
   public Object clone() {
      MsgQueueEntry entry = null;
      try {
         entry = (MsgQueueEntry)super.clone();
         if (entry.wantReturnObj) {
            entry.setRefToCloneOrigin(this);
         }
      }
      catch(CloneNotSupportedException e) {
         log.severe("Internal clone problem: " + e.toString());
      }
      return entry;
   }

   /**
    * Return a human readable identifier for logging output.
    * @return e.g. "callback:/node/heron/client/joe/2/17/HIGH/23455969/TheMessageOid"
    */
   public final String getLogId() {
      if (this.logId == null) {
         StringBuffer sb = new StringBuffer(80);
         sb.append(getStorageId());
         sb.append("/").append(priority);
         //sb.append("/").append(priority.toString());
         sb.append("/").append(getUniqueId());
         sb.append("/").append(getKeyOid());
         this.logId = sb.toString();
      }
      return this.logId;
   }

   /**
    * @see org.xmlBlaster.util.queue.I_Entry#setStored(boolean)
    */
   final public void setStored(boolean stored) {
      this.stored = stored;
   }

   /**
    * @see org.xmlBlaster.util.queue.I_Entry#isStored()
    */
   final public boolean isStored() {
      return this.stored;
   }

   /**
    *
    * @return null (always)
    */
   abstract public MsgUnit getMsgUnit() throws XmlBlasterException;
  
  
   /**
    * For the new queues
    */
   public XBMeat getMeat() throws XmlBlasterException {
      XBMeat meat = new XBMeat();
      meat.setByteSize(getSizeInBytes());
      meat.setDataType(getEmbeddedType());
      meat.setDurable(isPersistent());
      // meat.setFlag1(flag1);
      meat.setId(getUniqueId());
      MsgUnit unit = getMsgUnit();
      if (unit != null) {
         meat.setContent(unit.getContent());
         meat.setKey(unit.getKey());
         meat.setQos(unit.getQos());
      }
      meat.setRefCount(1);
      return meat;
   }

   /**
    * For the new queues
    */
   public XBRef getRef() {
      XBRef ref = new XBRef();
      ref.setByteSize(getSizeInBytes());
      ref.setDurable(isPersistent());
      ref.setId(getUniqueId());
      ref.setMeatId(getUniqueId());
      ref.setPrio(getPriority());
      ref.setMethodName(entryType);
      return ref;
   }

  
  
}
TOP

Related Classes of org.xmlBlaster.util.queuemsg.MsgQueueEntry

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.