/*
* Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com
* The software in this package is published under the terms of the CPAL v1.0
* license, a copy of which has been included with this distribution in the
* LICENSE.txt file.
*/
package org.mule.runtime.core.internal.streaming.bytes;
import org.mule.runtime.api.streaming.bytes.CursorStream;
import org.mule.runtime.api.streaming.bytes.CursorStreamProvider;
import java.io.IOException;
/**
* Base class for implementations of {@link CursorStream}.
* <p>
* Provides template methods and enforces default behavior.
*
* @since 4.0
*/
abstract class AbstractCursorStream extends CursorStream {
private final CursorStreamProvider provider;
private long mark = 0;
private boolean released = false;
protected long position = 0;
public AbstractCursorStream(CursorStreamProvider provider) {
this.provider = provider;
}
/**
* {@inheritDoc}
*/
@Override
public long getPosition() {
return position;
}
/**
* {@inheritDoc}
*/
@Override
public void seek(long position) throws IOException {
assertNotDisposed();
this.position = position;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isReleased() {
return released;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized final void release() {
if (!released) {
doRelease();
released = true;
}
}
/**
* {@inheritDoc}
*/
@Override
public CursorStreamProvider getProvider() {
return provider;
}
protected abstract void doRelease();
protected void assertNotDisposed() throws IOException {
if (released) {
throw new IOException("Stream is closed");
}
}
/**
* Closes this stream and invokes the closing callback received in the constructor.
*/
@Override
public final void close() throws IOException {
if (!released) {
released = true;
release();
}
}
/**
* {@inheritDoc}
*
* @throws IllegalStateException if {@code this} instance has been disposed
*/
@Override
public final int read() throws IOException {
assertNotDisposed();
return doRead();
}
/**
* Template method to support the {@link #read()} method.
*
* @return the read byte or {@code -1} if no more elements are present in the stream
* @throws IOException
*/
protected abstract int doRead() throws IOException;
/**
* {@inheritDoc}
*/
@Override
public int read(byte[] b, int off, int len) throws IOException {
assertNotDisposed();
return doRead(b, off, len);
}
/**
* Template method to support the {@link #read(byte[], int, int)} method
*
* @param b the buffer into which the data is read.
* @param off the start offset in array <code>b</code> at which the data is written.
* @param len the maximum number of bytes to read.
* @return the total number of bytes read into the buffer, or {@code -1} if there is no more data because the end of
* the stream has been reached.
* @throws IOException
*/
protected abstract int doRead(byte[] b, int off, int len) throws IOException;
/**
* {@inheritDoc}
* Equivalent to {@code this.seek(this.getPosition() + n)}
*/
@Override
public final long skip(long n) throws IOException {
seek(getPosition() + n);
return n;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized void mark(int readlimit) {
mark = readlimit;
}
/**
* {@inheritDoc}
*/
@Override
public synchronized void reset() throws IOException {
seek(mark);
}
/**
* {@inheritDoc}
*
* @return {@code true}
*/
@Override
public boolean markSupported() {
return true;
}
protected int unsigned(int value) {
return value & 0xff;
}
}