Package org.xmlBlaster.engine.queuemsg

Source Code of org.xmlBlaster.engine.queuemsg.TopicEntry

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

import java.util.logging.Logger;

import org.xmlBlaster.engine.ServerScope;
import org.xmlBlaster.engine.msgstore.I_Map;
import org.xmlBlaster.engine.msgstore.I_MapEntry;
import org.xmlBlaster.util.MsgUnit;
import org.xmlBlaster.util.Timestamp;
import org.xmlBlaster.util.XmlBlasterException;
import org.xmlBlaster.util.def.Constants;
import org.xmlBlaster.util.def.ErrorCode;
import org.xmlBlaster.util.def.PriorityEnum;
import org.xmlBlaster.util.key.MsgKeyData;
import org.xmlBlaster.util.qos.MsgQosData;
import org.xmlBlaster.util.queue.StorageId;
import org.xmlBlaster.util.queue.jdbc.XBMeat;
import org.xmlBlaster.util.queue.jdbc.XBRef;


/**
* Wraps an publish() message into an entry for a persistence cache.
* <p>
* There are two options to make this object persistent (measure on a 2GHz Intel Linux laptop with Postgres):
* </p>
* <p>
* 1. QoS and Key are stored as XML ASCII strings, the content as byte[]<br />
* This variant takes about 50 microsec to serialize (toXml()) and 380 microsec to create the object again (SAX parse).
* The size for an empty content is approx. 80 bytes for a medium sized key and QoS.
* </p>
* <p>
* 2. The whole object is java.io.Serialized<br />
* This variant takes about 160 microsec to serialize and 750 microsec to deserialize.
* </p>
* <p>
* So we have chosen the XML variant as it is faster, has no versioning problems and has smaller size
* </p>
* @author xmlBlaster@marcelruff.info
* @see org.xmlBlaster.engine.queuemsg.ServerEntryFactory#main(String[])
*/
public final class TopicEntry implements I_MapEntry
{
   private static Logger log = Logger.getLogger(TopicEntry.class.getName());
   private static final long serialVersionUID = 1L;
   private transient final String ME;
   private transient final long uniqueId;
   private transient final String uniqueIdStr;    // cache uniqueId as String
   private transient final String embeddedType;

   private MsgUnit msgUnit;
   private final long immutableSizeInBytes;

   private transient boolean stored = false;
   private transient boolean swapped = false;
   private transient Timestamp sortTimestamp;
   private transient StorageId storageId;

   /**
    * Use this constructor if a new message object is fed by method publish().
    * <p />
    * @param msgUnit The raw data
    * @param storageId TODO
    */
   public TopicEntry(ServerScope glob, MsgUnit msgUnit, StorageId storageId) throws XmlBlasterException {
      this(glob, msgUnit, storageId, (String)null, -1L);
   }

   /**
    * Used when message comes from persistence, the owning I_Map is unknown
    * @param storageId TODO
    * @param embeddedType Allows you to control how to make this object persistent:<br />
    *         ServerEntryFactory.ENTRY_TYPE_TOPIC_XML Dump strings as XML ASCII (which is smaller, faster, portable -> and therefor default)<br />
    *         ServerEntryFactory.ENTRY_TYPE_TOPIC_SERIAL Dump object with java.io.Serializable
    * @param sizeInByte The estimated size of the entry in RAM (can be totally different on HD).
    *                   If -1L it is estimated for you
    */
   public TopicEntry(ServerScope glob, MsgUnit msgUnit, StorageId storageId, String embeddedType, long sizeInBytes) throws XmlBlasterException {
      if (msgUnit == null) {
         throw new XmlBlasterException(glob, ErrorCode.INTERNAL_ILLEGALARGUMENT, "TopicEntry", "Invalid constructor parameter msgUnit==null");
      }
      this.msgUnit = msgUnit;
      this.storageId = storageId;
      this.embeddedType = (embeddedType == null) ? ServerEntryFactory.ENTRY_TYPE_TOPIC_XML : embeddedType;
      //this.uniqueId = getKeyOid()+getMsgQosData().getRcvTimestamp();
      if (getMsgQosData().getRcvTimestamp() == null) {
         throw new XmlBlasterException(glob, ErrorCode.INTERNAL_ILLEGALARGUMENT, "TopicEntry", "Missing timestamp, try to create publish QoS with PublishQosServer.java");
      }
      this.uniqueId = getMsgQosData().getRcvTimestamp().getTimestamp();
      this.uniqueIdStr = ""+this.uniqueId;
      this.ME = "TopicEntry-" + getLogId();
      this.immutableSizeInBytes = (sizeInBytes >= 0L) ? sizeInBytes : this.msgUnit.size();
      //this.glob.getLog("core").info(ME, "Created message" + toXml());
   }

