Package org.xmlBlaster.contrib

Source Code of org.xmlBlaster.contrib.MomEventEngine

/*------------------------------------------------------------------------------
Name:      MomEventHandler.java
Project:   xmlBlaster.org
Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
------------------------------------------------------------------------------*/

package org.xmlBlaster.contrib;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import org.xmlBlaster.client.I_Callback;
import org.xmlBlaster.client.I_XmlBlasterAccess;
import org.xmlBlaster.client.key.PublishKey;
import org.xmlBlaster.client.key.UpdateKey;
import org.xmlBlaster.client.qos.ConnectQos;
import org.xmlBlaster.client.qos.PublishQos;
import org.xmlBlaster.client.qos.UpdateQos;
import org.xmlBlaster.contrib.dbwatcher.DbWatcherConstants;
import org.xmlBlaster.jms.XBSession;
import org.xmlBlaster.util.Global;
import org.xmlBlaster.util.MsgUnit;
import org.xmlBlaster.util.XmlBlasterException;
import org.xmlBlaster.util.def.Constants;
import org.xmlBlaster.util.def.ErrorCode;
import org.xmlBlaster.util.qos.ClientProperty;
import org.xmlBlaster.util.qos.address.CallbackAddress;

public class MomEventEngine implements I_Callback, I_ChangePublisher {

   private static Logger log = Logger.getLogger(MomEventEngine.class.getName());
   protected Global glob;
   protected I_XmlBlasterAccess con;
   protected String loginName;
   protected String password;
   protected List subscribeKeyList;
   protected List subscribeQosList;
   protected ConnectQos connectQos;
   protected I_Update eventHandler;
   protected boolean shutdownMom;
   private int compressSize;
  
   public MomEventEngine() {
      this.subscribeKeyList = new ArrayList();
      this.subscribeQosList = new ArrayList();
   }
  
  
   /**
    * @see org.xmlBlaster.contrib.I_ContribPlugin#getUsedPropertyKeys()
    */
   public Set getUsedPropertyKeys() {
      Set set = new HashSet();
      set.add("mom.loginName");
      set.add("mom.password");
      set.add("mom.subscriptions");
      // TODO add also the kind mom.subscribeKeys[*] and qos
      set.add("mom.subscribeKey");
      set.add("mom.subscribeQos");
      set.add("mom.connectQos");
      set.add("mom.maxSessions");
      set.add("dbWriter.shutdownMom");
      return set;
   }


