Package org.xmlBlaster.protocol.xmlrpc

Source Code of org.xmlBlaster.protocol.xmlrpc.CallbackXmlRpcDriver

/*------------------------------------------------------------------------------
Name:      CallbackXmlRpcDriver.java
Project:   xmlBlaster.org
Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
------------------------------------------------------------------------------*/
package org.xmlBlaster.protocol.xmlrpc;

import java.util.logging.Logger;
import java.util.logging.Level;
import org.xmlBlaster.util.Global;
import org.xmlBlaster.util.XmlBlasterException;
import org.xmlBlaster.util.def.Constants;
import org.xmlBlaster.util.def.ErrorCode;
import org.xmlBlaster.protocol.I_CallbackDriver;
import org.xmlBlaster.util.protocol.xmlrpc.XmlRpcClientFactory;
import org.xmlBlaster.util.qos.address.CallbackAddress;
import org.xmlBlaster.util.xbformat.I_ProgressListener;
import org.xmlBlaster.util.MsgUnitRaw;
import org.xmlBlaster.client.protocol.xmlrpc.XmlRpcConnection; // The XmlRpcException to XmlBlasterException converter

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;

import java.io.IOException;
import java.util.Properties;
import java.util.Vector;

/**
* This object sends a MsgUnitRaw back to a client using XMLRPC interface, in
* the same JVM.
* <p>
* The I_CallbackDriver.update() method of the client will be invoked
*
* @author Michele Laghi (michele@laghi.eu)
* @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a>.
* @see org.xmlBlaster.protocol.xmlrpc.XmlRpcDriver
*/
public class CallbackXmlRpcDriver implements I_CallbackDriver {
   private String ME = "CallbackXmlRpcDriver";
   private Global glob = null;
   private static Logger log = Logger.getLogger(CallbackXmlRpcDriver.class.getName());
   private CallbackAddress callbackAddress = null;
   private XmlRpcClient xmlRpcClient = null;

   private CallbackXmlRpcDriverSingleChannel singleChannelDriver;
   private boolean contentAsString;
   private boolean initializing = true;
  
   /** Get a human readable name of this driver */
   public String getName() {
      return ME;
   }

   /**
    * Access the xmlBlaster internal name of the protocol driver.
    * @return "XMLRPC"
    */
   public String getProtocolId() {
      return "XMLRPC";
   }

   /** Enforced by I_Plugin */
   public String getType() {
      return getProtocolId();
   }

   /** Enforced by I_Plugin */
   public String getVersion() {
      return "1.0";
   }

   /**
    * This method is called by the PluginManager (enforced by I_Plugin).
    * @see org.xmlBlaster.util.plugin.I_Plugin#init(org.xmlBlaster.util.Global,org.xmlBlaster.util.plugin.PluginInfo)
    */
   public void init(org.xmlBlaster.util.Global glob, org.xmlBlaster.util.plugin.PluginInfo pluginInfo) {
      initializing = true;
      if (log.isLoggable(Level.FINE))
         log.fine("init invoked");
   }

   /**
    * Get the address how to access this driver.
    * @return "http://server.mars.universe:8080/"
    */
   public String getRawAddress() {
      return callbackAddress.getRawAddress();
   }

   /**
    * Get callback reference here.
    * <p />
    * This method is enforced by interface I_CallbackDriver and is called by
    * xmlBlaster after instantiation of this class, telling us
    * the address to callback.
    * @param  callbackAddress Contains the stringified XMLRPC callback handle of
    *                      the client
    */
   public void init(Global global, CallbackAddress cbAddress) throws XmlBlasterException {
      initializing = true;
      this.glob = global;
      // workaround to pass this callback driver object to the other side (the AuthenticateImpl)
      glob.putInWeakRegistry(Thread.currentThread(), this);
      this.callbackAddress = cbAddress;
      if (callbackAddress != null)
         contentAsString = callbackAddress.getEnv("contentAsString", false).getValue();
     
      org.xmlBlaster.engine.ServerScope
         engineGlob = (org.xmlBlaster.engine.ServerScope)glob.getObjectEntry(Constants.OBJECT_ENTRY_ServerScope);
      if (engineGlob == null)
         throw new XmlBlasterException(this.glob, ErrorCode.INTERNAL_UNKNOWN, ME + ".init", "could not retreive the ServerNodeScope. Am I really on the server side ?");
   }


