/* * JMeter Report Server * Copyright (C) 2010 eXcentia * dev@sonar.codehaus.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 */ package es.excentia.jmeter.report.server; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import es.excentia.jmeter.report.client.JMeterReportConst; import es.excentia.jmeter.report.server.exception.JMeterReportServerException; import es.excentia.jmeter.report.server.service.ConfigService; import es.excentia.jmeter.report.server.service.OperationService; import es.excentia.jmeter.report.server.service.ServiceFactory; /** * Servidor de resultados de tests de JMeter para Sonar * * @author cfillol */ public class JMeterReportServer { private static final Logger log = LoggerFactory.getLogger(JMeterReportServer.class); private static final boolean LOG_DEBUG = log.isDebugEnabled(); private static final boolean LOG_TRACE = log.isTraceEnabled(); private ServerSocket listener; private Thread serverThread; private int connections = 0; private int maxConnections = 0; private boolean stopWhenPossible = false; protected ConfigService configService = ServiceFactory.get(ConfigService.class); protected OperationService metricService = ServiceFactory.get(OperationService.class); /** * Atendemos en forma de hilos las peticiones de los clientes */ class RequestThread implements Runnable { private Socket socket; RequestThread(Socket socket) { this.socket = socket; } public void run() { try { DataInputStream in = new DataInputStream(socket.getInputStream()); DataOutputStream out = new DataOutputStream(socket.getOutputStream()); int op = in.readInt(); if (LOG_DEBUG) { log.debug("Attending client request operation: " + op); } try { String config; String metric; switch (op) { case JMeterReportConst.OP_GET_GLOBAL_SUMMARY: config = in.readUTF(); metricService.writeGlobalSummary(out, config); break; case JMeterReportConst.OP_GET_BUCKET_MEASURES: config = in.readUTF(); metric = in.readUTF(); int millisBucket = in.readInt(); metricService.writeBucketMeasures(out, config, metric, millisBucket); break; default: throw new JMeterReportServerException("Invalid operation code: " + op); } } catch (IOException ioe) { log.error("IOException on socket when serving request", ioe); } catch (Exception e) { log.error("Report request exception", e); // Send error to client out.writeInt(JMeterReportConst.RETURN_CODE_ERROR); out.writeUTF(e.getMessage()); } } catch (IOException ioe) { log.error("Could not get socket streams", ioe); } finally { try { connections--; socket.close(); log.debug("Request finished"); } catch (Exception e) { log.error("Could not close server socket", e); } } } } /** * Send error to client and close the socket */ private void connectionLimitExceeded(Socket socket) { if (LOG_DEBUG) { log.debug("Connection limit exceeded ("+maxConnections+"). Closing socket ..."); } try { socket.close(); } catch (Exception e) { log.error("Could not close server socket", e); } } /** * Listen for incoming connections and handle them */ private void startListening() { try { int port = configService.getPort(); log.info("Starting server on port " + port); maxConnections = configService.getMaxConnections(); listener = new ServerSocket(port); Socket socket; do { socket = listener.accept(); if (maxConnections!=0 && connections>=maxConnections) { // The number of opened connections is limited and has been exceeded connectionLimitExceeded(socket); } else { // Serve request connections++; RequestThread requestThread = new RequestThread(socket); Thread t = new Thread(requestThread); t.start(); } } while (true); } catch (IOException ioe) { if (LOG_TRACE) { log.trace("IOException on socket listen", ioe); } else if (!stopWhenPossible) { log.error("IOException on socket listen", ioe); } } log.info("Server stopped"); } /** * Listen for incoming connections and handle them in a thread, without * stopping execution */ public void start() { if (serverThread == null) { stopWhenPossible = false; serverThread = new Thread(new Runnable() { public void run() { startListening(); } }); serverThread.start(); } } public void stop() { if (listener != null) { log.info("Stopping server ..."); stopWhenPossible = true; try { listener.close(); } catch (IOException e) { log.error("Error stoping server", e); } finally { listener = null; } } } public static void main(String[] args) { new JMeterReportServer().startListening(); } }