View Javadoc

1   /*
2    * $Id: LengthProtocol.java 7976 2007-08-21 14:26:13Z dirk.olmes $
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.providers.tcp.protocols;
12  
13  import java.io.DataInputStream;
14  import java.io.DataOutputStream;
15  import java.io.IOException;
16  import java.io.InputStream;
17  import java.io.OutputStream;
18  
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  
22  /**
23   * The LengthProtocol is an application level tcp protocol that can be used to
24   * transfer large amounts of data without risking some data to be loss. The protocol
25   * is defined by sending / reading an integer (the packet length) and then the data
26   * to be transferred.
27   *
28   * <p>Note that use of this protocol must be symmetric - both the sending and receiving
29   * connectors must use the same protocol.</p>
30   */
31  public class LengthProtocol extends DefaultProtocol
32  {
33  
34      private static final Log logger = LogFactory.getLog(LengthProtocol.class);
35      // TODO - can we not get this from the API somewhere?
36      private static final int SIZE_INT = 4;
37  
38      public LengthProtocol()
39      {
40          super(NO_STREAM, SIZE_INT);
41      }
42  
43      public Object read(InputStream is) throws IOException
44      {
45          // original comments indicated that we nede to use read(byte[]) rather than readInt()
46          // to avoid socket timeouts - don't understand, but don't want to risk change.
47  
48          // first read the data necessary to know the length of the payload
49          DataInputStream dis = new DataInputStream(is);
50          dis.mark(SIZE_INT);
51          // this pulls through SIZE_INT bytes
52          if (null == super.read(dis, SIZE_INT))
53          {
54              return null; // eof
55          }
56  
57          // reset and read the integer
58          dis.reset();
59          int length = dis.readInt();
60          if (logger.isDebugEnabled())
61          {
62              logger.debug("length: " + length);
63          }
64  
65          // finally read the rest of the data
66          byte[] buffer = new byte[length];
67          dis.readFully(buffer);
68          if (logger.isDebugEnabled())
69          {
70              logger.debug("length read: " + buffer.length);
71          }
72  
73          return buffer;
74      }
75  
76      // @Override
77      protected void writeByteArray(OutputStream os, byte[] data) throws IOException
78      {
79          // Write the length and then the data.
80          DataOutputStream dos = new DataOutputStream(os);
81          dos.writeInt(data.length);
82          dos.write(data);
83          dos.flush();
84      }
85  
86      /**
87       * Read all four bytes for initial integer (limit is set in read)
88       *
89       * @param len Amount transferred last call (-1 on EOF or socket error)
90       * @param available Amount available
91       * @return true if the transfer should continue
92       */
93      // @Override
94      protected boolean isRepeat(int len, int available)
95      {
96          return true;
97      }
98  
99  }