KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mysql > jdbc > ChannelBuffer


1 /*
2  Copyright (C) 2002-2004 MySQL AB
3
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of version 2 of the GNU General Public License as
6  published by the Free Software Foundation.
7
8  There are special exceptions to the terms and conditions of the GPL
9  as it is applied to this software. View the full text of the
10  exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
11  software distribution.
12
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22
23
24  */

25 package com.mysql.jdbc;
26
27 import java.io.UnsupportedEncodingException JavaDoc;
28 import java.nio.ByteBuffer JavaDoc;
29
30 import java.sql.SQLException JavaDoc;
31
32 /**
33  * Buffer contains code to read and write packets from/to the MySQL server.
34  *
35  * @version $Id: ChannelBuffer.java,v 1.1.2.2 2005/05/19 15:52:24 mmatthews Exp $
36  * @author Mark Matthews
37  */

38 class ChannelBuffer extends Buffer {
39
40     private byte[] asBytes = null;
41
42     // private int position = 0;
43

44     private int bufLength = 0;
45
46     private ByteBuffer JavaDoc directBuffer;
47
48     private boolean dirty = true;
49
50     ChannelBuffer(byte[] buf) {
51         this.directBuffer = ByteBuffer.wrap(buf);
52         setBufLength(buf.length);
53     }
54
55     ChannelBuffer(int size, boolean direct) {
56
57         if (direct) {
58             this.directBuffer = ByteBuffer.allocateDirect(size);
59         } else {
60             this.directBuffer = ByteBuffer.allocate(size);
61         }
62
63         // this.directBuffer.limit(size);
64
setBufLength(size);
65         // this.position = MysqlIO.HEADER_LENGTH;
66
this.directBuffer.position(MysqlIO.HEADER_LENGTH);
67     }
68
69     private byte[] bufferToArray() {
70         if (!this.dirty) {
71             return this.asBytes;
72         } else if (this.directBuffer.hasArray()) {
73             this.asBytes = this.directBuffer.array();
74             this.dirty = false;
75
76             return this.asBytes;
77         } else {
78             int bufferLength = this.directBuffer.limit();
79
80             this.asBytes = new byte[bufferLength];
81
82             int oldPosition = getPosition();
83
84             this.directBuffer.position(0);
85             this.directBuffer.get(this.asBytes, 0, bufferLength);
86             this.directBuffer.position(oldPosition);
87             this.dirty = false;
88
89             return this.asBytes;
90         }
91     }
92
93     final void clear() {
94         this.directBuffer.position(MysqlIO.HEADER_LENGTH);
95     }
96
97     final void ensureCapacity(int additionalData) throws SQLException JavaDoc {
98         int bufferCapacity = this.directBuffer.capacity();
99
100         int currentPosition = this.directBuffer.position();
101
102         if ((currentPosition + additionalData) > getBufLength()) {
103             if ((currentPosition + additionalData) < bufferCapacity) {
104                 // byteBuffer.length is != getBufLength() all of the time
105
// due to re-using of packets (we don't shrink them)
106
//
107
// If we can, don't re-alloc, just set buffer length
108
// to size of current buffer
109
setBufLength(currentPosition + additionalData);
110             } else {
111                 //
112
// Otherwise, re-size, and pad so we can avoid
113
// allocing again in the near future
114
//
115

116                 int newLength = (int) (bufferCapacity * 1.25);
117
118                 if (newLength < 4096) {
119                     newLength = 4096;
120                 }
121
122                 if (newLength < (bufferCapacity + additionalData)) {
123                     newLength = bufferCapacity + (int) (additionalData * 1.25);
124                 }
125
126                 if (newLength < bufferCapacity) {
127                     newLength = bufferCapacity + additionalData;
128                 }
129
130                 ByteBuffer JavaDoc largerBuffer = ByteBuffer.allocateDirect(newLength);
131
132                 this.directBuffer.position(0);
133                 largerBuffer.put(this.directBuffer);
134                 this.directBuffer = largerBuffer;
135                 this.directBuffer.position(currentPosition);
136
137                 bufferCapacity = this.directBuffer.capacity(); // re-alloc'd
138
setBufLength(bufferCapacity);
139
140             }
141         }
142     }
143
144     /**
145      * Skip over a length-encoded string
146      *
147      * @return The position past the end of the string
148      */

149     public int fastSkipLenString() {
150         long len = this.readFieldLength();
151
152         // position += len;
153

154         this.directBuffer.position((int) (this.directBuffer.position() + len));
155
156         return (int) len; // this is safe, as this is only
157
}
158
159     int getBufLength() {
160         return this.directBuffer.limit();
161     }
162
163     /**
164      * Returns the array of bytes this Buffer is using to read from.
165      *
166      * @return byte array being read from
167      */

168     public byte[] getByteBuffer() {
169         return bufferToArray();
170     }
171
172     final byte[] getBytes(int len) {
173         byte[] b = new byte[len];
174         byte[] nioByteBuffer = bufferToArray();
175
176         try {
177
178             System.arraycopy(nioByteBuffer, this.directBuffer.position(), b, 0,
179                     len);
180             // this.position += len; // update cursor
181
this.directBuffer.position((this.directBuffer.position() + len));
182         } catch (ArrayIndexOutOfBoundsException JavaDoc aiobex) {
183             throw aiobex;
184         }
185
186         return b;
187     }
188
189     /*
190      * (non-Javadoc)
191      *
192      * @see com.mysql.jdbc.Buffer#getBytes(int, int)
193      */

194     byte[] getBytes(int offset, int len) {
195         byte[] b = new byte[len];
196         byte[] nioByteBuffer = bufferToArray();
197
198         try {
199
200             System.arraycopy(nioByteBuffer, offset, b, 0, len);
201             // this.position += len; // update cursor
202
this.directBuffer.position((offset + len));
203         } catch (ArrayIndexOutOfBoundsException JavaDoc aiobex) {
204             throw aiobex;
205         }
206
207         return b;
208     }
209
210     int getCapacity() {
211         return this.directBuffer.capacity();
212     }
213
214     public ByteBuffer JavaDoc getNioBuffer() {
215         return this.directBuffer;
216     }
217
218     /**
219      * Returns the current position to write to/ read from
220      *
221      * @return the current position to write to/ read from
222      */

223     public int getPosition() {
224         // if (directBuffer.position() != this.position) {
225
// System.err.println("WARN: directBuffer position != this.position");
226
// }
227

228         return this.directBuffer.position();
229     }
230
231     // 2000-06-05 Changed
232
final boolean isLastDataPacket() {
233         boolean hasMarker = ((this.directBuffer.get(0) & 0xff) == 254);
234
235         return (hasMarker && this.bufLength < 9);
236     }
237
238     final long newReadLength() {
239         int sw = this.directBuffer.get(this.directBuffer.position()) & 0xff;
240         this.directBuffer.position(this.directBuffer.position() + 1);
241
242         switch (sw) {
243         case 251:
244             return 0;
245
246         case 252:
247             return readInt();
248
249         case 253:
250             return readLongInt();
251
252         case 254: // changed for 64 bit lengths
253
return readLongLong();
254
255         default:
256             return sw;
257         }
258     }
259
260     final byte readByte() {
261         byte b = this.directBuffer.get();
262
263         return b;
264     }
265
266     final byte readByte(int readAt) {
267         return this.directBuffer.get(readAt);
268     }
269
270     final long readFieldLength() {
271         int sw = this.directBuffer.get() & 0xff;
272
273         switch (sw) {
274         case 251:
275             return NULL_LENGTH;
276
277         case 252:
278             return readInt();
279
280         case 253:
281             return readLongInt();
282
283         case 254:
284             return readLongLong();
285
286         default:
287             return sw;
288         }
289     }
290
291     final int readInt() {
292         return (this.directBuffer.get() & 0xff)
293                 | ((this.directBuffer.get() & 0xff) << 8);
294     }
295
296     final int readIntAsLong() {
297         int i = (this.directBuffer.get() & 0xff)
298                 | ((this.directBuffer.get() & 0xff) << 8)
299                 | ((this.directBuffer.get() & 0xff) << 16)
300                 | ((this.directBuffer.get() & 0xff) << 24);
301
302         // this.directBuffer.position(this.position);
303

304         return i;
305     }
306
307     final byte[] readLenByteArray(int offset) {
308         long len = this.readFieldLength();
309
310         if (len == NULL_LENGTH) {
311             return null;
312         }
313
314         if (len == 0) {
315             return Constants.EMPTY_BYTE_ARRAY;
316         }
317
318         this.directBuffer.position(this.directBuffer.position() + offset);
319         // this.directBuffer.position(this.position);
320

321         return getBytes((int) len);
322     }
323
324     final long readLength() {
325         int sw = this.directBuffer.get() & 0xff;
326         // this.directBuffer.position(this.position);
327

328         switch (sw) {
329         case 251:
330             return 0;
331
332         case 252:
333             return readInt();
334
335         case 253:
336             return readLongInt();
337
338         case 254:
339             return readLong();
340
341         default:
342             return sw;
343         }
344     }
345
346     final long readLong() {
347         long l = (this.directBuffer.get() & 0xff)
348                 | ((this.directBuffer.get() & 0xff) << 8)
349                 | ((this.directBuffer.get() & 0xff) << 16)
350                 | ((this.directBuffer.get() & 0xff) << 24);
351
352         // this.directBuffer.position(this.position);
353

354         return l;
355     }
356
357     final int readLongInt() {
358
359         int i = (this.directBuffer.get() & 0xff)
360                 | ((this.directBuffer.get() & 0xff) << 8)
361                 | ((this.directBuffer.get() & 0xff) << 16);
362
363         // this.directBuffer.position(this.position);
364

365         return i;
366     }
367
368     // 2000-06-05 Fixed
369
final long readLongLong() {
370
371         long l = (this.directBuffer.get() & 0xff)
372                 | ((long) (this.directBuffer.get() & 0xff) << 8)
373                 | ((long) (this.directBuffer.get() & 0xff) << 16)
374                 | ((long) (this.directBuffer.get() & 0xff) << 24)
375                 | ((long) (this.directBuffer.get() & 0xff) << 32)
376                 | ((long) (this.directBuffer.get() & 0xff) << 40)
377                 | ((long) (this.directBuffer.get() & 0xff) << 48)
378                 | ((long) (this.directBuffer.get() & 0xff) << 56);
379
380         // this.directBuffer.position(this.position);
381

382         return l;
383     }
384
385     final int readnBytes() {
386         int sw = this.directBuffer.get() & 0xff;
387         // this.directBuffer.position(this.position);
388

389         switch (sw) {
390         case 1:
391             return this.directBuffer.get() & 0xff;
392
393         case 2:
394             return this.readInt();
395
396         case 3:
397             return this.readLongInt();
398
399         case 4:
400             return (int) this.readLong();
401
402         default:
403             return 255;
404         }
405     }
406
407     //
408
// Read a null-terminated string
409
//
410
// To avoid alloc'ing a new byte array, we
411
// do this by hand, rather than calling getNullTerminatedBytes()
412
//
413
final String JavaDoc readString() {
414
415         int len = 0;
416         int maxLen = getBufLength();
417         int oldPosition = getPosition();
418
419         while ((getPosition() < maxLen) && (this.directBuffer.get() != 0)) {
420             len++;
421         }
422
423         setPosition(oldPosition);
424
425         String JavaDoc s = new String JavaDoc(bufferToArray(), getPosition(), len);
426
427         this.directBuffer.position(getPosition() + len + 1); // update cursor
428

429         return s;
430     }
431
432     final String JavaDoc readString(String JavaDoc encoding) throws SQLException JavaDoc {
433
434         int len = 0;
435
436         int maxLen = getBufLength();
437
438         while ((getPosition() < maxLen) && (this.directBuffer.get() != 0)) {
439             len++;
440         }
441
442         try {
443             return new String JavaDoc(bufferToArray(), getPosition(), len, encoding);
444         } catch (UnsupportedEncodingException JavaDoc uEE) {
445             throw new SQLException JavaDoc(
446                     Messages.getString("ChannelBuffer.0") //$NON-NLS-1$
447
+ encoding + Messages.getString("ChannelBuffer.1"), SQLError.SQL_STATE_ILLEGAL_ARGUMENT); //$NON-NLS-1$
448
} finally {
449             this.directBuffer.position(getPosition() + len + 1); // update
450
// cursor
451
}
452     }
453
454     void setBufLength(int bufLengthToSet) {
455         this.bufLength = bufLengthToSet;
456         this.directBuffer.limit(this.bufLength);
457         this.dirty = true;
458     }
459
460     /**
461      * Sets the array of bytes to use as a buffer to read from.
462      *
463      * @param byteBuffer
464      * the array of bytes to use as a buffer
465      */

466     public void setByteBuffer(byte[] byteBuffer) {
467         this.directBuffer = ByteBuffer.wrap(byteBuffer);
468     }
469
470     /**
471      * Set the current position to write to/ read from
472      *
473      * @param position
474      * the position (0-based index)
475      */

476     public void setPosition(int position) {
477         // this.position = position;
478
this.directBuffer.position(position);
479     }
480
481     final void writeByte(byte b) throws SQLException JavaDoc {
482         ensureCapacity(1);
483
484         this.directBuffer.put(b);
485         this.dirty = true;
486     }
487
488     // Write a byte array
489
final void writeBytesNoNull(byte[] bytes) throws SQLException JavaDoc {
490         int len = bytes.length;
491         ensureCapacity(len);
492
493         this.directBuffer.put(bytes, 0, len);
494         this.dirty = true;
495     }
496
497     // Write a byte array with the given offset and length
498
final void writeBytesNoNull(byte[] bytes, int offset, int length)
499             throws SQLException JavaDoc {
500         ensureCapacity(length);
501
502         this.directBuffer.put(bytes, offset, length);
503
504         this.dirty = true;
505     }
506
507     final void writeDouble(double d) throws SQLException JavaDoc {
508         long l = Double.doubleToLongBits(d);
509         writeLongLong(l);
510         this.dirty = true;
511     }
512
513     final void writeFieldLength(long length) throws SQLException JavaDoc {
514         if (length < 251) {
515             writeByte((byte) length);
516         } else if (length < 65536L) {
517             ensureCapacity(3);
518             writeByte((byte) 252);
519             writeInt((int) length);
520         } else if (length < 16777216L) {
521             ensureCapacity(4);
522             writeByte((byte) 253);
523             writeLongInt((int) length);
524         } else {
525             ensureCapacity(9);
526             writeByte((byte) 254);
527             writeLongLong(length);
528         }
529
530     }
531
532     final void writeFloat(float f) throws SQLException JavaDoc {
533         ensureCapacity(4);
534
535         int i = Float.floatToIntBits(f);
536
537         this.directBuffer.put((byte) (i & 0xff));
538         this.directBuffer.put((byte) (i >>> 8));
539         this.directBuffer.put((byte) (i >>> 16));
540         this.directBuffer.put((byte) (i >>> 24));
541
542         this.dirty = true;
543     }
544
545     // 2000-06-05 Changed
546
final void writeInt(int i) throws SQLException JavaDoc {
547         ensureCapacity(2);
548         this.directBuffer.put((byte) (i & 0xff));
549         this.directBuffer.put((byte) (i >>> 8));
550
551         this.dirty = true;
552     }
553
554     // Write a String using the specified character
555
// encoding
556
final void writeLenBytes(byte[] b) throws SQLException JavaDoc {
557         int len = b.length;
558         ensureCapacity(len + 9);
559         writeFieldLength(len);
560         this.directBuffer.put(b, 0, len);
561
562         this.dirty = true;
563     }
564
565     // Write a String using the specified character
566
// encoding
567
final void writeLenString(String JavaDoc s, String JavaDoc encoding, String JavaDoc serverEncoding,
568             SingleByteCharsetConverter converter, boolean parserKnowsUnicode)
569             throws UnsupportedEncodingException JavaDoc, SQLException JavaDoc {
570         byte[] b = null;
571
572         if (converter != null) {
573             b = converter.toBytes(s);
574         } else {
575             b = StringUtils.getBytes(s, encoding, serverEncoding,
576                     parserKnowsUnicode);
577         }
578
579         int len = b.length;
580         ensureCapacity(len + 9);
581         writeFieldLength(len);
582         this.directBuffer.put(b, 0, len);
583
584         this.dirty = true;
585     }
586
587     // 2000-06-05 Changed
588
final void writeLong(long i) throws SQLException JavaDoc {
589         ensureCapacity(4);
590
591         this.directBuffer.put((byte) (i & 0xff));
592         this.directBuffer.put((byte) (i >>> 8));
593         this.directBuffer.put((byte) (i >>> 16));
594         this.directBuffer.put((byte) (i >>> 24));
595
596         this.dirty = true;
597     }
598
599     // 2000-06-05 Changed
600
final void writeLongInt(int i) throws SQLException JavaDoc {
601         ensureCapacity(3);
602
603         this.directBuffer.put((byte) (i & 0xff));
604         this.directBuffer.put((byte) (i >>> 8));
605         this.directBuffer.put((byte) (i >>> 16));
606
607         this.dirty = true;
608     }
609
610     final void writeLongLong(long i) throws SQLException JavaDoc {
611         ensureCapacity(8);
612
613         this.directBuffer.put((byte) (i & 0xff));
614         this.directBuffer.put((byte) (i >>> 8));
615         this.directBuffer.put((byte) (i >>> 16));
616         this.directBuffer.put((byte) (i >>> 24));
617         this.directBuffer.put((byte) (i >>> 32));
618         this.directBuffer.put((byte) (i >>> 40));
619         this.directBuffer.put((byte) (i >>> 48));
620         this.directBuffer.put((byte) (i >>> 56));
621
622         this.dirty = true;
623     }
624
625     // Write null-terminated string
626
final void writeString(String JavaDoc s) throws SQLException JavaDoc {
627         ensureCapacity((s.length() * 2) + 1);
628
629         writeStringNoNull(s);
630         this.directBuffer.put((byte) 0);
631
632         this.dirty = true;
633     }
634
635     // Write string, with no termination
636
final void writeStringNoNull(String JavaDoc s) throws SQLException JavaDoc {
637         int len = s.length();
638         ensureCapacity(len * 2);
639
640         this.directBuffer.put(s.getBytes(), 0, len);
641
642         this.dirty = true;
643     }
644
645     // Write a String using the specified character
646
// encoding
647
final void writeStringNoNull(String JavaDoc s, String JavaDoc encoding,
648             String JavaDoc serverEncoding, boolean parserKnowsUnicode)
649             throws UnsupportedEncodingException JavaDoc, SQLException JavaDoc {
650         byte[] b = StringUtils.getBytes(s, encoding, serverEncoding,
651                 parserKnowsUnicode);
652
653         int len = b.length;
654         ensureCapacity(len);
655
656         this.directBuffer.put(b, 0, len);
657
658         this.dirty = true;
659     }
660 }
661
Popular Tags