package org.webpieces.data.impl;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.webpieces.data.api.DataWrapper;
import org.webpieces.data.api.DataWrapperGenerator;
import org.webpieces.data.api.DataWrapperGeneratorFactory;
public class DataWrapperGeneratorImpl implements DataWrapperGenerator {
private static final ByteBufferDataWrapper EMPTY_WRAPPER = new ByteBufferDataWrapper(ByteBuffer.allocate(0));
@Override
public DataWrapper wrapString(String string) {
return wrapByteArray(string.getBytes());
}
@Override
public DataWrapper wrapByteArray(byte[] data) {
return new ByteBufferDataWrapper(ByteBuffer.wrap(data));
}
@Override
public DataWrapper wrapByteArray(byte[] data, int offset, int length) {
ByteBuffer buf = ByteBuffer.wrap(data, offset, length);
return new ByteBufferDataWrapper(buf);
}
@Override
public DataWrapper wrapByteBuffer(ByteBuffer buffer) {
if(buffer.position() != 0)
throw new IllegalArgumentException("You probably forgot to call buffer.flip() so the buffer is made readable after writing to it. position must be 0");
else if(!buffer.hasRemaining()) {
return DataWrapperGeneratorFactory.EMPTY;
}
return new ByteBufferDataWrapper(buffer);
}
@Override
public DataWrapper chainDataWrappers(DataWrapper firstData, ByteBuffer...secondData) {
DataWrapper wrapper = firstData;
for(ByteBuffer buffer : secondData) {
DataWrapper second = wrapByteBuffer(buffer);
wrapper = chainDataWrappers(wrapper, second);
}
return wrapper;
}
@Override
public DataWrapper chainDataWrappers(DataWrapper firstData, DataWrapper secondData) {
if(firstData.getReadableSize() == 0) {
return secondData;
} else if(secondData.getReadableSize() == 0) {
return firstData;
} else if(firstData instanceof ChainedDataWrapper) {
ChainedDataWrapper chained = (ChainedDataWrapper) firstData;
chained.addMoreData(secondData);
return chained;
} else if(!(firstData instanceof SliceableDataWrapper)) {
throw new IllegalArgumentException("Only SliceableDataWrappers or ChainedDataWrappers are allowed to be chained");
} else if(secondData instanceof ChainedDataWrapper) {
//convert first to ChainedDataWrapped and then do above code...
ChainedDataWrapper wrapper = new ChainedDataWrapper((SliceableDataWrapper) firstData);
wrapper.addMoreData(secondData);
return wrapper;
} else if(!(secondData instanceof SliceableDataWrapper)) {
throw new IllegalArgumentException("Only SliceableDataWrappers or ChainedDataWrappers are allowed to be chained");
}
SliceableDataWrapper first = (SliceableDataWrapper) firstData;
SliceableDataWrapper second = (SliceableDataWrapper) secondData;
return new ChainedDataWrapper(first, second);
}
@Override
public DataWrapper emptyWrapper() {
return EMPTY_WRAPPER;
}
@Override
public List<? extends DataWrapper> split(DataWrapper dataToRead2, int splitAtPosition) {
if(dataToRead2 instanceof ChainedDataWrapper) {
//A split proxy should never have a reference to a chained one or there is the potential for
//a memory leak in that as you grow, the right side is not releasing data from ChainedDataWrapper and you end
//up with byteWrapper <-chained <- split <-chained <-split <- chained.... and it keeps going as data
//comes in never releasing the first set of data
return splitChainedWrapper((ChainedDataWrapper) dataToRead2, splitAtPosition);
} else if(!(dataToRead2 instanceof SliceableDataWrapper)) {
throw new IllegalArgumentException("Only SliceableDataWrappers or ChainedDataWrappers are allowed to be split");
}
SliceableDataWrapper dataToRead = (SliceableDataWrapper) dataToRead2;
return splitSliceableWrapper(dataToRead, splitAtPosition);
}
List<SliceableDataWrapper> splitSliceableWrapper(SliceableDataWrapper dataToRead, int splitAtPosition) {
List<SliceableDataWrapper> tuple = new ArrayList<>();
if(splitAtPosition > dataToRead.getReadableSize()) {
throw new IllegalArgumentException("splitPosition="+splitAtPosition+" is greater than size of data="+dataToRead.getReadableSize());
} else if(dataToRead.getReadableSize() == 0) {
tuple.add(EMPTY_WRAPPER);
tuple.add(EMPTY_WRAPPER);
return tuple;
} else if(dataToRead.getReadableSize() == splitAtPosition) {
tuple.add(dataToRead);
tuple.add(EMPTY_WRAPPER);
return tuple;
}
SplitProxyWrapper wrapper1 = new SplitProxyWrapper(dataToRead, 0, splitAtPosition);
dataToRead.increaseRefCount();
SliceableDataWrapper wrapper2 =
new SplitProxyWrapper(dataToRead, splitAtPosition, dataToRead.getReadableSize() - splitAtPosition);
tuple.add(wrapper1);
tuple.add(wrapper2);
return tuple;
}
private List<DataWrapper> splitChainedWrapper(ChainedDataWrapper dataToRead, int splitAtPosition) {
List<SliceableDataWrapper> wrappersInBegin = new ArrayList<>();
List<SliceableDataWrapper> wrappersInEnd = new ArrayList<>();
boolean foundSplit = false;
List<SliceableDataWrapper> splitBuffers = null;
for(SliceableDataWrapper wrapper : dataToRead.getWrappers()) {
if (!foundSplit) {
if(splitAtPosition == wrapper.getReadableSize()) {
wrappersInBegin.add(wrapper);
foundSplit = true;
} else if(splitAtPosition < wrapper.getReadableSize()) {
splitBuffers = splitSliceableWrapper(wrapper, splitAtPosition);
wrappersInBegin.add(splitBuffers.get(0));
wrappersInEnd.add(splitBuffers.get(1));
foundSplit = true;
} else {
wrappersInBegin.add(wrapper);
splitAtPosition = splitAtPosition - wrapper.getReadableSize();
}
} else {
wrappersInEnd.add(wrapper);
}
}
DataWrapper wrapper1;
if(wrappersInBegin.size() > 0)
wrapper1 = new ChainedDataWrapper(wrappersInBegin);
else
wrapper1 = EMPTY_WRAPPER;
DataWrapper wrapper2;
if(wrappersInEnd.size() > 0)
wrapper2 = new ChainedDataWrapper(wrappersInEnd);
else
wrapper2 = EMPTY_WRAPPER;
List<DataWrapper> finalTwo = new ArrayList<>();
finalTwo.add(wrapper1);
finalTwo.add(wrapper2);
return finalTwo;
}
}