Java tutorial
/* Copyright 1995-2015 Esri Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. For additional information, contact: Environmental Systems Research Institute, Inc. Attn: Contracts Dept 380 New York Street Redlands, California, USA 92373 email: contracts@esri.com */ package com.esri.geoevent.test.performance; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper; import com.esri.geoevent.test.performance.jaxb.Config; import com.esri.geoevent.test.performance.jaxb.ConsumerConfig; import com.esri.geoevent.test.performance.jaxb.ProducerConfig; import com.esri.geoevent.test.performance.utils.KryoUtils; import com.esri.geoevent.test.performance.utils.MessageUtils; public abstract class PerformanceCollectorBase implements PerformanceCollector, Runnable { private static final String REQUEST_SEPERATOR = "::::"; protected int numberOfEvents; protected int numberOfExpectedResults; protected Map<Integer, Long[]> timeStamps = new ConcurrentHashMap<Integer, Long[]>(); protected AtomicBoolean running = new AtomicBoolean(false); protected RunningStateListener runningStateListener; protected List<String> events = new ArrayList<String>(); private CommandInterpreter commandInterpreter; private Thread commandInterpreterThread; protected AtomicLong successfulEvents = new AtomicLong(); protected AtomicLong successfulEventBytes = new AtomicLong(); protected final Mode mode; private Integer commandPort; private Boolean isLocal; private ClockSync clockSync = null; private FileType eventFileType = FileType.UNKNOWN; private boolean DEBUG = false; public PerformanceCollectorBase(Mode mode) { this.mode = mode; } public int getNumberOfEvents() { return numberOfEvents; } public void setNumberOfEvents(int numberOfEvents) { this.numberOfEvents = numberOfEvents; } public int getNumberOfExpectedResults() { return numberOfExpectedResults; } public void setNumberOfExpectedResults(int numberOfExpectedResults) { this.numberOfExpectedResults = numberOfExpectedResults; } public long getSuccessfulEvents() { return successfulEvents.get(); } public long getSuccessfulEventBytes() { return successfulEventBytes.get(); } public synchronized Map<Integer, Long[]> getTimeStamps() { return timeStamps; } public FileType getEventFileType() { return eventFileType; } @Override public void start() throws RunningException { running = new AtomicBoolean(true); Thread thread = new Thread(this); thread.start(); } @Override public void stop() { running.set(false); } @Override public boolean isRunning() { return running.get(); } @Override public void destroy() { reset(); } @Override public void reset() { successfulEvents.set(0); successfulEventBytes.set(0); synchronized (timeStamps) { timeStamps.clear(); } } @Override public RunningStateType getRunningState() { return running.get() ? RunningStateType.STARTED : RunningStateType.STOPPED; } @Override public void setRunningStateListener(RunningStateListener listener) { this.runningStateListener = listener; } protected void loadEvents(File file) throws TestException { if (!events.isEmpty()) { events.clear(); } // parse out json files differently if (FilenameUtils.isExtension(file.getName(), "json")) { eventFileType = FileType.JSON; try { ObjectMapper mapper = new ObjectMapper(); JsonNode node = mapper.readTree(file); addEventsToList(node); } catch (Exception error) { throw new TestException(error.getMessage()); } } else { eventFileType = FileType.TEXT; try (BufferedReader input = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) { String line = null; while ((line = input.readLine()) != null) { events.add(line + "\n"); } } catch (Exception error) { throw new TestException(error.getMessage()); } } } private void addEventsToList(JsonNode node) { if (node == null) { return; } if (node.isArray()) { for (final JsonNode eventNode : node) { addEventsToList(eventNode); } } else { events.add(node.toString()); } } @Override public void listenOnCommandPort(int commandPort, boolean isLocal) { // keep for re-initialization if (this.commandPort == null) { this.commandPort = commandPort; } if (this.isLocal == null) { this.isLocal = isLocal; } System.out.println(ImplMessages.getMessage("PERFORMANCE_COLLECTOR_LISTENING_CMD_PORT_MSG", String.valueOf(commandPort))); if (commandInterpreter != null) { commandInterpreter.stop(); commandInterpreter.destroy(); commandInterpreter = null; } commandInterpreter = new CommandInterpreter(commandPort); setRunningStateListener(commandInterpreter); if (commandInterpreterThread != null) { commandInterpreterThread.interrupt(); commandInterpreterThread = null; } commandInterpreterThread = new Thread(commandInterpreter); commandInterpreterThread.start(); if (!isLocal) { if (clockSync != null) { clockSync.stop(); clockSync = null; } clockSync = new ClockSync(); Thread thread = new Thread(clockSync); thread.start(); } } @Override public void disconnectCommandPort() { commandInterpreter.stop(); commandInterpreter.destroy(); commandInterpreter = null; commandInterpreterThread.interrupt(); commandInterpreterThread = null; if (clockSync != null) { clockSync.stop(); clockSync = null; } System.out.println(ImplMessages.getMessage("PERFORMANCE_COLLECTOR_DISCONNECTED_CMD_PORT_MSG")); } private class CommandInterpreter implements Runnable, RunningStateListener { int port; private BufferedReader in; private PrintWriter out; private ServerSocket server; private AtomicBoolean isRunning = new AtomicBoolean(false); public CommandInterpreter(int commandPort) { this.port = commandPort; isRunning = new AtomicBoolean(true); } public void run() { try { server = new ServerSocket(port); while (isRunning.get()) { // System.out.println("Listening for a connection from the orchestrator."); Socket commandSocket = server.accept(); try { commandSocket.setSoTimeout(100); in = new BufferedReader(new InputStreamReader(commandSocket.getInputStream())); out = new PrintWriter(commandSocket.getOutputStream()); while (isRunning.get() && in != null) { String command = null; try { command = in.readLine(); } catch (Exception ignored) { } if (StringUtils.isEmpty(command)) { continue; } // System.out.println("Received request (raw) \"" + command +"\""); command = MessageUtils.unescapeNewLineCharacters(command); String requestStr = command; String additionalDataStr = null; if (command.contains(REQUEST_SEPERATOR)) { String[] requestSplitter = command.split(REQUEST_SEPERATOR); if (requestSplitter == null || requestSplitter.length < 2) { continue; } requestStr = requestSplitter[0]; additionalDataStr = requestSplitter[1]; } // parse out the request object Request request = KryoUtils.fromString(requestStr, Request.class); if (DEBUG) { System.out.println("Received request \"" + request + "\""); } if (request == null) { System.err.println( ImplMessages.getMessage("PERFORMANCE_COLLECTOR_REQUEST_PARSE_ERROR")); continue; } // request action switch Response response = null; switch (request.getType()) { case INIT: response = new Response(ResponseType.OK); try { // parse out the init data if (additionalDataStr == null) { String errorMsg = ImplMessages .getMessage("PERFORMANCE_COLLECTOR_INIT_PARSE_ERROR"); response = new Response(ResponseType.ERROR, errorMsg); System.err.println(errorMsg); respond(response); continue; } Config config = null; if (mode == Mode.Consumer) { config = KryoUtils.fromString(additionalDataStr, ConsumerConfig.class); } else if (mode == Mode.Producer) { config = KryoUtils.fromString(additionalDataStr, ProducerConfig.class); } if (DEBUG) { System.out.println("Received additional config " + config); } init(config); } catch (Exception ex) { response = new Response(ResponseType.ERROR, ex.getMessage()); } finally { respond(response); } break; case START: response = new Response(ResponseType.OK); try { start(); } catch (Exception ex) { response = new Response(ResponseType.ERROR, ex.getMessage()); } finally { respond(response); } break; case STOP: response = new Response(ResponseType.OK); try { stop(); } catch (Exception ex) { response = new Response(ResponseType.ERROR, ex.getMessage()); } finally { respond(response); } break; case IS_RUNNING: response = new Response(ResponseType.OK); if (isRunning()) { response.setData("true"); } else { response.setData("false"); } respond(response); break; case GET_RUNNING_STATE: RunningStateType st = getRunningState(); response = new Response(ResponseType.OK, st.toString()); respond(response); break; case VALIDATE: response = new Response(ResponseType.OK); try { validate(); } catch (Exception ex) { response = new Response(ResponseType.ERROR, ex.getMessage()); } finally { respond(response); } break; case DESTROY: reset(); response = new Response(ResponseType.OK); respond(response); destroy(); PerformanceCollectorBase.this.destroy(); listenOnCommandPort(commandPort, isLocal); break; case RESET: reset(); response = new Response(ResponseType.OK); respond(response); break; case GET_NUMBER_OF_EVENTS: response = new Response(ResponseType.OK, String.valueOf(getNumberOfEvents())); respond(response); break; case GET_SUCCESSFUL_EVENTS: response = new Response(ResponseType.OK, String.valueOf(getSuccessfulEvents())); respond(response); break; case GET_SUCCESSFUL_EVENT_BYTES: response = new Response(ResponseType.OK, String.valueOf(getSuccessfulEventBytes())); respond(response); break; case SET_NUMBER_OF_EVENTS: setNumberOfEvents(Integer.parseInt(request.getData())); response = new Response(ResponseType.OK); respond(response); break; case SET_NUMBER_OF_EXPECTED_RESULTS: setNumberOfExpectedResults(Integer.parseInt(request.getData())); response = new Response(ResponseType.OK); respond(response); break; case GET_TIMESTAMPS: // TODO: We need a better way to send this across the wire // build the time stamps string Map<Integer, Long[]> values = getTimeStamps(); StringBuilder stringBuilder = new StringBuilder(); for (Integer key : values.keySet()) { stringBuilder.append("__" + key); Long[] valueArray = values.get(key); for (Long l : valueArray) { stringBuilder.append("::" + l); } } String timeStampsStr = null; if (stringBuilder.length() > 2) { timeStampsStr = stringBuilder.substring(2); } response = new Response(ResponseType.OK, timeStampsStr); respond(response); break; case UNKNOWN: String erroMsg = ImplMessages.getMessage( "PERFORMANCE_COLLECTOR_UNKNOWN_REQUEST_ERROR", RequestType.UNKNOWN, command); response = new Response(ResponseType.ERROR, erroMsg); System.err.println(erroMsg); respond(response); continue; } } } catch (Exception ex) { if (ex.getMessage().equals("Connection reset")) { System.out.println(ImplMessages.getMessage("PERFORMANCE_COLLECTOR_DISCONNECTED_MSG")); reset(); } else { ex.printStackTrace(); } } } } catch (SocketException error) { // ignored } catch (Exception error) { error.printStackTrace(); } } @Override public void onStateChange(RunningState newState) { if (out != null) { Response response = new Response(ResponseType.STATE_CHANGED, newState.getType().toString()); respond(response); if (DEBUG) { System.out.println("@@@ State change event(" + newState + ") sent!"); } } } private void respond(Response response) { if (out != null) { if (DEBUG) { System.out.println("Sending response: \"" + response + "\""); } String responseStr = KryoUtils.toString(response, Response.class); responseStr = MessageUtils.escapeNewLineCharacters(responseStr); // if( TestHarnessExecutor.DEBUG ) // System.out.println("Sending response (raw): \"" + responseStr + "\""); out.println(responseStr); out.flush(); } else { System.err.println("Failed to send the response: \"" + response + "\". The Output stream is NULL!"); } } public void stop() { isRunning.set(false); } private void destroy() { IOUtils.closeQuietly(in); IOUtils.closeQuietly(out); IOUtils.closeQuietly(server); } } }