/******************************************************************************* * Copyright (c) 2009 MATERNA Information & Communications. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html. For further * project-related information visit http://www.ws4d.org. The most recent * version of the JMEDS framework can be obtained from * http://sourceforge.net/projects/ws4d-javame. ******************************************************************************/ package org.ws4d.java.communication.connection.tcp; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.ws4d.java.communication.DPWSProtocolData; import org.ws4d.java.communication.ProtocolData; import org.ws4d.java.util.Log; /** * TCP connection. * <p> * This class represents an existing TCP connection based on a socket * implementation. The socket implementation is stored inside this class to * allow to correctly close the connection. * </p> */ public class TCPConnection { private final InputStream in; private final OutputStream out; private final Socket socket; private final DPWSProtocolData protocolData; private boolean closed = false; private boolean fstRead = true; private boolean fstWrite = true; public TCPConnection(InputStream in, OutputStream out, Socket socket) { this(in, out, socket, new DPWSProtocolData(null, ProtocolData.DIRECTION_OUT, socket.getLocalAddress().getAddressWithoutNicId(), socket.getLocalPort(), socket.getRemoteAddress().getAddressWithoutNicId(), socket.getRemotePort(), true)); } public TCPConnection(InputStream in, OutputStream out, Socket socket, DPWSProtocolData pd) { this.in = in; this.out = out; this.socket = socket; this.protocolData = pd; } /** * Returns the input stream for this connection. * * @return input stream for this connection. */ public InputStream getInputStream() { if (Log.isDebug()) { return new InputStreamWrapper(in, this); } else { return in; } } /** * Returns the output stream for this connection. * * @return output stream for this connection. */ public OutputStream getOutputStream() { if (Log.isDebug()) { return new OutputStreamWrapper(out, this); } else { return out; } } /** * Returns the transport/addressing information belonging to this TCP * connection. This includes the unique connection ID and the source and * destination addresses and ports. * * @return the addressing information belonging to this connection */ public DPWSProtocolData getProtocolData() { return protocolData; } /** * Closes this connection. * <p> * This will close the input and output stream and the socket. * </p> * * @throws IOException */ public void close() throws IOException { if (closed) return; out.flush(); in.close(); out.close(); socket.close(); closed = true; } /** * Returns the identifier for this connection. * * @return identifier for this connection. */ public Long getIdentifier() { return protocolData.getInstanceId(); } public String toString() { if (protocolData != null) { return "TCP Connection [ id = " + protocolData.getInstanceId() + " ]"; } else { return "TCP Connection"; } } synchronized boolean isFirstRead() { return fstRead; } synchronized boolean isFirstWrite() { return fstWrite; } synchronized void firstRead() { fstRead = false; } synchronized void firstWrite() { fstWrite = false; } /** * Returns <code>true</code> if the connection is closed, <code>false</code> * otherwise. * * @return <code>true</code> if the connection is closed, <code>false</code> * otherwise. */ public boolean isClosed() { return closed; } private class InputStreamWrapper extends InputStream { private InputStream in = null; private TCPConnection connection = null; InputStreamWrapper(InputStream in, TCPConnection connection) { this.in = in; this.connection = connection; } public int read() throws IOException { if (connection.isFirstRead() && Log.isDebug()) { connection.firstRead(); Log.debug("<I-TCP> Reading data, " + connection, Log.DEBUG_LAYER_COMMUNICATION); } return in.read(); } public int read(byte[] b, int off, int len) throws IOException { if (connection.isFirstRead() && Log.isDebug()) { connection.firstRead(); Log.debug("<I-TCP> Reading data, " + connection, Log.DEBUG_LAYER_COMMUNICATION); } return in.read(b, off, len); } public int read(byte[] b) throws IOException { if (connection.isFirstRead() && Log.isDebug()) { connection.firstRead(); Log.debug("<I-TCP> Reading data, " + connection, Log.DEBUG_LAYER_COMMUNICATION); } return in.read(b); } public void close() throws IOException { in.close(); } public int available() throws IOException { return in.available(); } public synchronized void mark(int readlimit) { in.mark(readlimit); } public boolean markSupported() { return in.markSupported(); } public synchronized void reset() throws IOException { in.reset(); } public long skip(long n) throws IOException { return in.skip(n); } } private class OutputStreamWrapper extends OutputStream { private OutputStream out = null; private TCPConnection connection = null; OutputStreamWrapper(OutputStream out, TCPConnection connection) { this.out = out; this.connection = connection; } public void write(int arg0) throws IOException { if (connection.isFirstWrite() && Log.isDebug()) { connection.firstWrite(); Log.debug("<O-TCP> Sending data, " + connection, Log.DEBUG_LAYER_COMMUNICATION); } out.write(arg0); } public void write(byte[] b) throws IOException { if (connection.isFirstWrite() && Log.isDebug()) { connection.firstWrite(); Log.debug("<O-TCP> Sending data, " + connection, Log.DEBUG_LAYER_COMMUNICATION); } out.write(b); } public void write(byte[] b, int off, int len) throws IOException { if (connection.isFirstWrite() && Log.isDebug()) { connection.firstWrite(); Log.debug("<O-TCP> Sending data, " + connection, Log.DEBUG_LAYER_COMMUNICATION); } out.write(b, off, len); } public void close() throws IOException { out.close(); } public void flush() throws IOException { out.flush(); } } }