/* * File : HttpReportServer.java * Created : 13-feb-2003 14:47 * By : fbusquets * * JClic - Authoring and playing system for educational activities * * Copyright (C) 2000 - 2005 Francesc Busquets & Departament * d'Educacio de la Generalitat de Catalunya * * 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 of the License, or * (at your option) any later version. * * 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 (see the LICENSE file). */ package edu.xtec.jclic.report; import edu.xtec.jclic.report.rp.*; import edu.xtec.servlet.RequestProcessor; import edu.xtec.servlet.ResourceRP; import edu.xtec.util.Messages; import java.io.IOException; import java.io.InterruptedIOException; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * * @author Francesc Busquets (fbusquets@xtec.cat) * @version 13.09.17 */ public class HTTPReportServer extends ReportServerEventMaker{ public static final int DEFAULT_PORT = 9000, DEFAULT_TIMEOUT=1200; protected static final String[] URI={"/login", "/main", "/dbAdmin", "/userReport", "/actReport", "/img", "/groupReport", "/groupAdmin", "/userAdmin", "/resource", "/JClicReportService"}; protected static final Class[] CLS={Login.class, Main.class, DbAdmin.class, UserReport.class, ActReport.class, Img.class, GroupReport.class, GroupAdmin.class, UserAdmin.class, ResourceRP.class, JClicReportService.class}; HttpThread httpThread; edu.xtec.util.Messages messages; /** Creates a new instance of HttpReportServer */ public HTTPReportServer(Messages messages) { this.messages=messages; httpThread=null; RequestProcessor.setDirectResources(true); } public boolean startServer(int port, int timeOut) { if(serverRunning()){ fireReportServerSystemEvent(messages.get("manage_server_already_started"), ReportServerEvent.ERROR); return false; } try{ httpThread=new HttpThread(port, timeOut); httpThread.start(); } catch(Exception e){ fireReportServerSystemEvent(e.toString(), ReportServerEvent.ERROR); return false; } return true; } public boolean stopServer(){ if(!serverRunning()){ fireReportServerSystemEvent("Server is not started!", ReportServerEvent.ERROR); return false; } httpThread.stopServer(); while(serverRunning()){ Thread.yield(); } return true; } @Override protected void finalize() throws Throwable{ try { if(serverRunning()) stopServer(); } finally { super.finalize(); } } public boolean serverRunning(){ return httpThread!=null; } protected class HttpThread extends Thread{ boolean running=false; ServerSocket ss=null; int socketTimeOut=0; HttpThread(int port, int timeOut) throws Exception{ ss=new ServerSocket(port); fireReportServerSystemEvent(Integer.toString(port), ReportServerEvent.START); socketTimeOut=timeOut; running=false; } @Override public void run(){ try{ running=true; ss.setSoTimeout(1000); while(running){ try{ Socket socket=ss.accept(); ClientConnection cc=new ClientConnection(socket); cc.start(); }catch(InterruptedIOException ioex){ // Timeout. start again... }catch(Exception ex){ fireReportServerSystemEvent(ex.toString(), ReportServerEvent.ERROR); running=false; } } ss.close(); fireReportServerSystemEvent(null, ReportServerEvent.STOP); } catch (IOException e){ fireReportServerSystemEvent(e.toString(), ReportServerEvent.ERROR); } running=false; httpThread=null; } public void stopServer(){ running=false; } protected class ClientConnection extends Thread{ Socket socket=null; int id=0; ClientConnection(Socket socket){ this.socket=socket; //fireReportServerSocketEvent(socket, null, ReportServerEvent.CONNECT); //fireReportServerSocketEvent(socket, null, ReportServerEvent.CONNECTION); } @Override public void run(){ RequestProcessor rp=null; HTTPRequest re=null; try{ re=new HTTPRequest(socket); fireReportServerSocketEvent(socket, re.firstLine, ReportServerEvent.CONNECTION); String url=re.urlBase; if(url==null || url.length()==0 || url.equals("/")) url=URI[0]; Class<?> cl=null; for(int i=0; i<URI.length; i++){ if(URI[i].equals(url)){ cl=CLS[i]; break; } } int p=0; if(cl==null && re.urlBase!=null && (p=re.urlBase.lastIndexOf('/'))>=0 && p<re.urlBase.length()-1){ String s=re.urlBase.substring(p+1); re.params.put(ResourceRP.ID, new String[]{s}); //System.out.println(s); cl=ResourceRP.class; } if(cl==null){ re.error(HTTPRequest.NOT_FOUND, null); } else{ rp=(RequestProcessor)cl.newInstance(); rp.setParams(re.params); if(rp.wantsInputStream()) rp.setInputStream(re.inputStream); for(String key : re.cookies.keySet()){ rp.setCookie(key, (String)re.cookies.get(key)); } rp.init(); re.head.cache=!rp.noCache(); List<String[]> v=new ArrayList<String[]>(); rp.header(v); if(!v.isEmpty()){ Iterator it=v.iterator(); while(it.hasNext() && !re.head.commited){ String[] h=(String[])it.next(); if(h[0].equals(RequestProcessor.ERROR)){ re.error(Integer.parseInt(h[1]), h[2]); } else if(h[0].equals(RequestProcessor.REDIRECT)){ re.redirect(h[1]); break; } else if(h[0].equals(RequestProcessor.CONTENT_TYPE)) re.head.contentType=h[1]; else if(h[0].equals(RequestProcessor.CONTENT_LENGTH)) re.head.contentLength=Integer.parseInt(h[1]); else if(h[0].equals(RequestProcessor.EXTRA)){ StringBuilder sb=new StringBuilder(100); if(re.head.extra!=null) sb.append(re.head.extra).append("\r\n"); sb.append(h[1]).append(": ").append(h[2]); re.head.extra=sb.substring(0); } else if(h[0].equals(RequestProcessor.COOKIE)) re.cookies.put(h[1], h[2]); } } if(!re.head.commited){ re.head.write(); if(rp.usesWriter()){ rp.process(re.pw); re.pw.flush(); re.pw.close(); } else{ rp.process(re.os); re.os.flush(); re.os.close(); } re.commited=true; } rp.end(); rp=null; } } catch(Exception ex){ int errCode = (rp!=null && rp.errCode>=0) ? rp.errCode : HTTPRequest.SERVER_ERROR; String errMsg = (rp!=null && rp.errMsg!=null) ? rp.errMsg : ex.getMessage(); if(re!=null && !re.head.commited){ try{ re.error(errCode, errMsg); } catch(Exception ex2){ System.err.println("Unable to report error due to\n"+ex2); } } fireReportServerSocketEvent(socket, ex.toString(), ReportServerEvent.ERROR); System.err.println("ERROR "+errCode+": "+errMsg); ex.printStackTrace(System.err); } finally { if(rp!=null) rp.end(); try{ socket.close(); } catch(Exception ex){ System.err.println("Unable to close socket due to:\n"+ex); } } } } } }