/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.activemq.artemis.core.client.impl; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import io.netty.buffer.ByteBuf; import org.apache.activemq.artemis.api.core.ActiveMQBuffer; import org.apache.activemq.artemis.api.core.ActiveMQBuffers; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.SimpleString; import org.apache.activemq.artemis.core.client.ActiveMQClientLogger; import org.apache.activemq.artemis.utils.ActiveMQBufferInputStream; import org.apache.activemq.artemis.utils.DataConstants; import org.apache.activemq.artemis.utils.InflaterReader; import org.apache.activemq.artemis.utils.InflaterWriter; import org.apache.activemq.artemis.utils.UTF8Util; final class CompressedLargeMessageControllerImpl implements LargeMessageController { private static final String OPERATION_NOT_SUPPORTED = "Operation not supported"; private final LargeMessageController bufferDelegate; CompressedLargeMessageControllerImpl(final LargeMessageController bufferDelegate) { this.bufferDelegate = bufferDelegate; } /** * */ @Override public void discardUnusedPackets() { bufferDelegate.discardUnusedPackets(); } /** * Add a buff to the List, or save it to the OutputStream if set */ @Override public void addPacket(byte[] chunk, int flowControlSize, boolean isContinues) { bufferDelegate.addPacket(chunk, flowControlSize, isContinues); } @Override public synchronized void cancel() { bufferDelegate.cancel(); } @Override public synchronized void close() { bufferDelegate.cancel(); } @Override public void setOutputStream(final OutputStream output) throws ActiveMQException { bufferDelegate.setOutputStream(new InflaterWriter(output)); } @Override public synchronized void saveBuffer(final OutputStream output) throws ActiveMQException { setOutputStream(output); waitCompletion(0); } /** * @param timeWait Milliseconds to Wait. 0 means forever */ @Override public synchronized boolean waitCompletion(final long timeWait) throws ActiveMQException { return bufferDelegate.waitCompletion(timeWait); } @Override public int capacity() { return -1; } DataInputStream dataInput = null; private DataInputStream getStream() { if (dataInput == null) { try { InputStream input = new ActiveMQBufferInputStream(bufferDelegate); dataInput = new DataInputStream(new InflaterReader(input)); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } return dataInput; } private void positioningNotSupported() { throw new IllegalStateException("Position not supported over compressed large messages"); } @Override public byte readByte() { try { return getStream().readByte(); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); } } @Override public byte getByte(final int index) { positioningNotSupported(); return 0; } @Override public void getBytes(final int index, final ActiveMQBuffer dst, final int dstIndex, final int length) { positioningNotSupported(); } @Override public void getBytes(final int index, final byte[] dst, final int dstIndex, final int length) { positioningNotSupported(); } @Override public void getBytes(final int index, final ByteBuffer dst) { positioningNotSupported(); } @Override public int getInt(final int index) { positioningNotSupported(); return 0; } @Override public long getLong(final int index) { positioningNotSupported(); return 0; } @Override public short getShort(final int index) { positioningNotSupported(); return 0; } @Override public void setByte(final int index, final byte value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setBytes(final int index, final ActiveMQBuffer src, final int srcIndex, final int length) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setBytes(final int index, final byte[] src, final int srcIndex, final int length) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setBytes(final int index, final ByteBuffer src) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setInt(final int index, final int value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setLong(final int index, final long value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setShort(final int index, final short value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public ByteBuffer toByteBuffer(final int index, final int length) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void release() { //no-op } @Override public int readerIndex() { return 0; } @Override public void readerIndex(final int readerIndex) { // TODO } @Override public int writerIndex() { // TODO return 0; } @Override public long getSize() { return this.bufferDelegate.getSize(); } @Override public void writerIndex(final int writerIndex) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setIndex(final int readerIndex, final int writerIndex) { positioningNotSupported(); } @Override public void clear() { } @Override public boolean readable() { return true; } @Override public boolean writable() { return false; } @Override public int readableBytes() { return 1; } @Override public int writableBytes() { return 0; } @Override public void markReaderIndex() { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void resetReaderIndex() { // TODO: reset positioning if possible } @Override public void markWriterIndex() { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void resetWriterIndex() { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void discardReadBytes() { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public short getUnsignedByte(final int index) { return (short) (getByte(index) & 0xFF); } @Override public int getUnsignedShort(final int index) { return getShort(index) & 0xFFFF; } @Override public long getUnsignedInt(final int index) { return getInt(index) & 0xFFFFFFFFL; } @Override public void getBytes(int index, final byte[] dst) { // TODO: optimize this by using System.arraycopy for (int i = 0; i < dst.length; i++) { dst[i] = getByte(index++); } } @Override public void getBytes(final int index, final ActiveMQBuffer dst) { getBytes(index, dst, dst.writableBytes()); } @Override public void getBytes(final int index, final ActiveMQBuffer dst, final int length) { if (length > dst.writableBytes()) { throw new IndexOutOfBoundsException(); } getBytes(index, dst, dst.writerIndex(), length); dst.writerIndex(dst.writerIndex() + length); } @Override public void setBytes(final int index, final byte[] src) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setBytes(final int index, final ActiveMQBuffer src) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setBytes(final int index, final ActiveMQBuffer src, final int length) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public int readUnsignedByte() { try { return getStream().readUnsignedByte(); } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } @Override public short readShort() { try { return getStream().readShort(); } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } @Override public int readUnsignedShort() { try { return getStream().readUnsignedShort(); } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } @Override public int readInt() { try { return getStream().readInt(); } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } @Override public long readUnsignedInt() { return readInt() & 0xFFFFFFFFL; } @Override public long readLong() { try { return getStream().readLong(); } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } @Override public void readBytes(final byte[] dst, final int dstIndex, final int length) { try { int nReadBytes = getStream().read(dst, dstIndex, length); if (nReadBytes < length) { ActiveMQClientLogger.LOGGER.compressedLargeMessageError(length, nReadBytes); } } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } @Override public void readBytes(final byte[] dst) { readBytes(dst, 0, dst.length); } @Override public void readBytes(final ActiveMQBuffer dst) { readBytes(dst, dst.writableBytes()); } @Override public void readBytes(final ActiveMQBuffer dst, final int length) { if (length > dst.writableBytes()) { throw new IndexOutOfBoundsException(); } readBytes(dst, dst.writerIndex(), length); dst.writerIndex(dst.writerIndex() + length); } @Override public void readBytes(final ActiveMQBuffer dst, final int dstIndex, final int length) { byte[] destBytes = new byte[length]; readBytes(destBytes); dst.setBytes(dstIndex, destBytes); } @Override public void readBytes(final ByteBuffer dst) { byte[] bytesToGet = new byte[dst.remaining()]; readBytes(bytesToGet); dst.put(bytesToGet); } @Override public int skipBytes(final int length) { try { for (int i = 0; i < length; i++) { getStream().read(); } return length; } catch (Exception e) { throw new IllegalStateException(e.getMessage(), e); } } /** * from {@link java.io.DataInput} interface */ @Override public void readFully(byte[] b) throws IOException { readBytes(b); } /** * from {@link java.io.DataInput} interface */ @Override public void readFully(byte[] b, int off, int len) throws IOException { readBytes(b, off, len); } /** * from {@link java.io.DataInput} interface */ @Override @SuppressWarnings("deprecation") public String readLine() throws IOException { return getStream().readLine(); } @Override public void writeByte(final byte value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeShort(final short value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeInt(final int value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeLong(final long value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeBytes(final byte[] src, final int srcIndex, final int length) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeBytes(final byte[] src) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeBytes(final ActiveMQBuffer src, final int length) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeBytes(final ByteBuffer src) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeBytes(ByteBuf src, int srcIndex, int length) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public ByteBuffer toByteBuffer() { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } public Object getUnderlyingBuffer() { return this; } @Override public boolean readBoolean() { return readByte() != 0; } @Override public char readChar() { return (char) readShort(); } @Override public char getChar(final int index) { return (char) getShort(index); } @Override public double getDouble(final int index) { return Double.longBitsToDouble(getLong(index)); } @Override public float getFloat(final int index) { return Float.intBitsToFloat(getInt(index)); } @Override public ActiveMQBuffer readBytes(final int length) { byte[] bytesToGet = new byte[length]; readBytes(bytesToGet); return ActiveMQBuffers.wrappedBuffer(bytesToGet); } @Override public double readDouble() { return Double.longBitsToDouble(readLong()); } @Override public float readFloat() { return Float.intBitsToFloat(readInt()); } @Override public SimpleString readNullableSimpleString() { int b = readByte(); if (b == DataConstants.NULL) { return null; } else { return readSimpleString(); } } @Override public String readNullableString() { int b = readByte(); if (b == DataConstants.NULL) { return null; } else { return readString(); } } @Override public SimpleString readSimpleString() { int len = readInt(); byte[] data = new byte[len]; readBytes(data); return new SimpleString(data); } @Override public String readString() { int len = readInt(); if (len < 9) { char[] chars = new char[len]; for (int i = 0; i < len; i++) { chars[i] = (char) readShort(); } return new String(chars); } else if (len < 0xfff) { return readUTF(); } else { return readSimpleString().toString(); } } @Override public String readUTF() { return UTF8Util.readUTF(this); } @Override public void writeBoolean(final boolean val) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeChar(final char val) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeDouble(final double val) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeFloat(final float val) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeNullableSimpleString(final SimpleString val) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeNullableString(final String val) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeSimpleString(final SimpleString val) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeString(final String val) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeUTF(final String utf) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public ActiveMQBuffer copy() { throw new UnsupportedOperationException(); } @Override public ActiveMQBuffer slice(final int index, final int length) { throw new UnsupportedOperationException(); } // Inner classes ------------------------------------------------- @Override public ByteBuf byteBuf() { return null; } @Override public ActiveMQBuffer copy(final int index, final int length) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public ActiveMQBuffer duplicate() { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public ActiveMQBuffer readSlice(final int length) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setChar(final int index, final char value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setDouble(final int index, final double value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void setFloat(final int index, final float value) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public ActiveMQBuffer slice() { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } @Override public void writeBytes(final ActiveMQBuffer src, final int srcIndex, final int length) { throw new IllegalAccessError(OPERATION_NOT_SUPPORTED); } }