package com.jaivox.agent;
import java.io.*;
import java.net.*;
import com.jaivox.interpreter.InterServer;
import com.jaivox.util.Log;
/**
* Sessions are created by agents in response to connection requests.
* Sessions manage conversations between agents. Each session interprets
* messages using a Responder.
*
* This class is usually subclassed to produce Responders that have
* specific functions.
*/
public class Session extends Thread implements Runnable {
protected String sid;
protected Server server;
protected Socket socket;
protected Responder responder;
public static final int defaultWait = 100; // milliseconds
public static final int maxWaits = 10; // checking for In.ready
protected int waitTime;
protected BufferedReader in;
protected PrintWriter out;
public String outbuffer;
public static String
terminateMessage = "JviaTerminate",
invalidMessage = "JviaInvalid",
responseMessage = "JviaResponse",
finishedMessage = "JviaFinished";
/**
* Create a session with the specific details
@param s id of the session
@param serve server that owns this session
@param sock socket for communicating with this session
@param r responder associated with this session
*/
public Session (String s, Server serve, Socket sock, Responder r) {
sid = s;
server = serve;
socket = sock;
responder = r;
r.owner = this;
waitTime = defaultWait; // can modify if needed
try {
start ();
}
catch (Exception e) {
Log.severe ("Session " + e.toString ());
}
}
public Session () {
}
/**
* The session stays in its run method. It handles each request
* that is received within this method and creates responses to
* those requests. Some requests, such as those asking to terminate
* the session are handled within the run () method.
*/
public void run () {
try {
in = new BufferedReader (new InputStreamReader (
socket.getInputStream ()));
out = new PrintWriter (socket.getOutputStream ());
while (true) {
if (outbuffer != null) {
out.println (outbuffer);
out.flush ();
sleep (waitTime);
Log.info ("sent:" + outbuffer);
outbuffer = null;
}
String line = readLineFromSocket ();
if (line == null) continue;
Log.fine ("read "+line);
MessageData response = responder.respond (line);
String result = response.getValue ("action");
if (result.equals (terminateMessage)) {
break;
}
else if (result.equals (invalidMessage)) {
Log.warning ("Invalid message: "+line);
continue;
}
else if (result.equals (responseMessage)) {
outbuffer = response.createMessage ();
Log.info ("replying: " + outbuffer);
}
else if (result.equals (finishedMessage)) {
Log.info ("Response received, no further action required");
continue;
}
else {
Log.warning ("Unhandled message:"+line);
continue;
}
}
Log.info ("Closing session "+sid);
terminate ();
socket.close ();
server.removeSession (this);
interrupt ();
Log.info (sid+" interrupted.");
}
catch (Exception e) {
Log.severe (sid+":run "+e.toString ());
e.printStackTrace ();
}
}
protected String readLineFromSocket () {
// wait for a while
try {
for (int i=0; i < maxWaits && !(in.ready ()); i++)
sleep (waitTime);
if (in.ready ()) {
StringBuffer sb = new StringBuffer ();
while(true) {
if (in.ready ()) {
char ch = (char)in.read ();
if(ch == '\n')
break;
sb.append (ch);
}
else break;
}
String msg = new String (sb);
msg = msg.trim ();
if (msg.length() > 1)
return msg;
else {
return null;
}
}
else
return null;
}
catch (Exception e) {
Log.fine ("readLineFromSocket: " + e.toString ());
return null;
}
}
/**
* You can call this function to end a session, but not kill the
* agent.
*/
public void terminate () {
try {
socket.close ();
server.removeSession (this);
Log.info ("terminated");
}
catch (Exception e) {
Log.severe (sid+":terminate "+e.toString ());
}
}
/**
* The sid is the string id of the session. You need to refer to this
* to send a message (since there can be many sessions managed by a
* single agent, just like there are many connections to an http server.
@return
*/
public String getSid () {
return sid;
}
/**
* Use this function to set the string id of the session to something
* you like.
@param id
*/
public void setSid (String id) {
this.sid = id;
}
/**
* Get a link to the server that owns this session.
@return
*/
public Server getServer () {
return server;
}
/**
* Set the server to be a specific one
@param s
*/
public void setServer (Server s) {
server = s;
}
/**
* Get the id of the agent that owns this session.
@return
*/
public String getServerId () {
InterServer server = (InterServer)getServer ();
String serverId = server.getServerId ();
return serverId;
}
/**
* Get the socket used by this session
@return
*/
public Socket getSocket () {
return socket;
}
/**
* Set the socket to a particular one. This is used for example by
* an HtpSession
@param socket
*/
public void setSocket (Socket sock) {
socket = sock;
}
/**
* Get the responder attached to this session.
@return
*/
public Responder getResponder () {
return responder;
}
/**
* Set the responder of this session to be a particular previously
* created one. This amounts to changing the behavior of the session.
@param responder
*/
public void setResponder (Responder responder) {
this.responder = responder;
}
/**
* The wait time is the time that the session waits while looking
* for messages. Increasing this will make the session respond slower.
* See the run () method where this is used.
@return
*/
public int getWaitTime () {
return waitTime;
}
/**
* Normally the wait time is defaultWait, but this can be changed by
* calling the setWaitTime function. The time is in milliseconds.
@param waitTime
*/
public void setWaitTime (int waitTime) {
this.waitTime = waitTime;
}
/**
* Get the default wait time, wait time is normally set to this value
* unless it is changed with setWaitTime.
@return
*/
public static int getDefaultWait () {
return defaultWait;
}
}