   /*
   public void finalize() {
      this.glob.getLog("core").info(ME, "finalize: " + toXml());
      super.finalize();
   }
   */

   /**
    * @return The owning TopicHandler, never null
   public TopicHandler getTopicHandler() throws XmlBlasterException {
      TopicHandler topicHandler = glob.getRequestBroker().getMessageHandlerFromOid(getKeyOid());
      if (topicHandler == null) {
         throw new XmlBlasterException(glob, ErrorCode.INTERNAL_UNKNOWN, ME, "getTopicHandler() - storage lookup of topic '" + getKeyOid() + "' failed");
      }
      return topicHandler;
   }
    */

   /** Returns a dummy only as sorting is not important in this context. */
   public int getPriority() {
      return PriorityEnum.NORM_PRIORITY.getInt();
   }

   /*
   public boolean isExpired() {
      return getMsgQosData().isExpired();
   }
   */

   public MsgQosData getMsgQosData() {
      return (MsgQosData)this.msgUnit.getQosData();
   }

   public boolean isPersistent() {
      return getMsgQosData().isPersistent();
   }

   public MsgKeyData getMsgKeyData() {
      return (MsgKeyData)this.msgUnit.getKeyData();
   }

   public MsgUnit getMsgUnit() {
      return this.msgUnit;
   }

   public String getKeyOid() {
      return getMsgKeyData().getOid();
   }

   public String getContentMime() {
      return getMsgKeyData().getContentMime();
   }

   public String getContentMimeExtended() {
      return getMsgKeyData().getContentMimeExtended();
   }

   public String getDomain() {
      return getMsgKeyData().getDomain();
   }

   public void setMsgUnit(MsgUnit msg) {
      this.msgUnit = msg;
   }

   public long getSizeInBytes() {
      return this.immutableSizeInBytes;
   }

   /**
    * The unique ID for this entry = getMsgQosData().getRcvTimestamp().getTimestamp()
    */
   public long getUniqueId() {
      return this.uniqueId;
   }

   public String getUniqueIdStr() {
      return this.uniqueIdStr;
   }

   public String getLogId() {
      return getKeyOid() + "/" + getMsgQosData().getRcvTimestamp();
   }

   public final boolean isInternal() {
      return getMsgKeyData().isInternal();
   }

   /**
    * @return ServerEntryFactory.ENTRY_TYPE_TOPIC_XML or ServerEntryFactory.ENTRY_TYPE_TOPIC_SERIAL
    */
   public String getEmbeddedType() {
      return this.embeddedType;
   }

   /**
    * The embedded object.
    * Object[] = { this.msgUnit }  or<br />
    * qos.toXml, key.toXml, contentBytes
    */
   public Object getEmbeddedObject() {
      if (this.embeddedType.equals(ServerEntryFactory.ENTRY_TYPE_TOPIC_SERIAL)) {
         Object[] obj = { this.msgUnit };
         return obj;
      }
      else {
         Object[] obj = { this.msgUnit.getQosData().toXml(), this.msgUnit.getKeyData().toXml() };
         return obj;
      }
   }

   /**
    * Returns a shallow clone
    */
   public Object clone() {
      try {
         return super.clone();
      }
      catch (CloneNotSupportedException e) {
         return null;
      }
   }

   public final String toXml() {
      return toXml((String)null);
   }

   public String toXml(String extraOffset) {
      StringBuffer sb = new StringBuffer(2000);
      if (extraOffset == null) extraOffset = "";
      String offset = Constants.OFFSET + extraOffset;

      sb.append(offset).append("<TopicEntry id='").append(getLogId()).append("'>");
      sb.append(this.msgUnit.toXml(Constants.INDENT + extraOffset));
      sb.append(offset).append("</TopicEntry>");
      return sb.toString();
   }