   public void init(I_Info info) throws Exception {
      if (this.con != null) return;
     
      Global globOrig = (Global)info.getObject("org.xmlBlaster.engine.Global");
      if (globOrig == null) {
        
         if (info instanceof GlobalInfo)
            this.glob = ((GlobalInfo)info).global;
         else {
            Iterator iter = info.getKeys().iterator();
            ArrayList argsList = new ArrayList();
            while (iter.hasNext()) {
               String key = (String)iter.next();
               String value = info.get(key, null);
               if (value != null) {
                  argsList.add("-" + key);
                  argsList.add(value);
               }
            }
            this.glob = new Global((String[])argsList.toArray(new String[argsList.size()]));
         }
      }
      else {
         this.glob = globOrig.getClone(globOrig.getNativeConnectArgs());
         this.glob.addObjectEntry(Constants.OBJECT_ENTRY_ServerScope, globOrig.getObjectEntry(Constants.OBJECT_ENTRY_ServerScope)); // "ServerNodeScope"
      }

      this.compressSize = info.getInt(DbWatcherConstants.MOM_COMPRESS_SIZE, 0);
      this.shutdownMom = info.getBoolean("dbWriter.shutdownMom", false); // avoid to disconnect (otherwise it looses persistent subscriptions)
      this.loginName = info.get("mom.loginName", "dbWriter/1");
      this.password  = info.get("mom.password", "secret");

      /* comma separated list of names for the subscriptions */
      String subscriptionNames = info.get("mom.subscriptions", (String)null);
      if (subscriptionNames != null) {
         StringTokenizer tokenizer = new StringTokenizer(subscriptionNames.trim(), ",");
         while (tokenizer.hasMoreTokens()) {
            String name = tokenizer.nextToken();
            if (name != null) {
               name = name.trim();
               if (name.length() > 0) {
                  String tmp = "mom.subscribeKey[" + name + "]";
                  String key = info.get(tmp, null);
                  if (key == null)
                     throw new Exception(".init: the attribute '" + tmp + "' has not been found but '" + name +"' was listed in 'mom.subscriptions' solve the inconsistency");
                  tmp = "mom.subscribeQos[" + name + "]";
                  String qos = info.get(tmp, "<qos/>");
                  log.info(".init: adding subscription '" + name + "' to the list: key='" + key + "' and qos='" + qos + "'");
                  this.subscribeKeyList.add(key);
                  this.subscribeQosList.add(qos);
               }
            }
         }
      }
      // Either subscriptionNames are null or not we use the mom.subscriptionKey and mom.subscriptionQos
      String tmp = "mom.subscribeKey";
      String key = info.get(tmp, null);
      if (key != null) {
         tmp = "mom.subscribeQos";
         String qos = info.get(tmp, "<qos/>");
         log.info(".init: adding unnamed subscription to the list: key='" + key + "' and qos='" + qos + "'");
         this.subscribeKeyList.add(key);
         this.subscribeQosList.add(qos);
      }


      tmp  = info.get("mom.connectQos", (String)null);
      if (tmp != null) {
         this.connectQos = new ConnectQos(this.glob, this.glob.getConnectQosFactory().readObject(tmp));
      }
      else {
         this.connectQos = new ConnectQos(this.glob, this.loginName, this.password);
         int maxSessions = info.getInt("mom.maxSessions", 100);
         this.connectQos.setMaxSessions(maxSessions);
         this.connectQos.getAddress().setRetries(-1);
         this.connectQos.setSessionTimeout(0L);
         if (info.getBoolean("mom.updateBulkAck", false))
            this.connectQos.addClientProperty(Constants.UPDATE_BULK_ACK, "true");
         CallbackAddress cbAddr = new CallbackAddress(this.glob);
         cbAddr.setRetries(-1);
         String dispatcherPlugin = info.get("mom.dispatcherPlugin", null);
         if (dispatcherPlugin != null)
            cbAddr.setDispatchPlugin(dispatcherPlugin);
         this.connectQos.addCallbackAddress(cbAddr);
      }
      log.info("Connecting with qos '" + this.connectQos.toXml() + "'");
      this.con = this.glob.getXmlBlasterAccess();
      this.con.connect(this.connectQos, this);

      // TODO cleanup in an own method and avoid unsubscribe and disconnect on shutdown ...
      if (this.subscribeKeyList.size() < 1)
         log.info("init: no subscription has been registered.");
      else
         log.info("init: " + this.subscribeKeyList.size() + " subscriptions have been registered.");
      for (int i=0; i < this.subscribeKeyList.size(); i++) {
         log.fine("init: subscribing '" + i + "' with key '" + this.subscribeKeyList.get(i) + "' and qos '" + this.subscribeQosList.get(i) + "'");
         this.con.subscribe((String)this.subscribeKeyList.get(i), (String)this.subscribeQosList.get(i), this);
      }
     
      // Make myself available
      info.putObject("org.xmlBlaster.contrib.dbwriter.mom.MomEventEngine", this);
      info.putObject("org.xmlBlaster.contrib.dbwatcher.mom.I_EventEngine", this);
   }

   public String update(String cbSessionId, UpdateKey updateKey, byte[] content, UpdateQos updateQos) throws XmlBlasterException {
      String timestamp = null;
      try {
         InputStream is = decompress(new ByteArrayInputStream(content), updateQos.getClientProperties());
         timestamp = "" + updateQos.getRcvTimestamp().getTimestamp();
         updateQos.getData().addClientProperty(ContribConstants.TIMESTAMP_ATTR, timestamp);
        
         if (this.eventHandler != null)
            this.eventHandler.update(updateKey.getOid(), is, updateQos.getClientProperties());
         else
            throw new Exception("update: No event handler has been registered, you must register one");
         return Constants.RET_OK;
      }
      catch (Exception ex) {
         if (ex instanceof XmlBlasterException) {
            String msg = ex.getMessage();
            if (msg.indexOf("SAXParseException") > -1) {
               // then try it again without uncompressing
               InputStream is = new ByteArrayInputStream(content);
               try {
                  if (eventHandler != null) {
                     eventHandler.update(updateKey.getOid(), is, updateQos.getClientProperties());
                     return Constants.RET_OK;
                  }
               }
               catch (Exception e) {
                  log.warning("Exception occured also when running uncompressed");
               }
            }
         }
         ex.printStackTrace();
         throw new XmlBlasterException(this.glob, ErrorCode.USER_UPDATE_HOLDBACK, "MomEventEngine.update", "user exception", ex);
      }
      catch (Throwable ex) {
         ex.printStackTrace();
         throw new XmlBlasterException(this.glob, ErrorCode.USER_UPDATE_HOLDBACK, "MomEventEngine.update", "user throwable", ex);
      }
   }


