1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package uk.ac.rdg.resc.jstyx.messages;
30
31 import org.apache.log4j.Logger;
32
33 import org.apache.mina.common.ByteBuffer;
34
35 import org.apache.mina.protocol.ProtocolViolationException;
36 import org.apache.mina.protocol.ProtocolEncoderOutput;
37
38 import uk.ac.rdg.resc.jstyx.types.DirEntry;
39 import uk.ac.rdg.resc.jstyx.StyxUtils;
40
41 /***
42 * Message returned by the server in response to a TreadMessage
43 *
44 * @author Jon Blower
45 * $Revision: 507 $
46 * $Date: 2005-12-01 08:21:56 +0000 (Thu, 01 Dec 2005) $
47 * $Log$
48 * Revision 1.18 2005/12/01 08:21:56 jonblower
49 * Fixed javadoc comments
50 *
51 * Revision 1.17 2005/11/03 21:47:17 jonblower
52 * getElements() and toFriendlyString() now use getData()
53 *
54 * Revision 1.16 2005/11/03 17:09:27 jonblower
55 * Created more efficient RreadMessage that involves less copying of buffers (still reliable)
56 *
57 * Revision 1.15 2005/11/03 16:02:54 jonblower
58 * Created simplified version (less efficient, more reliable)
59 *
60 * Revision 1.13 2005/09/02 16:52:38 jonblower
61 * Fixed bugs that caused message payload to be printed as empty string
62 *
63 * Revision 1.11 2005/05/10 19:17:54 jonblower
64 * Added dispose() method
65 *
66 * Revision 1.10 2005/05/10 08:02:06 jonblower
67 * Changes related to implementing MonitoredFileOnDisk
68 *
69 * Revision 1.9 2005/03/22 17:48:27 jonblower
70 * Removed debug code that tracked ByteBuffer allocation
71 *
72 * Revision 1.8 2005/03/21 17:57:10 jonblower
73 * Trying to fix ByteBuffer leak in SGS server
74 *
75 * Revision 1.7 2005/03/18 13:56:00 jonblower
76 * Improved freeing of ByteBuffers, and bug fixes
77 *
78 * Revision 1.6 2005/03/16 22:16:43 jonblower
79 * Added Styx Grid Service classes to core module
80 *
81 * Revision 1.5 2005/03/16 17:56:22 jonblower
82 * Replaced use of java.nio.ByteBuffer with MINA's ByteBuffer to minimise copying of buffers
83 *
84 * Revision 1.4 2005/03/15 09:01:48 jonblower
85 * Message type now stored as short, not int
86 *
87 * Revision 1.3 2005/03/11 14:02:15 jonblower
88 * Merged MINA-Test_20059309 into main line of development
89 *
90 * Revision 1.2.2.2 2005/03/11 12:30:45 jonblower
91 * Changed so that message payloads are always ints, not longs
92 *
93 * Revision 1.2.2.1 2005/03/10 11:50:59 jonblower
94 * Changed to fit with MINA framework
95 *
96 * Revision 1.2 2005/02/24 07:44:43 jonblower
97 * Added getFriendlyString()
98 *
99 * Revision 1.1.1.1 2005/02/16 18:58:27 jonblower
100 * Initial import
101 *
102 */
103 public class RreadMessage extends StyxMessage
104 {
105
106 private static final Logger log = Logger.getLogger(RreadMessage.class);
107
108 private ByteBuffer data;
109 private int pos;
110 private int count;
111
112 /***
113 * Creates a new RversionMessage
114 * @param length The total length of the message (including all header info)
115 * @param type The type of the message (a number between 100 and 127)
116 * @param tag The tag that identifies this message
117 */
118 public RreadMessage(int length, short type, int tag)
119 {
120 super(length, type, tag);
121 this.name = "Rread";
122 }
123
124 /***
125 * Creates an RreadMessage from the given byte array
126 */
127 public RreadMessage(byte[] bytes)
128 {
129 this(bytes, 0, bytes.length);
130 }
131
132 /***
133 * Creates an RreadMessage from the given byte array. This will return
134 * <code>count</code> bytes, starting at position <code>pos</code> in the
135 * given array
136 * @throws IllegalArgumentException if <code>pos + count > bytes.length</code>
137 */
138 public RreadMessage(byte[] bytes, int pos, int count)
139 {
140 this(0, (short)117, 0);
141 if (pos + count > bytes.length)
142 {
143 throw new IllegalArgumentException("Not enough bytes in the given byte array:" +
144 " pos = " + pos + ", count = " + count + ", length = " + bytes.length);
145 }
146 this.data = ByteBuffer.wrap(bytes, pos, count);
147 this.pos = pos;
148 this.count = count;
149 this.length = StyxUtils.HEADER_LENGTH + 4 + this.count;
150 if (log.isDebugEnabled())
151 {
152 log.debug("Created RreadMessage from array with " + bytes.length
153 + " bytes, pos = " + pos + ", count = " + count + ", length = " + this.length);
154 }
155 }
156
157 /***
158 * Creates an RreadMessage from the given org.apache.mina.common.ByteBuffer.
159 * The position and limit of the buffer must be set correctly. This method
160 * will not acquire() or release() the buffer: the buffer will be released
161 * automatically when the data are written to the network. Users of this
162 * constructor therefore should not release the buffer after using this
163 * constructor otherwise the data will no longer be valid.
164 */
165 public RreadMessage(ByteBuffer data)
166 {
167 this(0, (short)117, 0);
168 this.data = data;
169 this.pos = data.position();
170 this.count = data.remaining() - this.pos;
171 this.length = StyxUtils.HEADER_LENGTH + 4 + this.count;
172 if (log.isDebugEnabled())
173 {
174 log.debug("Created RreadMessage from buffer with pos = " +
175 data.position() + ", limit = " + data.limit() +
176 ", length = " + this.length);
177 }
178 }
179
180 /***
181 * @throws ProtocolViolationException if the payload of the message is more
182 * than Integer.MAX_VALUE
183 */
184 protected final void decodeBody(StyxBuffer buf)
185 throws ProtocolViolationException
186 {
187 long n = buf.getUInt();
188 if (n < 0 || n > Integer.MAX_VALUE)
189 {
190 throw new ProtocolViolationException("Payload of Rread message " +
191 "cannot be less than 0 or greater than Integer.MAX_VALUE bytes");
192 }
193 this.count = (int)n;
194
195 if (buf.remaining() == this.count)
196 {
197
198
199
200 this.data = buf.getBuffer();
201
202
203
204 this.data.acquire();
205
206
207 this.pos = this.data.position();
208
209
210
211
212 this.data.position(this.data.limit());
213 }
214 else
215 {
216
217 log.debug("Need to make a copy of the data in this buffer: " +
218 this.count + " bytes");
219 byte[] b = buf.getData(this.count);
220 this.data = ByteBuffer.wrap(b);
221 this.pos = 0;
222 }
223 }
224
225 /***
226 * Writes the message into the given StyxBuffer.
227 */
228 protected final void encodeBody(StyxBuffer buf)
229 {
230 buf.putUInt(this.count).putData(this.getData());
231 }
232
233 /***
234 * @return the data contained in this message as a MINA ByteBuffer. Makes
235 * sure that the position and limit of the buffer are set correctly
236 */
237 public ByteBuffer getData()
238 {
239
240
241 this.data.position(this.pos).limit(this.pos + this.count);
242 return this.data;
243 }
244
245 /***
246 * @return the number of bytes returned in the message (i.e. the payload size)
247 */
248 public int getCount()
249 {
250 return this.count;
251 }
252
253 /***
254 * This is called <b>after</b> the message has been sent (in
255 * StyxServerProtocolHandler.messageSent(). This releases the ByteBuffer
256 * holding the payload of the message.
257 */
258 public void dispose()
259 {
260 this.data.release();
261 }
262
263 protected String getElements()
264 {
265 StringBuffer s = new StringBuffer(", " + this.count + ", ");
266 s.append(StyxUtils.getDataSummary(30, this.getData()));
267 return s.toString();
268 }
269
270 public String toFriendlyString()
271 {
272 StringBuffer s = new StringBuffer("count: ");
273 s.append(this.count);
274 s.append(", ");
275 s.append(StyxUtils.getDataSummary(30, this.getData()));
276 return s.toString();
277 }
278
279 }