   /**
    * Notification if this entry is added to storage
    * @see org.xmlBlaster.util.queue.I_Entry#added(StorageId)
    */
   public void added(StorageId storageId) {
      log.severe(ME + "added("+storageId.getId()+") invocation not expected (internal illegal argument)");
   }

   /**
    * Notification if this entry is removed from storage
    * @see org.xmlBlaster.util.queue.I_Entry#removed(StorageId)
    */
   public void removed(StorageId storageId) {
      log.severe(ME + "removed("+storageId.getId()+") invocation not expected (internal illegal argument)");
   }

   /**
    */
   public boolean isExpired() {
      return false;
   }

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


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

   /**
    * Enforced by I_Map
    * @see I_Map#isSwapped()
    */
   public boolean isSwapped() {
      return this.swapped;
   }

   /**
    * Enforced by I_Map
    * @see I_Map#isSwapped(boolean)
    */
   public void isSwapped(boolean swapped) {
      this.swapped = swapped;
   }

   /**
    * Can be used by cache implementation to implement LRU
    * @return null if not previously set by setSortTimestamp()
    */
   public final Timestamp getSortTimestamp() {
      return this.sortTimestamp;
   }

   /**
    * Can be used by cache implementation to implement LRU
    * @return timestamp This is chosen by the cache algorithm
    */
   public final void setSortTimestamp(Timestamp timestamp) {
      this.sortTimestamp = timestamp;
   }

   public final void embeddedObjectToXml(java.io.OutputStream out, java.util.Properties props) throws java.io.IOException {
      MsgUnit msgUnit = getMsgUnit();
      if (msgUnit != null)
         msgUnit.toXml(out, props);
   }
  
   /**
    * Measure size for XML-ASCII versus java.io.Serializable persistence.
    * <pre>
    * java org.xmlBlaster.engine.TopicEntry
    * </pre>
    * Result:
    * <p>
    * java.io.Serialized file 'TopicEntry.ser' size=1407 bytes versus XML dump=123 bytes
    * </p>
    */
   public static void main(String[] args) {
      ServerScope glob = new ServerScope(args);
      String fileName = "TopicEntry.ser";
      try {
         org.xmlBlaster.client.key.PublishKey publishKey = new org.xmlBlaster.client.key.PublishKey(glob, "HA");
         org.xmlBlaster.engine.qos.PublishQosServer publishQosServer = new org.xmlBlaster.engine.qos.PublishQosServer(glob, "<qos><persistent/></qos>");
         publishQosServer.getData().setPriority(PriorityEnum.HIGH_PRIORITY);
         MsgUnit msgUnit = new MsgUnit(publishKey.getData(), "HO".getBytes(), publishQosServer.getData());
         TopicEntry msgUnitWrapper = new TopicEntry(glob, msgUnit, null);
         try {
            java.io.FileOutputStream f = new java.io.FileOutputStream(fileName);
            java.io.ObjectOutputStream objStream = new java.io.ObjectOutputStream(f);
            objStream.writeObject(msgUnitWrapper);
            objStream.flush();
            java.io.File file = new java.io.File(fileName);
            System.out.println("SUCCESS written java.io.Serialized file '" + fileName + "' size=" + file.length() +
                               " versus XML dump=" + msgUnitWrapper.getSizeInBytes());
         }
         catch (Exception e) {
            System.err.println("ERROR: " + e.getMessage());
         }
      }
      catch (XmlBlasterException e) {
         System.err.println("ERROR: " + e.getMessage());
      }
   }
  
   /**
    * For the new queues
    */
   public XBMeat getMeat() {
      XBMeat meat = new XBMeat();
      meat.setByteSize(getSizeInBytes());
      meat.setContent(msgUnit.getContent());
      meat.setDataType(getEmbeddedType());
      meat.setDurable(isPersistent());
      // meat.setFlag1(flag1);
      meat.setId(uniqueId);
      meat.setKey(msgUnit.getKey());
      meat.setQos(msgUnit.getQos());
      meat.setRefCount(1);
      return meat;
   }

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

   public StorageId getStorageId() {
      return storageId;
   }
}
TOP

Related Classes of org.xmlBlaster.engine.queuemsg.TopicEntry

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.