/* * (c) 2000-2009 Carlos G�mez Rodr�guez, todos los derechos reservados / all rights reserved. * Licencia en license/bsd.txt / License in license/bsd.txt */ package eu.irreality.age; import java.net.*; import java.util.*; import java.io.*; import javax.swing.*; import eu.irreality.age.debug.Debug; public class ServerProxy extends Thread implements ARSPConstants { Socket sock; MultimediaInputOutputClient cliente; VersatileBufferedInputStream br; PrintWriter pw; InputStream is; OutputStream os; ArrayList requestedFiles = new ArrayList(); private String worldDir = null; boolean input_thread_flag = false; public ServerProxy ( Socket s , MultimediaInputOutputClient ioc ) { this.sock = s; this.cliente = ioc; try { if (s != null) { br = new VersatileBufferedInputStream ( sock.getInputStream() ); //br = new BufferedReader(new InputStreamReader((is=new BufferedInputStream(sock.getInputStream(),100000)))); pw = new PrintWriter(new OutputStreamWriter((os=new BufferedOutputStream(sock.getOutputStream(),100000)),"UTF-8")) { public void println(String linea) { print(linea); print("\r\n"); //System.err.println("ServerProxy says: " + linea); } }; } } catch (Exception e) { System.err.println("Error: " + e); } } public void run() { try { String linea="Inicial"; for ( ;; ) { if ( cliente.isDisconnected() ) { //client disconnected (for example, closed the window): we stop executing this proxy. pw.println(GOODBYE); sock.close(); return; } Debug.println("Last linea: " + linea); br.mark(500000); linea = br.readLine(); if ( linea == null ) { System.err.println("Read null line. Disconnected, I guess.\n"); cliente.write("Null line: the server seems to have disconnected.\n"); return; } //is.mark(500000); Debug.println("Current linea: " + linea); parseMessage ( linea ); } } catch ( IOException ioe ) { cliente.write("Exception: the server seems to have disconnected.\n"); System.err.println(ioe);ioe.printStackTrace(); } } public void parseMessage ( String mesg ) { Debug.println("Command to parse by client-side server proxy: " + mesg); StringTokenizer st = new StringTokenizer ( mesg , " " ); String command; if ( st.hasMoreTokens() ) command = st.nextToken().trim(); else command = ""; String arguments; if ( st.hasMoreTokens() ) arguments = st.nextToken("").trim(); else arguments = ""; if ( command.equalsIgnoreCase( WRITE ) ) cliente.write( StringMethods.textualSubstitution ( arguments , "\\n" , "\n" ) ); else if ( command.equalsIgnoreCase( WRITE_TITLE ) ) cliente.writeTitle(arguments); else if ( command.equalsIgnoreCase( CLEAR_SCREEN ) ) cliente.clearScreen(); /*sound handler cmd's*/ else if ( command.equalsIgnoreCase( STOP_ALL_SOUND ) ) { try { if ( cliente.isSoundEnabled() ) cliente.getSoundClient().stopAllSound(); } catch ( Exception e ) { e.printStackTrace(); } } else if ( command.equalsIgnoreCase( MIDI_INIT ) ) { try { if ( cliente.isSoundEnabled() ) cliente.getSoundClient().midiInit(); } catch ( Exception e ) { e.printStackTrace(); } } else if ( command.equalsIgnoreCase( MIDI_PRELOAD ) ) { try { if ( cliente.isSoundEnabled() ) cliente.getSoundClient().midiPreload(arguments); } catch ( Exception e ) { e.printStackTrace(); } } else if ( command.equalsIgnoreCase( MIDI_START ) ) { try { if ( cliente.isSoundEnabled() ); { if ( arguments != null && !arguments.equals("") ) cliente.getSoundClient().midiStart(arguments); else cliente.getSoundClient().midiStart(); } } catch ( Exception e ) { e.printStackTrace(); } } else if ( command.equalsIgnoreCase( MIDI_OPEN ) ) { try { if ( cliente.isSoundEnabled() ) cliente.getSoundClient().midiOpen(arguments); } catch ( Exception e ) { e.printStackTrace(); } } else if ( command.equalsIgnoreCase( MIDI_STOP ) ) { if ( cliente.isSoundEnabled() ) cliente.getSoundClient().midiStop(); } else if ( command.equalsIgnoreCase( MIDI_CLOSE ) ) { if ( cliente.isSoundEnabled() ) cliente.getSoundClient().midiClose(); } else if ( command.equalsIgnoreCase( AUDIO_PRELOAD ) ) { try { if ( cliente.isSoundEnabled() ) cliente.getSoundClient().audioPreload(arguments); } catch ( Exception e ) { e.printStackTrace(); } } else if ( command.equalsIgnoreCase( AUDIO_UNLOAD ) ) { try { if ( cliente.isSoundEnabled() ) cliente.getSoundClient().audioUnload(arguments); } catch ( Exception e ) { e.printStackTrace(); } } else if ( command.equalsIgnoreCase( AUDIO_STOP ) ) { if ( cliente.isSoundEnabled() ); { StringTokenizer st2 = new StringTokenizer(arguments); String file = st2.nextToken(); if ( st2.hasMoreTokens() ) { double fadeTime = Double.parseDouble(st2.nextToken()); cliente.getSoundClient().audioFadeOut(file,fadeTime); } else cliente.getSoundClient().audioStop(file); } } else if ( command.equalsIgnoreCase( AUDIO_START ) ) { try { if ( cliente.isSoundEnabled() ) { StringTokenizer st2 = new StringTokenizer(arguments); try { int loopTimes; if ( (loopTimes=Integer.valueOf(st2.nextToken()).intValue()) > 0 ) { if ( st2.hasMoreTokens() ) { double seconds = Double.parseDouble(st2.nextToken()); double delay = Double.parseDouble(st2.nextToken()); cliente.getSoundClient().audioFadeIn(st2.nextToken("").trim(),loopTimes,seconds,delay); } else cliente.getSoundClient().audioStart(st2.nextToken("").trim(),loopTimes); } } catch ( NumberFormatException nfe ) { cliente.getSoundClient().audioStart(arguments); } } } catch ( Exception e ) { e.printStackTrace(); } } else if ( command.equalsIgnoreCase( AUDIO_SET_GAIN ) ) { if ( cliente.isSoundEnabled() ) { StringTokenizer st2 = new StringTokenizer(arguments); try { double gain = 0.0; if ( st2.hasMoreTokens() ) gain = Double.valueOf(st2.nextToken()).doubleValue(); if ( st2.hasMoreTokens() ) cliente.getSoundClient().audioSetGain(st2.nextToken(""),gain); } catch ( NumberFormatException nfe ) { nfe.printStackTrace(); } } } else if ( command.equalsIgnoreCase( FORCE_INPUT ) ) { StringTokenizer argTok = new StringTokenizer ( arguments , " " ); String outputEnabled = argTok.nextToken(); String inputText = argTok.nextToken("").trim(); cliente.forceInput(inputText,Boolean.valueOf(outputEnabled).booleanValue()); } else if ( command.equalsIgnoreCase( GET_INPUT ) ) //aqu� todo as�ncrono, ya se encargar� el servidor de interpretarlo como s�ncrono si procede //<- i think this comment should be in reverse. this is treated in a synchronous way. But if the server doesn't // receive input on time and is on asynchronous mode, it will go on simulating the world. { Debug.println("Input get command"); //for(;;) //{ if ( !input_thread_flag ) { Debug.println("Spawning input-returning thread"); input_thread_flag = true; Thread th = new Thread () { public void run() { Debug.println("getInput called"); String s = cliente.getInput(null); //synchronous (blocking) call if ( s == null ) pw.println(GET_INPUT_RETURN_NULL); else pw.println(GET_INPUT_RETURN + " " +s); pw.flush(); input_thread_flag = false; } }; th.start(); //break; } //} } /* else if ( command.equalsIgnoreCase( GET_INPUT_ASYNCHRONOUS ) ) { Debug.println("getRealTimeInput called"); String s = cliente.getRealTimeInput(null); pw.println(GET_INPUT_RETURN + " " +s); pw.flush(); } */ else if ( command.equalsIgnoreCase( INSERT_ICON ) ) { if ( cliente.isGraphicsEnabled() ) { StringTokenizer argTok = new StringTokenizer ( arguments , " " ); String head = argTok.nextToken(); String tail = argTok.nextToken("").trim(); if ( head.equalsIgnoreCase("centered") ) { cliente.insertCenteredIcon(tail); } else { cliente.insertIcon(arguments); } } } else if ( command.equalsIgnoreCase( USE_IMAGE ) ) { if ( cliente.isGraphicsEnabled() ) { StringTokenizer argTok = new StringTokenizer ( arguments , " " ); String one = argTok.nextToken().trim(); String two = argTok.nextToken().trim(); String three = argTok.nextToken().trim(); String tail = argTok.nextToken("").trim(); cliente.useImage(tail,Integer.valueOf(one).intValue(),Integer.valueOf(two).intValue(),Integer.valueOf(three).intValue()); } } else if ( command.equalsIgnoreCase( ADD_FRAME ) ) { if ( cliente.isGraphicsEnabled() ) { StringTokenizer argTok = new StringTokenizer ( arguments , " " ); String one = argTok.nextToken().trim(); String two = argTok.nextToken().trim(); cliente.addFrame(Integer.valueOf(one).intValue(),Integer.valueOf(two).intValue()); } } else if ( command.equalsIgnoreCase( REMOVE_FRAMES ) ) { if ( cliente.isGraphicsEnabled() ) { cliente.removeFrames(); } } /* inexistent else if ( command == SET_INPUT_STRING ) { cliente.setInputString ( arguments ); } */ else if ( command.equalsIgnoreCase( WAIT_KEY_PRESS ) ) { cliente.waitKeyPress(); pw.println(KEY_PRESSED); pw.flush(); } else if ( command.equalsIgnoreCase( CLIENT_TYPE_REQUEST ) ) { pw.println(CLIENT_TYPE_REPLY + " sound" + " images" + " color" + " title" + " :ServerProxy for generic MultimediaInputOutputClient" ); Debug.println("Client type reply sent.\n"); pw.flush(); } else if ( command.equalsIgnoreCase( COLORCODE_REQUEST ) ) { Debug.println("COLORCODE REQUEST COMMAND FOUND!" + cliente.getColorCode("description")); pw.println(COLORCODE_INFO_BEGIN); pw.println(COLORCODE_INFO_LINE + " " + "description" + " " + cliente.getColorCode("description") ); pw.println(COLORCODE_INFO_LINE + " " + "input" + " " + cliente.getColorCode("input") ); pw.println(COLORCODE_INFO_LINE + " " + "error" + " " + cliente.getColorCode("error") ); pw.println(COLORCODE_INFO_LINE + " " + "information" + " " + cliente.getColorCode("information") ); pw.println(COLORCODE_INFO_LINE + " " + "denial" + " " + cliente.getColorCode("denial") ); pw.println(COLORCODE_INFO_LINE + " " + "action" + " " + cliente.getColorCode("action") ); pw.println(COLORCODE_INFO_LINE + " " + "default" + " " + cliente.getColorCode("default") ); pw.println(COLORCODE_INFO_LINE + " " + "important" + " " + cliente.getColorCode("important") ); pw.println(COLORCODE_INFO_LINE + " " + "story" + " " + cliente.getColorCode("story") ); pw.println(COLORCODE_INFO_LINE + " " + "reset" + " " + cliente.getColorCode("reset") ); pw.println(COLORCODE_INFO_END); pw.flush(); } else if ( command.equalsIgnoreCase( WORLD_DIR ) ) { worldDir = arguments; } else if ( command.equalsIgnoreCase( VISUALCONF_INIT_BEGIN ) ) { String xmlText = ""; boolean terminamos = false; while ( !terminamos ) { String linea; try { Debug.println("Tryin' to read newline:"); linea = br.readLine(); Debug.println("Line read, " + linea); } catch ( IOException ioe ) { System.err.println("Exception (0) " + ioe); break; } StringTokenizer sto = new StringTokenizer ( linea ); //System.err.println("String: " + linea + " (len " + linea.length() + ")"); if ( linea.length() == 0 ) continue; String token = sto.nextToken(); if ( token.equalsIgnoreCase ( VISUALCONF_INIT_LINE ) ) { xmlText += ( sto.nextToken("").trim() ); xmlText += "\n"; } else if ( token.equalsIgnoreCase ( VISUALCONF_INIT_END ) ) { terminamos = true; } else { Debug.println("Callin' emergency parseMessage recursion."); parseMessage ( linea ); } } //crear la visconf que nos mandan Debug.println("Gonna create 'doc.\n"); org.w3c.dom.Document d = null; BufferedReader br2; try { br2 = new BufferedReader ( new StringReader ( xmlText ) ); org.xml.sax.InputSource is = new org.xml.sax.InputSource(br2); javax.xml.parsers.DocumentBuilder db = javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder(); d = db.parse(is); } catch ( javax.xml.parsers.ParserConfigurationException pce ) { System.err.println(pce); } catch ( org.xml.sax.SAXException se ) //parse() { System.err.println(se); } catch ( IOException ioe ) //parse() { Debug.println("ServerProxy throws: "); Debug.println(ioe);ioe.printStackTrace(); Debug.println("When text was " + xmlText); } Debug.println("Doc " + d + " created."); if ( d!=null) { try { VisualConfiguration vc = new VisualConfiguration ( d.getDocumentElement() , worldDir ); if ( cliente instanceof ColoredSwingClient ) ((ColoredSwingClient)cliente).setVisualConfiguration(vc); Debug.println("Visconf set."); } catch ( XMLtoWorldException xml2we ) { ; } } Debug.println("Returnin' from parseMessage()\n"); } else if ( command.equalsIgnoreCase( FILE_LIST_BEGIN ) ) { boolean terminamos = false; Vector ficheros = new Vector(); Debug.println("File list begin."); while ( !terminamos ) { String linea; try { linea = br.readLine(); } catch ( IOException ioe ) { System.err.println(ioe);ioe.printStackTrace();break; } StringTokenizer sto = new StringTokenizer ( linea ); String token = sto.nextToken(); if ( token.equalsIgnoreCase ( FILE_LIST_LINE ) ) { ficheros.add ( sto.nextToken("").trim() ); } else if ( token.equalsIgnoreCase ( FILE_LIST_END ) ) { terminamos = true; //do all the ask-for-file-get, etc. stuff. requestUserSelectedFiles ( ficheros ); } else { System.out.println("Callin' emergency parseMessage recursion."); parseMessage ( linea ); } } } else if ( command.equalsIgnoreCase ( FILE_HEADER_LINE ) ) //nos env�an un fichero { System.out.println("File header line."); StringTokenizer argTok = new StringTokenizer ( arguments , " " ); String remoteName = argTok.nextToken(); int byteSize = Integer.valueOf(argTok.nextToken()).intValue(); boolean ficheroDeseado = false; for ( int i = 0 ; i < requestedFiles.size() ; i++ ) { StringTokenizer st2 = new StringTokenizer( (String) requestedFiles.get(i) ); String filename = st2.nextToken(); if ( filename.equals(remoteName) ) { ficheroDeseado = true; break; } } /* if ( !ficheroDeseado ) { pw.println(FILE_REJECT); pw.flush(); System.out.println("Rejected."); return; } */ //{fichero deseado} /* pw.println(FILE_ACCEPT); pw.flush(); System.out.println("Accepted."); */ char[] charArray = new char[byteSize]; byte[] byteArray = new byte[byteSize]; //read the file from socket try { //br.reset(); int lei = 0; /* while ( lei < byteArray.length ) { System.out.println("To request this time: " + (byteArray.length-lei)); lei += is.read ( byteArray , lei , byteArray.length-lei ); System.out.println("Finally read " + lei + " bytes."); System.out.println("Data read till mom't eez:\n\n"); System.out.write(byteArray,0,lei); System.out.println("\n\n"); //create test file FileOutputStream juasesblases = new FileOutputStream(new File("prueba.txt")); juasesblases.write(byteArray,0,lei); juasesblases.flush(); } */ System.out.println("LASTREAD: " + mesg); System.out.println("Reading file from socket."); System.out.println("To read " + byteArray.length + " bytes from input stream."); /*ASCII mode works while ( lei < byteArray.length ) { System.out.println("To request this time: " + (byteArray.length-lei)); lei += br.read ( byteArray , lei , byteArray.length-lei ); System.out.println("Finally read " + lei + " bytes."); System.out.println("Data read till mom't eez:\n\n"); System.out.print(byteArray); System.out.println("\n\n"); //create test file FileWriter osw = new FileWriter ( "Prueba.txt" ); BufferedWriter bw2 = new BufferedWriter ( osw , lei ); System.out.println("lei is: " + lei); int escribi = 0; bw2.write(byteArray,0,lei); bw2.flush(); } */ while ( lei < byteArray.length ) { /* int cur = br.read(); char curAsChar = (char)cur; byteArray[lei] = (byte)cur; charArray[lei] = curAsChar; lei++; //16 by 16 System.out.print( Integer.toString(cur,16) + " " ); if ( lei % 16 == 0 ) System.out.println(); */ lei += br.read ( byteArray , lei , byteSize-lei ); System.out.println(lei + " bytes read."); } /* String s = new String ( charArray ); byteArray = s.getBytes(); */ /* //ponemos la stream antes de leer la FILE_HEADER_LINE br.reset(); //skipeamos dicha linea int jal=0; char c; while ( (c = (char)is.read()) != '\n' ) {jal++; System.out.println("Byte " + jal + ": " + (int)(c) ); } is.mark(5); if ( (c = (char)is.read()) != '\r' ) { System.out.println("Stream reset. Read: " + (int)(c) ); is.reset(); } //is.skip(mesg.length()+1); while ( lei < byteArray.length ) { System.out.println("To request this time: " + (byteArray.length-lei)); lei += is.read ( byteArray , lei , byteArray.length-lei ); System.out.println("Finally read " + lei + " bytes."); System.out.println("Data read till mom't eez:\n\n"); System.out.write(byteArray,0,lei); System.out.println("\n\n"); //create test file FileOutputStream juasesblases = new FileOutputStream(new File("prueba.txt")); juasesblases.write(byteArray,0,lei); } //System.out.println("Skipped (br): " + br.skip(byteArray.length)); */ } catch ( IOException ioe ) { ioe.printStackTrace(); return; } /* System.out.println("REMOTE NAME: " + remoteName); System.out.println("REQUESTED FILES:"); for ( int i = 0 ; i < requestedFiles.size() ; i++ ) { String s = (String) requestedFiles.get(i); System.out.println(s); } */ //if ( ficheroDeseado ) //que un cliente falso no nos mande otro fichero { System.out.println("Writin' actual file."); try { FileOutputStream fos = new FileOutputStream ( remoteName ); OutputStreamWriter osw = new OutputStreamWriter ( fos ); fos.write( /*new String(byteArray).getBytes()*/byteArray ); fos.flush(); fos.close(); cliente.write(cliente.getColorCode("information") + "Descargado con �xito " + remoteName + " (" + byteSize + " bytes)\n" + cliente.getColorCode("reset")); } catch ( IOException ioe ) { ioe.printStackTrace(); } } } else if ( command.equalsIgnoreCase(UNRECOGNIZED_MESSAGE)) { System.out.println("Protocol error!"); } else { System.out.println("I'm the ServerProxy and I can't recognize " + command ); pw.println(UNRECOGNIZED_MESSAGE + " " + command); pw.flush(); } } public void requestServerFiles ( List /*of String*/ fnames ) { for ( int i = 0 ; i < fnames.size() ; i++ ) { String fName = (String)fnames.get(i); pw.println(GET_FILE+" "+fName); pw.flush(); } requestedFiles.addAll(fnames); } //public void requestServerFiles ( List /*of String*/ fnames ) /*{ for ( int i = 0 ; i < fnames.size() ; i++ ) { String fName = (String)fnames.get(i); pw.println(GET_FILE+" "+fName); pw.flush(); String linea; try { System.out.println("Expecting file data:"); linea = br.readLine(); } catch ( IOException ioe ) { System.out.println(ioe);ioe.printStackTrace(); return; } StringTokenizer sto = new StringTokenizer ( linea ); String token = sto.nextToken(); String remoteName; int byteSize; if ( token.equalsIgnoreCase ( FILE_HEADER_LINE ) ) { remoteName = sto.nextToken(); byteSize = Integer.valueOf(sto.nextToken()).intValue(); byte[] byteArray = new byte[byteSize]; //read the file from socket try { System.out.println("Reading file from socket."); is.read ( byteArray , 0 , byteArray.length ); } catch ( IOException ioe ) { ioe.printStackTrace(); return; } if ( remoteName == fName ) //que un cliente falso no nos mande otro fichero { try { FileOutputStream fos = new FileOutputStream ( fName ); fos.write(byteArray); fos.close(); } catch ( IOException ioe ) { ioe.printStackTrace(); continue; } } } //end if token is file header line else { System.out.println("Parsing non-file data."); parseMessage(linea); i--; //didn't do this file } } } */ public void requestUserSelectedFiles ( final Vector /*of String*/ ficheros ) { //show dialog: no, esto deber�a ser swing-independent. //se podr�a hacer un swingserverproxy extends serverproxy que //detallara esto, en forma de m�todo gen�rico getChosenFilesFromClient() final JDialog jd = new JDialog(); jd.setModal(true); jd.setTitle("Ficheros"); jd.setSize(500,500); jd.getContentPane().setLayout ( new java.awt.BorderLayout ( ) ); final JList jl = new JList(ficheros); for ( int i = 0 ; i < ficheros.size() ; i++ ) { StringTokenizer st1 = new StringTokenizer ( (String)ficheros.get(i) ); String fileName = st1.nextToken(); File theFile = new File ( fileName ); if ( !theFile.exists() ) jl.setSelectedValue(ficheros.get(i),false); } jd.getContentPane().add ( new JLabel("El servidor ofrece los siguientes ficheros:") , java.awt.BorderLayout.NORTH ); jd.getContentPane().add ( new JScrollPane(jl) , java.awt.BorderLayout.CENTER ); JPanel jp = new JPanel(); JButton b1 = new JButton("Descargar todos"); JButton b2 = new JButton("Descargar seleccionados"); JButton b3 = new JButton("No descargar ninguno"); b1.addActionListener ( new java.awt.event.ActionListener() { public void actionPerformed ( java.awt.event.ActionEvent evt ) { requestServerFiles ( ficheros ); jd.dispose(); } } ); b2.addActionListener ( new java.awt.event.ActionListener() { public void actionPerformed ( java.awt.event.ActionEvent evt ) { Vector seleccionados = new Vector(); for ( int i = 0 ; i < ficheros.size() ; i++ ) { if ( jl.isSelectedIndex(i) ) seleccionados.add ( ficheros.get(i) ); } requestServerFiles ( seleccionados ); jd.dispose(); } } ); b3.addActionListener ( new java.awt.event.ActionListener() { public void actionPerformed ( java.awt.event.ActionEvent evt ) { jd.dispose(); } } ); jp.add(b1); jp.add(b2); jp.add(b3); jd.getContentPane().add(jp , java.awt.BorderLayout.SOUTH ); System.out.println("Size of list: " + ficheros.size() ); jd.pack(); jd.setVisible(true); } }