Package org.xmlBlaster.protocol.socket

Source Code of org.xmlBlaster.protocol.socket.SocketDriver$UDPListener

/*------------------------------------------------------------------------------
Name:      SocketDriver.java
Project:   xmlBlaster.org
Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
Comment:   SocketDriver class to invoke the xmlBlaster server in the same JVM.
------------------------------------------------------------------------------*/
package org.xmlBlaster.protocol.socket;

import java.util.logging.Logger;
import java.util.logging.Level;
import org.xmlBlaster.util.Global;
import org.xmlBlaster.util.XmlBlasterException;
import org.xmlBlaster.util.context.ContextNode;
import org.xmlBlaster.util.def.ErrorCode;
import org.xmlBlaster.util.def.Constants;
import org.xmlBlaster.engine.qos.AddressServer;
import org.xmlBlaster.protocol.I_Authenticate;
import org.xmlBlaster.protocol.I_XmlBlaster;
import org.xmlBlaster.protocol.I_Driver;
import org.xmlBlaster.util.plugin.I_PluginConfig;
import org.xmlBlaster.util.plugin.PluginInfo;
import org.xmlBlaster.util.protocol.socket.SocketUrl;
import org.xmlBlaster.util.xbformat.MsgInfo;

import java.net.DatagramSocket;
import java.net.DatagramPacket;
import java.io.IOException;

import java.net.ServerSocket;
import java.net.Socket;

import java.util.Set;
import java.util.HashSet;

import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.io.ByteArrayInputStream;
import java.io.InputStream;


/**
* Socket driver class to invoke the xmlBlaster server over a native message format
* <p />
* This "SOCKET:" driver needs to be registered in xmlBlaster.properties
* and will be started on xmlBlaster startup, for example:
* <pre>
* ProtocolPlugin[SOCKET][1.0]=org.xmlBlaster.protocol.socket.SocketDriver
*
* CbProtocolPlugin[SOCKET][1.0]=org.xmlBlaster.protocol.socket.CallbackSocketDriver
* </pre>
*
* The variable plugin/socket/port (default 7607) sets the socket server port,
* you may change it in xmlBlaster.properties or on command line:
* <pre>
* java -jar lib/xmlBlaster.jar  -plugin/socket/port 9090
* </pre>
*
* The interface I_Driver is needed by xmlBlaster to instantiate and shutdown
* this driver implementation.
* <p />
* All adjustable parameters are explained in {@link org.xmlBlaster.protocol.socket.SocketDriver#usage()}
* @author <a href="mailto:xmlBlaster@marcelruff.info">Marcel Ruff</a>
* @author <a href="mailto:bpoka@axelero.hu">Balázs Póka</a> (SSL embedding, zlib compression)
*
* @see org.xmlBlaster.util.xbformat.MsgInfo
* @see <a href="http://www.xmlBlaster.org/xmlBlaster/doc/requirements/protocol.socket.html">The protocol.socket requirement</a>
*/
public class SocketDriver extends Thread implements I_Driver /* which extends I_Plugin */, SocketDriverMBean
{
   private String ME = "SocketDriver";
   /** The global handle */
   private Global glob;
   private static Logger log = Logger.getLogger(SocketDriver.class.getName());
   /** The singleton handle for this authentication server */
   private I_Authenticate authenticate;
   /** The singleton handle for this xmlBlaster server */
   private I_XmlBlaster xmlBlasterImpl;
   /** The socket address info object holding hostname (useful for multi homed hosts) and port */
   private SocketUrl socketUrl;
   /** The socket server */
   private ServerSocket listen = null;
   /** The URL which clients need to use to access this server, e.g. "server.mars.univers:6701" */
   private DatagramSocket socketUDP = null;
   /** State of server */
   private Thread listenerUDP;

   private int sslMarker;

   private boolean running = true;
   private boolean runningUDP = true;
   private boolean listenerReady = false;
   private boolean listenerReadyUDP = false;
   /** Remember all client connections */
   private Set handleClientSet = new HashSet();

   private Map/*<secretSessionId, HandleClient>*/ handleClientMap = new HashMap();

   /** The address configuration */
   private AddressServer addressServer;

   private PluginInfo pluginInfo;

