Skip to content

Commit

Permalink
Merge pull request #340 from scijava/stream-locations
Browse files Browse the repository at this point in the history
Add stream locations
  • Loading branch information
ctrueden authored Oct 16, 2018
2 parents 6c094f7 + 183c2e4 commit b25bd7c
Show file tree
Hide file tree
Showing 10 changed files with 644 additions and 19 deletions.
105 changes: 105 additions & 0 deletions src/main/java/org/scijava/io/handle/AbstractSeekableStreamHandle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* #%L
* SciJava Common shared library for SciJava software.
* %%
* Copyright (C) 2009 - 2017 Board of Regents of the University of
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
* Institute of Molecular Cell Biology and Genetics.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

package org.scijava.io.handle;

import java.io.IOException;

import org.scijava.io.location.Location;

public abstract class AbstractSeekableStreamHandle<L extends Location> extends
AbstractStreamHandle<L> implements SeekableStreamHandle<L>
{

private long jumpCutoff = 10000;

@Override
public void seek(final long pos) throws IOException {

// how much and which direction we have to jump
final long delta = pos - offset();

if (delta == 0) {
return;
// nothing to do
}
else if (delta > 0) {
// offset position is "downstream"

// try to reconnect instead of linearly reading large chunks
if (recreatePossible() && delta > jumpCutoff) {
recreateStreamFromPos(pos);
}
else {
jump(delta);
}

}
else { // delta < 0
// need to recreate the stream
if (recreatePossible()) {
recreateStreamFromPos(pos);
}
else {
resetStream();
jump(pos);
}
}
setOffset(pos);
}

/**
* Recreates the internal input stream available through {@link #in()}, so
* that it starts from the specified position.
*
* @param pos
* @throws IOException
*/
protected abstract void recreateStreamFromPos(long pos) throws IOException;

/**
* In some implementations of this class, the ability to recreate the stream
* depends on external factors (e.g. server support). This influences a
*
* @return if recreate is actually possible.
* @throws IOException
*/
protected abstract boolean recreatePossible() throws IOException;

/**
* Sets the maximum of bytes which are read from the stream when seeking
* forward. Any larger number will result in a call to
* {@link #recreateStreamFromPos(long)}.
*/
protected void setJumpCutoff(long jumpCutoff) {
this.jumpCutoff = jumpCutoff;
}
}
65 changes: 65 additions & 0 deletions src/main/java/org/scijava/io/handle/AbstractStreamHandle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* #%L
* SciJava Common shared library for SciJava software.
* %%
* Copyright (C) 2009 - 2017 Board of Regents of the University of
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
* Institute of Molecular Cell Biology and Genetics.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

package org.scijava.io.handle;

import org.scijava.io.location.Location;

/**
* Abstract base class for {@link StreamHandle} implementations.
*
* @author Curtis Rueden
* @author Melissa Linkert
*/
public abstract class AbstractStreamHandle<L extends Location> extends
AbstractDataHandle<L> implements StreamHandle<L>
{

// -- Fields --

/** Current position within the stream(s). */
private long offset;

// -- StreamHandle methods --

@Override
public void setOffset(final long offset) {
this.offset = offset;
}

// -- DataHandle methods --

@Override
public long offset() {
return offset;
}

}
22 changes: 10 additions & 12 deletions src/main/java/org/scijava/io/handle/DataHandle.java
Original file line number Diff line number Diff line change
Expand Up @@ -350,10 +350,7 @@ default String findString(final boolean saveString, final int blockSize,
final StringBuilder out = new StringBuilder();
final long startPos = offset();
long bytesDropped = 0;
final long inputLen = length();
long maxLen = inputLen - startPos;
final boolean tooLong = saveString && maxLen > MAX_SEARCH_SIZE;
if (tooLong) maxLen = MAX_SEARCH_SIZE;
final long maxLen = saveString ? MAX_SEARCH_SIZE : Long.MAX_VALUE;
boolean match = false;
int maxTermLen = 0;
for (final String term : terminators) {
Expand All @@ -366,7 +363,10 @@ default String findString(final boolean saveString, final int blockSize,
new DataHandleInputStream<>(this), getEncoding());
final char[] buf = new char[blockSize];
long loc = 0;
while (loc < maxLen && offset() < length() - 1) {
int r = 0;

// NB: we need at least 2 bytes to read a char
while (loc < maxLen && ((r = in.read(buf, 0, blockSize)) > 1)) {
// if we're not saving the string, drop any old, unnecessary output
if (!saveString) {
final int outLen = out.length();
Expand All @@ -378,16 +378,12 @@ default String findString(final boolean saveString, final int blockSize,
bytesDropped += dropIndex;
}
}

// read block from stream
final int r = in.read(buf, 0, blockSize);
if (r <= 0) throw new IOException("Cannot read from stream: " + r);

// append block to output
out.append(buf, 0, r);

// check output, returning smallest possible string
int min = Integer.MAX_VALUE, tagLen = 0;
int min = Integer.MAX_VALUE;
int tagLen = 0;
for (final String t : terminators) {
final int len = t.length();
final int start = (int) (loc - bytesDropped - len);
Expand Down Expand Up @@ -415,7 +411,9 @@ default String findString(final boolean saveString, final int blockSize,
}

// no match
if (tooLong) throw new IOException("Maximum search length reached.");
if (loc > MAX_SEARCH_SIZE) {
throw new IOException("Maximum search length reached.");
}
return saveString ? out.toString() : null;
}

Expand Down
72 changes: 72 additions & 0 deletions src/main/java/org/scijava/io/handle/ResettableStreamHandle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* #%L
* SciJava Common shared library for SciJava software.
* %%
* Copyright (C) 2009 - 2017 Board of Regents of the University of
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
* Institute of Molecular Cell Biology and Genetics.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

package org.scijava.io.handle;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.scijava.io.location.Location;

/**
* A {@link DataHandle} backed by an {@link InputStream} and/or
* {@link OutputStream}. Supports resetting the handle to the start of the
* internal stream(s).
*/
public interface ResettableStreamHandle<L extends Location> extends
StreamHandle<L>
{

@Override
default void seek(final long pos) throws IOException {
final long off = offset();
if (pos == off) return; // nothing to do
if (pos > off) {
// jump from the current offset
jump(pos - off);
}
else {
// jump from the beginning of the stream
resetStream();
jump(pos);
}
setOffset(pos);
}

/**
* Resets the stream to its start.
*
* @throws IOException If something goes wrong with the reset
*/
@Override
void resetStream() throws IOException;
}
53 changes: 53 additions & 0 deletions src/main/java/org/scijava/io/handle/SeekableStreamHandle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* #%L
* SciJava Common shared library for SciJava software.
* %%
* Copyright (C) 2009 - 2017 Board of Regents of the University of
* Wisconsin-Madison, Broad Institute of MIT and Harvard, and Max Planck
* Institute of Molecular Cell Biology and Genetics.
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

package org.scijava.io.handle;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.scijava.io.location.Location;

/**
* A {@link DataHandle} backed by an {@link InputStream} and/or
* {@link OutputStream}. Supports seeking to an arbitrary position within the
* stream.
*
* @author Gabriel Einsdorf
*/
public interface SeekableStreamHandle<L extends Location> extends
ResettableStreamHandle<L>
{

@Override
void seek(long pos) throws IOException;
}
Loading

0 comments on commit b25bd7c

Please sign in to comment.