/* * Copyright 2009-2010 Brian S O'Neill * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.cojen.dirmi.io; import java.io.Flushable; import java.io.Closeable; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.rmi.Remote; import org.cojen.dirmi.Link; import org.cojen.dirmi.RejectedException; /** * Basic interface for a blocking bidirectional I/O channel. * * @author Brian S O'Neill */ public interface Channel extends Flushable, Closeable, Link { /** * Returns an input stream for the channel, which when closed, closes the * channel. When a channel is closed, all read operations throw * IOException. */ InputStream getInputStream(); /** * Returns an output stream for the channel, which when closed, closes the * channel. When a channel is closed, all write operations throw * IOException. */ OutputStream getOutputStream(); /** * Returns true if bytes can read from channel without blocking. * * @throws IOException if channel is closed */ boolean isInputReady() throws IOException; /** * Returns true if bytes can written to channel without blocking. * * @throws IOException if channel is closed */ boolean isOutputReady() throws IOException; /** * Sets the size of the input buffer, returning the actual size applied. */ int setInputBufferSize(int size); /** * Sets the size of the output buffer, returning the actual size applied. */ int setOutputBufferSize(int size); /** * Register a listener which is asynchronously notified when a call to * isInputReady will return true. Listener is called at most once per * registration. */ void inputNotify(Listener listener); /** * Register a listener which is asynchronously notified when a call to * isOutputReady will return true. Listener is called at most once per * registration. */ void outputNotify(Listener listener); /** * Returns true to indicate that asynchronous notifications use channel * selection instead of blocked threads. For channels that aren't * select-based, it can be more efficient to block on I/O streams directly * rather than wait for notifications. */ boolean usesSelectNotification(); /** * Allows input to resume after reading a suspend marker. * * @return false if not supported or if no suspend marker is present */ boolean inputResume(); boolean isResumeSupported(); /** * If supported, writes a suspend marker and flushes the output. Input side * will read EOF until resumed. Input must be resumed for each suspend. * * @return false if not supported or stream is closed */ boolean outputSuspend() throws IOException; /** * Register this channel with at least one group. When this channel is * closed, it removes itself from all groups it has been registered with. */ void register(CloseableGroup<? super Channel> group); /** * Returns true if channel is absolutely closed or disconnected. A return * value of false doesn't imply that the next I/O operation will succeed. */ boolean isClosed(); /** * Close channel, flushing any remaining output first. */ void close() throws IOException; /** * Forcibly close channel, potentially discarding unflushed output and any * exceptions. */ void disconnect(); // Note: I don't like the magic control object design, but it makes it much // easier to implement a reliable socket recycling scheme. /** * Install a recycler which is called after this channel has been closed * and a recyled channel has been created. Method returns an opaque remote * object which allows remote channel endpoint to control this * channel. Channels which don't use this feature return null. * * @throws IllegalStateException if a recycler is already installed */ Remote installRecycler(Recycler recycler); /** * Set the recycling control object from the remote channel * endpoint. Method does nothing if channel doesn't use this feature. * * @throws IllegalArgumentException if channel uses control feature and * instance is same as local control or is unsupported */ void setRecycleControl(Remote control); public static interface Listener { /** * Called when bytes can be read or written to channel, depending on * how listener was registered. This method is always invoked in a * separate thread from registration, and so it may safely block. */ void ready(); /** * Called if no threads are available to invoke any listeners, but does * not imply that channel is closed. This method is usually invoked by * a registration thread. */ void rejected(RejectedException cause); /** * Called if listener notification failed because channel is closed. * This method may be invoked by a registration thread. */ void closed(IOException cause); } public static interface Recycler { /** * Called with a newly recycled channel, which does not yet have a * recycler installed. */ void recycled(Channel channel); } }