Package org.xmlBlaster.util.xbformat

Source Code of org.xmlBlaster.util.xbformat.XmlScriptParser

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

import org.xmlBlaster.client.script.XmlScriptInterpreter;
import org.xmlBlaster.util.Global;
import org.xmlBlaster.util.XmlBlasterException;
import org.xmlBlaster.util.def.Constants;
import org.xmlBlaster.util.def.MethodName;
import org.xmlBlaster.util.def.ErrorCode;
import org.xmlBlaster.util.plugin.I_PluginConfig;
import org.xmlBlaster.util.MsgUnitRaw;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* XmlScriptParser class for XML formated messages. <br />
* This class creates and parses xml script messages which can be used to
* transfer over a email or socket connection. <br />
* XmlScriptParser instances may be reused, but are NOT reentrant (there are
* many 'global' variables) <br />
* Please read the requirement specification <a
* href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/client.script.html">The
* client.script requirement</a>
*
* @author xmlBlaster@marcelruff.info
* @see <a
*      href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/client.script.html">The
*      client.script requirement</a>
* @see <a
*      href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/protocol.socket.html#script">The
*      protocol.socket requirement used with scripting protocol.</a>
* @see <a
*      href="http://www.xmlBlaster.org/xmlBlaster/doc/examples/xmlScriptMsgExamples.txt">Some examples
*      of xmlScript messages.</a>
* @see <a
*      href="http://www.xmlBlaster.org/xmlBlaster/src/java/org/xmlBlaster/client/script/XmlBlasterScript.xsd">XSD For XmlScript Messages.</a>
*     
*/
public class XmlScriptParser extends XmlScriptInterpreter implements
      I_MsgInfoParser {
   private static Logger log = Logger
         .getLogger(XmlScriptParser.class.getName());

   private static final String ME = "xbformat.XmlScriptParser";

   private Global glob;

   public static final String XMLSCRIPT_EXTENSION = ".xml";

   public static final String XMLSCRIPT_ZLIB_EXTENSION = ".xmlz";

   public static final String XMLSCRIPT_MIMETYPE = "text/xmlBlasterScript";
  
   public static final String XMLSCRIPT_ZLIB_MIMETYPE = "application/xmlBlasterScriptz";
  
   /**
    *  If used by email, the InputStream finishes when the attaachment is read,
    *  if used over socket, we need to terminate the script with a null byte
    */
   private boolean isNullTerminated;
  
   /** <?xml version='1.0' encoding='UTF-8'?> */
   private String xmlDecl;
  
   private boolean sendResponseSessionId;
   private boolean sendResponseRequestId;

   /**
    *  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
    *   xsi:noNamespaceSchemaLocation='xmlBlasterPublish.xsd'
   */
   private String schemaDecl;
  
   static {
      MsgInfoParserFactory.instance().register(XMLSCRIPT_EXTENSION, XmlScriptParser.class.getName());
      MsgInfoParserFactory.instance().register(XMLSCRIPT_ZLIB_EXTENSION, XmlScriptParser.class.getName());
      MsgInfoParserFactory.instance().register(XMLSCRIPT_MIMETYPE, XmlScriptParser.class.getName());
      MsgInfoParserFactory.instance().register(XMLSCRIPT_ZLIB_MIMETYPE, XmlScriptParser.class.getName());
   }

   /**
    * If not null somebody wants to be notified about the current bytes send
    * over socket
    */
   private I_ProgressListener progressListener;

   private ArrayList msgInfoParsed;

   public XmlScriptParser() {
   }

   public void init(Global glob, I_ProgressListener progressListener,
         I_PluginConfig pluginConfig) throws XmlBlasterException {
      this.glob = glob;
      this.progressListener = progressListener;
      this.xmlDecl = glob.get("xmlDeclaration", (String)null, null, pluginConfig);
      this.schemaDecl = glob.get("schemaDeclaration", (String)null, null, pluginConfig);
      this.sendResponseSessionId = glob.get("sendResponseSessionId", true, null, pluginConfig);
      this.sendResponseRequestId = glob.get("sendResponseRequestId", true, null, pluginConfig);
      this.isNullTerminated = glob.get("isNullTerminated", false, null, pluginConfig);
      super.sendSimpleExceptionFormat = glob.get("sendSimpleExceptionFormat", false, null, pluginConfig);
      super.forceReadable = glob.get("forceReadable", false, null, pluginConfig);
      super.inhibitContentCDATAWrapping = glob.get(Constants.INHIBIT_CONTENT_CDATA_WRAPPING, false, null, pluginConfig);
      super.initialize(glob, null, null);
   }

   /**
    * Get a specific extension for this format.
    * @return For example
    *  XMLSCRIPT_MIMETYPE = "text/xmlBlasterScript" or
    *  XMLSCRIPT_MIMETYPE_ZLIB = "text/xmlBlasterScriptz"
    */
   public String getMimetype(boolean isCompressed) {
      return (isCompressed) ? XMLSCRIPT_ZLIB_MIMETYPE : XMLSCRIPT_MIMETYPE;
   }

   /**
    * @param isCompressed
    *           true/false
    * @return XMLSCRIPT_EXTENSION = ".xml"; XMLSCRIPT_ZLIB_EXTENSION = ".xmlz";
    */
   public final String getExtension(boolean isCompressed) {
      return (isCompressed) ? XMLSCRIPT_ZLIB_EXTENSION : XMLSCRIPT_EXTENSION;
   }

   /**
    * This parses the raw message from an InputStream (typically from a email or
    * a socket). Use the get...() methods to access the data.
    * <p />
    * This method blocks until a message arrives
    */
   public final MsgInfo[] parse(InputStream in) throws IOException, XmlBlasterException {
      if (log.isLoggable(Level.FINER))
         log.finer("Entering parse()");
     
      MsgInfo[] msgInfos = new MsgInfo[0];

      if (this.isNullTerminated) {
         // If bytes are coming over a socket, we need to distinguish
         // one script from the next one: Here we do it by a ZERO byte after
         // each script.
         // If "in" is coming from an email attachment, it terminates automatically
         // after the script, so we don't enter this "if" statement
         try {
            ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
            while (true) {
               int bt = in.read();
               if (bt == -1) { // EOF
                  throw new IOException(ME + ": Got EOF");
               }
               if (bt == 0) break;
               out.write(bt);
            }
            in = new ByteArrayInputStream(out.toByteArray()); // Now "in" contains exactly one script
            if (log.isLoggable(Level.FINEST)) log.finest("Got script [" + new String(out.toByteArray()) + "]");
         } catch (IOException e) {
            throw e;
         } catch (Exception e) {
            throw new XmlBlasterException(glob, ErrorCode.INTERNAL_UNKNOWN, ME, "Socket connection failure", e);
         }
      }
     
      this.msgInfoParsed = new ArrayList();

      Reader reader = new InputStreamReader(in);
      super.parse(reader);
      /*
      byte[] buf = new byte[100];
      in.read(buf);
      //reader.read(buf);
      System.out.println("XmlScriptParser:" + new String(buf));
      //super.parse(reader);
      
       */
      msgInfos = (MsgInfo[])this.msgInfoParsed.toArray(new MsgInfo[this.msgInfoParsed.size()]);
     
      if (this.progressListener != null) {
         long size = 0;
         String text = (msgInfos.length > 0) ? msgInfos[0].getMethodNameStr() : "XmlScript";
         for (int i=0; i<msgInfos.length; i++)
            size += msgInfos[i].getUserDataLen();
         this.progressListener.progressRead(text, size, size);
      }

      if (log.isLoggable(Level.FINE))
         log.fine("Leaving parse(), message successfully parsed");
      this.msgInfoParsed = null;
      return msgInfos;
   }

   /**
    * Called during XML parsing.
    */
   public void setProperty(String key, String value) throws XmlBlasterException {
      this.glob.getProperty().set(key, value);
   }
  
   /**
    * Called during XML parsing.
    */
   public boolean fireMethod(MethodName methodName,
         String sessionId, String requestId, byte type)
         throws XmlBlasterException {
      MsgInfo msgInfo = new MsgInfo(this.glob);
      msgInfo.setMsgInfoParser(this);
      if (msgInfo.getNumMessages() > 0) {
         log.severe("Multiple method invocation in one message is not supported, we ignore "
                     + methodName.toString());
         return false;
      }
      if (super.messageList != null && super.messageList.size() > 0) {
         // MethodName.PUBLISH_ARR and PUBLISH_ONEWAY
         log.severe("Sending message arrays with '" + methodName.toString() + "' is not implemented");
         return false;
      }
     
     
      MsgUnitRaw msgUnitRaw = new MsgUnitRaw(super.key.toString(),
            super.contentData, super.qos.toString());
      msgInfo.setMethodName(methodName);
      msgInfo.setSecretSessionId(sessionId);
      msgInfo.setRequestId(requestId);
      msgInfo.setType(type);
      msgInfo.addMessage(msgUnitRaw);
      this.msgInfoParsed.add(msgInfo);
      return true;
   }

   /**
    * Returns a XML data string.
    */
   public final byte[] createRawMsg(MsgInfo msgInfo) throws XmlBlasterException {
      try {
         long len = msgInfo.getUserDataLen() + 500;
         ByteArray out = new ByteArray((int) len);
        
         boolean isResponseOrException =
              msgInfo.getType() == MsgInfo.RESPONSE_BYTE ||
              msgInfo.getType() == MsgInfo.EXCEPTION_BYTE;
        
         String sessionId = msgInfo.getSecretSessionId();
         if (isResponseOrException && !this.sendResponseSessionId)
            sessionId = null;
        
         String requestId = msgInfo.getRequestId();
         if (isResponseOrException && !this.sendResponseRequestId)
            requestId = null;
        
         super.serialize(msgInfo.getMethodName(),
                         sessionId,
                         requestId,
                         msgInfo.getMessageArr(),
                         this.xmlDecl, null, this.schemaDecl,
                         out, msgInfo.getType());
         if (this.progressListener != null) {
            this.progressListener.progressWrite(msgInfo.getMethodNameStr(),
                  len, len);
         }
         return out.toByteArray();
      } catch (IOException e) {
         String text = "Creation of message failed.";
         log.warning(text + " " + e.toString());
         throw new XmlBlasterException(glob, ErrorCode.INTERNAL_UNKNOWN, ME,
               text, e);
      }
   }

   /**
    * Get the raw messages as a string, for tests and for dumping only
    *
    * @return The stringified message, null bytes are replaced by '*'
    */
   public final String toLiteral(MsgInfo msgInfo) throws XmlBlasterException {
      return toLiteral(createRawMsg(msgInfo));
   }

   public final String toLiteral(byte[] arr) {
      //return new String(arr);
      byte[] tmp = new byte[arr.length];
      for (int ii=0; ii<arr.length; ii++) {
         if (arr[ii] == 0)
            tmp [ii] = (byte)'*';
         else
            tmp[ii] = arr[ii];
      }
      return new String(tmp);
   }

   /**
    * java org.xmlBlaster.util.xbformat.XmlScriptParser
    */
   public static void main(String[] args) {
      try {
         Global glob = Global.instance();
         XmlScriptParser parser = new XmlScriptParser();
         {
            System.out.println("TEST0 PING");
            parser.init(glob, null, null);
            MsgInfo msgInfo = new MsgInfo(glob, MsgInfo.RESPONSE_BYTE, "12",
                  MethodName.PING, "secret", null);
            byte[] content = null;
            String qos = null;
            MsgUnitRaw msg = new MsgUnitRaw(null, content, qos);
            msgInfo.addMessage(msg);
            byte[] raw = parser.createRawMsg(msgInfo);
            System.out.println(parser.toLiteral(raw));

            PipedInputStream in = new PipedInputStream();
            PipedOutputStream out = new PipedOutputStream(in);
            out.write(raw);
            out.flush();
            out.close();
            MsgInfo msgInfoNew = parser.parse(in)[0];
            byte[] rawNew = parser.createRawMsg(msgInfoNew);
            System.out.println("Parsed and dumped again:" + parser.toLiteral(rawNew));
         }
         {
            System.out.println("TEST1 SHOULD FORCE BASE64");
            parser.init(glob, null, null);
            MsgInfo msgInfo = new MsgInfo(glob, MsgInfo.INVOKE_BYTE, "12",
                  MethodName.PUBLISH, "secret", null);
            byte[] content = "hello&bye]]>".getBytes();
            //content[3] = 0;
            MsgUnitRaw msg = new MsgUnitRaw("<key oid='hello'/>", content, "<qos></qos>");
            msgInfo.addMessage(msg);
            byte[] raw = parser.createRawMsg(msgInfo);
            System.out.println("Initial creation:" + parser.toLiteral(raw));

            PipedInputStream in = new PipedInputStream();
            PipedOutputStream out = new PipedOutputStream(in);
            out.write(raw);
            out.flush();
            out.close();
            MsgInfo msgInfoNew = parser.parse(in)[0];
            byte[] rawNew = parser.createRawMsg(msgInfoNew);
            System.out.println("Parsed and dumped again:" + parser.toLiteral(rawNew));
         }
         {
            System.out.println("TEST2 SHOULD KEEP LITERAL STRING");
            parser.init(glob, null, null);
            MsgInfo msgInfo = new MsgInfo(glob, MsgInfo.INVOKE_BYTE, "12",
                  MethodName.PUBLISH, "secret", null);
            byte[] content = "Hello World!".getBytes();
            MsgUnitRaw msg = new MsgUnitRaw("<key oid='hello'/>", content, "<qos></qos>");
            msgInfo.addMessage(msg);
            byte[] raw = parser.createRawMsg(msgInfo);
            System.out.println("Initial creation:" + parser.toLiteral(raw));

            PipedInputStream in = new PipedInputStream();
            PipedOutputStream out = new PipedOutputStream(in);
            out.write(raw);
            out.flush();
            out.close();
            MsgInfo msgInfoNew = parser.parse(in)[0];
            byte[] rawNew = parser.createRawMsg(msgInfoNew);
            System.out.println("Parsed and dumped again:" + parser.toLiteral(rawNew));
         }
         {
            System.out.println("TEST3");
            parser.init(glob, null, null);
            MsgInfo msgInfo = new MsgInfo(glob, MsgInfo.RESPONSE_BYTE, "12",
                  MethodName.PUBLISH, "secret", null);
            byte[] content = null;
            String qos = "<qos>" +
                         "\n  <key oid='1'/>" +
                         "\n  <rcvTimestamp nanos='1131654994574000000'/>" +
                         "\n  <isPublish/>" +
                         "\n</qos>";
            MsgUnitRaw msg = new MsgUnitRaw(null, content, qos);
            msgInfo.addMessage(msg);
            byte[] raw = parser.createRawMsg(msgInfo);
            System.out.println(parser.toLiteral(raw));
         }
      } catch (Exception e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }

   /**
    *  If used by email, the InputStream finishes when the attaachment is read,
    *  if used over socket, we need to terminate each script with a null byte
    */
   public boolean isNullTerminated() {
      return isNullTerminated;
   }
}
TOP

Related Classes of org.xmlBlaster.util.xbformat.XmlScriptParser

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.