   public void postInit(String sessionId, XmlBlasterImpl xblImpl, boolean singleChannel, boolean useCDATA) throws XmlBlasterException {
      try {
         if (singleChannel) {
            singleChannelDriver = new CallbackXmlRpcDriverSingleChannel();
            singleChannelDriver.init(glob, callbackAddress);
            singleChannelDriver.register(sessionId, xblImpl);
         }
         else {
            try {
               xmlRpcClient = XmlRpcClientFactory.getXmlRpcClient(glob, null, callbackAddress, useCDATA);
               if (log.isLoggable(Level.FINE))
                  log.fine("Accessing client callback web server using given url=" + callbackAddress.getRawAddress());
            }
            catch (IOException ex1) {
               throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "init() failed", ex1);
            }
         }
      }
      finally {
         initializing = false;
      }
   }
  
   /**
    * This sends the update to the client.
    * <p />
    * This method is enforced by interface I_CallbackDriver and is called by
    * @return Clients should return a qos as follows.
    *         An empty qos string "" is valid as well and
    *         interpreted as OK
    * <pre>
    *  &lt;qos>
    *     &lt;state id='OK'/>
    *  &lt;/qos>
    * </pre>
    * @exception e.id="CallbackFailed", should be caught and handled appropriate
    */
   public final String[] sendUpdate(MsgUnitRaw[] msgArr) throws XmlBlasterException {

      // wait until initialization process has been fully completed since we don't know yet how the
      // client will have it: singleChannel or not
      long count = 0L;
      while (initializing) {
         try {
            Thread.sleep(50L);
            count++;
            if (count > 2400L) // try maximum 2 minutes
               break;
         }
         catch (Exception ex) {
         }
      }
     
     
      if (singleChannelDriver != null)
         return singleChannelDriver.sendUpdate(msgArr);
     
      if (msgArr == null || msgArr.length < 1) throw new XmlBlasterException(glob, ErrorCode.INTERNAL_ILLEGALARGUMENT, ME, "Illegal update argument");

      if (xmlRpcClient == null) {
         throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "The xmlRpcClient on the server side is null");
      }
      // transform the msgUnits to Vectors
      try {
         String[] retVal = new String[msgArr.length];
         for (int ii=0; ii < msgArr.length; ii++) {
            Vector<Object> args = new Vector<Object>();
            MsgUnitRaw msgUnit = msgArr[ii];
            args.addElement(callbackAddress.getSecretSessionId());
            args.addElement(msgUnit.getKey());
            if (contentAsString)
               args.addElement(msgUnit.getContentStr());
            else
               args.addElement(msgUnit.getContent());
            args.addElement(msgUnit.getQos());

            if (log.isLoggable(Level.FINE)) log.fine("Send an update to the client ...");

            String tmp = (String)xmlRpcClient.execute("$default.update", args);

            final String XMLSCRIPT_UPDATE_TAG_START = "<update type='R'>";
            final String XMLSCRIPT_UPDATE_TAG_END = "</update>";
            int pos = tmp.indexOf(XMLSCRIPT_UPDATE_TAG_START);
            if (pos > -1) {
               tmp = tmp.substring(pos + XMLSCRIPT_UPDATE_TAG_START.length());
               pos = tmp.indexOf(XMLSCRIPT_UPDATE_TAG_END);
               if (pos > -1)
                  tmp = tmp.substring(0, pos);
               tmp = tmp.trim();
            }
            retVal[ii] = tmp;
            if (log.isLoggable(Level.FINE))
               log.fine("Successfully sent message update to '" + callbackAddress.getSecretSessionId() + "'");
         }
         return retVal;
      }
      catch (XmlRpcException ex) {
         int start = ex.toString().indexOf("errorCode=");
        
         // org.apache.xmlrpc.XmlRpcException: java.lang.Exception: RPC handler object not found for "update": no default handler registered.
         boolean isServerSide = ex.toString().indexOf("no default handler registered") != -1;
         if (isServerSide) {
            throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, ex.toString());
         }
        
         if (start == -1) {
            ex.printStackTrace();
            String str = "Sending message to " + ((callbackAddress!=null)?callbackAddress.getRawAddress():"?") + " failed, received unexpected exception format from client";
            XmlBlasterException e2 = new XmlBlasterException(glob, ErrorCode.USER_UPDATE_ERROR, ME, str, ex);
            e2.isServerSide(false);
            e2.setLocation("client");
            throw e2;
         }
         XmlBlasterException e = XmlRpcConnection.extractXmlBlasterException(glob, ex, ErrorCode.USER_UPDATE_ERROR, ME+".sendUpdate");
         e.isServerSide(false);
         e.setLocation(this.getClass().getName());
         String str = "Sending message to " + ((callbackAddress!=null)?callbackAddress.getRawAddress():"?") + " failed in client: " + ex.toString();
         if (log.isLoggable(Level.FINE)) log.fine(str);
         // The remote client is only allowed to throw USER* errors!
         throw XmlBlasterException.tranformCallbackException(e);
      }
      catch (Throwable e) { // e.g. IOException
         String str = "Sending message to " + ((callbackAddress!=null)?callbackAddress.getRawAddress():"?") + " failed: " + e.toString();
         if (log.isLoggable(Level.FINE)) log.fine(str);
         e.printStackTrace();
         throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "CallbackFailed", e);
      }
   }

   /**
    * The oneway variant, without return value.
    * @exception XmlBlasterException Is never from the client (oneway).
    */
   public void sendUpdateOneway(MsgUnitRaw[] msgArr) throws XmlBlasterException {
      if (singleChannelDriver != null) {
         singleChannelDriver.sendUpdateOneway(msgArr);
         return;
      }
      if (msgArr == null || msgArr.length < 1)
         throw new XmlBlasterException(glob, ErrorCode.INTERNAL_ILLEGALARGUMENT, ME, "Illegal sendUpdateOneway() argument");

      // transform the msgUnits to Vectors
      try {
         for (int ii=0; ii < msgArr.length; ii++) {
            Vector<Object> args = new Vector<Object>();
            MsgUnitRaw msgUnit = msgArr[ii];
            args.addElement(callbackAddress.getSecretSessionId());
            args.addElement(msgUnit.getKey());
            if (contentAsString)
               args.addElement(msgUnit.getContentStr());
            else
               args.addElement(msgUnit.getContent());
            args.addElement(msgUnit.getQos());
         
            if (log.isLoggable(Level.FINE)) log.fine("Send an updateOneway to the client ...");

            xmlRpcClient.execute("$default.updateOneway", args);

            if (log.isLoggable(Level.FINE)) log.fine("Successfully sent message update to '" + callbackAddress.getSecretSessionId() + "'");
         }
      }
      catch (XmlRpcException ex) { // oneway: the client never sends an XmlBlasterException
         String str = "Sending oneway message to " + callbackAddress.getRawAddress() + " failed in client: " + ex.toString();
         if (log.isLoggable(Level.FINE)) log.fine(str);
         throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, ex.toString());
      }
      catch (Throwable e) {
         String str = "Sending oneway message to " + callbackAddress.getRawAddress() + " failed: " + e.toString();
         if (log.isLoggable(Level.FINE)) log.fine(str);
         //e.printStackTrace();
         throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "CallbackFailed", e);
      }
   }

   /**
    * Ping to check if callback server is alive.
    * This ping checks the availability on the application level.
    * @param qos Currently an empty string ""
    * @return    Currently an empty string ""
    * @exception XmlBlasterException If client not reachable
    */
   public final String ping(String qos) throws XmlBlasterException {
      if (singleChannelDriver != null)
         return singleChannelDriver.ping(qos);
     
      if (xmlRpcClient == null)
         return "OK"; // make the initial ping happy since it is not completely set up yet
      try {
         Vector args = new Vector();
         args.addElement(qos);
         String ret = (String)xmlRpcClient.execute("$default.ping", args);
        
         final String XMLSCRIPT_PING_TAG_START = "<ping type='R'>";
         final String XMLSCRIPT_PING_TAG_END = "</ping>";
         int pos = ret.indexOf(XMLSCRIPT_PING_TAG_START);
         if (pos > -1) {
            ret = ret.substring(pos + XMLSCRIPT_PING_TAG_START.length());
            pos = ret.indexOf(XMLSCRIPT_PING_TAG_END);
            if (pos > -1)
               ret = ret.substring(0, pos);
            ret = ret.trim();
         }

         return ret;
      }
      catch (XmlRpcException ex) {
         String str = "Sending ping to " + callbackAddress.getRawAddress() + " failed in client: " + ex.toString();
         if (log.isLoggable(Level.FINEST)) log.finest(str);
         throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, ex.toString());
      }
      catch (Throwable e) {
         if (!(e instanceof IOException)) // IOException: callback connection refused if client is away, is normal behavior
            e.printStackTrace();
         throw new XmlBlasterException(glob, ErrorCode.COMMUNICATION_NOCONNECTION, ME, "XmlRpc callback ping failed", e);
      }
   }

   public I_ProgressListener registerProgressListener(I_ProgressListener listener) {
      if (log.isLoggable(Level.FINE))
         log.fine("Registering I_ProgressListener is not supported with this protocol plugin");
      return null;
   }

   /**
    * This method shuts down the driver.
    * <p />
    */
   public void shutdown() {
      //if (xmlRpcClient != null) xmlRpcClient.shutdown(); method is missing in XmlRpc package !!!
      initializing = false;
      if (singleChannelDriver != null) {
         singleChannelDriver.shutdown();
         singleChannelDriver = null;
      }
      callbackAddress = null;
      xmlRpcClient = null;
      if (log.isLoggable(Level.FINE)) log.fine("Shutdown implementation is missing");
   }

   /**
    * @return true if the plugin is still alive, false otherwise
    */
   public boolean isAlive() {
      return true;
   }

   public CallbackXmlRpcDriverSingleChannel getSingleChannelDriver() {
      return singleChannelDriver;
   }

  

}
TOP

Related Classes of org.xmlBlaster.protocol.xmlrpc.CallbackXmlRpcDriver

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.