   private boolean startUdpListener = false;

   /**
    * Setting by plugin configuration, see xmlBlasterPlugins.xml, for example
    * <br />
    *  &lt;attribute id='useUdpForOneway'>true&lt;/attribute>
    */
   private boolean useUdpForOneway = false;

   /** My JMX registration */
   protected Object mbeanHandle;
   protected ContextNode contextNode;

   protected boolean isShutdown;

   void addClient(String sessionId, HandleClient h) {
      synchronized(handleClientMap) {
         handleClientMap.put(sessionId, h);
      }
   }

   HandleClient getClient(String sessionId) {
      synchronized(handleClientMap) {
         return (HandleClient) handleClientMap.get(sessionId);
      }
   }

   public I_PluginConfig getPluginConfig() {
      return this.pluginInfo;
   }

   /**
    * There is exactly one UDP listener thread which receives datagrams for all clients.
    * The datagrams are forwarded to the correct client with the sessionId
    * Only the methods publishOneway() and updateOneway() may use UDP, you can
    * choose TCP or UDP for those messages with the
    * <tt>plugin/socket/useUdpForOneway</tt> setting
    */
   class UDPListener
       implements Runnable {
      static final int MAX_PACKET_SIZE = 1024 * 10;
      public void run() {
         try {
            try {
               socketUDP = new DatagramSocket(socketUrl.getPort(), socketUrl.getInetAddress());
            }
            catch (java.net.SocketException e) {
               log.severe("Cannot open UDP socket '" + socketUrl.getUrl() + "' : " + e.toString());
               return;
            }

            int threadPrio = getAddressServer().getEnv("threadPrio", Thread.NORM_PRIORITY).getValue();
            try {
               Thread.currentThread().setPriority(threadPrio);
               if (log.isLoggable(Level.FINE))
                  log.fine("-" + getEnvPrefix() + "threadPrio " + threadPrio);
            }
            catch (IllegalArgumentException e) {
               log.warning("Your -" + getEnvPrefix() + "threadPrio " + threadPrio + " is out of range, we continue with default setting " + Thread.NORM_PRIORITY);
            }

            log.info("Started successfully " + getType() + " UDP driver on '" + socketUrl.getUrl() + "'");

            byte packetBuffer[] = new byte[MAX_PACKET_SIZE];
            DatagramPacket packet = new DatagramPacket(packetBuffer, packetBuffer.length);
            MsgInfo receiver = null;
            listenerReadyUDP = true;
            while (runningUDP) {
               try {
                  socketUDP.receive(packet);
               }
               catch (IOException e) {
                  if (e.toString().indexOf("closed") == -1) {
                     log.severe("Error receiving packet from '" + socketUrl.getUrl() + "' : " + e.toString());
                  }
                  else {
                     if (log.isLoggable(Level.FINE)) log.fine("UDP datagram socket shutdown '" + socketUrl.getUrl() + "' : " + e.toString());
                  }
                  return;
               }
               if (log.isLoggable(Level.FINE))
                  log.fine("UDP packet arrived, size=" + packet.getLength() + " bytes");
               if (!runningUDP) {
                  log.info("Closing server '" + socketUrl.getUrl() + "'");
                  return;
               }
               int actualSize = packet.getLength();
               if (packet.getLength() > MAX_PACKET_SIZE) {
                  log.warning("Packet has been truncated, size=" + packet.getLength() + ", MAX_PACKET_SIZE=" + MAX_PACKET_SIZE);
                  actualSize = MAX_PACKET_SIZE;
               }
               InputStream iStream = new ByteArrayInputStream(packet.getData(), 0, actualSize);
               try {
                  receiver = MsgInfo.parse(glob, null, iStream, null/*getMsgInfoParserClassName()*/, getPluginConfig())[0];
               }
               catch (Throwable e) {
                  log.severe("Error parsing data from UDP packet: " + e);
                  continue;
               }
               String sessionId = receiver.getSecretSessionId();
               HandleClient hh = getClient(sessionId);
               if (hh == null)
                  log.severe("Request from unknown client, sessionId: " + sessionId);
               else
                  hh.handleMessage(receiver, true);
            } // while (runningUDP) {
         }

         finally {
            listenerReadyUDP = false;
            if (socketUDP != null) {
               socketUDP.close();
               socketUDP = null;
            }
         }
      }
   }