   /**
    * @param changeKey The topic of the message as a string.
    * @param message the content of the message to publish.
    * @þaram attrMap an attribute map which can be null. A single attribute
    * is currently used: qos, containing the qos literal.
    * @return the PublishQos as a string.
    */
   public String publish(String oid, byte[] message, Map attrMap) throws Exception {
      message = compress(message, attrMap, this.compressSize, null);
      String qos = null;
      if (attrMap != null)
         qos = (String)attrMap.get("qos");
      if (qos == null) {
         if (attrMap != null) {
            PublishQos pubQos = new PublishQos(this.glob);
            ClientPropertiesInfo tmpInfo = new ClientPropertiesInfo(pubQos.getData().getClientProperties(), null);
            InfoHelper.fillInfoWithEntriesFromMap(tmpInfo, attrMap);
            qos = pubQos.toXml();
         }
         else {
            qos = "<qos/>";
         }
      }
      PublishKey pubKey = new PublishKey(this.glob, oid);
      MsgUnit msg = new MsgUnit(this.glob, pubKey.toXml(), message, qos);
      return this.con.publish(msg).toXml();
   }

   public boolean registerAlertListener(I_Update update, Map attrs) throws Exception {
      if (this.eventHandler != null)
         return false;
      this.eventHandler = update;
      return true;
   }

   public void shutdown() {
      log.fine("Closing xmlBlaster connection");
      if (this.con != null && this.shutdownMom) {
         this.con.disconnect(null);
         this.con = null;
         this.glob = null;
      }
   }
  
  
   /**
    * @see org.xmlBlaster.contrib.I_ChangePublisher#getJmsSession()
    */
   public XBSession getJmsSession() {
      return new XBSession(this.glob, XBSession.AUTO_ACKNOWLEDGE, false);
   }

   /**
    * Compresses the message if needed.
    * @param buffer The buffer to compress
    * @param props The properties to update with the compressed flag (uncompressed size)
    * @param compressSizeLimit The limit for compression. If less than one no compression
    * is done. If the size of the buffer is less than this limit it is not compressed either.
    * @return the compressed buffer or the input buffer if no compression was needed.
    * @deprecated
    */
   public static byte[] compressOLD(byte[] buffer, Map props, int compressSizeLimit, String zipType) {
      if (compressSizeLimit <  1L)
         return buffer;
      if (buffer.length < compressSizeLimit)
         return buffer;
      int uncompressedLength = buffer.length;

      // check if not already compressed
      if (props != null && props.containsKey(DbWatcherConstants._COMPRESSION_TYPE)) {
         log.fine("The message is already compressed, will not compress it");
         return buffer;
      }
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      byte[] ret = null;
      try {
          GZIPOutputStream zippedStream = new GZIPOutputStream(baos);
          ObjectOutputStream objectOutputStream = new ObjectOutputStream(zippedStream);
          objectOutputStream.writeObject(buffer);
          objectOutputStream.flush();
          zippedStream.finish();
          ret = baos.toByteArray();
          objectOutputStream.close();
          if (ret.length >= uncompressedLength) {
             log.fine("The compressed size is bigger than the original. Will not compress since it does not make sense");
             return buffer;
          }
          if (props != null) {
             props.put(DbWatcherConstants._UNCOMPRESSED_SIZE, "" + uncompressedLength);
             props.put(DbWatcherConstants._COMPRESSION_TYPE, DbWatcherConstants.COMPRESSION_TYPE_GZIP);
          }
          return ret;
      }
      catch(IOException ex) {
         log.severe("An exception occured when compressing: '" + ex.getMessage() + "' will not compress");
         return buffer;
      }
   }

   /**
    * Compresses the message if needed.
    * @param buffer The buffer to compress
    * @param props The properties to update with the compressed flag (uncompressed size)
    * @param compressSizeLimit The limit for compression. If less than one no compression
    * is done. If the size of the buffer is less than this limit it is not compressed either.
    * @return the compressed buffer or the input buffer if no compression was needed.
    */
   public static byte[] compress(byte[] buffer, Map props, int compressSizeLimit, String zipType) {
      if (compressSizeLimit <  1L)
         return buffer;
      if (buffer.length < compressSizeLimit)
         return buffer;
      int uncompressedLength = buffer.length;

      // check if not already compressed
      if (props != null && props.containsKey(DbWatcherConstants._COMPRESSION_TYPE)) {
         log.fine("The message is already compressed, will not compress it");
         return buffer;
      }
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      byte[] ret = null;
      try {
          GZIPOutputStream zippedStream = new GZIPOutputStream(baos);
          zippedStream.write(buffer);
          zippedStream.finish();
          ret = baos.toByteArray();
          if (ret.length >= uncompressedLength) {
             log.fine("The compressed size is bigger than the original. Will not compress since it does not make sense");
             return buffer;
          }
          if (props != null) {
             props.put(DbWatcherConstants._UNCOMPRESSED_SIZE, "" + uncompressedLength);
             props.put(DbWatcherConstants._COMPRESSION_TYPE, DbWatcherConstants.COMPRESSION_TYPE_GZIP);
          }
          return ret;
      }
      catch(IOException ex) {
         log.severe("An exception occured when compressing: '" + ex.getMessage() + "' will not compress");
         return buffer;
      }
   }

