package com.dronecontrol.droneapi; import com.google.inject.Inject; import com.dronecontrol.droneapi.commands.Command; import com.dronecontrol.droneapi.commands.ComposedCommand; import com.dronecontrol.droneapi.commands.SimpleCommand; import com.dronecontrol.droneapi.data.DroneConfiguration; import com.dronecontrol.droneapi.data.NavData; import com.dronecontrol.droneapi.listeners.DroneConfigurationListener; import com.dronecontrol.droneapi.listeners.NavDataListener; import org.apache.log4j.Logger; import static com.google.common.base.Preconditions.checkState; import static com.dronecontrol.droneapi.helpers.ThreadHelper.sleep; public class CommandSenderCoordinator implements NavDataListener, DroneConfigurationListener { private static final int MAX_RETRIES = 5; private final Logger logger = Logger.getLogger(CommandSenderCoordinator.class); private final CommandSender commandSender; private NavData currentNavData; private DroneConfiguration currentDroneConfiguration; @Inject public CommandSenderCoordinator(CommandSender commandSender, NavigationDataRetriever navigationDataRetriever, ConfigurationDataRetriever configurationDataRetriever) { this.commandSender = commandSender; navigationDataRetriever.addNavDataListener(this); configurationDataRetriever.addDroneConfigurationListener(this); } public void executeCommand(Command command) { if (command instanceof SimpleCommand) { executeSimpleCommand((SimpleCommand) command); } else if (command instanceof ComposedCommand) { executeComposedCommand((ComposedCommand) command); } } private void executeSimpleCommand(SimpleCommand command) { int currentTry = 0; do { command.execute(commandSender, this); if (checkSuccessful(command, currentTry)) { break; } currentTry++; } while (true); } private void executeComposedCommand(ComposedCommand command) { int currentTry = 0; do { executeAllSubCommands(command); if (checkSuccessful(command, currentTry)) { break; } currentTry++; } while (true); } private void executeAllSubCommands(ComposedCommand command) { for (Command subCommand : command.getCommands()) { executeCommand(subCommand); } } private boolean checkSuccessful(Command command, int currentTry) { waitFor(command); try { command.checkSuccess(currentNavData, currentDroneConfiguration); return true; } catch (Exception e) { checkCurrentTry(currentTry, e); logger.debug(String.format("Command check failed: %s", e.getMessage())); return false; } } private void checkCurrentTry(int currentTry, Exception e) { checkState(currentTry <= MAX_RETRIES, "A check operation was not successful: " + e.getMessage()); } private void waitFor(Command command) { if (command.getTimeoutMillis() != Command.NO_TIMEOUT) { sleep(command.getTimeoutMillis()); } } public void resetConfiguration() { currentDroneConfiguration = null; } @Override public void onDroneConfiguration(DroneConfiguration configuration) { currentDroneConfiguration = configuration; } @Override public void onNavData(NavData navData) { currentNavData = navData; } }