/* 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); } }