/*
*Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
*WSO2 Inc. licenses this file to you 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.wso2.carbon.automation.test.utils.tcpmon.client;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.Map;
/**
* this class handles the pumping of data from the incoming socket to the
* outgoing socket
*/
class SocketRR extends Thread {
private static final Log log = LogFactory.getLog(SocketRR.class);
private Socket inSocket = null;
private Socket outSocket = null;
private StringBuffer message;
private InputStream inputStream = null;
private OutputStream outputStream = null;
private boolean xmlFormat;
private volatile boolean done = false;
private volatile long elapsed = 0;
private Map<Integer, ConnectionData> connectionData = null;
private int index = 0;
private String type = null;
private Connection connection = null;
private SlowLinkSimulator slowLink;
public SocketRR(Connection connection, Socket inputSocket,
InputStream inputStream, Socket outputSocket,
OutputStream outputStream, StringBuffer message,
boolean format, Map<Integer, ConnectionData> connectionData, int index,
final String type, SlowLinkSimulator slowLink) {
this.inSocket = inputSocket;
this.inputStream = inputStream;
this.outSocket = outputSocket;
this.outputStream = outputStream;
this.message = message;
xmlFormat = format;
this.connectionData = connectionData;
this.index = index;
this.type = type;
this.connection = connection;
this.slowLink = slowLink;
start();
}
/**
* Method isDone
*
* @return boolean
*/
public boolean isDone() {
return done;
}
public String getElapsed() {
return String.valueOf(elapsed);
}
/**
* Method run
*/
public void run() {
try {
byte[] buffer = new byte[4096];
byte[] tmpbuffer = new byte[8192];
int saved = 0;
int len;
int i1, i2;
int i;
int reqSaved = 0;
int tabWidth = 3;
boolean atMargin = true;
int thisIndent = -1, nextIndent = -1, previousIndent = -1;
if (connectionData != null) {
String tmpStr = connectionData.get(index).getRequest();
if (!"".equals(tmpStr)) {
reqSaved = tmpStr.length();
}
}
long start = System.currentTimeMillis();
a:
for (; ; ) {
elapsed = System.currentTimeMillis() - start;
if (done) {
break;
}
len = buffer.length;
// Used to be 1, but if we block it doesn't matter
// however 1 will break with some servers, including apache
if (len == 0) {
len = buffer.length;
}
if (saved + len > buffer.length) {
len = buffer.length - saved;
}
int len1 = 0;
while (len1 == 0) {
try {
len1 = inputStream.read(buffer, saved, len);
} catch (Exception ex) {
if (done && (saved == 0)) {
break a;
}
len1 = -1;
break;
}
}
len = len1;
if ((len == -1) && (saved == 0)) {
break;
}
if (len == -1) {
done = true;
}
// No matter how we may (or may not) format it, send it
// on unformatted - we don't want to mess with how its
// sent to the other side, just how its displayed
if ((outputStream != null) && (len > 0)) {
slowLink.pump(len);
outputStream.write(buffer, saved, len);
}
if ((connectionData != null) && (reqSaved < 50)) {
String old = connectionData.get(index).getRequest();
old = old + new String(buffer, saved, len, Charset.defaultCharset());
if (old.length() > 50) {
old = old.substring(0, 50);
}
reqSaved = old.length();
if ((i = old.indexOf('\n')) > 0) {
old = old.substring(0, i - 1);
reqSaved = 50;
}
connectionData.get(index).setRequest(old);
}
if (xmlFormat) {
// Do XML Formatting
boolean inXML = false;
int bufferLen = saved;
if (len != -1) {
bufferLen += len;
}
i1 = 0;
i2 = 0;
saved = 0;
for (; i1 < bufferLen; i1++) {
// Except when we're at EOF, saved last char
if ((len != -1) && (i1 + 1 == bufferLen)) {
saved = 1;
break;
}
thisIndent = -1;
if ((buffer[i1] == '<')
&& (buffer[i1 + 1] != '/')) {
previousIndent = nextIndent++;
thisIndent = nextIndent;
inXML = true;
}
if ((buffer[i1] == '<')
&& (buffer[i1 + 1] == '/')) {
if (previousIndent > nextIndent) {
thisIndent = nextIndent;
}
previousIndent = nextIndent--;
inXML = true;
}
if ((buffer[i1] == '/')
&& (buffer[i1 + 1] == '>')) {
previousIndent = nextIndent--;
inXML = true;
}
if (thisIndent != -1) {
if (thisIndent > 0) {
tmpbuffer[i2++] = (byte) '\n';
}
for (i = tabWidth * thisIndent; i > 0; i--) {
tmpbuffer[i2++] = (byte) ' ';
}
}
atMargin = ((buffer[i1] == '\n')
|| (buffer[i1] == '\r'));
if (!inXML || !atMargin) {
tmpbuffer[i2++] = buffer[i1];
}
}
message.append(new String(tmpbuffer, 0, i2, Charset.defaultCharset()));
// Shift saved bytes to the beginning
for (i = 0; i < saved; i++) {
buffer[i] = buffer[bufferLen - saved + i];
}
} else {
message.append(new String(buffer, 0, len, Charset.defaultCharset()));
}
}
} catch (Exception e) {
log.error("Error while SocketRR.run() : " + e.getMessage());
} finally {
done = true;
try {
if (outputStream != null) {
outputStream.flush();
if (null != outSocket) {
outSocket.shutdownOutput();
} else {
outputStream.close();
}
outputStream = null;
}
} catch (Exception e) {
log.error("Error while closing outSocket and outputStream : " + e.getMessage());
}
try {
if (inputStream != null) {
if (inSocket != null) {
inSocket.shutdownInput();
} else {
inputStream.close();
}
inputStream = null;
}
} catch (Exception e) {
log.error("Error while closing inSocket and inputStream : " + e.getMessage());
}
connection.wakeUp();
}
}
/**
* Method halt
*/
public void halt() {
try {
if (inSocket != null) {
inSocket.close();
}
if (outSocket != null) {
outSocket.close();
}
inSocket = null;
outSocket = null;
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
inputStream = null;
outputStream = null;
done = true;
} catch (Exception e) {
log.error("Error while closing SocketRR : " + e.getMessage());
}
}
}