/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* 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
*
* Contributors:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.swt.event.server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import com.windowtester.internal.debug.LogHandler;
import com.windowtester.internal.debug.Logger;
import com.windowtester.internal.debug.TraceHandler;
import com.windowtester.recorder.event.ISemanticEvent;
import com.windowtester.recorder.event.ISemanticEventHandler;
import com.windowtester.swt.event.recorder.IEventRecorderPluginTraceOptions;
/**
* A controller class that receives meta events from developer Workbench and delegates them to GUI Recorder
*/
public class SemanticEventServer extends Thread {
/** A special handler for meta-events */
private ISemanticEventHandler handler;
/** Flag to interrupt endless loop process */
private boolean disposed = true;
/** The server socket */
private ServerSocket server = null;
/** The server port. The default is 0 meaning it will take any available port */
private int port = 0;
public SemanticEventServer(String name){
super(name);
try {
server = new ServerSocket(port);
} catch (IOException e) {
Logger.log("An error occured creating the codegen server socket: "+name, e);
}
disposed = false;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
public void run() {
super.run();
Socket socket = null;
// ObjectInputStream in = null;
SemanticEventStream in = null;
while (!disposed) {
try {
socket = server.accept();
// in = new ObjectInputStream(socket.getInputStream());
in = SemanticEventStream.forSocket(socket);
// ISemanticEvent event = (ISemanticEvent)in.readObject();
ISemanticEvent event = in.readEvent();
handleEvent(event);
in.close();
} catch(SocketException e) {
//socket exceptions are "expected" when the app tears down out from under
//the event server -- a better solution would detect this and close the socket
//preventatively... in the meantime we just catch and ignore (or trace)
//if trace is on and the exception does not appear to be of the "close" variety
//trace it
if (!isSocketClosed(e))
TraceHandler.trace(IEventRecorderPluginTraceOptions.BASIC, "Socket exception caught in event server: " + e.getMessage());
} catch (Exception e) {
// log all other exceptions!
LogHandler.log(e);
}
}
}
/**
* Test if this exception is of the "socket closed" variety
*/
private boolean isSocketClosed(SocketException e) {
String message = e.getMessage();
if (message == null)
return false;
return message.trim().equalsIgnoreCase("socket closed");
}
/**
* Handle the given event.
* @param event the event to handle
*/
protected void handleEvent(ISemanticEvent event) {
if (event == null) {
Logger.log(new IllegalArgumentException("event null"));
return;
}
// accept event event for handling
if(handler!=null)
event.accept(handler);
else
Logger.log("Event handler was not supported!");
}
public void stopServer() {
// this is asynchronous event - first set thread termination flag to true
disposed = true;
// then close socket if the thread was blocked on accept,
// this will completely terminate this thread
try {
server.close();
} catch (IOException e) {
}
}
public int getPort() {
if(server!=null&&!server.isClosed()&&server.isBound())
return server.getLocalPort();
return -1;
}
public void setPort(int port){
this.port = port;
}
public ISemanticEventHandler getHandler() {
return handler;
}
public void setHandler(ISemanticEventHandler handler) {
this.handler = handler;
}
public boolean isDisposed() {
return disposed;
}
}