/*******************************************************************************
* Copyright (c) 2009 Fujitsu Services Ltd. Author: Nick Battle This file is part of VDMJ. VDMJ is free software: you
* can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any later version. VDMJ 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 General Public License for more details. You should have received a
* copy of the GNU General Public License along with VDMJ. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package org.overture.combinatorialtesting.vdmj.server;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
import org.overture.combinatorialtesting.vdmj.server.common.Utils;
import org.overture.combinatorialtesting.vdmj.server.xml.XMLNode;
import org.overture.combinatorialtesting.vdmj.server.xml.XMLParser;
import org.overture.combinatorialtesting.vdmj.server.xml.XMLTagNode;
public class ConnectionThread extends Thread
{
private final boolean principal;
private final Socket socket;
private final BufferedInputStream input;
private final BufferedOutputStream output;
private String id = "";
// private long xid = 0;
private boolean connected;
private static boolean trace = false;
private static boolean quiet = false;
// private static ConnectionThread focus = null;
private final IClientMonitor monitor;
public ConnectionThread(ThreadGroup group, Socket conn, boolean principal,
IClientMonitor monitor) throws IOException
{
super(group, null, "DBGp Connection");
this.socket = conn;
this.input = new BufferedInputStream(conn.getInputStream());
this.output = new BufferedOutputStream(conn.getOutputStream());
this.principal = principal;
this.monitor = monitor;
setDaemon(true);
}
public String getIdeId()
{
return id;
}
public static synchronized boolean setTrace()
{
trace = !trace;
return trace;
}
public static synchronized boolean setQuiet()
{
quiet = !quiet;
return quiet;
}
@Override
public void run()
{
connected = true;
try
{
if (!principal)
{
// runme(); // Send run command to start new thread
}
while (connected)
{
if(!receive()) // Blocking
{
return;
}
}
} catch (SocketException e)
{e.printStackTrace();
monitor.traceError("Connection error: " + e.getMessage());
// Caused by die(), and VDMJ death
} catch (IOException e)
{
System.out.println("Connection exception: " + e.getMessage());
} finally
{
die();
}
if (!principal && !quiet)
{
System.out.println("Thread stopped: " + this);
}
}
public synchronized void die()
{
try
{
connected = false;
socket.close();
} catch (IOException e)
{
// ?
}
}
private boolean receive() throws IOException
{
// <ascii length> \0 <XML data> \0
int c = input.read();
int length = 0;
while (c >= '0' && c <= '9')
{
length = length * 10 + c - '0';
c = input.read();
}
if (c == -1)
{
connected = false; // End of thread
return false;
}
if (c != 0)
{
throw new IOException("Malformed DBGp count on " + this);
}
byte[] data = new byte[length];
int offset = 0;
int remaining = length;
int retries = 10;
int done = input.read(data, offset, remaining);
while (done < remaining && --retries > 0)
{
Utils.milliPause(100);
remaining -= done;
offset += done;
done = input.read(data, offset, remaining);
}
if (retries == 0)
{
throw new IOException("Timeout DBGp reply on thread " + this.id
+ ", got [" + new String(data) + "]");
}
if (done != remaining)
{
throw new IOException("Short DBGp reply on thread " + this.id
+ ", got [" + new String(data) + "]");
}
if (input.read() != 0)
{
throw new IOException("Malformed DBGp terminator on thread "
+ this.id + ", got [" + new String(data) + "]");
}
return process(data);
}
private boolean process(byte[] data) throws IOException
{
// System.out.println(new String(data));
XMLParser parser = new XMLParser(data);
XMLNode node = parser.readNode();
if (trace)
{
System.err.println("[" + id + "] " + node); // diags!
}
try
{
XMLTagNode tagnode = (XMLTagNode) node;
if (tagnode.tag.equals("init"))
{
processInit(tagnode);
return true;
} else
{
return processResponse(tagnode);
}
} catch (Exception e)
{
throw new IOException("Unexpected XML response: " + node);
}
}
private boolean processResponse(XMLTagNode tagnode)
{
String traceName = tagnode.getAttr("tracename");
String progress = tagnode.getAttr("progress");
String status = tagnode.getAttr("status");
if (monitor == null)
{
System.out.println("PROGRESS: " + traceName + " " + progress);
} else if (status.equals("combinatorialtestingtart"))
{
monitor.traceStart(traceName);
} else if (status.equals("progress"))
{
Integer p = Integer.parseInt(progress);
monitor.progress(traceName, p);
} else if (status.equals("error"))
{
String errorMessage = tagnode.getAttr("message");
monitor.traceError(errorMessage);
} else if (status.equals("completed"))
{
try
{
output.write("exit".getBytes());
output.flush();
} catch (IOException e)
{
}
monitor.completed();
monitor.terminating();
return false;
}
return true;
}
private void processInit(XMLTagNode tagnode)
{
String module = tagnode.getAttr("module");
if (monitor == null)
{
System.out.println("INIT: " + module);
} else
{
monitor.initialize(module);
}
}
}