Coverage Report - org.mule.transport.tcp.protocols.AbstractByteProtocol
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractByteProtocol
0%
0/56
0%
0/24
3
 
 1  
 /*
 2  
 * $Id$
 3  
 * --------------------------------------------------------------------------------------
 4  
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.MuleMessage;
 15  
 import org.mule.transport.tcp.TcpProtocol;
 16  
 import org.mule.util.ClassUtils;
 17  
 import org.mule.util.IOUtils;
 18  
 import org.mule.util.SerializationUtils;
 19  
 
 20  
 import java.io.IOException;
 21  
 import java.io.InputStream;
 22  
 import java.io.OutputStream;
 23  
 import java.io.Serializable;
 24  
 import java.net.Socket;
 25  
 import java.net.SocketException;
 26  
 import java.net.SocketTimeoutException;
 27  
 
 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  0
     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  0
     private boolean rethrowExceptionOnRead = false;
 54  
 
 55  
     public AbstractByteProtocol(boolean streamOk)
 56  0
     {
 57  0
         this.streamOk = streamOk;
 58  0
     }
 59  
 
 60  
     public void write(OutputStream os, Object data) throws IOException
 61  
     {
 62  0
         if (data instanceof InputStream)
 63  
         {
 64  0
             if (streamOk)
 65  
             {
 66  0
                 InputStream is = (InputStream) data;
 67  0
                 IOUtils.copyLarge(is, os);
 68  0
                 os.flush();
 69  0
                 os.close();
 70  0
                 is.close();
 71  0
             }
 72  
             else
 73  
             {
 74  0
                 throw new IOException("TCP protocol " + ClassUtils.getSimpleName(getClass())
 75  
                         + " cannot handle streaming");
 76  
             }
 77  
         }
 78  0
         else if (data instanceof MuleMessage)
 79  
         {
 80  0
             write(os, ((MuleMessage) data).getPayload());
 81  
         }
 82  0
         else if (data instanceof byte[])
 83  
         {
 84  0
             writeByteArray(os, (byte[]) data);
 85  
         }
 86  0
         else if (data instanceof String)
 87  
         {
 88  
             // TODO SF: encoding is lost/ignored; it is probably a good idea to have
 89  
             // a separate "stringEncoding" property on the protocol
 90  0
             writeByteArray(os, ((String) data).getBytes());
 91  
         }
 92  0
         else if (data instanceof Serializable)
 93  
         {
 94  0
             writeByteArray(os, SerializationUtils.serialize((Serializable) data));
 95  
         }
 96  
         else
 97  
         {
 98  0
             throw new IllegalArgumentException("Cannot serialize data: " + data);
 99  
         }
 100  0
     }
 101  
 
 102  
     protected void writeByteArray(OutputStream os, byte[] data) throws IOException
 103  
     {
 104  0
         os.write(data);
 105  0
     }
 106  
 
 107  
     /**
 108  
      * Manage non-blocking reads and handle errors
 109  
      *
 110  
      * @param is     The input stream to read from
 111  
      * @param buffer The buffer to read into
 112  
      * @return The amount of data read (always non-zero, -1 on EOF or socket exception)
 113  
      * @throws IOException other than socket exceptions
 114  
      */
 115  
     protected int safeRead(InputStream is, byte[] buffer) throws IOException
 116  
     {
 117  0
         return safeRead(is, buffer, buffer.length);
 118  
     }
 119  
 
 120  
     /**
 121  
      * Manage non-blocking reads and handle errors
 122  
      *
 123  
      * @param is     The input stream to read from
 124  
      * @param buffer The buffer to read into
 125  
      * @param size   The amount of data (upper bound) to read
 126  
      * @return The amount of data read (always non-zero, -1 on EOF or socket exception)
 127  
      * @throws IOException other than socket exceptions
 128  
      */
 129  
     protected int safeRead(InputStream is, byte[] buffer, int size) throws IOException
 130  
     {
 131  
         int len;
 132  
         try
 133  
         {
 134  
             do
 135  
             {
 136  0
                 len = is.read(buffer, 0, size);
 137  0
                 if (0 == len)
 138  
                 {
 139  
                     // wait for non-blocking input stream
 140  
                     // use new lock since not expecting notification
 141  
                     try
 142  
                     {
 143  0
                         Thread.sleep(PAUSE_PERIOD);
 144  
                     }
 145  0
                     catch (InterruptedException e)
 146  
                     {
 147  
                         // no-op
 148  0
                     }
 149  
                 }
 150  
             }
 151  0
             while (0 == len);
 152  0
             return len;
 153  
         }
 154  0
         catch (SocketException e)
 155  
         {
 156  
             // do not pollute the log with a stacktrace, log only the message
 157  0
             logger.info("Socket exception occured: " + e.getMessage());
 158  0
             if (this.rethrowExceptionOnRead)
 159  
             {
 160  0
                 throw e;
 161  
             }
 162  
             else
 163  
             {
 164  0
                 return EOF;
 165  
             }
 166  
         }
 167  0
         catch (SocketTimeoutException e)
 168  
         {
 169  0
             logger.debug("Socket timeout.");
 170  0
             if (this.rethrowExceptionOnRead)
 171  
             {
 172  0
                 throw e;
 173  
             }
 174  
             else
 175  
             {
 176  0
                 return EOF;
 177  
             }
 178  
         }
 179  
     }
 180  
 
 181  
     /**
 182  
      * Make a single transfer from source to dest via a byte array buffer
 183  
      *
 184  
      * @param source Source of data
 185  
      * @param buffer Buffer array for transfer
 186  
      * @param dest   Destination of data
 187  
      * @return Amount of data transferred, or -1 on eof or socket error
 188  
      * @throws IOException On non-socket error
 189  
      */
 190  
     protected int copy(InputStream source, byte[] buffer, OutputStream dest) throws IOException
 191  
     {
 192  0
         return copy(source, buffer, dest, buffer.length);
 193  
     }
 194  
 
 195  
     /**
 196  
      * Make a single transfer from source to dest via a byte array buffer
 197  
      *
 198  
      * @param source Source of data
 199  
      * @param buffer Buffer array for transfer
 200  
      * @param dest   Destination of data
 201  
      * @param size   The amount of data (upper bound) to read
 202  
      * @return Amount of data transferred, or -1 on eof or socket error
 203  
      * @throws IOException On non-socket error
 204  
      */
 205  
     protected int copy(InputStream source, byte[] buffer, OutputStream dest, int size) throws IOException
 206  
     {
 207  0
         int len = safeRead(source, buffer, size);
 208  0
         if (len > 0)
 209  
         {
 210  0
             dest.write(buffer, 0, len);
 211  
         }
 212  0
         return len;
 213  
     }
 214  
 
 215  
     protected byte[] nullEmptyArray(byte[] data)
 216  
     {
 217  0
         if (0 == data.length)
 218  
         {
 219  0
             return null;
 220  
         }
 221  
         else
 222  
         {
 223  0
             return data;
 224  
         }
 225  
     }
 226  
 
 227  
     public ResponseOutputStream createResponse(Socket socket) throws IOException
 228  
     {
 229  0
         return new ResponseOutputStream(socket, new ProtocolStream(this, streamOk, socket.getOutputStream()));
 230  
     }
 231  
 
 232  
     public boolean isRethrowExceptionOnRead()
 233  
     {
 234  0
         return rethrowExceptionOnRead;
 235  
     }
 236  
 
 237  
     public void setRethrowExceptionOnRead(boolean rethrowExceptionOnRead)
 238  
     {
 239  0
         this.rethrowExceptionOnRead = rethrowExceptionOnRead;
 240  0
     }
 241  
 
 242  
 }