   /**
    * Creates the driver.
    * Note: getName() is enforced by interface I_Driver, but is already defined in Thread class
    */
   public SocketDriver() {
      super("XmlBlaster.SocketDriver");
      setDaemon(true);
   }

   /**
    * Access the xmlBlaster internal name of the protocol driver.
    * @return The configured [type] in xmlBlaster.properties, defaults to "SOCKET"
    */
   public String getProtocolId() {
      return (this.pluginInfo == null) ? "SOCKET" : this.pluginInfo.getType();
   }

   /**
    * Enforced by I_Plugin
    * @return The configured type in xmlBlaster.properties, defaults to "SOCKET"
    */
   public String getType() {
      return getProtocolId();
   }

   /**
    * The command line key prefix
    * @return The configured type in xmlBlasterPlugins.xml, defaults to "plugin/socket"
    */
   public String getEnvPrefix() {
      return (addressServer != null) ? addressServer.getEnvPrefix() : "plugin/"+getType().toLowerCase();
   }

   /** Enforced by I_Plugin */
   public String getVersion() {
      return (this.pluginInfo == null) ? "1.0" : this.pluginInfo.getVersion();
   }

   /**
    * Switch on/off UDP socket listener
    */
   public boolean startUdpListener() {
      return this.startUdpListener;
   }

   /**
    * Configuration option to use UDP for updateOneway() calls.
    * <br />
    * Typically a setting from the plugin configuration, see xmlBlasterPlugins.xml, for example
    * <br />
    *  &lt;attribute id='useUdpForOneway'>true&lt;/attribute>
    */
   public boolean useUdpForOneway() {
      return this.useUdpForOneway;
   }

   /**
    * 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, PluginInfo pluginInfo)
      throws XmlBlasterException {
      this.pluginInfo = pluginInfo;
      this.glob = glob;
      this.ME = getType();
      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 ?");

      // For JMX instanceName may not contain ","
      String vers = ("1.0".equals(getVersion())) ? "" : getVersion();
      this.contextNode = new ContextNode(ContextNode.SERVICE_MARKER_TAG,
            "SocketDriver[" + getType() + vers + "]", glob.getContextNode());
      this.mbeanHandle = this.glob.registerMBean(this.contextNode, this);

      try {
         this.authenticate = engineGlob.getAuthenticate();
         if (this.authenticate == null) {
            throw new XmlBlasterException(this.glob, ErrorCode.INTERNAL_UNKNOWN, ME + ".init", "authenticate object is null");
         }
         I_XmlBlaster xmlBlasterImpl = this.authenticate.getXmlBlaster();
         if (xmlBlasterImpl == null) {
            throw new XmlBlasterException(this.glob, ErrorCode.INTERNAL_UNKNOWN, ME + ".init", "xmlBlasterImpl object is null");
         }

         init(glob, new AddressServer(glob, getType(), glob.getId(), pluginInfo.getParameters()), this.authenticate, xmlBlasterImpl);

         this.useUdpForOneway = this.addressServer.getEnv("useUdpForOneway", this.useUdpForOneway).getValue();
         this.startUdpListener = this.addressServer.getEnv("startUdpListener", this.startUdpListener).getValue();

         // Now we have logging ...
         if (log.isLoggable(Level.FINE)) log.fine("Using pluginInfo=" + this.pluginInfo.toString() + ", startUdpListener=" + this.startUdpListener + ", useUdpForOneway=" + this.useUdpForOneway);

         activate();
      }
      catch (XmlBlasterException ex) {
         throw ex;
      }
      catch (Throwable ex) {
         throw new XmlBlasterException(this.glob, ErrorCode.INTERNAL_UNKNOWN, ME + ".init", "init. Could'nt initialize the driver.", ex);
      }
   }

   /**
    * Get the address how to access this driver.
    * @return "server.mars.univers:6701"
    */
   public String getRawAddress() {
      return this.socketUrl.getUrl(); // this.socketUrl.getHostname() + ":" + this.socketUrl.getPort();
   }

