package nl.tudelft.bw4t.server.environment; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.rmi.RemoteException; import javax.xml.bind.JAXBException; import org.apache.log4j.Logger; import org.apache.log4j.PropertyConfigurator; import eis.exceptions.ManagementException; import nl.tudelft.bw4t.server.BW4TServer; import nl.tudelft.bw4t.server.model.robots.DefaultEntityFactory; import nl.tudelft.bw4t.server.model.robots.EntityFactory; import nl.tudelft.bw4t.util.FileUtils; import nl.tudelft.bw4t.util.LauncherException; import repast.simphony.scenario.ScenarioLoadException; /** * This class handles the startup of the server interpreting the configuration * variables and invoking the proper classes. First the parameters are parsed, * next the envirnment is started and lastly the server is setup to accept * client connections. */ public class Launcher { /** * The instance of the Launcher used to start this server. */ private static Launcher instance; /** * The Bw4tEnvironment at the core of this server. */ private static BW4TEnvironment environment; /** * The log4j logger, logs to the console. */ private static final Logger LOGGER = Logger.getLogger(Launcher.class); // Parameters from the operatingsystem /** * The path to the scenario folder required by repast. */ private String paramScenario; /** * the name of the map file in the /maps/ folder. */ private String paramMap; /** * the ip to bind this server to. */ private String paramServerIp; /** * the port to bind this server to. */ private int paramServerPort; /** * true if GUI should be enabled, false if server should run without GUI. */ private boolean paramGUI; /** * The key necessary to remotely kill the server. */ private String paramKey; /** * stores a reference to the robot factory being used to create new robots. */ private EntityFactory entityFactory; /** * true if collisions are enabled. */ private boolean paramCollision; /** * True if draw paths is enabled */ private boolean paramDrawPaths; /** * This class cannot be externally instantiated, it is a utility startup * class. * * @param args * The arguments received from the commandline */ protected Launcher(final String[] args) { setInstance(this); /** * Set up the logging environment to log on the console. */ PropertyConfigurator.configure(Launcher.class.getResource("/log4j.xml")); LOGGER.info("Starting up BW4T Server."); LOGGER.info("Reading console arguments..."); readParameters(args); LOGGER.info("Setting up correct directory structure."); setupDirectoryStructure(); LOGGER.info("Setting up BW4T Environment."); setupEnvironment(); setupFactories(); LOGGER.info("Starting the BW4T Environment."); startEnvironment(); } /** * Interpret the parameter sent from the operating system. * * @param args * the commandline arguments */ private void readParameters(final String[] args) { paramScenario = findArgument(args, "-repast", "./BW4T.rs"); paramMap = findArgument(args, "-map", "Random"); paramServerIp = findArgument(args, "-serverip", "localhost"); paramServerPort = Integer.parseInt(findArgument(args, "-serverport", "8000")); paramGUI = Boolean.parseBoolean(findArgument(args, "-gui", "true")); paramKey = findArgument(args, "-key", "GuVC7TZ38NN49X8utMspV3Z5"); paramCollision = Boolean.parseBoolean(findArgument(args, "-collision", "false")); paramDrawPaths = Boolean.parseBoolean(findArgument(args, "-paths", "false")); } /** * Find a certain argument in the string array and return its setting. * * @param args * the string array containing all the arguments * @param def * The default value for this argument * @param name * what to check for * @return the result */ private String findArgument(String[] args, String name, String def) { String result = def; LOGGER.debug("Default for parameter '" + name + "' is '" + def + "'"); for (int i = 0; i < args.length - 1; i++) { if (args[i].equalsIgnoreCase(name)) { LOGGER.debug("Found parameter '" + name + "' with '" + args[i + 1] + "'"); result = args[i + 1]; break; } } return result; } /** * Check the directory structure to ensure that repast runs properly */ private void setupDirectoryStructure() { boolean success = true; File userDir = new File(System.getProperty("user.dir")); File mapsFolder = new File(userDir.getAbsolutePath() + "/maps"); if (!mapsFolder.exists()) { LOGGER.debug("exporting maps to: " + mapsFolder.getPath()); success &= mapsFolder.mkdir(); success &= FileUtils.copyResourcesRecursively(this.getClass().getResource("/setup/maps"), userDir); } File scenarioFolder = new File(userDir.getAbsolutePath() + "/BW4T.rs"); if (!scenarioFolder.exists()) { LOGGER.debug("exporting scenario to: " + scenarioFolder.getPath()); success &= scenarioFolder.mkdir(); success &= FileUtils.copyResourcesRecursively(this.getClass().getResource("/setup/BW4T.rs"), userDir); } File logFolder = new File(userDir.getAbsolutePath() + "/log"); if (!logFolder.exists()) { LOGGER.debug("creating log folder at: " + logFolder.getPath()); success &= logFolder.mkdir(); } File binFolder = new File(userDir.getAbsolutePath() + "/bin/nl/tudelft"); if (!binFolder.exists()) { LOGGER.debug("exporting server classes to: " + binFolder.getPath()); success &= binFolder.mkdirs(); success &= FileUtils.copyResourcesRecursively(this.getClass().getResource("/nl/tudelft/bw4t"), binFolder); } if (!success) { throw new LauncherException("Could not generate neccessary directories and files," + " please copy the following folders from the jar file " + "(some are in the setup and bin folder): /logs , /BW4T.rs , /maps and /nl"); } } /** * setup the environment. */ private void setupEnvironment() { try { environment = new BW4TEnvironment(setupRemoteServer(), paramScenario, paramMap, paramGUI, paramKey, paramCollision, paramDrawPaths); } catch (ManagementException | IOException | ScenarioLoadException | JAXBException e) { LOGGER.fatal("Failed to setup the BW4T Environment."); throw new LauncherException("failed to setup the bw4t environment", e); } } /** * Setup the factories used by the system. */ private void setupFactories() { entityFactory = new DefaultEntityFactory(); } /** * start the environment, repast and all. */ private void startEnvironment() { try { environment.launchAll(); } catch (ManagementException | IOException | ScenarioLoadException | JAXBException e) { LOGGER.fatal("Failed to start the BW4T Environment."); throw new LauncherException("failed to start the bw4t environment", e); } } /** * Setup the rpc server so clients can connect to this environment. * * @return a server bound to the given ip and port */ public final BW4TServer setupRemoteServer() { try { return new BW4TServer(paramServerIp, paramServerPort); } catch (RemoteException | MalformedURLException e) { LOGGER.fatal("Failed to start the RPC Server."); throw new LauncherException("failed to start the rpc server", e); } } public EntityFactory getEntityFactory() { return entityFactory; } /** * The main method to start up the bw4t server. * * @param args * the command line arguments transmitted by the operating * systems */ public static void main(final String[] args) { new Launcher(args); } /** * Get the environment that is at the core of this bw4t server. * * @return the environment */ public BW4TEnvironment getEnvironment() { return environment; } /** * get the instance of the launcher that started the bw4t server. * * @return the instance */ public static Launcher getInstance() { return instance; } /** * set the launcher instance to the global field * * @param inst * the instance to be used to startup the environment */ private static void setInstance(Launcher inst) { Launcher.instance = inst; } }