Java tutorial
/* * Copyright (c) 2013-2014 the original author or authors * * Licensed 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 io.werval.server.netty; import io.netty.buffer.AbstractByteBuf; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.werval.api.exceptions.WervalException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; import java.nio.file.Files; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static io.netty.buffer.Unpooled.wrappedBuffer; /** * Read-only ByteBuff wrapping a File. * <p>Used by {@link HttpRequestAggregator} to aggregate requests bodies.</p> * <p>Used by {@link WervalHttpHandler} to parse requests bodies.</p> */ // CHECKSTYLE:OFF public final class FileByteBuff extends AbstractByteBuf { private static final Logger LOG = LoggerFactory.getLogger(FileByteBuff.class); private static final String NOT_SUPPORTED = "Not supported"; private static final String READ_ONLY = "Read Only."; private final File file; private final long length; private int refCnt = 1; public FileByteBuff(File file) throws FileNotFoundException { super(Integer.MAX_VALUE); this.file = file; this.length = file.length(); } @Override public int readableBytes() { if (length < Integer.MIN_VALUE || length > Integer.MAX_VALUE) { throw new IllegalArgumentException(length + " cannot be cast to int without changing its value."); } return (int) length; } public InputStream getInputStream() { try { return new FileInputStream(file); } catch (FileNotFoundException ex) { throw new WervalException("File " + file + " backing FileByteBuff disapeared! " + ex.getMessage(), ex); } } public byte[] readAllBytes() { try { return Files.readAllBytes(file.toPath()); } catch (IOException ex) { throw new WervalException(ex.getMessage(), ex); } } @Override protected byte _getByte(int index) { try (RandomAccessFile raf = new RandomAccessFile(file, "r")) { raf.seek(index); return raf.readByte(); } catch (IOException ex) { throw new WervalException(ex.getMessage(), ex); } } @Override protected short _getShort(int index) { try (RandomAccessFile raf = new RandomAccessFile(file, "r")) { raf.seek(index); return raf.readShort(); } catch (IOException ex) { throw new WervalException(ex.getMessage(), ex); } } @Override protected int _getUnsignedMedium(int index) { throw new UnsupportedOperationException(NOT_SUPPORTED); } @Override protected int _getInt(int index) { try (RandomAccessFile raf = new RandomAccessFile(file, "r")) { raf.seek(index); return raf.readInt(); } catch (IOException ex) { throw new WervalException(ex.getMessage(), ex); } } @Override protected long _getLong(int index) { try (RandomAccessFile raf = new RandomAccessFile(file, "r")) { raf.seek(index); return raf.readLong(); } catch (IOException ex) { throw new WervalException(ex.getMessage(), ex); } } @Override protected void _setByte(int index, int value) { throw new UnsupportedOperationException(READ_ONLY); } @Override protected void _setShort(int index, int value) { throw new UnsupportedOperationException(READ_ONLY); } @Override protected void _setMedium(int index, int value) { throw new UnsupportedOperationException(READ_ONLY); } @Override protected void _setInt(int index, int value) { throw new UnsupportedOperationException(READ_ONLY); } @Override protected void _setLong(int index, long value) { throw new UnsupportedOperationException(READ_ONLY); } @Override public int capacity() { if (length < Integer.MIN_VALUE || length > Integer.MAX_VALUE) { throw new IllegalArgumentException(length + " cannot be cast to int without changing its value."); } return (int) length; } @Override public ByteBuf capacity(int newCapacity) { throw new UnsupportedOperationException(READ_ONLY); } @Override public ByteBufAllocator alloc() { return null; } @Override public ByteOrder order() { return ByteOrder.nativeOrder(); } @Override public ByteBuf unwrap() { return null; } @Override public boolean isDirect() { return true; } @Override public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { throw new UnsupportedOperationException(NOT_SUPPORTED); } @Override public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { checkIndex(index, length); checkDstIndex(index, length, dstIndex, dst.length); try (RandomAccessFile raf = new RandomAccessFile(file, "r")) { raf.seek(index); raf.read(dst, dstIndex, length); return this; } catch (IOException ex) { throw new WervalException(ex.getMessage(), ex); } } @Override public ByteBuf getBytes(int index, ByteBuffer dst) { checkIndex(index); try (RandomAccessFile raf = new RandomAccessFile(file, "r")) { raf.seek(index); byte[] buffer = new byte[8]; while (dst.position() < dst.limit()) { int read = raf.read(buffer); if (read == -1) { break; } dst.put(buffer, 0, read); } return this; } catch (IOException ex) { throw new WervalException(ex.getMessage(), ex); } } @Override public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { throw new UnsupportedOperationException(NOT_SUPPORTED); } @Override public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { throw new UnsupportedOperationException(NOT_SUPPORTED); } @Override public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { throw new UnsupportedOperationException(READ_ONLY); } @Override public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { throw new UnsupportedOperationException(READ_ONLY); } @Override public ByteBuf setBytes(int index, ByteBuffer src) { throw new UnsupportedOperationException(READ_ONLY); } @Override public int setBytes(int index, InputStream in, int length) throws IOException { throw new UnsupportedOperationException(READ_ONLY); } @Override public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { throw new UnsupportedOperationException(READ_ONLY); } @Override public ByteBuf copy(int index, int length) { byte[] buf = new byte[length]; try (RandomAccessFile raf = new RandomAccessFile(file, "r")) { raf.read(buf, index, length); return wrappedBuffer(buf); } catch (IOException ex) { throw new WervalException(ex.getMessage(), ex); } } @Override public int nioBufferCount() { return -1; } @Override public ByteBuffer nioBuffer(int index, int length) { throw new UnsupportedOperationException(NOT_SUPPORTED); } @Override public ByteBuffer[] nioBuffers(int index, int length) { throw new UnsupportedOperationException(NOT_SUPPORTED); } @Override public boolean hasArray() { return false; } @Override public byte[] array() { throw new UnsupportedOperationException(NOT_SUPPORTED); } @Override public int arrayOffset() { throw new UnsupportedOperationException(NOT_SUPPORTED); } @Override public boolean hasMemoryAddress() { return false; } @Override public long memoryAddress() { throw new UnsupportedOperationException(NOT_SUPPORTED); } @Override public ByteBuf retain(int increment) { refCnt += increment; return this; } @Override public ByteBuf retain() { return retain(1); } @Override public int refCnt() { return refCnt; } @Override public boolean release() { return release(1); } @Override public boolean release(int decrement) { refCnt -= decrement; if (refCnt <= 0) { try { Files.deleteIfExists(file.toPath()); } catch (IOException ex) { LOG.warn("Unable to delete File in FileByteBuff on release: {}", ex.getMessage(), ex); } return true; } return false; } @Override public ByteBuffer internalNioBuffer(int index, int length) { throw new UnsupportedOperationException(NOT_SUPPORTED); } } // CHECKSTYLE:ON