   /**
    * Access the handle to the xmlBlaster authenication core
    */
   I_Authenticate getAuthenticate() {
      return this.authenticate;
   }

   /**
    * Access the handle to the xmlBlaster core
    */
   I_XmlBlaster getXmlBlaster() {
      return this.xmlBlasterImpl;
   }

   AddressServer getAddressServer() {
      return this.addressServer;
   }

   /**
    * Start xmlBlaster SOCKET access.
    * <p />
    * Enforced by interface I_Driver.<br />
    * This method returns as soon as the listener socket is alive and ready or on error.
    * @param glob Global handle to access logging, property and commandline args
    * @param authenticate Handle to access authentication server
    * @param xmlBlasterImpl Handle to access xmlBlaster core
    */
   private synchronized void init(Global glob, AddressServer addressServer, I_Authenticate authenticate, I_XmlBlaster xmlBlasterImpl)
      throws XmlBlasterException
   {
      this.glob = glob;
      this.ME = "SocketDriver" + this.glob.getLogPrefixDashed() + "-" + getType();

      if (log.isLoggable(Level.FINER)) log.finer("Entering init()");
      this.addressServer = addressServer;
      this.authenticate = authenticate;
      this.xmlBlasterImpl = xmlBlasterImpl;

      this.socketUrl = new SocketUrl(glob, this.addressServer);

      if (Constants.COMPRESS_ZLIB_STREAM.equals(this.addressServer.getCompressType())) {
         log.info("Full stream compression enabled with '" + Constants.COMPRESS_ZLIB_STREAM + "' for " + getType());
      }
      else if (Constants.COMPRESS_ZLIB.equals(this.addressServer.getCompressType())) {
         log.info("Message compression enabled with  '" + Constants.COMPRESS_ZLIB + "', minimum size for compression is " + this.addressServer.getMinSize() + " bytes for " + getType());
      }

      if (this.socketUrl.getPort() < 1) {
         log.info("Option protocol/socket/port set to " + this.socketUrl.getPort() + ", socket server not started");
         return;
      }
   }

   /**
    * Activate xmlBlaster access through this protocol.
    */
   public synchronized void activate() throws XmlBlasterException {
      if (log.isLoggable(Level.FINER)) log.finer("Entering activate");

      if (startUdpListener()) {
         listenerUDP = new Thread(new UDPListener());
         listenerUDP.setName("XmlBlaster."+getType()+".udpListener");
         listenerUDP.start();
         while (!listenerReadyUDP) {
            try { Thread.sleep(10); } catch( InterruptedException i) {}
         }
      }

      super.setName("XmlBlaster.SocketDriver-"+getType()); // Thread name
      start(); // Start the listen thread
      while (!listenerReady) {
         try { Thread.sleep(10); } catch( InterruptedException i) {}
      }
   }

   public boolean isActive() {
      return running == true;
   }

   /**
    * Deactivate xmlBlaster access (standby), no clients can connect.
    */
   public synchronized void deActivate() throws RuntimeException {
      if (log.isLoggable(Level.FINER)) log.finer("Entering deActivate");
      running = false; runningUDP = false;

      boolean closeHack = true;
      if (listen != null && closeHack) {
         // On some JDKs, listen.close() is not immediate (has a delay for about 1 sec.)
         // force closing by invoking server with this temporary client:
         try {
            java.net.Socket socket = new Socket(listen.getInetAddress(), this.socketUrl.getPort());
            socket.close();
         } catch (java.io.IOException e) {
            log.warning("Tcp shutdown problem: " + e.toString());
         }
      }
      /*
      if (socketUDP != null && closeHack) {
         // On some JDKs, listen.close() is not immediate (has a delay for about 1 sec.)
         // force closing by invoking server with this temporary client:
         try {
            java.net.DatagramSocket socket = new DatagramSocket(this.socketUrl.getPort(), socketUDP.getLocalAddress());
            socket.close();
         } catch (java.io.IOException e) {
            log.warn(ME, "Udp shutdown problem: " + e.toString());
         }
      }
      */
      if (listen != null) {
         try {
            listen.close();
         } catch (java.io.IOException e) {
            log.warning("TCP socket shutdown problem: " + e.toString());
         }
         listen = null;
         //log.info(ME, "TCP socket driver stopped, all resources released.");
      }
      if (socketUDP != null) {
         socketUDP.close();
         socketUDP = null;
         //log.info(ME, "UDP socket driver stopped, all resources released.");
      }

      // shutdown all clients connected
      while (true) {
         HandleClient h = null;
         synchronized (handleClientSet) {
            Iterator it = handleClientSet.iterator();
            if (it.hasNext()) {
               h = (HandleClient)it.next();
               it.remove();
            }
            else
               break;
         }
         if (h == null)
            break;
         h.shutdown();
      }
      synchronized (handleClientSet) {
        handleClientSet.clear();
      }
      synchronized (handleClientMap) {
        handleClientMap.clear();
      }
   }

