/* * Copyright 2017 Nokia Solutions and Networks * Licensed under the Apache License, Version 2.0, * see license.txt file for details. */ package org.rf.ide.core.execution.server; import static com.google.common.collect.Lists.newArrayList; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.type.TypeReference; import org.rf.ide.core.execution.LogLevel; import org.rf.ide.core.execution.RobotAgentEventListener; import org.rf.ide.core.execution.RobotAgentEventListener.RobotAgentEventsListenerException; import org.rf.ide.core.execution.Status; import com.google.common.base.Strings; import com.google.common.collect.Iterables; class RobotAgentEventDispatcher { private final List<RobotAgentEventListener> eventsListeners; RobotAgentEventDispatcher(final AgentClient client, final RobotAgentEventListener... eventsListeners) { final List<RobotAgentEventListener> listeners = newArrayList(eventsListeners); listeners.add(0, new AgentServerProtocolVersionChecker()); this.eventsListeners = Collections.synchronizedList(listeners); for (final RobotAgentEventListener listener : this.eventsListeners) { listener.setClient(client); } } void addEventsListener(final RobotAgentEventListener listener) { eventsListeners.add(listener); } void removeEventsListener(final RobotAgentEventListener listener) { eventsListeners.remove(listener); } void runEventsLoop(final BufferedReader eventReader) throws IOException, RobotAgentEventsListenerException { String event = eventReader.readLine(); final ObjectMapper mapper = new ObjectMapper(); while (event != null && anyListenerIsHandlingEvents()) { final TypeReference<Map<String, Object>> stringToObjectMapType = new TypeReference<Map<String, Object>>() { }; final Map<String, Object> eventMap = mapper.readValue(event, stringToObjectMapType); final String eventType = getEventType(eventMap); if (eventType == null) { continue; } switch (eventType) { case "ready_to_start": handleReadyToStart(); break; case "agent_initializing": handleAgentInitializing(); break; case "version": handleVersion(eventMap); break; case "resource_import": handleResourceImport(eventMap); break; case "start_suite": handleStartSuite(eventMap); break; case "end_suite": handleEndSuite(eventMap); break; case "start_test": handleStartTest(eventMap); break; case "end_test": handleEndTest(eventMap); break; case "start_keyword": handleStartKeyword(eventMap); break; case "end_keyword": handleEndKeyword(eventMap); break; case "vars": handleVariables(eventMap); break; case "global_vars": handleGlobalVariables(eventMap); break; case "check_condition": handleCheckCondition(); break; case "condition_result": handleConditionResult(eventMap); break; case "condition_error": handleConditionError(eventMap); break; case "condition_checked": handleConditionChecked(); break; case "paused": handlePause(); break; case "close": handleClose(); break; case "log_message": handleLogMessage(eventMap); break; case "output_file": handleOutputFile(eventMap); break; case "library_import": handleLibraryImport(eventMap); break; case "message": handleMessage(eventMap); break; default: break; } event = eventReader.readLine(); } } private void handleReadyToStart() { for (final RobotAgentEventListener listener : eventsListeners) { listener.handleAgentIsReadyToStart(); } } private void handleAgentInitializing() { for (final RobotAgentEventListener listener : eventsListeners) { listener.handleAgentInitializing(); } } private void handleVersion(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("version"); final Map<?, ?> attributes = (Map<?, ?>) arguments.get(0); final String pythonVersion = (String) attributes.get("python"); final String robotVersion = (String) attributes.get("robot"); final int protocolVersion = (Integer) attributes.get("protocol"); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleVersions(pythonVersion, robotVersion, protocolVersion); } } private void handleResourceImport(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("resource_import"); final Map<?, ?> attributes = (Map<?, ?>) arguments.get(1); final File resourceFilePath = new File((String) attributes.get("source")); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleResourceImport(resourceFilePath); } } private void handleStartSuite(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("start_suite"); final String name = (String) arguments.get(0); final Map<?, ?> attributes = (Map<?, ?>) arguments.get(1); final File suiteFilePath = new File((String) attributes.get("source")); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleSuiteStarted(name, suiteFilePath); } } private void handleEndSuite(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("end_suite"); final String name = (String) arguments.get(0); final Map<?, ?> attributes = (Map<?, ?>) arguments.get(1); final int elapsedTime = (Integer) attributes.get("elapsedtime"); final String errorMessage = (String) attributes.get("message"); final Status suiteStatus = Status.valueOf((String) attributes.get("status")); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleSuiteEnded(name, elapsedTime, suiteStatus, errorMessage); } } private void handleStartTest(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("start_test"); final String name = (String) arguments.get(0); final Map<?, ?> attributes = (Map<?, ?>) arguments.get(1); final String longName = (String) attributes.get("longname"); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleTestStarted(name, longName); } } private void handleEndTest(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("end_test"); final String name = (String) arguments.get(0); final Map<?, ?> attributes = (Map<?, ?>) arguments.get(1); final String longName = (String) attributes.get("longname"); final int elapsedTime = (Integer) attributes.get("elapsedtime"); final String errorMessage = (String) attributes.get("message"); final Status testStatus = Status.valueOf((String) attributes.get("status")); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleTestEnded(name, longName, elapsedTime, testStatus, errorMessage); } } private void handleStartKeyword(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("start_keyword"); final String name = (String) arguments.get(0); final Map<?, ?> attributes = (Map<?, ?>) arguments.get(1); final String keywordType = (String) attributes.get("type"); final List<String> keywordArgs = ensureListOfStrings((List<?>) attributes.get("args")); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleKeywordStarted(name, keywordType, keywordArgs); } } private void handleEndKeyword(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("end_keyword"); final String name = (String) arguments.get(0); final Map<?, ?> attributes = (Map<?, ?>) arguments.get(1); final String keywordType = (String) attributes.get("type"); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleKeywordEnded(name, keywordType); } } private void handleVariables(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("vars"); final Map<String, Object> vars = ensureOrderedMapOfStringsToObjects((Map<?, ?>) arguments.get(1)); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleVariables(vars); } } private void handleGlobalVariables(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("global_vars"); final Map<String, String> globalVars = ensureOrderedMapOfStringsToStrings((Map<?, ?>) arguments.get(1)); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleGlobalVariables(globalVars); } } private void handleCheckCondition() { for (final RobotAgentEventListener listener : eventsListeners) { listener.handleCheckCondition(); } } private void handleConditionResult(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("condition_result"); final boolean result = (Boolean) arguments.get(0); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleConditionResult(result); } } private void handleConditionError(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("condition_error"); final String error = (String) arguments.get(0); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleConditionError(error); } } private void handleConditionChecked() { for (final RobotAgentEventListener listener : eventsListeners) { listener.handleConditionChecked(); } } private void handlePause() { for (final RobotAgentEventListener listener : eventsListeners) { listener.handlePaused(); } } private void handleClose() { for (final RobotAgentEventListener listener : eventsListeners) { listener.handleClosed(); } } private void handleLogMessage(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("log_message"); final Map<?, ?> message = (Map<?, ?>) arguments.get(0); final String msg = (String) message.get("message"); final String timestamp = (String) message.get("timestamp"); final LogLevel level = LogLevel.valueOf(((String) message.get("level")).toUpperCase()); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleLogMessage(msg, level, timestamp); } } private void handleOutputFile(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("output_file"); final String filepath = (String) arguments.get(0); final File path = filepath == null ? null : new File(filepath); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleOutputFile(path); } } private void handleLibraryImport(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("library_import"); final String libraryName = (String) arguments.get(0); final Map<?, ?> attributes = (Map<?, ?>) arguments.get(1); final String originalName = (String) attributes.get("originalname"); final String name = Strings.isNullOrEmpty(originalName) ? libraryName : originalName; final String importer = (String) attributes.get("importer"); final String source = (String) attributes.get("source"); final List<String> args = ensureListOfStrings((List<?>) attributes.get("args")); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleLibraryImport(name, importer, source, args); } } private void handleMessage(final Map<String, Object> eventMap) { final List<?> arguments = (List<?>) eventMap.get("message"); final Map<?, ?> attributes = (Map<?, ?>) arguments.get(0); final String msg = (String) attributes.get("message"); final LogLevel level = LogLevel.valueOf(((String) attributes.get("level")).toUpperCase()); for (final RobotAgentEventListener listener : eventsListeners) { listener.handleMessage(msg, level); } } private String getEventType(final Map<String, ?> eventMap) { if (eventMap == null) { return null; } return Iterables.getFirst(eventMap.keySet(), null); } private boolean anyListenerIsHandlingEvents() { for (final RobotAgentEventListener listener : eventsListeners) { if (listener.isHandlingEvents()) { return true; } } return false; } private static List<String> ensureListOfStrings(final List<?> list) { return list.stream().map(String.class::cast).collect(Collectors.toList()); } private static Map<String, Object> ensureOrderedMapOfStringsToObjects(final Map<?, ?> map) { final LinkedHashMap<String, Object> result = new LinkedHashMap<>(); map.entrySet().stream().forEach(e -> result.put((String) e.getKey(), e.getValue())); return result; } private static Map<String, String> ensureOrderedMapOfStringsToStrings(final Map<?, ?> map) { final LinkedHashMap<String, String> result = new LinkedHashMap<>(); map.entrySet().stream().forEach(e -> result.put((String) e.getKey(), (String) e.getValue())); return result; } }