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

org.jboss.remoting.transport.multiplex.MultiplexingOutputStream Maven / Gradle / Ivy

There is a newer version: 5.0.29.Final
Show newest version
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

/*
 * Created on Jul 22, 2005
 */
 
package org.jboss.remoting.transport.multiplex;

import java.io.IOException;
import java.io.OutputStream;
import java.net.SocketException;

import org.jboss.logging.Logger;

/**
 * MultiplexingOutputStream is the class returned by
 * VirtualSocket.getOutputStream().  
 * It supports the methods and behavior implemented by the OutputStream returned by
 * java.net.Socket.getOutputStream().  For more information about the behavior
 * of the methods, see the javadoc for java.io.OutputStream.
 * 

* Copyright (c) 2005 *

* @author Ron Sigal */ public class MultiplexingOutputStream extends OutputStream { protected static final Logger log = Logger.getLogger(MultiplexingOutputStream.class); private MultiplexingManager manager; private OutputMultiplexor outputMultiplexor; private VirtualSocket virtualSocket; private SocketId socketId; private boolean outputShutdown = false; private boolean closed = false; private IOException writeException; private static final int OPEN = 0; private static final int CONNECTION_RESET = 1; private static final int CLOSED = 2; private int connectionState = OPEN; private byte[] oneByte = new byte[1]; private byte[] fourBytes = new byte[4]; /** * * @param manager * @param socketId */ public MultiplexingOutputStream(MultiplexingManager manager, SocketId socketId) { this(manager, null, socketId); } /** * * @param manager * @param virtualSocket * @param socketId */ public MultiplexingOutputStream(MultiplexingManager manager, VirtualSocket virtualSocket, SocketId socketId) { this.manager = manager; this.virtualSocket = virtualSocket; this.socketId = socketId; this.outputMultiplexor = manager.getOutputMultiplexor(); } ////////////////////////////////////////////////////////////////////////////////////////////////// /// The following methods are required of all OutputStreams '/// ////////////////////////////////////////////////////////////////////////////////////////////////// /************************************************************************************************* ok: public void write(int b) throws IOException; ok: public void write(byte b[]) throws IOException; ok: public void write(byte b[], int off, int len) throws IOException; public void flush() throws IOException; ok: public void close() throws IOException; *************************************************************************************************/ /** * See superclass javadoc. */ public void close() throws IOException { log.debug("MultiplexingOutputStream.close() entered"); if (closed) return; closed = true; if (virtualSocket != null) virtualSocket.close(); } /** * See superclass javadoc. */ public void flush() throws IOException { // Could use flush() to raise priority of messages waiting in OutputMultiplexor's write queue. } /** * See superclass javadoc. */ public void write(int i) throws IOException { checkStatus(); oneByte[0] = (byte) i; outputMultiplexor.write(manager, socketId, oneByte); } /** * See superclass javadoc. */ public void write(byte[] array) throws IOException, NullPointerException { checkStatus(); outputMultiplexor.write(manager, socketId, array); } /** * See superclass javadoc. */ public void write(byte[] array, int off, int len) throws IOException, NullPointerException, IndexOutOfBoundsException { checkStatus(); if (array == null) throw new NullPointerException(); if (off < 0 || len < 0 || off + len > array.length) throw new IndexOutOfBoundsException(); byte[] subArray = new byte[len]; for (int i = 0; i < len; i++) subArray[i] = array[off + i]; outputMultiplexor.write(manager, socketId, subArray); } ////////////////////////////////////////////////////////////////////////////////////////////////// /// The following methods are specific to MultiplexingOutputStream '/// ////////////////////////////////////////////////////////////////////////////////////////////////// protected void setWriteException(IOException e) { writeException = e; } /** * writeInt() is borrowed from DataOutputStream. * It saves the extra expense of creating a DataOutputStream. * @param i * @throws IOException */ public void writeInt(int i) throws IOException { fourBytes[0] = (byte) ((i >>> 24) & 0xff); fourBytes[1] = (byte) ((i >>> 16) & 0xff); fourBytes[2] = (byte) ((i >>> 8) & 0xff); fourBytes[3] = (byte) ((i >>> 0) & 0xff); outputMultiplexor.write(manager, socketId, fourBytes); } /** * Determines how to handle a write request depending on what this socket knows about the state * of the peer socket. *

* Once this socket knows that the peer socket has closed, no more write requests will be honored. * There seem to be two ways for a socket A to learn that its peer socket B has closed. *

*

    *
  1. If socket A has executed a write, but no subsequent write is performed on B, * then the acknowledgement of the write will carry back the information that B has closed. *
  2. If socket B has no pending acknowledgements to send at the time it closes, and then socket A * does a write after B has closed, the (negative) acknowledgement of the write will carry back * the information that B has closed. *
*

* Java seems to respond differently to the two cases. The first write after this socket has learned * of the peer's closing through the first scenario will result in a SocketException("Connection reset"). * In the second scenario, the first write by this socket after the peer has closed * will quietly fail (no exception is thrown). All subsequent writes after either of these two * scenarios will result in a SocketException("Broken pipe"). *

* Currently, MultiplexingOutputStream implements only a simplified version of this behavior. In * particular, it allows in all cases one write to silently fail, after which all writes result in a * SocketException("Broken pipe"); *

* Note. This discussion is based on empirical observation on a linux system, not on examination of code. * Your mileage may vary. */ protected void checkStatus() throws IOException { if (closed) throw new SocketException("Socket closed"); if (outputShutdown) throw new SocketException("Broken pipe"); if (writeException != null) throw writeException; switch (connectionState) { case OPEN: return; case CONNECTION_RESET: connectionState = CLOSED; return; case CLOSED: throw new SocketException("Broken pipe"); default: log.error("unrecognized connection state: " + connectionState); } } /** * */ protected void handleRemoteDisconnect() { log.debug("entering handleRemoteDisconnect()"); switch (connectionState) { case OPEN: connectionState = CONNECTION_RESET; return; default: connectionState = CLOSED; log.error("invalid connection state in handleRemoteDisconnect(): " + connectionState); } } /** * */ protected void shutdown() { outputShutdown = true; } /** * @param i * @param brackets * @throws IOException */ protected void write(int i, int brackets) throws IOException { log.debug("brackets: " + brackets); oneByte[0] = (byte) i; outputMultiplexor.write(manager, socketId, oneByte, brackets); } /** * @param i * @param brackets * @throws IOException */ protected void writeInt(int i, int brackets) throws IOException { log.debug("brackets: " + brackets); fourBytes[0] = (byte) ((i >>> 24) & 0xff); fourBytes[1] = (byte) ((i >>> 16) & 0xff); fourBytes[2] = (byte) ((i >>> 8) & 0xff); fourBytes[3] = (byte) ((i >>> 0) & 0xff); outputMultiplexor.write(manager, socketId, fourBytes, brackets); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy