/* * JacORB - a free Java ORB * * Copyright (C) 2000-2014 Gerald Brose / The JacORB Team. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.jacorb.orb.etf; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.Socket; import org.jacorb.util.ObjectUtil; /** * This an abstract base implementation of the ETF::Connection interface. * * @author Nicolas Noffke * @author Andre Spiegel */ public abstract class StreamConnectionBase extends ConnectionBase { /** * Reads performed on this stream. */ protected InputStream in_stream = null; /** * Writes performed on this stream. */ protected OutputStream out_stream = null; protected StreamConnectionBase() { super(); } /** * Initialise this instance as a copy of another. Intended for use within subclass * constructors. */ protected StreamConnectionBase(StreamConnectionBase other) { super(other); this.in_stream = other.in_stream; this.out_stream = other.out_stream; } /** * Reads bytes from the connection. * * @param data holds a byte array to which the bytes will be written. The * field <code>data.value</code> must be initialized with a valid byte * array already, it cannot be null. * @param offset the index in <code>data.value</code> at which the first * byte will be written. * @param min_length the minimum number of bytes that shall be read from * the Connection. The method will block until at least this many bytes * have been read. If <code>min_length</code> is 0, the method will always * return immediately without reading any data. * @param max_length the maximum number of bytes that shall be read from * the Connection. If <code>max_length</code> is greater than * <code>min_length</code>, then the transport is free to read * (<code>max_length</code> - <code>min_length</code>) additional bytes * beyond <code>min_length</code>. * @param time_out timeout for this particular read operation. Currently * ignored in JacORB; we use socket-level timeouts. * @return the number of bytes actually read. The last byte written to * <code>data.value</code> is at the index <code>offset</code> + this return * value. This return type is a change to the ETF draft spec in JacORB. * It is needed because the mechanism suggested in the draft does not work * in Java. * @throws org.omg.CORBA.TIMEOUT if the socket-level timeout expires * before the read operation completes. * @throws org.omg.CORBA.TRANSIENT if the I/O is interrupted. * @throws org.omg.CORBA.COMM_FAILURE if the read operation fails, * for example because the connection has been closed. */ public int read(org.omg.ETF.BufferHolder data, int offset, int min_length, int max_length, long time_out) { int read = 0; while (read < min_length) { int n = 0; try { n = in_stream.read(data.value, offset + read, max_length - read); } catch (InterruptedIOException e) { int soTimeout = getTimeout(); if (soTimeout != 0) { if (logger.isDebugEnabled()) { logger.debug("Socket timeout (timeout period: " + soTimeout + ")"); } throw new org.omg.CORBA.TIMEOUT(); } throw new org.omg.CORBA.TRANSIENT("Interrupted I/O: " + e); } catch (IOException se) { if (logger.isDebugEnabled()) { logger.debug("Transport to " + connection_info + ": stream closed " + se.getMessage()); } throw handleCommFailure(se); } if (n < 0) { if (logger.isDebugEnabled()) { logger.debug("Transport to " + connection_info + ": stream closed on read < 0"); } throw new org.omg.CORBA.COMM_FAILURE("read() did not return any data"); } read += n; } if (logger.isDebugEnabled()) { // guard this with isDebugEnabled() because auto-boxing of // parameter "read" would cost too much time logger.debug("read {} bytes from {}", read, connection_info); } return read; } /** * Writes bytes to this Connection. * * @param is_first Currently not used in JacORB. * @param is_last Currently not used in JacORB. * @param data the buffer that holds the data that is to be written. * @param offset index of the first byte in <code>data</code> that shall * be written to the Connection. * @param length the number of bytes in data that shall be written. The * last byte in <code>data</code> that is written is at the index * <code>offset + length</code>. * @param time_out timeout for this particular write operation. Currently * ignored in JacORB. * @throws org.omg.CORBA.COMM_FAILURE if anything goes wrong during * the write operation. */ public void write(boolean is_first, boolean is_last, byte[] data, int offset, int length, long time_out) { try { out_stream.write(data, offset, length); if (b_out != null) { b_out.write(data, offset, length); } if (logger.isDebugEnabled()) { logger.debug("wrote {} bytes to {}", length, connection_info); } } catch (IOException ex) { throw handleCommFailure(ex); } } /** * Causes any buffered data to be actually written to the Connection. */ public void flush() { try { if (b_out != null) { if (logger.isInfoEnabled()) { byte[] buffer = b_out.toByteArray(); logger.info("sendMessages(): " + ObjectUtil.bufToString(buffer, 0, buffer.length)); } b_out.reset(); } out_stream.flush(); } catch (IOException ex) { throw handleCommFailure(ex); } } /** * Simply return true if calling a read on this instance would * find data in the connection. Otherwise, the function shall * return false. */ public boolean is_data_available() { try { return in_stream.available() > 0; } catch (IOException ex) { throw handleCommFailure(ex); } } /** * Closes the parameter without throwing an exception * TODO: Use {@link java.io.Closeable}. */ protected void silentClose(Object c) { try { if (c != null) { if (c instanceof Socket) { ((Socket) c).close(); } else if (c instanceof Closeable) { ((Closeable) c).close(); } else { logger.error("Unknown parameter " + c.getClass().getName()); } } } catch (IOException e) { logger.warn("Exception when closing " + this, e); } } public abstract boolean isSSL(); }