Coverage Report - org.mule.transport.tcp.protocols.AbstractByteProtocol
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractByteProtocol
82%
37/45
70%
14/20
3
 
 1  
 /*
 2  
 * $Id: AbstractByteProtocol.java 10489 2008-01-23 17:53:38Z dfeist $
 3  
 * --------------------------------------------------------------------------------------
 4  
 * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
 *
 6  
 * The software in this package is published under the terms of the CPAL v1.0
 7  
 * license, a copy of which has been included with this distribution in the
 8  
 * LICENSE.txt file.
 9  
 */
 10  
 
 11  
 package org.mule.transport.tcp.protocols;
 12  
 
 13  
 import org.mule.ResponseOutputStream;
 14  
 import org.mule.api.transport.MessageAdapter;
 15  
 import org.mule.transport.tcp.TcpProtocol;
 16  
 import org.mule.util.ClassUtils;
 17  
 import org.mule.util.IOUtils;
 18  
 
 19  
 import java.io.IOException;
 20  
 import java.io.InputStream;
 21  
 import java.io.OutputStream;
 22  
 import java.io.Serializable;
 23  
 import java.net.Socket;
 24  
 import java.net.SocketException;
 25  
 import java.net.SocketTimeoutException;
 26  
 
 27  
 import org.apache.commons.lang.SerializationUtils;
 28  
 import org.apache.commons.logging.Log;
 29  
 import org.apache.commons.logging.LogFactory;
 30  
 
 31  
 /**
 32  
  * This Abstract class has been introduced so as to have the byte protocols (i.e. the
 33  
  * protocols that had only a single write method taking just an array of bytes as a
 34  
  * parameter) to inherit from since they will all behave the same, i.e. if the object
 35  
  * is serializable, serialize it into an array of bytes and send it.
 36  
  * <p/>
 37  
  * <p>Note that the raw write method has changed name from <code>write</code> to
 38  
  * <code>writeByteArray</code>.  This is to remove ambiguity from the code.  In almost
 39  
  * all cases it is possible to call {@link #write(java.io.OutputStream, Object)} which
 40  
  * will, via {@link #write(java.io.OutputStream, Object)}, dispatch to
 41  
  * {@link #writeByteArray(java.io.OutputStream, byte[])}.</p>.
 42  
  */
 43  
 public abstract class AbstractByteProtocol implements TcpProtocol
 44  
 {
 45  2
     private static final Log logger = LogFactory.getLog(DirectProtocol.class);
 46  
     private static final long PAUSE_PERIOD = 100;
 47  
     public static final int EOF = -1;
 48  
 
 49  
     // make this really clear in subclasses, because otherwise people will forget
 50  
     public static final boolean STREAM_OK = true;
 51  
     public static final boolean NO_STREAM = false;
 52  
     private boolean streamOk;
 53  
 
 54  
     public AbstractByteProtocol(boolean streamOk)
 55  404
     {
 56  404
         this.streamOk = streamOk;
 57  404
     }
 58  
 
 59  
     public void write(OutputStream os, Object data) throws IOException
 60  
     {
 61  1904
         if (data instanceof InputStream)
 62  
         {
 63  14
             if (streamOk)
 64  
             {
 65  14
                 IOUtils.copyLarge((InputStream) data, os);
 66  14
                 os.flush();
 67  14
                 os.close();
 68  
             }
 69  
             else
 70  
             {
 71  0
                 throw new IOException("TCP protocol " + ClassUtils.getSimpleName(getClass())
 72  
                         + " cannot handle streaming");
 73  
             }
 74  
         }
 75  1890
         else if (data instanceof MessageAdapter)
 76  
         {
 77  48
             write(os, ((MessageAdapter) data).getPayload());
 78  
         }
 79  1842
         else if (data instanceof byte[])
 80  
         {
 81  1426
             writeByteArray(os, (byte[]) data);
 82  
         }
 83  416
         else if (data instanceof String)
 84  
         {
 85  
             // TODO SF: encoding is lost/ignored; it is probably a good idea to have
 86  
             // a separate "stringEncoding" property on the protocol
 87  416
             writeByteArray(os, ((String) data).getBytes());
 88  
         }
 89  0
         else if (data instanceof Serializable)
 90  
         {
 91  0
             writeByteArray(os, SerializationUtils.serialize((Serializable) data));
 92  
         }
 93  
         else
 94  
         {
 95  0
             throw new IllegalArgumentException("Cannot serialize data: " + data);
 96  
         }
 97  1862
     }
 98  
 
 99  
     protected void writeByteArray(OutputStream os, byte[] data) throws IOException
 100  
     {
 101  1367
         os.write(data);
 102  1367
     }
 103  
 
 104  
     /**
 105  
      * Manage non-blocking reads and handle errors
 106  
      *
 107  
      * @param is     The input stream to read from
 108  
      * @param buffer The buffer to read into
 109  
      * @return The amount of data read (always non-zero, -1 on EOF or socket exception)
 110  
      * @throws IOException other than socket exceptions
 111  
      */
 112  
     protected int safeRead(InputStream is, byte[] buffer) throws IOException
 113  
     {
 114  172
         return safeRead(is, buffer, buffer.length);
 115  
     }
 116  
 
 117  
     /**
 118  
      * Manage non-blocking reads and handle errors
 119  
      *
 120  
      * @param is     The input stream to read from
 121  
      * @param buffer The buffer to read into
 122  
      * @param size   The amount of data (upper bound) to read
 123  
      * @return The amount of data read (always non-zero, -1 on EOF or socket exception)
 124  
      * @throws IOException other than socket exceptions
 125  
      */
 126  
     protected int safeRead(InputStream is, byte[] buffer, int size) throws IOException
 127  
     {
 128  
         int len;
 129  
         try
 130  
         {
 131  
             do
 132  
             {
 133  4761
                 len = is.read(buffer, 0, size);
 134  4751
                 if (0 == len)
 135  
                 {
 136  
                     // wait for non-blocking input stream
 137  
                     // use new lock since not expecting notification
 138  
                     try
 139  
                     {
 140  0
                         Thread.sleep(PAUSE_PERIOD);
 141  
                     }
 142  0
                     catch (InterruptedException e)
 143  
                     {
 144  
                         // no-op
 145  0
                     }
 146  
                 }
 147  
             }
 148  4751
             while (0 == len);
 149  4751
             return len;
 150  
         }
 151  6
         catch (SocketException e)
 152  
         {
 153  
             // do not pollute the log with a stacktrace, log only the message
 154  6
             logger.info("Socket exception occured: " + e.getMessage());
 155  6
             return EOF;
 156  
         }
 157  4
         catch (SocketTimeoutException e)
 158  
         {
 159  4
             logger.debug("Socket timeout.");
 160  4
             return EOF;
 161  
         }
 162  
     }
 163  
 
 164  
     /**
 165  
      * Make a single transfer from source to dest via a byte array buffer
 166  
      *
 167  
      * @param source Source of data
 168  
      * @param buffer Buffer array for transfer
 169  
      * @param dest   Destination of data
 170  
      * @return Amount of data transferred, or -1 on eof or socket error
 171  
      * @throws IOException On non-socket error
 172  
      */
 173  
     protected int copy(InputStream source, byte[] buffer, OutputStream dest) throws IOException
 174  
     {
 175  0
         return copy(source, buffer, dest, buffer.length);
 176  
     }
 177  
 
 178  
     /**
 179  
      * Make a single transfer from source to dest via a byte array buffer
 180  
      *
 181  
      * @param source Source of data
 182  
      * @param buffer Buffer array for transfer
 183  
      * @param dest   Destination of data
 184  
      * @param size   The amount of data (upper bound) to read
 185  
      * @return Amount of data transferred, or -1 on eof or socket error
 186  
      * @throws IOException On non-socket error
 187  
      */
 188  
     protected int copy(InputStream source, byte[] buffer, OutputStream dest, int size) throws IOException
 189  
     {
 190  4589
         int len = safeRead(source, buffer, size);
 191  4589
         if (len > 0)
 192  
         {
 193  1833
             dest.write(buffer, 0, len);
 194  
         }
 195  4589
         return len;
 196  
     }
 197  
 
 198  
     protected byte[] nullEmptyArray(byte[] data)
 199  
     {
 200  3311
         if (0 == data.length)
 201  
         {
 202  1437
             return null;
 203  
         }
 204  
         else
 205  
         {
 206  1874
             return data;
 207  
         }
 208  
     }
 209  
 
 210  
     public ResponseOutputStream createResponse(Socket socket) throws IOException
 211  
     {
 212  1426
         return new ResponseOutputStream(socket, new ProtocolStream(this, streamOk, socket.getOutputStream()));
 213  
     }
 214  
 
 215  
 }