All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.logspace.jvm.agent.shaded.tape.FileObjectQueue Maven / Gradle / Ivy

The newest version!
// Copyright 2012 Square, Inc.
package io.logspace.jvm.agent.shaded.tape;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

import static java.util.Collections.unmodifiableList;

/**
 * Base queue class, implements common functionality for a QueueFile-backed
 * queue manager.  This class is not thread safe; instances should be kept
 * thread-confined.
 * 

* The {@link #add( Object )}, {@link #peek()}, {@link #remove()}, and * {@link #setListener(ObjectQueue.Listener)} methods may throw a * {@link FileException} if the underlying {@link QueueFile} experiences an * {@link java.io.IOException}. * * @param The type of elements in the queue. */ public class FileObjectQueue implements ObjectQueue { /** Backing storage implementation. */ private final QueueFile queueFile; /** Reusable byte output buffer. */ private final DirectByteArrayOutputStream bytes = new DirectByteArrayOutputStream(); /** Keep file around for error reporting. */ private final File file; private final Converter converter; private Listener listener; public FileObjectQueue(File file, Converter converter) throws IOException { this.file = file; this.converter = converter; this.queueFile = new QueueFile(file); } @Override public int size() { return queueFile.size(); } @Override public final void add(T entry) { try { bytes.reset(); converter.toStream(entry, bytes); queueFile.add(bytes.getArray(), 0, bytes.size()); if (listener != null) listener.onAdd(this, entry); } catch (IOException e) { throw new FileException("Failed to add entry.", e, file); } } @Override public T 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); } } /** * Reads up to {@code max} entries from the head of the queue without removing the entries. * If the queue's {@link #size()} is less than {@code max} then only {@link #size()} entries * are read. */ public List peek(final int max) { try { final List entries = new ArrayList(max); queueFile.forEach(new QueueFile.ElementVisitor() { int count; @Override public boolean read(InputStream in, int length) throws IOException { byte[] data = new byte[length]; in.read(data, 0, length); entries.add(converter.from(data)); return ++count < max; } }); return unmodifiableList(entries); } catch (IOException e) { throw new FileException("Failed to peek.", e, file); } } public List asList() { return peek(size()); } @Override public final void remove() { try { queueFile.remove(); if (listener != null) listener.onRemove(this); } catch (IOException e) { throw new FileException("Failed to remove.", e, file); } } public final void remove(int n) throws IOException { try { queueFile.remove(n); if (listener != null) { for (int i = 0; i < n; i++) { listener.onRemove(this); } } } catch (IOException e) { throw new FileException("Failed to remove.", e, file); } } public final void close() { try { queueFile.close(); } catch (IOException e) { throw new FileException("Failed to close.", e, file); } } @Override public void setListener(final Listener listener) { if (listener != null) { try { queueFile.forEach(new QueueFile.ElementVisitor() { @Override public boolean read(InputStream in, int length) throws IOException { byte[] data = new byte[length]; in.read(data, 0, length); listener.onAdd(FileObjectQueue.this, converter.from(data)); return true; } }); } catch (IOException e) { throw new FileException("Unable to iterate over QueueFile contents.", e, file); } } this.listener = listener; } /** * Convert a byte stream to and from a concrete type. * * @param Object type. */ public interface Converter { /** 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; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy