/* Copyright (c) 1997-2006
Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
http://www.math.tu-berlin.de/polymake, mailto:polymake@math.tu-berlin.de
This program 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 2, or (at your option) any
later version: http://www.gnu.org/licenses/gpl.txt.
This program 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.
$Project: polymake $$Id: SelectorThread.java 7529 2006-12-20 16:57:12Z thilosch $
*/
package de.tuberlin.polymake.common;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.Pipe;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
/**
* This class is the heart of the polymake java interface. It implements a Thread
* listening to multiple channels. A Selector
* is used to wake the Thread up and process the input of the two channels.
* The input will be treated according to the run method.
*
* @author Thilo Schröder
* @version 1.0
*/
public class SelectorThread extends Thread {
/** Selector to listen to socket and pipe simultanously. */
protected Selector selector = null;
/** Channel to communicate with polymake-server. */
protected SocketChannel polyChannel = null;
/** SelectionKey to check read access of socket. */
protected SelectionKey polyKey = null;
/** Reader to read from socket. */
protected BufferedReader polyReader = null;
/** Encoding used for socket communication. */
protected Charset charset = null;
/** mapping clientChannels to PolymakeControls */
protected HashMap clientControlMap = new HashMap(8);
/**
* Describe variable pipeControlMap here.
*
*/
protected HashMap pipeControlMap = new HashMap(8);
/**
* Describe variable pipeClientMap here.
*
*/
protected HashMap pipeClientMap = new HashMap(8);
/** Buffer to read from pipe. */
protected ByteBuffer dbuf = ByteBuffer.allocateDirect(8);
/**
* Describe variable staticGeometryKey here.
*
*/
protected SelectionKey staticGeometryKey = null;
/**
* Creates a new SelectorThread instance.
*
* @param psChannel a SocketChannel value
* @param charset a String value
* @exception IOException if an error occurs
*/
public SelectorThread(SocketChannel psChannel, String charset) throws IOException {
super("SelectorThread");
selector = Selector.open();
if(psChannel != null) {
polyChannel = psChannel;
polyReader = new BufferedReader( Channels.newReader(polyChannel,charset));
}
this.charset = Charset.forName(charset);
setPriority(Thread.NORM_PRIORITY);
}
/**
* Describe registerControl method here.
*
* @param pc a PolymakeControl value
* @param sc a SocketChannel value
* @param p a Pipe value
* @return a SelectionKey value
* @exception IOException if an error occurs
*/
public SelectionKey registerControl(PolymakeControl pc, SocketChannel sc, Pipe p ) throws IOException {
SelectionKey pk = p.source().register(selector, SelectionKey.OP_READ);
SelectionKey sk = sc.register(selector,SelectionKey.OP_READ);
clientControlMap.put(sk,pc);
pipeControlMap.put(pk,pc);
pipeClientMap.put(pk,sk);
return sk;
}
/**
* Describe registerControl method here.
*
* @param pc a PolymakeControl value
* @param p a Pipe value
* @exception IOException if an error occurs
*/
public void registerControl(PolymakeControl pc, Pipe p) throws IOException {
SelectionKey pk = p.source().register(selector, SelectionKey.OP_READ);
if(staticGeometryKey == null) {
staticGeometryKey = pk;
}
pipeControlMap.put(pk,pc);
pipeClientMap.put(pk,null);
}
/**
* Describe run method here.
*
*/
public void run() {
try {
polyKey = polyChannel.register(selector, SelectionKey.OP_READ);
while (true) {
if(System.getProperty("polymake.debug") != null) {
System.err.println("java: selecting");
}
selector.select();
Set selectedKeys = selector.selectedKeys();
Iterator it = selectedKeys.iterator();
while (it.hasNext()) {
SelectionKey actKey = (SelectionKey) it.next();
it.remove();
if (pipeControlMap.containsKey(actKey)) {
if(System.getProperty("polymake.debug") != null) {
System.err.println("controlPipe...");
}
dbuf.clear();
((Pipe.SourceChannel)actKey.channel()).read(dbuf);
dbuf.flip();
PolymakeControl pc = (PolymakeControl)pipeControlMap.get(actKey);
SelectionKey clientKey = (SelectionKey)pipeClientMap.get(actKey);
if(!pc.isAlive()) {
pipeControlMap.remove(actKey);
pipeClientMap.remove(actKey);
if(clientKey != null && clientControlMap.containsKey(clientKey)) {
clientControlMap.remove(clientKey);
clientKey.channel().close();
}
if(pipeClientMap.size() == 0) {
System.exit(0);
}
continue;
}
if(clientKey != null) {
SocketChannel clientChannel = (SocketChannel)clientKey.channel();
String msg = pc.getMessage();
if(System.getProperty("polymake.debug") != null) {
System.err.println("jv>:\n" + msg + "sent.");
}
if(!pc.getAnswer()) {
clientChannel.write(charset.encode(msg));
pc.popMessage();
} else {
clientChannel.write(charset.encode(msg));
}
}
} else if (clientControlMap.containsKey(actKey)) {
if(System.getProperty("polymake.debug") != null) {
System.err.println("clientChannel...");
}
((PolymakeControl)clientControlMap.get(actKey)).update();
} else if (polyKey.equals(actKey)) {
if(System.getProperty("polymake.debug") != null) {
System.err.println("polyChannel...");
}
((PolymakeControl)pipeControlMap.get(staticGeometryKey)).update();
}
}
Thread.yield();
}
} catch (IOException e) {
System.err.println("SelectorThread: caught IOException in IOThread");
e.printStackTrace(System.err);
}
}
/**
* Close the channels and exit application, if ALL_ClOSED was received.
*
* @throws IOException if any problems closing the channels
*/
protected void cleanUp() throws IOException{
if( System.getProperty("polymake.debug") != null ){
System.err.print("java exiting...");
}
if(polyChannel != null) {
polyChannel.close();
}
if( System.getProperty("polymake.debug") != null ){
System.err.println("done!");
}
System.exit(0);
}
}