Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stream locations #340

Merged
merged 6 commits into from
Oct 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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