   private final static String dumpProps(Map clientProperties) {
      if (clientProperties == null)
         return "";
      Iterator iter = clientProperties.values().iterator();
      StringBuffer buf = new StringBuffer(512);
      while (iter.hasNext()) {
         ClientProperty prop = (ClientProperty)iter.next();
         buf.append(prop.toXml()).append("\n");
      }
      return buf.toString();
   }
  
   /**
    *
    * @param buffer
    * @param clientProperties
    * @deprecated you should use the one with InputStream instead since less memory hungry (for big messages)
    * @return
    */
   public static byte[] decompressXX(byte[] buffer, Map clientProperties) {
      if (clientProperties == null)
         return buffer;
      Object obj = clientProperties.get(DbWatcherConstants._COMPRESSION_TYPE);
      if (obj == null) {
         log.fine("The client property '" + DbWatcherConstants._COMPRESSION_TYPE + "' was not found. Will not expand");
         return buffer;
      }
      if (obj instanceof String)
         obj = new ClientProperty(DbWatcherConstants._COMPRESSION_TYPE, null, null, (String)obj);
      ClientProperty prop = (ClientProperty)obj;
      String compressionType = prop.getStringValue().trim();
      if (DbWatcherConstants.COMPRESSION_TYPE_GZIP.equals(compressionType)) {
         obj = clientProperties.get(DbWatcherConstants._UNCOMPRESSED_SIZE);
         if (obj == null) {
            log.severe("Can not expand message since no uncompressed size defined (will return it unexpanded)");
            return buffer;
         }
         if (obj instanceof String)
            obj = new ClientProperty(DbWatcherConstants._UNCOMPRESSED_SIZE, null, null, (String)obj);
         prop = (ClientProperty)obj;
        
         ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
         byte[] ret = null;
         try {
             GZIPInputStream zippedStream = new GZIPInputStream(bais);
             ObjectInputStream objectInputStream = new ObjectInputStream(zippedStream);
             ret = (byte[])objectInputStream.readObject();
             objectInputStream.close();
             // in case we cascade it still works fine
             clientProperties.remove(DbWatcherConstants._COMPRESSION_TYPE);
             clientProperties.remove(DbWatcherConstants._UNCOMPRESSED_SIZE);
             return ret;
         }
         catch(IOException ex) {
            log.severe("An IOException occured when uncompressing. Will not expand: " + ex.getMessage() + ": props='" + dumpProps(clientProperties) + "' and content '" + new String(buffer) + "'");
            if (log.isLoggable(Level.FINE))
               ex.printStackTrace();
            return buffer;
         }
         catch(ClassNotFoundException ex) {
            log.severe("A ClassCastException occured when uncompressing. Will not expand: " + ex.getMessage());
            if (log.isLoggable(Level.FINE))
               ex.printStackTrace();
            return buffer;
         }
        
      }
      else {
         log.warning("The compression type '" + compressionType + "' is unknown: will not decompress");
         return buffer;
      }
   }

   public static InputStream decompress(InputStream is, Map clientProperties) {
      if (clientProperties == null)
         return is;
      Object obj = clientProperties.get(DbWatcherConstants._COMPRESSION_TYPE);
      if (obj == null) {
         log.fine("The client property '" + DbWatcherConstants._COMPRESSION_TYPE + "' was not found. Will not expand");
         return is;
      }
      if (obj instanceof String)
         obj = new ClientProperty(DbWatcherConstants._COMPRESSION_TYPE, null, null, (String)obj);
      ClientProperty prop = (ClientProperty)obj;
      String compressionType = prop.getStringValue().trim();
      if (DbWatcherConstants.COMPRESSION_TYPE_GZIP.equals(compressionType)) {
         obj = clientProperties.get(DbWatcherConstants._UNCOMPRESSED_SIZE);
         if (obj == null) {
            log.severe("Can not expand message since no uncompressed size defined (will return it unexpanded)");
            return is;
         }
         if (obj instanceof String)
            obj = new ClientProperty(DbWatcherConstants._UNCOMPRESSED_SIZE, null, null, (String)obj);
         prop = (ClientProperty)obj;
        
         try {
            GZIPInputStream ret = new GZIPInputStream(is);
            clientProperties.remove(DbWatcherConstants._COMPRESSION_TYPE);
            clientProperties.remove(DbWatcherConstants._UNCOMPRESSED_SIZE);
            return ret;
         }
         catch (IOException ex) {
            log.severe("An Exception occured when trying to decompress the stream, probably not gzipped");
            ex.printStackTrace();
            return is;
         }
      }
      return is;
   }
}
TOP

Related Classes of org.xmlBlaster.contrib.MomEventEngine

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.