protected File promptForFile() { // prompt the user to pick a file final FileChooser fc = FileChooser.createFileChooser( window, (DirectoryConfigurer) Prefs.getGlobalPrefs().getOption(Prefs.MODULES_DIR_KEY)); addFileFilters(fc); // loop until cancellation or we get an existing file if (fc.showOpenDialog() == FileChooser.APPROVE_OPTION) { lr.module = fc.getSelectedFile(); if (lr.module != null) { if (lr.module.exists()) { final AbstractMetaData metadata = MetaDataFactory.buildMetaData(lr.module); if (metadata == null || !(metadata instanceof ModuleMetaData)) { ErrorDialog.show("Error.invalid_vassal_module", lr.module.getAbsolutePath()); Logger.log( "-- Load of " + lr.module.getAbsolutePath() + " failed: Not a Vassal module"); lr.module = null; } } else { lr.module = null; } // FIXME: do something to warn about nonexistant file // FileNotFoundDialog.warning(window, lr.module); } } return lr.module; }
/** * Read and validate a Module file. - Check it has a Zip Entry named buildfile - If it has a * metadata file, read and parse it. * * @param file Module File */ public void read(ZipFile zip) { version = ""; try { // Try to parse the metadata. Failure is not catastrophic, we can // treat it like an old-style module with no metadata and parse // the first lines of the buildFile DefaultHandler handler = null; ZipEntry data = zip.getEntry(ZIP_ENTRY_NAME); if (data == null) { data = zip.getEntry(GameModule.BUILDFILE); if (data == null) return; handler = new ModuleBuildFileXMLHandler(); } else { handler = new MetadataXMLHandler(); } BufferedInputStream in = null; try { in = new BufferedInputStream(zip.getInputStream(data)); synchronized (parser) { parser.setContentHandler(handler); parser.setDTDHandler(handler); parser.setEntityResolver(handler); parser.setErrorHandler(handler); parser.parse(new InputSource(in)); } in.close(); } finally { IOUtils.closeQuietly(in); } zip.close(); } catch (IOException e) { Logger.log(e); } catch (SAXEndException e) { // Indicates End of module/extension parsing. not an error. } catch (SAXException e) { Logger.log(e); } finally { IOUtils.closeQuietly(zip); } }
protected Process launch(String[] args) throws IOException { Logger.log(StringUtils.join(args, " ")); // set up and start the child process final ProcessBuilder pb = new ProcessBuilder(args); pb.directory(Info.getBinDir()); final Process p = pb.start(); // write the port for this socket to child's stdin and close ObjectOutputStream oout = null; try { oout = new ObjectOutputStream(p.getOutputStream()); oout.writeInt(serverSocket.getLocalPort()); oout.writeObject(lr); // Note: We don't try to close() the socket here because the // pipe might already have been closed from the other end, // and that would cause close() to throw spuriously. } finally { IOUtils.closeQuietly(oout); } // FIXME: this is probably too long try { Thread.sleep(1000); } catch (InterruptedException e) { } // check whether the child is still alive try { // If this doesn't throw, our baby is dead. p.exitValue(); Logger.log(IOUtils.toString(p.getErrorStream())); return null; } catch (IllegalThreadStateException e) { // It's alive! It's ALIIIIIIVE!!! return p; } }
/** * Factory method to build and return an appropriate MetaData class based on the contents of the * file. Return null if the file is not a Zip archive, or it is not a VASSAL Module, Extension or * Save Game. * * @param file metadata file * @return MetaData object */ public static AbstractMetaData buildMetaData(File file) { // Check the file exists and is a file if (file == null || !file.exists() || !file.isFile()) return null; ZipFile zip = null; try { // Check it is a Zip file zip = new ZipFile(file); // Check if it is a Save Game file ZipEntry entry = zip.getEntry(GameState.SAVEFILE_ZIP_ENTRY); if (entry != null) { return new SaveMetaData(zip); } // Check if it has a buildFile ZipEntry buildFileEntry = zip.getEntry(GameModule.BUILDFILE); if (buildFileEntry == null) { return null; } // It's either a module or an Extension, check for existence of metadata entry = zip.getEntry(ExtensionMetaData.ZIP_ENTRY_NAME); if (entry != null) { return new ExtensionMetaData(zip); } entry = zip.getEntry(ModuleMetaData.ZIP_ENTRY_NAME); if (entry != null) { return new ModuleMetaData(zip); } // read the first few lines of the buildFile BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(zip.getInputStream(buildFileEntry))); for (int i = 0; i < 10; i++) { final String s = br.readLine(); if (s.indexOf(BUILDFILE_MODULE_ELEMENT1) > 0 || s.indexOf(BUILDFILE_MODULE_ELEMENT2) > 0) { br.close(); return new ModuleMetaData(zip); } else if (s.indexOf(BUILDFILE_EXTENSION_ELEMENT) > 0) { br.close(); return new ExtensionMetaData(zip); } } br.close(); } finally { IOUtils.closeQuietly(br); } zip.close(); } catch (ZipException e) { // It is not a Zip file, check for an Importable file return ImportAction.buildMetaData(file); } catch (IOException e) { Logger.log(e); } finally { IOUtils.closeQuietly(zip); } return null; }
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; }