Skip to content

Package: BufferWrapper

BufferWrapper

nameinstructionbranchcomplexitylinemethod
BufferWrapper(Object, Buffer, BufferWrapper.BufferType)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
compress(byte[])
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
compress(byte[], int, int)
M: 43 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 16 C: 0
0%
M: 1 C: 0
0%
compressBuffer(Buffer, MemoryManager)
M: 33 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
create(Object, Buffer, BufferWrapper.BufferType)
M: 20 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
decompress(byte[])
M: 10 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
decompress(byte[], int, int)
M: 70 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 26 C: 0
0%
M: 1 C: 0
0%
decompressBuffer(Buffer, int, int, MemoryManager)
M: 41 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%
getBuffer()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getOrigin()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getType()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
initialize(Object, Buffer, BufferWrapper.BufferType)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
recycle()
M: 14 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
toString()
M: 22 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
unwrap(Buffer, BufferWrapper.BufferType, MemoryManager)
M: 13 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
unwrap(Buffer, int, int, BufferWrapper.BufferType, MemoryManager)
M: 306 C: 0
0%
M: 52 C: 0
0%
M: 35 C: 0
0%
M: 93 C: 0
0%
M: 1 C: 0
0%
wrap(Object, MemoryManager)
M: 352 C: 0
0%
M: 44 C: 0
0%
M: 23 C: 0
0%
M: 88 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 2012, 2017 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package org.glassfish.grizzly.memcached;
18:
19: import org.glassfish.grizzly.Buffer;
20: import org.glassfish.grizzly.Cacheable;
21: import org.glassfish.grizzly.Grizzly;
22: import org.glassfish.grizzly.ThreadCache;
23: import org.glassfish.grizzly.memory.Buffers;
24: import org.glassfish.grizzly.memory.MemoryManager;
25: import org.glassfish.grizzly.utils.BufferInputStream;
26: import org.glassfish.grizzly.utils.BufferOutputStream;
27:
28: import java.io.ByteArrayInputStream;
29: import java.io.ByteArrayOutputStream;
30: import java.io.IOException;
31: import java.io.ObjectInputStream;
32: import java.io.ObjectOutputStream;
33: import java.io.UnsupportedEncodingException;
34: import java.nio.ByteBuffer;
35: import java.util.Date;
36: import java.util.logging.Level;
37: import java.util.logging.Logger;
38: import java.util.zip.GZIPInputStream;
39: import java.util.zip.GZIPOutputStream;
40:
41: /**
42: * Simple wrapper class for {@link Buffer}, which has original message {@code origin}, original object type {@link BufferType} and converted {@link Buffer}
43: * <p>
44: * Messages which should be sent to the remote peer via network will be always converted into {@link Buffer} instance by {@link #wrap},
45: * and the received packet will be always restored to its original messages by {@link #unwrap}
46: *
47: * @author Bongjae Chang
48: */
49: public class BufferWrapper<T> implements Cacheable {
50:
51: private static final Logger logger = Grizzly.logger(BufferWrapper.class);
52:
53: private static final ThreadCache.CachedTypeIndex<BufferWrapper> CACHE_IDX =
54: ThreadCache.obtainIndex(BufferWrapper.class, 16);
55: private static final String DEFAULT_CHARSET = "UTF-8";
56:
57: // if the size of packets is more than 16K, packets will be compressed by GZIP
58: public static final int DEFAULT_COMPRESSION_THRESHOLD = 16 * 1024; // 16K
59:
60: private Buffer buffer;
61: private BufferType type;
62: private T origin;
63:
64: public static enum BufferType {
65: NONE(0), STRING(1), STRING_COMPRESSED(2), BYTE_ARRAY(3), BYTE_ARRAY_COMPRESSED(4), BYTE_BUFFER(5), BYTE_BUFFER_COMPRESSED(6), BYTE(7), BOOLEAN(8), SHORT(9), INTEGER(10), FLOAT(11), DOUBLE(12), LONG(13), DATE(14), OBJECT(15), OBJECT_COMPRESSED(16);
66:
67: public final int flags;
68:
69: private BufferType(final int typeFlags) {
70: this.flags = typeFlags;
71: }
72:
73: public static BufferType getBufferType(final int flags) {
74: // use only 2 bytes in flags
75: final short typeFlags = (short) (flags & 0xFFFF);
76: switch (typeFlags) {
77: case 0:
78: return NONE;
79: case 1:
80: return STRING;
81: case 2:
82: return STRING_COMPRESSED;
83: case 3:
84: return BYTE_ARRAY;
85: case 4:
86: return BYTE_ARRAY_COMPRESSED;
87: case 5:
88: return BYTE_BUFFER;
89: case 6:
90: return BYTE_BUFFER_COMPRESSED;
91: case 7:
92: return BYTE;
93: case 8:
94: return BOOLEAN;
95: case 9:
96: return SHORT;
97: case 10:
98: return INTEGER;
99: case 11:
100: return FLOAT;
101: case 12:
102: return DOUBLE;
103: case 13:
104: return LONG;
105: case 14:
106: return DATE;
107: case 15:
108: return OBJECT;
109: case 16:
110: return OBJECT_COMPRESSED;
111: default:
112: throw new IllegalArgumentException("invalid type");
113: }
114: }
115: }
116:
117: private BufferWrapper(final T origin, final Buffer buffer, final BufferType type) {
118: initialize(origin, buffer, type);
119: }
120:
121: private void initialize(final T origin, final Buffer buffer, final BufferType type) {
122: this.origin = origin;
123: this.buffer = buffer;
124: this.type = type;
125: }
126:
127: /**
128: * Return original object
129: *
130: * @return original object
131: */
132: public T getOrigin() {
133: return origin;
134: }
135:
136: /**
137: * Return buffer corresponding to original object
138: *
139: * @return the converted buffer
140: */
141: public Buffer getBuffer() {
142: return buffer;
143: }
144:
145: /**
146: * Return original object's type
147: *
148: * @return buffer type
149: */
150: public BufferType getType() {
151: return type;
152: }
153:
154: @Override
155: public void recycle() {
156: origin = null;
157: buffer = null;
158: type = null;
159: ThreadCache.putToCache(CACHE_IDX, this);
160: }
161:
162: @SuppressWarnings("unchecked")
163: private static <T> BufferWrapper<T> create(final T origin, final Buffer buffer, final BufferType type) {
164: final BufferWrapper<T> bufferWrapper = ThreadCache.takeFromCache(CACHE_IDX);
165:• if (bufferWrapper != null) {
166: bufferWrapper.initialize(origin, buffer, type);
167: return bufferWrapper;
168: }
169: return new BufferWrapper<T>(origin, buffer, type);
170: }
171:
172: /**
173: * Return {@code BufferWrapper} instance from original object
174: *
175: * @param origin original object
176: * @param memoryManager the memory manager for allocating {@link Buffer}
177: * @return the buffer wrapper which included origin, buffer type and buffer corresponding to {@code origin}
178: * @throws IllegalArgumentException if given parameters are not valid
179: */
180: public static <T> BufferWrapper<T> wrap(final T origin, MemoryManager memoryManager) throws IllegalArgumentException {
181:• if (origin == null) {
182: throw new IllegalArgumentException("object must not be null");
183: }
184:• if (origin instanceof Buffer) {
185: return create(origin, (Buffer) origin, BufferWrapper.BufferType.NONE);
186: }
187:• if (memoryManager == null) {
188: memoryManager = MemoryManager.DEFAULT_MEMORY_MANAGER;
189: }
190: final Buffer buffer;
191: final BufferWrapper<T> bufferWrapper;
192:• if (origin instanceof String) {
193: buffer = Buffers.wrap(memoryManager, (String) origin);
194:• if (buffer.remaining() > DEFAULT_COMPRESSION_THRESHOLD) {
195: bufferWrapper = create(origin, compressBuffer(buffer, memoryManager), BufferType.STRING_COMPRESSED);
196: } else {
197: bufferWrapper = create(origin, buffer, BufferWrapper.BufferType.STRING);
198: }
199:• } else if (origin instanceof byte[]) {
200: final byte[] originBytes = (byte[]) origin;
201:• if (originBytes.length > DEFAULT_COMPRESSION_THRESHOLD) {
202: buffer = Buffers.wrap(memoryManager, compress(originBytes));
203: bufferWrapper = create(origin, buffer, BufferType.BYTE_ARRAY_COMPRESSED);
204: } else {
205: buffer = Buffers.wrap(memoryManager, originBytes);
206: bufferWrapper = create(origin, buffer, BufferType.BYTE_ARRAY);
207: }
208:• } else if (origin instanceof ByteBuffer) {
209: buffer = Buffers.wrap(memoryManager, (ByteBuffer) origin);
210:• if (buffer.remaining() > DEFAULT_COMPRESSION_THRESHOLD) {
211: bufferWrapper = create(origin, compressBuffer(buffer, memoryManager), BufferType.BYTE_BUFFER_COMPRESSED);
212: } else {
213: bufferWrapper = create(origin, buffer, BufferWrapper.BufferType.BYTE_BUFFER);
214: }
215:• } else if (origin instanceof Byte) {
216: buffer = memoryManager.allocate(1);
217: buffer.put((Byte) origin);
218: buffer.flip();
219: bufferWrapper = create(origin, buffer, BufferType.BYTE);
220:• } else if (origin instanceof Boolean) {
221: buffer = memoryManager.allocate(1);
222:• if ((Boolean) origin) {
223: buffer.put((byte) '1');
224: } else {
225: buffer.put((byte) '0');
226: }
227: buffer.flip();
228: bufferWrapper = create(origin, buffer, BufferType.BOOLEAN);
229:• } else if (origin instanceof Short) {
230: buffer = memoryManager.allocate(2);
231: buffer.putShort((Short) origin);
232: buffer.flip();
233: bufferWrapper = create(origin, buffer, BufferType.SHORT);
234:• } else if (origin instanceof Integer) {
235: buffer = memoryManager.allocate(4);
236: buffer.putInt((Integer) origin);
237: buffer.flip();
238: bufferWrapper = create(origin, buffer, BufferType.INTEGER);
239:• } else if (origin instanceof Float) {
240: buffer = memoryManager.allocate(4);
241: buffer.putFloat((Float) origin);
242: buffer.flip();
243: bufferWrapper = create(origin, buffer, BufferType.FLOAT);
244:• } else if (origin instanceof Double) {
245: buffer = memoryManager.allocate(8);
246: buffer.putDouble((Double) origin);
247: buffer.flip();
248: bufferWrapper = create(origin, buffer, BufferType.DOUBLE);
249:• } else if (origin instanceof Long) {
250: buffer = memoryManager.allocate(8);
251: buffer.putLong((Long) origin);
252: buffer.flip();
253: bufferWrapper = create(origin, buffer, BufferType.LONG);
254:• } else if (origin instanceof Date) {
255: buffer = memoryManager.allocate(8);
256: buffer.putLong(((Date) origin).getTime());
257: buffer.flip();
258: bufferWrapper = create(origin, buffer, BufferType.DATE);
259: } else {
260: BufferOutputStream bos = null;
261: ObjectOutputStream oos = null;
262: try {
263: bos = new BufferOutputStream(memoryManager) {
264: @Override
265: protected Buffer allocateNewBuffer(
266: final MemoryManager memoryManager, final int size) {
267: final Buffer b = memoryManager.allocate(size);
268: b.allowBufferDispose(true);
269: return b;
270: }
271: };
272: oos = new ObjectOutputStream(bos);
273: oos.writeObject(origin);
274: buffer = bos.getBuffer();
275: buffer.flip();
276:• if (buffer.remaining() > DEFAULT_COMPRESSION_THRESHOLD) {
277: bufferWrapper = create(origin, compressBuffer(buffer, memoryManager), BufferType.OBJECT_COMPRESSED);
278: } else {
279: bufferWrapper = create(origin, buffer, BufferType.OBJECT);
280: }
281: } catch (IOException ie) {
282: throw new IllegalArgumentException("Non-serializable object", ie);
283: } finally {
284:• if (oos != null) {
285: try {
286: oos.close();
287: } catch (IOException ignore) {
288: }
289: }
290:• if (bos != null) {
291: try {
292: bos.close();
293: } catch (IOException ignore) {
294: }
295: }
296: }
297: }
298:• if (buffer != null) {
299: buffer.allowBufferDispose(true);
300: }
301: return bufferWrapper;
302: }
303:
304: /**
305: * Return the original instance from {@code buffer}
306: *
307: * @param buffer the {@link Buffer} for being restored
308: * @param type the type of original object
309: * @param memoryManager the memory manager which will be used for decompressing packets
310: * @return the restored object
311: */
312: public static Object unwrap(final Buffer buffer, final BufferWrapper.BufferType type, final MemoryManager memoryManager) {
313:• if (buffer == null) {
314: return null;
315: }
316: return unwrap(buffer, buffer.position(), buffer.limit(), type, memoryManager);
317: }
318:
319: /**
320: * Return the original instance from {@code buffer}
321: *
322: * @param buffer the {@link Buffer} for being restored
323: * @param position the position of buffer to convert {@code buffer} into origin
324: * @param limit the limit of buffer to convert {@code buffer} into origin
325: * @param type the type of original object
326: * @param memoryManager the memory manager which will be used for decompressing packets
327: * @return the restored object
328: */
329: public static Object unwrap(final Buffer buffer, final int position, final int limit, final BufferWrapper.BufferType type, final MemoryManager memoryManager) {
330:• if (buffer == null || position > limit || type == null) {
331: return null;
332: }
333:• switch (type) {
334: case NONE:
335: return buffer;
336: case STRING:
337: final int length = limit - position;
338: final byte[] bytes = new byte[length];
339: buffer.get(bytes, 0, length);
340: try {
341: return new String(bytes, DEFAULT_CHARSET);
342: } catch (UnsupportedEncodingException uee) {
343:• if (logger.isLoggable(Level.WARNING)) {
344: logger.log(Level.WARNING, "failed to decode the buffer", uee);
345: }
346: return null;
347: }
348: case STRING_COMPRESSED:
349: final int length2 = limit - position;
350: final byte[] bytes2 = new byte[length2];
351: buffer.get(bytes2, 0, length2);
352: final byte[] decompressedBytes = decompress(bytes2);
353:• if (decompressedBytes == null) {
354: return null;
355: }
356: try {
357: return new String(decompressedBytes, DEFAULT_CHARSET);
358: } catch (UnsupportedEncodingException uee) {
359:• if (logger.isLoggable(Level.WARNING)) {
360: logger.log(Level.WARNING, "failed to decode the buffer", uee);
361: }
362: return null;
363: }
364: case BYTE_ARRAY:
365: final int length3 = limit - position;
366: final byte[] bytes3 = new byte[length3];
367: buffer.get(bytes3, 0, length3);
368: return bytes3;
369: case BYTE_ARRAY_COMPRESSED:
370: final int length4 = limit - position;
371: final ByteBuffer byteBuffer = buffer.toByteBuffer(position, limit);
372: return decompress(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), length4);
373: case BYTE_BUFFER:
374: return buffer.toByteBuffer(position, limit);
375: case BYTE_BUFFER_COMPRESSED:
376: final Buffer decompressedBuffer2 = decompressBuffer(buffer, position, limit, memoryManager);
377:• if (decompressedBuffer2 == null) {
378: return null;
379: }
380: final ByteBuffer result = decompressedBuffer2.toByteBuffer();
381: decompressedBuffer2.tryDispose();
382: return result;
383: case BYTE:
384: return buffer.get();
385: case BOOLEAN:
386:• return buffer.get() == '1';
387: case SHORT:
388: return buffer.getShort();
389: case INTEGER:
390: return buffer.getInt();
391: case FLOAT:
392: return buffer.getFloat();
393: case DOUBLE:
394: return buffer.getDouble();
395: case LONG:
396: return buffer.getLong();
397: case DATE:
398: long dateLong = buffer.getLong();
399: return new Date(dateLong);
400: case OBJECT:
401: BufferInputStream bis = null;
402: ObjectInputStream ois = null;
403: Object obj = null;
404: try {
405: bis = new BufferInputStream(buffer, position, limit);
406: ois = new ObjectInputStream(bis);
407: obj = ois.readObject();
408: } catch (IOException ie) {
409:• if (logger.isLoggable(Level.SEVERE)) {
410: logger.log(Level.SEVERE, "failed to read the object", ie);
411: }
412: } catch (ClassNotFoundException cnfe) {
413:• if (logger.isLoggable(Level.SEVERE)) {
414: logger.log(Level.SEVERE, "failed to read the object", cnfe);
415: }
416: } finally {
417:• if (ois != null) {
418: try {
419: ois.close();
420: } catch (IOException ignore) {
421: }
422: }
423:• if (bis != null) {
424: try {
425: bis.close();
426: } catch (IOException ignore) {
427: }
428: }
429: }
430: return obj;
431: case OBJECT_COMPRESSED:
432: final Buffer decompressedBuffer3 = decompressBuffer(buffer, position, limit, memoryManager);
433:• if (decompressedBuffer3 == null) {
434: return null;
435: }
436: BufferInputStream bis2 = null;
437: ObjectInputStream ois2 = null;
438: Object obj2 = null;
439: try {
440: bis2 = new BufferInputStream(decompressedBuffer3);
441: ois2 = new ObjectInputStream(bis2);
442: obj2 = ois2.readObject();
443: } catch (IOException ie) {
444:• if (logger.isLoggable(Level.SEVERE)) {
445: logger.log(Level.SEVERE, "failed to read the object", ie);
446: }
447: } catch (ClassNotFoundException cnfe) {
448:• if (logger.isLoggable(Level.SEVERE)) {
449: logger.log(Level.SEVERE, "failed to read the object", cnfe);
450: }
451: } finally {
452:• if (ois2 != null) {
453: try {
454: ois2.close();
455: } catch (IOException ignore) {
456: }
457: }
458:• if (bis2 != null) {
459: try {
460: bis2.close();
461: } catch (IOException ignore) {
462: }
463: }
464: }
465: decompressedBuffer3.tryDispose();
466: return obj2;
467: default:
468: return null;
469: }
470: }
471:
472: private static Buffer compressBuffer(final Buffer buffer, final MemoryManager memoryManager) {
473:• if (buffer == null) {
474: throw new IllegalArgumentException("failed to compress the buffer. buffer should be not null");
475: }
476: final ByteBuffer byteBuffer = buffer.toByteBuffer();
477: final byte[] compressed = compress(byteBuffer.array(),
478: byteBuffer.arrayOffset() + byteBuffer.position(),
479: byteBuffer.remaining());
480: byteBuffer.position(byteBuffer.limit());
481: buffer.tryDispose();
482: return Buffers.wrap(memoryManager, compressed);
483: }
484:
485: private static byte[] compress(final byte[] in) {
486: return compress(in, 0, in.length);
487: }
488:
489: private static byte[] compress(final byte[] in, final int offset, final int length) {
490:• if (in == null) {
491: throw new IllegalArgumentException("Can't compress null");
492: }
493: final ByteArrayOutputStream bos = new ByteArrayOutputStream();
494: GZIPOutputStream gz = null;
495: try {
496: gz = new GZIPOutputStream(bos);
497: gz.write(in, offset, length);
498: } catch (IOException ie) {
499: throw new RuntimeException("IO exception compressing data", ie);
500: } finally {
501:• if (gz != null) {
502: try {
503: gz.close();
504: } catch (IOException ignore) {
505: }
506: }
507: try {
508: bos.close();
509: } catch (IOException ignore) {
510: }
511: }
512: return bos.toByteArray();
513: }
514:
515: private static Buffer decompressBuffer(final Buffer buffer, final int position, final int limit, final MemoryManager memoryManager) {
516:• if (buffer == null || position > limit) {
517: return null;
518: }
519: final int length = limit - position;
520: final ByteBuffer byteBuffer = buffer.toByteBuffer(position, limit);
521: final byte[] decompressed = decompress(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), length);
522: byteBuffer.position(byteBuffer.position() + length);
523:• if (decompressed == null) {
524: return null;
525: }
526: return Buffers.wrap(memoryManager, decompressed);
527: }
528:
529: private static byte[] decompress(final byte[] in) {
530:• if (in == null) {
531: return null;
532: }
533: return decompress(in, 0, in.length);
534: }
535:
536: private static byte[] decompress(final byte[] in, final int offset, final int length) {
537: ByteArrayOutputStream bos;
538: byte[] result = null;
539:• if (in != null) {
540: ByteArrayInputStream bis = new ByteArrayInputStream(in, offset, length);
541: bos = new ByteArrayOutputStream();
542: GZIPInputStream gis = null;
543: try {
544: gis = new GZIPInputStream(bis);
545:
546: byte[] buf = new byte[8192];
547: int r;
548:• while ((r = gis.read(buf)) > 0) {
549: bos.write(buf, 0, r);
550: }
551: result = bos.toByteArray();
552: } catch (IOException ie) {
553:• if (logger.isLoggable(Level.WARNING)) {
554: logger.log(Level.WARNING, "failed to decompress bytes", ie);
555: }
556: bos = null;
557: } finally {
558:• if (gis != null) {
559: try {
560: gis.close();
561: } catch (IOException ignore) {
562: }
563: }
564: try {
565: bis.close();
566: } catch (IOException ignore) {
567: }
568:• if (bos != null) {
569: try {
570: bos.close();
571: } catch (IOException ignore) {
572: }
573: }
574: }
575: }
576: return result;
577: }
578:
579: @Override
580: public String toString() {
581: return "BufferWrapper{" +
582: "buffer=" + buffer +
583: ", type=" + type +
584: ", origin=" + origin +
585: '}';
586: }
587: }