public Object execute() {
   final Future<?> future = Logger.enqueue(entry);
   if (entry.wait) FutureUtils.wait(future);
   return "OK";
 }
    @Override
    public Void doInBackground() throws InterruptedException, IOException {
      // FIXME: this should be in an abstract method and farmed out to subclasses
      // send some basic information to the log
      if (lr.module != null) {
        Logger.log("-- Loading module file " + lr.module.getAbsolutePath());
      }

      if (lr.game != null) {
        Logger.log("-- Loading game file " + lr.game.getAbsolutePath());
      }

      if (lr.importFile != null) {
        Logger.log("-- Importing module file " + lr.importFile.getAbsolutePath());
      }
      // end FIXME

      // set default heap sizes
      int initialHeap = DEFAULT_INITIAL_HEAP;
      int maximumHeap = DEFAULT_MAXIMUM_HEAP;

      String moduleName = null;

      // FIXME: this should be in an abstract method and farmed out to subclasses,
      // rather than a case structure for each kind of thing which may be loaded.
      // find module-specific heap settings, if any
      if (lr.module != null) {
        final AbstractMetaData data = MetaDataFactory.buildMetaData(lr.module);

        if (data == null) {
          ErrorDialog.show("Error.invalid_vassal_file", lr.module.getAbsolutePath());
          setWaitCursor(false);
          return null;
        }

        if (data instanceof ModuleMetaData) {
          moduleName = ((ModuleMetaData) data).getName();

          // log the module name
          Logger.log("-- Loading module " + moduleName);

          // read module prefs
          final ReadOnlyPrefs p = new ReadOnlyPrefs(moduleName);

          // read initial heap size
          initialHeap = getHeapSize(p, GlobalOptions.INITIAL_HEAP, DEFAULT_INITIAL_HEAP);

          // read maximum heap size
          maximumHeap = getHeapSize(p, GlobalOptions.MAXIMUM_HEAP, DEFAULT_MAXIMUM_HEAP);
        }
      } else if (lr.importFile != null) {
        final Prefs p = Prefs.getGlobalPrefs();

        // read initial heap size
        initialHeap = getHeapSize(p, GlobalOptions.INITIAL_HEAP, DEFAULT_INITIAL_HEAP);

        // read maximum heap size
        maximumHeap = getHeapSize(p, GlobalOptions.MAXIMUM_HEAP, DEFAULT_MAXIMUM_HEAP);
      }
      // end FIXME

      //
      // Heap size sanity checks: fall back to failsafe heap sizes in
      // case the given initial or maximum heap is not usable.
      //

      // FIXME: The heap size messages are too nonspecific. They should
      // differientiate between loading a module and importing a module,
      // since the heap sizes are set in different places for those two
      // actions.
      // maximum heap must fit in physical RAM
      if (maximumHeap > PHYS_MEMORY && PHYS_MEMORY > 0) {
        initialHeap = FAILSAFE_INITIAL_HEAP;
        maximumHeap = FAILSAFE_MAXIMUM_HEAP;

        FutureUtils.wait(
            WarningDialog.show("Warning.maximum_heap_too_large", FAILSAFE_MAXIMUM_HEAP));
      }
      // maximum heap must be at least the failsafe size
      else if (maximumHeap < FAILSAFE_MAXIMUM_HEAP) {
        initialHeap = FAILSAFE_INITIAL_HEAP;
        maximumHeap = FAILSAFE_MAXIMUM_HEAP;

        FutureUtils.wait(
            WarningDialog.show("Warning.maximum_heap_too_small", FAILSAFE_MAXIMUM_HEAP));
      }
      // initial heap must be at least the failsafe size
      else if (initialHeap < FAILSAFE_INITIAL_HEAP) {
        initialHeap = FAILSAFE_INITIAL_HEAP;
        maximumHeap = FAILSAFE_MAXIMUM_HEAP;

        FutureUtils.wait(
            WarningDialog.show("Warning.initial_heap_too_small", FAILSAFE_INITIAL_HEAP));
      }
      // initial heap must be less than or equal to maximum heap
      else if (initialHeap > maximumHeap) {
        initialHeap = FAILSAFE_INITIAL_HEAP;
        maximumHeap = FAILSAFE_MAXIMUM_HEAP;

        FutureUtils.wait(
            WarningDialog.show("Warning.initial_heap_too_large", FAILSAFE_INITIAL_HEAP));
      }

      // create a socket for communicating which the child process
      serverSocket = new ServerSocket(0, 0, InetAddress.getByName(null));
      cmdS = new LaunchCommandServer(serverSocket);
      new Thread(cmdS, "command server " + id).start();

      // build the argument list
      final ArrayList<String> al = new ArrayList<String>();
      al.add(Info.javaBinPath);
      al.add(""); // reserved for initial heap
      al.add(""); // reserved for maximum heap
      al.add("-DVASSAL.id=" + id); // instance id

      // pass on the user's home, if it's set
      final String userHome = System.getProperty("user.home");
      if (userHome != null) al.add("-Duser.home=" + userHome);

      // set the classpath
      al.add("-cp");
      al.add(System.getProperty("java.class.path"));

      if (Info.isMacOSX()) {
        // set the MacOS X dock parameters

        // use the module name for the dock if we found a module name
        // FIXME: should "Unnamed module" be localized?
        final String d_name =
            moduleName != null && moduleName.length() > 0 ? moduleName : "Unnamed module";

        // get the path to the app icon
        final String d_icon =
            new File(Info.getBaseDir(), "Contents/Resources/VASSAL.icns").getAbsolutePath();

        al.add("-Xdock:name=" + d_name);
        al.add("-Xdock:icon=" + d_icon);

        // Quartz can cause font rendering problems; turn it off?
        final Boolean disableQuartz =
            (Boolean) Prefs.getGlobalPrefs().getValue(Prefs.DISABLE_QUARTZ);

        al.add(
            "-Dapple.awt.graphics.UseQuartz="
                + (Boolean.TRUE.equals(disableQuartz) ? "false" : "true"));
      } else if (Info.isWindows()) {
        // Disable the 2D to Direct3D pipeline?
        final Boolean disableD3d = (Boolean) Prefs.getGlobalPrefs().getValue(Prefs.DISABLE_D3D);
        if (Boolean.TRUE.equals(disableD3d)) {
          al.add("-Dsun.java2d.d3d=false");
        }
      }

      al.add(entryPoint);

      final String[] args = al.toArray(new String[al.size()]);

      // try to start a child process with the given heap sizes
      args[1] = "-Xms" + initialHeap + "M";
      args[2] = "-Xmx" + maximumHeap + "M";
      Process p = launch(args);

      // launch failed, use conservative heap sizes
      if (p == null) {
        args[1] = "-Xms" + FAILSAFE_INITIAL_HEAP + "M";
        args[2] = "-Xmx" + FAILSAFE_MAXIMUM_HEAP + "M";
        p = launch(args);

        if (p == null) {
          throw new IOException("failed to start child process");
        } else {
          FutureUtils.wait(
              WarningDialog.show("Warning.maximum_heap_too_large", FAILSAFE_MAXIMUM_HEAP));
        }
      }

      // read the port for the child's socket from its stdout
      final DataInputStream din = new DataInputStream(p.getInputStream());
      final int childPort = din.readInt();

      // pump child's stderr to our own stderr
      new Thread(new StreamPump(p.getErrorStream(), System.err), "err pump " + id).start();

      // pump child's stdout to our own stdout
      new Thread(new StreamPump(p.getInputStream(), System.out), "out pump " + id).start();

      // Check that the child's port is sane. Reading stdout from a
      // failed launch tends to give impossible port numbers.
      if (childPort < 0 || childPort > 65535) {
        throw new IOException("port out of range: " + childPort);
      }

      // create the client for the child's socket
      clientSocket = new Socket((String) null, childPort);
      cmdC = new CommandClient(clientSocket);
      children.add(cmdC);

      // block until the process ends
      p.waitFor();
      return null;
    }