/*
* Copyright 2014 NAVER Corp.
*
* 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 com.navercorp.pinpoint.profiler.sender;
import com.navercorp.pinpoint.common.util.CollectionUtils;
import com.navercorp.pinpoint.rpc.util.ListUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
/**
* @author Taejin Koo
*/
public class PartitionedByteBufferLocator {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final byte[] baseBuffer;
private final List<Index> partitionIndexList;
private final int partitionedBufferCapacity;
private PartitionedByteBufferLocator(byte[] buffer, List<Index> partitionIndexList) {
if (buffer == null) {
throw new NullPointerException("buffer may not be null.");
}
if (CollectionUtils.isEmpty(partitionIndexList)) {
throw new NullPointerException("buffer may not be null or zero.");
}
Index firstPartitionIndex = ListUtils.getFirst(partitionIndexList);
Index lastPartitionIndex = ListUtils.getLast(partitionIndexList);
int partitionedBufferCapacity = lastPartitionIndex.getEndPosition() - firstPartitionIndex.getStartPosition();
if (partitionedBufferCapacity > buffer.length) {
throw new IllegalArgumentException("partitionedBufferCapacity(" + partitionedBufferCapacity + ") > bufferCapacity(" + buffer.length + ").");
}
if (lastPartitionIndex.getEndPosition() > buffer.length) {
throw new IllegalArgumentException("lastPartitionEndPosition(" + lastPartitionIndex.getEndPosition() + ") > bufferCapacity(" + buffer.length + ").");
}
this.baseBuffer = buffer;
this.partitionIndexList = new ArrayList<Index>(partitionIndexList);
this.partitionedBufferCapacity = partitionedBufferCapacity;
}
public int getPartitionedCount() {
return partitionIndexList.size();
}
public int getTotalByteBufferCapacity() {
return partitionedBufferCapacity;
}
public int getByteBufferCapacity(int partitionIndex) {
if (partitionIndex < 0) {
throw new IllegalArgumentException("partitionIndex = " + partitionIndex);
}
if (partitionIndex >= getPartitionedCount()) {
throw new IllegalArgumentException("partitionIndex(" + partitionIndex + ") >= partitionedCount(" + getPartitionedCount() + ").");
}
return partitionIndexList.get(partitionIndex).getCapacity();
}
public int getByteBufferCapacity(int fromPartitionIndex, int toPartitionIndex) {
checkRangeValidation(fromPartitionIndex, toPartitionIndex, getPartitionedCount());
int capacity = 0;
for (int i = fromPartitionIndex; i < toPartitionIndex; i++) {
capacity += partitionIndexList.get(i).getCapacity();
}
return capacity;
}
public ByteBuffer getByteBuffer() {
return getByteBuffer(0, getPartitionedCount() - 1);
}
public ByteBuffer getByteBuffer(int partitionIndex) {
if (partitionIndex < 0) {
throw new IllegalArgumentException("partitionIndex = " + partitionIndex);
}
if (partitionIndex >= getPartitionedCount()) {
throw new IllegalArgumentException("partitionIndex(" + partitionIndex + ") >= partitionedCount(" + getPartitionedCount() + ").");
}
Index fromIndex = partitionIndexList.get(partitionIndex);
Index toIndex = partitionIndexList.get(partitionIndex);
int startPosition = fromIndex.getStartPosition();
int endPosition = toIndex.getEndPosition();
logger.debug("getByteBuffer baseBuffer-length:{}, {}~{}.", baseBuffer.length, startPosition, endPosition);
return ByteBuffer.wrap(baseBuffer, fromIndex.getStartPosition(), toIndex.getEndPosition() - fromIndex.getStartPosition());
}
public ByteBuffer getByteBuffer(int fromPartitionIndex, int toPartitionIndex) {
checkRangeValidation(fromPartitionIndex, toPartitionIndex, getPartitionedCount());
Index fromIndex = partitionIndexList.get(fromPartitionIndex);
Index toIndex = partitionIndexList.get(toPartitionIndex);
int startPosition = fromIndex.getStartPosition();
int endPosition = toIndex.getEndPosition();
logger.debug("getByteBuffer baseBuffer-length:{}, {}~{}.", baseBuffer.length, startPosition, endPosition);
return ByteBuffer.wrap(baseBuffer, fromIndex.getStartPosition(), toIndex.getEndPosition() - fromIndex.getStartPosition());
}
private void checkRangeValidation(int fromPartitionIndex, int toPartitionIndex, int partitionedCount) {
if (fromPartitionIndex < 0) {
throw new IllegalArgumentException("fromPartitionIndex = " + fromPartitionIndex);
}
if (fromPartitionIndex > toPartitionIndex) {
throw new IllegalArgumentException("fromPartitionIndex(" + fromPartitionIndex + ") > toPartitionIndex(" + toPartitionIndex + ").");
}
if (toPartitionIndex >= partitionedCount) {
throw new IllegalArgumentException("toPartitionIndex(" + toPartitionIndex + ") >= partitionedCount(" + partitionedCount + ").");
}
}
public boolean isLastPartitionIndex(int partitionIndex) {
if (partitionIndex == partitionIndexList.size() - 1) {
return true;
}
return false;
}
@Override
public String toString() {
return "PartitionedByteBufferLocator [baseBuffer-length=" + baseBuffer.length + ", partitionedCount=" + partitionIndexList.size()
+ ", partitionedBufferCapacity=" + partitionedBufferCapacity + "]";
}
public static class Builder {
private byte[] buffer;
private List<Index> indexList = new ArrayList<Index>();
public void setBuffer(byte[] buffer) {
this.buffer = buffer;
}
public void addIndex(List<Index> indexList) {
if (indexList == null) {
return;
}
for (Index index : indexList) {
addIndex(index);
}
}
public void addIndex(int startBufferPosition, int endBufferPosition) {
addIndex(new Index(startBufferPosition, endBufferPosition));
}
public void addIndex(Index index) {
Index lastPartitionIndex = ListUtils.getLast(indexList);
int partitionedEndPosition = 0;
if (lastPartitionIndex != null) {
partitionedEndPosition = lastPartitionIndex.getEndPosition();
}
chechRangeValidation(index, partitionedEndPosition);
indexList.add(index);
}
private void chechRangeValidation(Index index, int partitionedEndPosition) {
int startPosition = index.getStartPosition();
int endPosition = index.getEndPosition();
if (startPosition < 0) {
throw new IllegalArgumentException("startPosition = " + startPosition);
}
if (startPosition > endPosition) {
throw new IllegalArgumentException("startPosition(" + startPosition + ") > endPosition(" + endPosition + ").");
}
if (startPosition != partitionedEndPosition) {
throw new IllegalArgumentException("support only stream buffer index. startPosition(" + startPosition + ") != partitionedEndPosition(" + partitionedEndPosition + ").");
}
}
public PartitionedByteBufferLocator build() {
return new PartitionedByteBufferLocator(buffer, indexList);
}
}
static class Index {
private final int startPosition;
private final int endPosition;
private final int capacity;
Index(int startPosition, int endPosition) {
this.startPosition = startPosition;
this.endPosition = endPosition;
this.capacity = endPosition - startPosition;
}
public int getStartPosition() {
return startPosition;
}
public int getEndPosition() {
return endPosition;
}
public int getCapacity() {
return capacity;
}
@Override
public String toString() {
return "Index [startPosition=" + startPosition + ", endPosition=" + endPosition + ", capacity=" + capacity + "]";
}
}
}