Skip to content

Instantly share code, notes, and snippets.

@f2prateek
Last active August 29, 2015 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save f2prateek/6b865d57dccae00ac532 to your computer and use it in GitHub Desktop.
Save f2prateek/6b865d57dccae00ac532 to your computer and use it in GitHub Desktop.
A Queue implementation for Tape.

A java.util.Queue implementation for Tape (does not support iteration).

Swapping implementations is easy!

@Module
class ProductionModule {
  @Provides @Named("payloads") Queue<Payload> providePayloadQueue(File queueFile, Converter<Payload> payloadConverter) {
    return new Tape<Payload>(queueFile, payloadConverter);
  }
}

@Module
class MockModule {
  @Provides @Named("payloads") Queue<Payload> providePayloadQueue() {
    return new ArrayDeque<Payload>(queueFile);
  }
}
package com.squareup.tape;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.AbstractQueue;
import java.util.Iterator;
/**
* This class is not thread safe, clients should wrap it in Collections.synchronizedMap()
* if it will be used from multiple threads.
*/
public class Tape<E> extends AbstractQueue<E> {
/** Backing storage implementation. */
private final QueueFile queueFile;
/** Keep file around for error reporting. */
private final File file;
/** Reusable byte output buffer. */
private final DirectByteArrayOutputStream bytes = new DirectByteArrayOutputStream();
/** Arbitrer to convert from bytes to concrete types and vice versa. */
private final Converter<E> converter;
public Tape(File file, Converter<E> converter) throws IOException {
this.file = file;
this.queueFile = new QueueFile(file);
this.converter = converter;
}
@Override public Iterator<E> iterator() {
throw new UnsupportedOperationException("Cannot iterate over tape.");
}
@Override public int size() {
return queueFile.size();
}
@Override public boolean offer(E e) {
if (e == null) {
throw new IllegalArgumentException("null element may not be inserted.");
}
try {
bytes.reset();
converter.toStream(e, bytes);
queueFile.add(bytes.getArray(), 0, bytes.size());
} catch (IOException exception) {
throw new FileException("Failed to add entry.", exception, file);
}
return true;
}
@Override public E poll() {
E e = peek();
if (e == null) {
return null;
} else {
try {
queueFile.remove();
return e;
} catch (IOException exception) {
throw new FileException("Failed to poll.", exception, file);
}
}
}
@Override public E peek() {
try {
byte[] bytes = queueFile.peek();
if (bytes == null) return null;
return converter.from(bytes);
} catch (IOException e) {
throw new FileException("Failed to peek.", e, file);
}
}
/**
* Convert a byte stream to and from a concrete type.
*
* @param <T> Object type.
*/
public interface Converter<T> {
/** Converts bytes to an object. */
T from(byte[] bytes) throws IOException;
/** Converts o to bytes written to the specified stream. */
void toStream(T o, OutputStream bytes) throws IOException;
}
/** Enables direct access to the internal array. Avoids unnecessary copying. */
private static class DirectByteArrayOutputStream extends ByteArrayOutputStream {
public DirectByteArrayOutputStream() {
super();
}
/**
* Gets a reference to the internal byte array. The {@link #size()} method indicates how many
* bytes contain actual data added since the last {@link #reset()} call.
*/
public byte[] getArray() {
return buf;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment