Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   package org.jboss.remoting.transport.socket;
   
   import  org.jboss.logging.Logger;
  import  org.jboss.util.propertyeditor.PropertyEditors;
  
  import java.net.Socket;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  
  import  EDU.oswego.cs.dl.util.concurrent.Semaphore;

SocketClientInvoker uses Sockets to remotely connect to the a remote ServerInvoker, which must be a SocketServerInvoker.

Author(s):
Jeff Haynie
Tom Elrod
Ovidiu Feodorov
Version:
$Revision: 6179 $
  
  public class MicroSocketClientInvoker extends RemoteClientInvoker
  {
     // Constants ------------------------------------------------------------------------------------
  
     private static final Logger log = Logger.getLogger(MicroSocketClientInvoker.class);

   
Can be either true or false and will indicate if client socket should have TCP_NODELAY turned on or off. TCP_NODELAY is for a specific purpose; to disable the Nagle buffering algorithm. It should only be set for applications that send frequent small bursts of information without getting an immediate response; where timely delivery of data is required (the canonical example is mouse movements). The default is false.
  
     public static final String TCP_NODELAY_FLAG = "enableTcpNoDelay";

   
The client side maximum number of threads. The default is MAX_POOL_SIZE.
  
     public static final String MAX_POOL_SIZE_FLAG = "clientMaxPoolSize";

   
Specifies the fully qualified class name for the custom SocketWrapper implementation to use on the client. Note, will need to make sure this is marked as a client parameter (using the 'isParam' attribute). Making this change will not affect the marshaller/unmarshaller that is used, which may also be a requirement.
  
     public static final String CLIENT_SOCKET_CLASS_FLAG = "clientSocketClass";
   
   
Key for setting timeout used by OnewayConnectionTask
  
     public static final String ONEWAY_CONNECTION_TIMEOUT = "onewayConnectionTimeout";
   
   
Key to determine if client side oneway invocations should wait to read version. See JBREM-706.
  
     public static final String USE_ONEWAY_CONNECTION_TIMEOUT = "useOnewayConnectionTimeout";

   
Key for setting time to wait to get permission to get a connection
  
     public static final String CONNECTION_WAIT = "connectionWait";
   
   
Key for setting socket write timeout
  
     public static final String WRITE_TIMEOUT = "writeTimeout";
   
   
Default value for enable TCP nodelay. Value is false.
 
    public static final boolean TCP_NODELAY_DEFAULT = false;

   
Default maximum number of times a invocation will be made when it gets a SocketException. Default is 3.
 
    public static final int MAX_CALL_RETRIES = 3;

   
Default maximum number of socket connections allowed at any point in time. Default is 50.
 
    public static final int MAX_POOL_SIZE = 50;

   
Default timeout value used by OnewayConnectionTask. Value is 2 seconds.
 
    public static final int ONEWAY_CONNECTION_TIMEOUT_DEFAULT = 2000;
   
   
Default time to wait to get permission to get a connection
 
    public static final int CONNECTION_WAIT_DEFAULT = 30000;
 
    // Static ---------------------------------------------------------------------------------------
 
    private static boolean trace = .isTraceEnabled();

   
Used for debugging (tracing) connections leaks
 
    static int counter = 0;
 
    protected static final Map connectionPools = new HashMap();
    
    protected static final Map semaphores = new HashMap();
 
    // Performance measurements
    public static long getSocketTime = 0;
    public static long readTime = 0;
    public static long writeTime = 0;
    public static long serializeTime = 0;
    public static long deserializeTime = 0;
    
    private static final String patternString = "^.*(?:connection.*reset|connection.*closed|connection.*abort|broken.*pipe|connection.*shutdown).*$";
    private static final Pattern RETRIABLE_ERROR_MESSAGE = Pattern.compile(.);
   
   
Close all sockets in a specific pool.
 
    public static void clearPool(LinkedList thepool)
    {
       try
       {
          if (thepool == null)
          {
             return;
          }
          synchronized (thepool)
          {
             int size = thepool.size();
             for (int i = 0; i < sizei++)
             {
                SocketWrapper socketWrapper = (SocketWrapper)thepool.removeFirst();
                try
                {
                   socketWrapper.close();
                   socketWrapper = null;
                }
                catch (Exception ignored)
                {
                }
             }
          }
       }
       catch (Exception ex)
       {
          .debug("Failure"ex);
       }
    }

   
Close all sockets in all pools.
 
    public static void clearPools()
    {
       synchronized ()
       {
          for(Iterator i = .keySet().iterator(); i.hasNext();)
          {
             ServerAddress sa = (ServerAddressi.next();
 
             if () { .trace("clearing pool for " + sa); }
             clearPool((LinkedList.get(sa));
             i.remove();
          }
          .clear();
       }
    }
 
    // Attributes -----------------------------------------------------------------------------------
 
    private boolean reuseAddress;
 
    protected InetAddress addr;
    protected int port;
 
    // flag being set on true by a disconnect request. If trying to create a connection goes on in a
    // loop and a disconnect request arrives, this flag will be used to sent this information into
    // the connect loop
    // private volatile boolean bailOut;
 
   
Indicates if will check the socket connection when getting from pool by sending byte over the connection to validate is still good.
 
    protected boolean shouldCheckConnection;

   
If the TcpNoDelay option should be used on the socket.
 
    protected boolean enableTcpNoDelay;
 
    protected String clientSocketClassName;
    protected Class clientSocketClass;
    protected int numberOfCallRetries;
    protected int maxPoolSize;
    protected int onewayConnectionTimeout;
    protected boolean useOnewayConnectionTimeout = true;
    protected int connectionWait = ;

   
Pool for this invoker. This is shared between all instances of proxies attached to a specific invoker.
 
    protected LinkedList pool;
    
    //Semaphore is also shared between all proxies - must 1-1 correspondence between pool and semaphore
    protected Semaphore semaphore;
   

   
connection information
 
    protected ServerAddress address;
    protected Home home;
   
   
Socket configuration parameters.
 
    protected boolean keepAlive;
    protected boolean keepAliveSet;
    protected boolean oOBInline;
    protected boolean oOBInlineSet;
    protected int receiveBufferSize = - 1;
    protected int sendBufferSize = -1;
    protected boolean soLinger;
    protected boolean soLingerSet;
    protected int soLingerDuration = -1;
    protected int trafficClass = -1;
   
   
If true, an IOException with message such as "Connection reset by peer: socket write error" will be treated like a SocketException.
 
    protected boolean generalizeSocketException;
    
    protected int writeTimeout = -1;
 
    // Constructors ---------------------------------------------------------------------------------
 
    {
       this(locatornull);
    }
 
    public MicroSocketClientInvoker(InvokerLocator locatorMap configuration)
    {
       super(locatorconfiguration);
 
        = null;
        = true;
        = false;
        = null;
        = null;
        = ;
 
       try
       {
          setup();
       }
       catch (Exception ex)
       {
          .debug("Error setting up " + thisex);
          throw new RuntimeException(ex.getMessage(), ex);
       }
 
       .debug(this + " constructed");
    }
 
    // Public ---------------------------------------------------------------------------------------
 
   
Indicates if will check socket connection when returning from pool by sending byte to the server. Default value will be false.
 
    public boolean checkingConnection()
    {
       return ;
    }

   
Returns if newly created sockets will have SO_REUSEADDR enabled. Default is for this to be true.
 
    public boolean getReuseAddress()
    {
       return ;
    }

   
Sets if newly created socket should have SO_REUSEADDR enable. Default is true.
 
    public void setReuseAddress(boolean reuse)
    {
        = reuse;
    }
 
    public boolean isKeepAlive()
    {
       return ;
    }
 
    public void setKeepAlive(boolean keepAlive)
    {
       this. = keepAlive;
        = true;
    }
 
    public boolean isOOBInline()
    {
       return ;
    }
 
    public void setOOBInline(boolean inline)
    {
        = inline;
        = true;
    }
 
    public int getReceiveBufferSize()
    {
       return ;
    }
 
    public void setReceiveBufferSize(int receiveBufferSize)
    {
       this. = receiveBufferSize;
    }
 
    public int getSendBufferSize()
    {
       return ;
    }
 
    public void setSendBufferSize(int sendBufferSize)
    {
       this. = sendBufferSize;
    }
 
    public boolean isSoLinger()
    {
       return ;
    }
    
    public int getSoLingerDuration()
    {
       return ;
    }
 
    public void setSoLinger(boolean soLinger)
    {
       this. = soLinger;
        = true;
    }
 
    public void setSoLingerDuration(int soLingerDuration)
    {
       this. = soLingerDuration;
    }
 
    public int getTrafficClass()
    {
       return ;
    }
 
    public void setTrafficClass(int trafficClass)
    {
       this. = trafficClass;
    }
 
    public int getWriteTimeout()
    {
       return ;
    }
 
    public void setWriteTimeout(int writeTimeout)
    {
       this. = writeTimeout;
    }
 
    public boolean isGeneralizeSocketException()
    {
       return ;
    }
 
    public void setGeneralizeSocketException(boolean generalizeSocketException)
    {
       this. = generalizeSocketException;
    }
 
    public synchronized void disconnect()
    {
       .debug(this + " disconnecting ...");
 //      bailOut = true;
       super.disconnect();
    }
 
    public void flushConnectionPool()
    {
       synchronized ()
       {
          while ( != null && .size() > 0)
          {
             SocketWrapper socketWrapper = (SocketWrapper).removeFirst();
             try
             {
                socketWrapper.close();
             }
             catch (IOException e)
             {
                .debug("Failed to close socket wrapper"e);
             }
          }
       }
    }
    
    public int getConnectionWait()
    {
       return ;
    }
 
    public void setConnectionWait(int connectionWait)
    {
       this. = connectionWait;
    }
 
    public Home getHomeInUse()
    {
       return ;
    }

   
Sets the number of times an invocation will retry based on getting SocketException.
 
    public void setNumberOfCallRetries(int numberOfCallRetries)
    {
       if (numberOfCallRetries < 1)
       {
          this. = ;
       }
       else
       {
          this. = numberOfCallRetries;
       }
    }
 
    public int getNumberOfCallRetries()
    {
       return ;
    }

   
Sets the number of retries to get a socket connection.

Parameters:
numberOfRetries Must be a number greater than 0.
 
    public void setNumberOfRetries(int numberOfRetries)
    {
       .warn("numberOfRetries is no longer used");
    }
 
    public int getNumberOfRetries()
    {
       .warn("numberOfRetries is no longer used");
       return -1;
    }

   
The name of of the server.
 
    public String getServerHostName() throws Exception
    {
       return .;
    }
    
    public int getNumberOfUsedConnections()
    {
       if ( == null)
          return 0;
       
       return  - (int.permits();
    }
    
    public int getNumberOfAvailableConnections()
    {
       if ( == null)
          return 0;
       
       return (int.permits();
    }
 
    // Package protected ----------------------------------------------------------------------------
 
    // Protected ------------------------------------------------------------------------------------
 
    protected void setup() throws Exception
    {
       Properties props = new Properties();
       props.putAll();
       mapJavaBeanProperties(MicroSocketClientInvoker.thispropsfalse);
       configureParameters();
 
       {
           = getAddressByName(.getHost());
           = .getPort();
           = createServerAddress();
       }
       else
       {
          List homes = .getConnectHomeList();
          if (homes.size() == 1)
          {
             // Treat as in non MULTIHOME case.
             Home home = (Homehomes.iterator().next();
              = getAddressByName(home.host);
              = createServerAddress(home.port);
          }
       }
    }
 
    protected void configureParameters()
    {
       Map params = ;
 
       if (params == null)
       {
          return;
       }
 
       // look for enableTcpNoDelay param
       Object val = params.get();
       if (val != null)
       {
          try
          {
              = Boolean.valueOf((String)val).booleanValue();
             .debug(this + " setting enableTcpNoDelay to " + );
          }
          catch (Exception e)
          {
             .warn(this + " could not convert " +  + " value of " +
                      val + " to a boolean value.");
          }
       }
 
       // look for maxPoolSize param
       val = params.get();
       if (val != null)
       {
          try
          {
              = Integer.valueOf((String)val).intValue();
             .debug(this + " setting maxPoolSize to " + );
          }
          catch (Exception e)
          {
             .warn(this + " could not convert " +  + " value of " +
                      val + " to a int value");
          }
       }
 
       // look for client socket class name
       val = params.get();
       if (val != null)
       {
          String value = (String)val;
          if (value.length() > 0)
          {
              = value;
             .debug(this + " setting client socket wrapper class name to " + );
          }
       }
 
       val = params.get(.);
       if (val != null && ((String)val).length() > 0)
       {
          String value = (Stringval;
           = Boolean.valueOf(value).booleanValue();
          .debug(this + " setting shouldCheckConnection to " + );
       }
       else if (getVersion() == .)
       {
           = true;
          .debug(this + " setting shouldCheckConnection to " + );
       }
       
       // look for onewayConnectionTimeout param
       val = params.get();
       if (val != null)
       {
          try
          {
              = Integer.valueOf((String)val).intValue();
             .debug(this + " setting onewayConnectionTimeout to " + );
          }
          catch (Exception e)
          {
             .warn(this + " could not convert " +  + " value of " +
                      val + " to an int value");
          }
       }
       
       // look for useOnewayConnectionTimeout param
       val = params.get();
       if (val != null)
       {
          try
          {
              = Boolean.valueOf((String)val).booleanValue();
             .debug(this + " setting useOnewayConnectionTimeout to " + );
          }
          catch (Exception e)
          {
             .warn(this + " could not convert " +  + " value of " +
                      val + " to a boolean value");
          }
       }
       
       // look for writeTimeout param
       val = params.get();
       if (val != null)
       {
          try
          {
              = Integer.valueOf((String)val).intValue();
             .debug(this + " setting writeTimeout to " + );
          }
          catch (Exception e)
          {
             .warn(this + " could not convert " +  + " value of " +
                      val + " to an int value");
          }
       }
    }
 
    protected ServerAddress createServerAddress(InetAddress addrint port)
    {
       return new ServerAddress(addr.getHostAddress(), port, -1, );
    }
 
    protected void finalize() throws Throwable
    {
       disconnect();
       super.finalize();
    }
 
    protected synchronized void handleConnect() throws ConnectionFailedException
    {
       initPool();
       
       {
           = getUsableAddress();
          if ( == null)
          {
             throw new ConnectionFailedException(this + " unable to find a usable address for: " + );
          }
          .setHomeInUse();
       }
       else
       {
           = new Home(.getHost(), .getPort());
       }
    }
 
    protected Home getUsableAddress(InvokerLocator locator)
    {
       List homes = getConnectHomes();
       Iterator it = homes.iterator();
       Home home = null;
       
       while (it.hasNext())
       {
          try
          {
             home = (Homeit.next();
              = getAddressByName(home.host);
              = createServerAddress(home.port);
             invoke(new InvocationRequest(nullnull.nullnullnull));
             if (.trace(this + " able to contact server at: " + home);
             return home;
          }
          catch (Throwable e)
          {
             .debug(this + " unable to contact server at: " + home);
          }
       }
    
       return null;
    }
 
    protected synchronized void handleDisconnect()
    {
       clearPools();
       clearPool();
    }

   
Each implementation of the remote client invoker should have a default data type that is used in the case it is not specified in the invoker locator URI.
 
    protected String getDefaultDataType()
    {
       return .;
    }
 
    protected Object transport(String sessionIDObject invocationMap metadata,
                               Marshaller marshallerUnMarshaller unmarshaller)
    {
       SocketWrapper socketWrapper = null;
       Object response = null;
       boolean oneway = false;
 
       // tempTimeout < 0 will indicate there is no per invocation timeout.
       int tempTimeout = -1;
       int timeLeft = -1;
       int savedTimeout = -1;
       long start = -1;
 
       if(metadata != null)
       {
          // check to see if is one way invocation and return after writing invocation if is
          Object val = metadata.get(....);
          if(val != null && val instanceof String && Boolean.valueOf((String)val).booleanValue())
          {
             oneway = true;
          }
 
          // look for temporary timeout values
          String tempTimeoutString = (Stringmetadata.get(.);
          {
             if (tempTimeoutString != null)
             {
                try
                {
                   tempTimeout = Integer.valueOf(tempTimeoutString).intValue();
                   .debug(this + " setting timeout to " + tempTimeout + " for this invocation");
                }
                catch (Exception e)
                {
                   .warn(this + " could not convert " + . + " value of " +
                            tempTimeoutString + " to an integer value.");
                }
             }
          }
       }
       
       if (tempTimeout >= 0)
       {
          start = System.currentTimeMillis();
       }
 
       boolean serverSideOneway = false;
       if (oneway && invocation instanceof InvocationRequest)
       {
          InvocationRequest ir = (InvocationRequestinvocation;
          if (ir.getParameter() instanceof OnewayInvocation)
             serverSideOneway = true;
       }
       
       int retryCount = 0;
       Exception sockEx = null;
 
       for (; retryCount < retryCount++)
       {
          if (.trace(this + " retryCount: " + retryCount);
          if (0 < tempTimeout)
          {
             // If a per invocation timeout has been set, the time spent retrying
             // should count toward the elapsed time.
             timeLeft = (int) (tempTimeout - (System.currentTimeMillis() - start));
             if (timeLeft <= 0)
                break;
          }
 
          try
          {
             boolean tryPool = retryCount < ( - 1)
                                  ||  == 1
                                  ||  == 1;
             socketWrapper = getConnection(marshallerunmarshallertryPooltimeLeft);
             .trace(this + " got socketWrapper: " + socketWrapper);
          }
          catch (InterruptedException e)
          {
             .release();
             if (.trace(this + " released semaphore: " + .permits(), e);
             throw new RuntimeException(e);
          }
          catch (Exception e)
          {
 //            if (bailOut)
 //               return null;
             .release();
             if (.trace(this + " released semaphore: " + .permits(), e);
             sockEx =  new CannotConnectException(
                   "Can not get connection to server. Problem establishing " +
                   "socket connection for " + e);
             continue;
          }
 
          if (tempTimeout >= 0)
          {
             timeLeft = (int) (tempTimeout - (System.currentTimeMillis() - start));
             if (timeLeft <= 0)
                break;
             savedTimeout = socketWrapper.getTimeout();            
             socketWrapper.setTimeout(timeLeft);
          }
 
          try
          {
             int version = getVersion();
             boolean performVersioning = Version.performVersioning(version);
 
             OutputStream outputStream = socketWrapper.getOutputStream();
             .trace(this + "got outputStream: " + outputStream);
             if (performVersioning)
             {
                .trace(this + " writing version");
                writeVersion(outputStreamversion);
                .trace(this + " wrote version");
             }
 
             //TODO: -TME so this is messed up as now ties remoting versioning to using a marshaller type
             versionedWrite(outputStreammarshallerinvocationversion);
 
             if (serverSideOneway)
             {
                if() { .trace(this + " sent oneway invocation, so not waiting for response, returning null"); }
             }
             else if (oneway)
             {
                if (performVersioning && )
                {
                   int onewaySavedTimeout = socketWrapper.getTimeout();
                   socketWrapper.setTimeout();
                   InputStream inputStream = socketWrapper.getInputStream();
                   version = readVersion(inputStream);
                   if (version == -1)
                   {
                      throw new EOFException("end of file");
                   }
                   if (version == .)
                   {
                      .trace(this + " received version 254: treating as end of file");
                      throw new EOFException("end of file");
                   }
 
                   // Note that if an exception is thrown, the socket is thrown away,
                   // so there's no need to reset the timeout value.
                   socketWrapper.setTimeout(onewaySavedTimeout);
                }
             }
             else
             {
                InputStream inputStream = socketWrapper.getInputStream();
                if (performVersioning)
                {
                   version = readVersion(inputStream);
                   if (version == -1)
                   {
                      throw new EOFException("end of file");
                   }
                   if (version == .)
                   {
                      .trace(this + " received version 254: treating as end of file");
                      throw new EOFException("end of file");
                   }
                }
 
                response = versionedRead(inputStreamunmarshallerversion);
             }
 
             // Note that resetting the timeout value after closing the socket results
             // in an exception, so the reset is not done in a finally clause.  However,
             // if a catch clause is ever added that does not close the socket, care
             // must be taken to reset the timeout in that case.
             if (tempTimeout >= 0)
             {
                socketWrapper.setTimeout(savedTimeout);
             }
          }
          catch (SocketException sex)
          {
             handleRetriableException(socketWrappersexretryCount);
             sockEx = sex;
             continue;
          }
          catch (EOFException ex)
          {
             handleRetriableException(socketWrapperexretryCount);
             sockEx = ex;
             continue;
          }
          catch (IOException e)
          {
             if (isGeneralizeSocketException() && e.getMessage() != null && .matcher(e.getMessage()).matches())
             {
                handleRetriableException(socketWrappereretryCount);
                sockEx = new SocketException(e.getMessage());
                continue;
             }
             else
             {
                return handleOtherException(esocketWrapperoneway);
             }
          }
          catch (Exception ex)
          {
             return handleOtherException(exsocketWrapperoneway);
          }
 
          // call worked, so no need to retry
          break;
       }
 
       // need to check if ran out of retries
       if (retryCount >= )
       {
          handleException(sockExsocketWrapper);
       }
       
       if (response == null && tempTimeout > 0 && timeLeft <= 0)
       {
          if (sockEx == null)
          {
             sockEx =  new CannotConnectException(
                          "Can not get connection to server. Timed out establishing " +
                          "socket connection for " + );
          }
          handleException(sockExsocketWrapper);
       }
 
       // Put socket back in pool for reuse
       synchronized ()
       {
          if (.size() < )
          {
             .add(socketWrapper);
             if () { .trace(this + " returned " + socketWrapper + " to pool"); }
          }
          else
          {
             if () { .trace(this + "'s pool is full, will close the connection"); }
             try
             {
                socketWrapper.close();
             }
             catch (Exception ignored)
             {
             }
          }         
          .release();
          if (.trace(this + " released semaphore: " + .permits());
       }
 
       if ( && !oneway) { .trace(this + " received response " + response);  }
       return response;
    }
 
    protected Object handleException(Exception exSocketWrapper socketWrapper)
    {
      if (ex instanceof ClassNotFoundException)
      {
         //TODO: -TME Add better exception handling for class not found exception
         .debug("Error loading classes from remote call result."ex);
         throw (ClassNotFoundException)ex;
      }
      
      if (ex instanceof CannotConnectException)
      {
         .debug(thisex);
         throw (CannotConnectExceptionex;
      }
      
      if (ex instanceof InterruptedException)
      {
         .debug(thisex);
         throw new RuntimeException(ex);
      }
      throw new InvocationFailureException("Unable to perform invocation"ex);
   }
   
   protected void handleRetriableException(SocketWrapper socketWrapperException eint retryCount)
   {
      if (.trace(this + "(" + socketWrapper + ") got Exception: " + e);
      try
      {
         .release();
         if (.trace(this + " released semaphore: " + .permits());
         socketWrapper.close();            
      }
      catch (Exception ex)
      {
         if () { .trace(this + " couldn't successfully close its socketWrapper"ex); }
      }

      
About to run out of retries and pool may be full of timed out sockets, so want to flush the pool and try with fresh socket as a last effort.
      if (retryCount == ( - 2))
      {
         flushConnectionPool();
      }
      
      if ()
      {
         if (retryCount < ( - 1))
         {
            .trace(this + " will try again, retries: " + retryCount + " < " + );
         }
         else
         {
            .trace(this + " retries exhausted");               
         }
      }
   }
   protected Object handleOtherException(Exception ex, Semaphore semaphoreSocketWrapper socketWrapperboolean oneway)
   {
      .debug(this + " got exception: " + socketWrapperex);
      try
      {
         semaphore.release();
         if (.trace(this + " released semaphore: " + semaphore.permits());
         socketWrapper.close();
      }
      catch (Exception ignored)
      {
      }
      
      if (oneway)
         return null;
      else
         return handleException(exsocketWrapper);
   }
   
   protected void initPool()
   {
      synchronized ()
      {
          = (LinkedList).get();
          = (Semaphore).get();
         if ( == null)
         {
             = new LinkedList();
            .put();
            .debug("Creating semaphore with size " + );
             = new Semaphore();
            .put();
            
            if ()
            {
               synchronized ()
               {
                  .trace(this + " added new pool (" +  + ") as " + );
               }
            }
         }
         else
         {
            if ()
            {
               synchronized ()
               {
                  .trace(this + " using pool (" +  + ") already defined for " + );
               }
            }
         }
      }
   }
   
   protected SocketWrapper getConnection(Marshaller marshaller,
                                         UnMarshaller unmarshaller,
                                         boolean tryPoolint timeAllowed)
      throws Exception
   {
      long start = System.currentTimeMillis();
      long timeToWait = (timeAllowed > 0) ? timeAllowed : ;
      boolean timedout = !.attempt(timeToWait);
      if (.trace(this + " obtained semaphore: " + .permits());
      
      if (timedout)
      {
         throw new IllegalStateException("Timeout waiting for a free socket");
      }
      
      SocketWrapper pooled = null;
      if (tryPool)
      {
         synchronized ()
         {
            // if connection within pool, use it
            if (.size() > 0)
            {
               pooled = getPooledConnection();
               if (.trace(this + " reusing pooled connection: " + pooled);
            }
         }
      }
      else
      {
         if (.trace(this + " avoiding connection pool, creating new socket");
      }
      if (pooled == null)
      {
         //Need to create a new one  
         Socket socket = null;
         if () { .trace(this + " creating socket "); }
         // timeAllowed < 0 indicates no per invocation timeout has been set.
         int timeRemaining = -1;
         if (0 <= timeAllowed)
         {
            timeRemaining = (int) (timeAllowed - (System.currentTimeMillis() - start));
         }
         
         socket = createSocket(..timeRemaining);
         if (.trace(this + " created socket: " + socket);
         socket.setTcpNoDelay(.);
         Map metadata = getLocator().getParameters();
         if (metadata == null)
         {
            metadata = new HashMap(2);
         }
         else
         {
            metadata = new HashMap(metadata);
         }
         metadata.put(.marshaller);
         metadata.put(.unmarshaller);
         if ( > 0)
         {
            metadata.put(.new Integer());
         }
         if (timeAllowed > 0)
         {
            timeRemaining = (int) (timeAllowed - (System.currentTimeMillis() - start));
            
            if (timeRemaining <= 0)
               throw new Il