   final void removeClient(HandleClient h) {
      synchronized (handleClientSet) {
         boolean removed = handleClientSet.remove(h);
         if (!removed) { // May be called twice: from SessionInfo.shutdown() and from HandleClient->exiting run()
            if (log.isLoggable(Level.FINE)) log.fine("Didn't find a client object to remove: " + h.toString());
         }
      }
      synchronized(handleClientMap) {
         Object removed = handleClientMap.remove(h.getSecretSessionId());
         if (removed == null) {
            if (log.isLoggable(Level.FINE)) log.fine("Didn't find a client handle to remove: " + h.toString());
         }
      }
   }

   final Global getGlobal()
   {
      return this.glob;
   }

   /**
    * Is SSL support switched on?
    */
   public final boolean isSSL()
   {
      if (sslMarker != 0) return sslMarker==-1 ? false : true;

      boolean ssl = this.addressServer.getEnv("SSL", false).getValue();
      sslMarker = ssl ? 1 : -1;
      if (log.isLoggable(Level.FINE)) log.fine(addressServer.getEnvLookupKey("SSL") + "=" + ssl);
      return ssl;
   }

   /**
    * Starts the server socket and waits for clients to connect.
    */
   public void run()
   {
      try {
         int backlog = this.addressServer.getEnv("backlog", 50).getValue(); // queue for max 50 incoming connection request
         if (log.isLoggable(Level.FINE)) log.fine(addressServer.getEnvLookupKey("backlog") + "=" + backlog);


         if (isSSL()) {
             listen = this.socketUrl.createServerSocketSSL(backlog, this.addressServer);
         }
         else {
             listen = new ServerSocket(this.socketUrl.getPort(), backlog, this.socketUrl.getInetAddress());
         }

         log.info("Started successfully " + getType() + " driver on '" + this.socketUrl.getUrl() + "'");
         listenerReady = true;
         while (running) {
            Socket accept = listen.accept();
            if (log.isLoggable(Level.INFO))
              log.info(ME + ": New incoming request on " + this.socketUrl.getUrl() + " from " + accept.getInetAddress() + ":" + accept.getPort());
            if (!running) {
               log.info("Closing server '" + this.socketUrl.getUrl() + "'");
               break;
            }
            HandleClient hh = new HandleClient(glob, this, accept, socketUDP);
            synchronized (handleClientSet) {
               handleClientSet.add(hh);
            }
            hh.startThread();
         }
      }
      catch (java.net.UnknownHostException e) {
         log.severe("Socket server problem, IP address '" + this.socketUrl.getHostname() + "' is invalid: " + e.toString());
      }
      catch (java.net.BindException e) {
         log.severe("Socket server problem '" + this.socketUrl.getUrl() + "', the port " + this.socketUrl.getPort() + " is not available: " + e.toString());
      }
      catch (java.net.SocketException e) {
         log.info("Socket '" + this.socketUrl.getUrl() + "' closed successfully: " + e.toString());
      }
      catch (IOException e) {
         log.severe("Socket server problem on '" + this.socketUrl.getUrl() + "': " + e.toString());
      }
      catch (Throwable e) {
         log.severe("Socket server problem on '" + this.socketUrl.getUrl() + "': " + e.toString());
         e.printStackTrace();
      }
      finally {
         listenerReady = false;
         if (listen != null) {
            try { listen.close(); } catch (java.io.IOException e) { log.warning("listen.close()" + e.toString()); }
            listen = null;
         }
      }
   }


   /**
    * Close the listener port, the driver shuts down.
    */
   public void shutdown() throws XmlBlasterException {
      if (log.isLoggable(Level.FINER)) log.finer("Entering shutdown");

      try {
         deActivate();
      } catch (Exception e) {
         log.severe(e.toString());
      }

      this.glob.unregisterMBean(this.mbeanHandle);

      this.isShutdown = true;

      log.info("Socket driver '" + getType() + "' stopped, all resources released.");
   }

   public boolean isShutdown() {
      return this.isShutdown;
   }

   /**
    * @return A link for JMX usage
    */
   public java.lang.String getUsageUrl() {
      return Global.getJavadocUrl(this.getClass().getName(), null);
   }

   /* dummy to have a copy/paste functionality in jconsole */
   public void setUsageUrl(java.lang.String url) {
   }

   /**
    * Command line usage.
    * <p />
    * <ul>
    <li><i>-plugin/socket/port</i>        The SOCKET web server port [7607]</li>
    <li><i>-plugin/socket/hostname</i>    Specify a hostname where the SOCKET web server runs
    *                                          Default is the localhost.</li>
    <li><i>-plugin/socket/backlog</i>     Queue size for incoming connection request [50]</li>
    <li><i>-dump[socket]</i>       true switches on detailed SOCKET debugging [false]</li>
    * </ul>
    * <p />
    * Enforced by interface I_Driver.
    */
   public String usage()
   {
      String text = "\n";
      text += "SocketDriver options:\n";
      text += "   -"+getEnvPrefix()+"port\n";
      text += "                       The SOCKET server port [7607].\n";
      text += "   -"+getEnvPrefix()+"hostname\n";
      text += "                       Specify a hostname where the SOCKET server runs.\n";
      text += "                       Default is the localhost.\n";
      text += "   -"+getEnvPrefix()+"startUdpListener\n";
      text += "                       Start a UDP datagram listener socket [false].\n";
      text += "   -"+getEnvPrefix()+"useUdpForOneway\n";
      text += "                       Use UDP instead of TCP for updateOneway() calls [false].\n";
      text += "   -"+getEnvPrefix()+"SoTimeout\n";
      text += "                       How long may a socket read block in msec [0] (0 is forever).\n";
      text += "   -"+getEnvPrefix()+"responseTimeout\n";
      text += "                       Max wait for the method return value/exception in msec.\n";
//      text += "                       The default is " +getDefaultResponseTimeout() + ".\n";
      text += "                       Defaults to 'forever', the value to pass is milli seconds.\n";
      text += "   -"+getEnvPrefix()+"backlog\n";
      text += "                       Queue size for incoming connection request [50].\n";
      text += "   -"+getEnvPrefix()+"threadPrio\n";
      text += "                       The priority 1=min - 10=max of the listener thread [5].\n";
      text += "   -"+getEnvPrefix()+"SSL\n";
      text += "                       True enables SSL support on server socket [false].\n";
      text += "   -"+getEnvPrefix()+"keyStore\n";
      text += "                       The path of your keystore file. Use the java utility keytool.\n";
      text += "   -"+getEnvPrefix()+"keyStorePassword\n";
      text += "                       The password of your keystore file.\n";
      text += "   -"+getEnvPrefix()+"compress/type\n";
      text += "                       Valid values are: '', '"+Constants.COMPRESS_ZLIB_STREAM+"', '"+Constants.COMPRESS_ZLIB+"' [].\n";
      text += "                       '' disables compression, '"+Constants.COMPRESS_ZLIB_STREAM+"' compresses whole stream.\n";
      text += "                       '"+Constants.COMPRESS_ZLIB+"' only compresses flushed chunks bigger than 'compress/minSize' bytes.\n";
      text += "   -"+getEnvPrefix()+"compress/minSize\n";
      text += "                       Compress message bigger than given bytes, see above.\n";
      text += "   -dump[socket]       true switches on detailed "+getType()+" debugging [false].\n";
      text += "   " + Global.getJmxUsageLinkInfo(this.getClass().getName(), null);
      text += "\n";
      return text;
   }
}
TOP

Related Classes of org.xmlBlaster.protocol.socket.SocketDriver$UDPListener

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.