de.schlichtherle.truezip.socket.OutputSocket Maven / Gradle / Ivy
/*
* Copyright (C) 2005-2015 Schlichtherle IT Services.
* All rights reserved. Use is subject to license terms.
*/
package de.schlichtherle.truezip.socket;
import de.schlichtherle.truezip.entry.Entry;
import edu.umd.cs.findbugs.annotations.CreatesObligation;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.SeekableByteChannel;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
/**
* An abstract factory for output resources for writing bytes to its
* local target.
*
* Note that the entity relationship between output sockets and input sockets
* is n:1, i.e. any output socket can have at most one peer input socket, but
* it may be the peer of many other input sockets.
*
* @param the type of the {@link #getLocalTarget() local target}
* for I/O operations.
* @see InputSocket
* @author Christian Schlichtherle
*/
// TODO: Extract Sink interface for the new*() methods.
@NotThreadSafe
public abstract class OutputSocket
extends IOSocket {
@CheckForNull
private InputSocket> peer;
/**
* {@inheritDoc}
*
* The peer target is {@code null} if and only if this socket is not
* {@link #connect}ed to another socket.
*
* @throws IOException On any I/O failure.
*/
// See https://java.net/jira/browse/TRUEZIP-203
@Override
public final @Nullable Entry getPeerTarget() throws IOException {
return null == peer ? null : peer.getLocalTarget();
}
/**
* Binds this socket to given socket by inheriting its
* {@link #getPeerTarget() peer target}.
* Note that this method does not change the state of the
* given socket and does not connect this socket to the peer
* socket, that is it does not set this socket as the peer of of the given
* socket.
*
* @param to the output socket with the peer target to inherit.
* @return {@code this}
* @throws IllegalArgumentException if {@code this} == {@code to}.
*/
public final OutputSocket bind(final OutputSocket> to) {
if (this == to)
throw new IllegalArgumentException();
this.peer = to.peer;
return this;
}
/**
* Connects this output socket to the given peer input socket.
* Note that this method changes the peer output socket of
* the given peer input socket to this instance.
*
* @param newPeer the nullable peer input socket to connect to.
* @return {@code this}
*/
final OutputSocket connect(@CheckForNull final InputSocket> newPeer) {
final InputSocket> oldPeer = peer;
if (oldPeer != newPeer) {
if (null != oldPeer) {
peer = null;
oldPeer.connect(null);
}
if (null != newPeer) {
peer = newPeer;
newPeer.connect(this);
}
}
return this;
}
/**
* Optional: Returns a new seekable byte channel for writing bytes
* to the {@link #getLocalTarget() local target} in arbitrary order.
*
* If this method is supported, implementations must enable calling it
* any number of times.
* Furthermore, the returned seekable byte channel should not be
* buffered.
* Buffering should be addressed by client applications instead.
*
* @return A new seekable byte channel.
* @throws IOException On any I/O failure.
* @throws UnsupportedOperationException if this operation is not supported
* by the implementation.
* @since TrueZIP 7.2
*/
@CreatesObligation
public SeekableByteChannel newSeekableByteChannel() throws IOException {
throw new UnsupportedOperationException();
}
/**
* Returns a new output stream for writing bytes to the
* {@link #getLocalTarget() local target}.
*
* Implementations must enable calling this method any number of times.
* Furthermore, the returned output stream should not be buffered.
* Buffering should be addressed by the caller instead - see
* {@link IOSocket#copy}.
*
* @return A new output stream.
* @throws IOException On any I/O failure.
*/
@CreatesObligation
public abstract OutputStream newOutputStream() throws IOException;
}