Java tutorial
/* * Copyright 2009 Connor Petty <cpmeister@users.sourceforge.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package pcgen.system; import java.awt.Component; import java.awt.Font; import java.awt.FontFormatException; import java.awt.GraphicsEnvironment; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Locale; import java.util.Properties; import java.util.Set; import java.util.logging.Level; import javax.swing.JOptionPane; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.SystemUtils; import net.sourceforge.argparse4j.ArgumentParsers; import net.sourceforge.argparse4j.impl.Arguments; import net.sourceforge.argparse4j.inf.ArgumentParser; import net.sourceforge.argparse4j.inf.MutuallyExclusiveGroup; import net.sourceforge.argparse4j.inf.Namespace; import pcgen.cdom.base.Constants; import pcgen.cdom.formula.PluginFunctionLibrary; import pcgen.core.CustomData; import pcgen.core.prereq.PrerequisiteTestFactory; import pcgen.facade.core.UIDelegate; import pcgen.gui2.PCGenUIManager; import pcgen.gui2.SplashScreen; import pcgen.gui2.UIPropertyContext; import pcgen.gui2.converter.TokenConverter; import pcgen.gui2.dialog.OptionsPathDialog; import pcgen.gui2.dialog.RandomNameDialog; import pcgen.gui2.plaf.LookAndFeelManager; import pcgen.gui2.tools.Utility; import pcgen.io.ExportHandler; import pcgen.persistence.CampaignFileLoader; import pcgen.persistence.GameModeFileLoader; import pcgen.persistence.PersistenceLayerException; import pcgen.persistence.lst.TokenStore; import pcgen.persistence.lst.output.prereq.PrerequisiteWriterFactory; import pcgen.persistence.lst.prereq.PreParserFactory; import pcgen.pluginmgr.PluginManager; import pcgen.rules.persistence.TokenLibrary; import pcgen.util.Logging; import pcgen.util.PJEP; /** * Main entry point for pcgen. */ public final class Main { private static PropertyContextFactory configFactory; // TODO: move startup modes into an extensible class based system private static boolean startGMGen; private static boolean startNPCGen; private static boolean startNameGen; private static String settingsDir; private static String campaignMode; private static String characterSheet; private static String exportSheet; private static String partyFile; private static String characterFile; private static String outputFile; private Main() { } public static boolean shouldStartInGMGen() { return startGMGen; } public static boolean shouldStartInNPCGen() { return startNPCGen; } public static boolean shouldStartInCharacterSheet() { return characterSheet != null; } public static String getStartupCampaign() { return campaignMode; } public static String getStartupCharacterFile() { return characterFile; } private static void logSystemProps() { Properties props = System.getProperties(); StringWriter writer = new StringWriter(); PrintWriter pwriter = new PrintWriter(writer); pwriter.println(); pwriter.println("-- listing properties --"); //$NON-NLS-1$ // Manually output the property values to avoid them being cut off at 40 characters Set<String> keys = props.stringPropertyNames(); //$NON-NLS-1$ keys.forEach(key -> { pwriter.println(key + '=' + props.getProperty(key)); }); Logging.log(Level.CONFIG, writer.toString()); } /** * @param args the command line arguments */ public static void main(String[] args) { Logging.log(Level.INFO, "Starting PCGen v" + PCGenPropBundle.getVersionNumber() //$NON-NLS-1$ + PCGenPropBundle.getAutobuildString()); Thread.setDefaultUncaughtExceptionHandler(new PCGenUncaughtExceptionHandler()); logSystemProps(); configFactory = new PropertyContextFactory(getConfigPath()); configFactory.registerAndLoadPropertyContext(ConfigurationSettings.getInstance()); parseCommands(args); if (startNameGen) { Component dialog = new RandomNameDialog(null, null); dialog.setVisible(true); System.exit(0); } if (exportSheet == null) { startupWithGUI(); } else { startupWithoutGUI(); shutdown(); } } private static String getConfigPath() { //TODO: convert to a proper command line argument instead of a -D java property // First see if it was specified on the command line String aPath = System.getProperty("pcgen.config"); //$NON-NLS-1$ if (aPath != null) { File testPath = new File(aPath); // Then make sure it's an existing folder if (testPath.exists() && testPath.isDirectory()) { return aPath; } } // Otherwise return user dir return SystemUtils.USER_DIR; } public static boolean loadCharacterAndExport(String characterFile, String exportSheet, String outputFile, String configFile) { Main.characterFile = characterFile; Main.exportSheet = exportSheet; Main.outputFile = outputFile; configFactory = new PropertyContextFactory(SystemUtils.USER_DIR); configFactory.registerAndLoadPropertyContext(ConfigurationSettings.getInstance(configFile)); return startupWithoutGUI(); } /** * Initialize Main - must be called before any other getter can be used. * * @param argv the command line arguments to be parsed */ private static Namespace parseCommands(String[] argv) { Namespace args = getParser().parseArgsOrFail(argv); if (args.getInt("verbose") > 0) { Logging.setCurrentLoggingLevel(Logging.DEBUG); } startGMGen = args.getBoolean("gmgen"); startNPCGen = args.getBoolean("npc"); settingsDir = args.getString("settingsdir"); campaignMode = args.getString("campaignmode"); characterSheet = args.get("D"); exportSheet = args.get("E"); partyFile = args.get("p"); characterFile = args.get("c"); outputFile = args.get("o"); startNameGen = args.get("name_generator"); return args; } private static void startupWithGUI() { // configure the UI before any type of user prompting may take place configureUI(); validateEnvironment(true); loadProperties(true); initPrintPreviewFonts(); boolean showSplash = Boolean.parseBoolean(ConfigurationSettings.initSystemProperty("showSplash", "true")); //TODO: allow commandline override of splash property SplashScreen splash = null; if (showSplash) { splash = new SplashScreen(); splash.setVisible(true); } PCGenTaskExecutor executor = new PCGenTaskExecutor(); executor.addPCGenTask(createLoadPluginTask()); executor.addPCGenTask(new GameModeFileLoader()); executor.addPCGenTask(new CampaignFileLoader()); if (splash != null) { executor.addPCGenTaskListener(splash); } executor.execute(); if (splash != null) { splash.setMessage(LanguageBundle.getString("in_taskInitUi")); //$NON-NLS-1$ } FacadeFactory.initialize(); PCGenUIManager.initializeGUI(); if (splash != null) { splash.dispose(); } PCGenUIManager.startGUI(); } private static void configureUI() { Utility.configurePlatformUI(); String language = ConfigurationSettings.getLanguage(); String country = ConfigurationSettings.getCountry(); if (StringUtils.isNotEmpty(language) && StringUtils.isNotEmpty(country)) { Locale.setDefault(new Locale(language, country)); } LanguageBundle.init(); LookAndFeelManager.initLookAndFeel(); Utility.setApplicationTitle(Constants.APPLICATION_NAME); } /** * Check that the runtime environment is suitable for PCGen to run. */ private static void validateEnvironment(boolean useGui) { // Check our main folders are present String[] neededDirs = { ConfigurationSettings.getSystemsDir(), ConfigurationSettings.getPccFilesDir(), ConfigurationSettings.getPluginsDir(), ConfigurationSettings.getPreviewDir(), ConfigurationSettings.getOutputSheetsDir() }; StringBuilder missingDirs = new StringBuilder(); for (final String dirPath : neededDirs) { File dir = new File(dirPath); if (!dir.exists()) { String path = dirPath; try { path = dir.getCanonicalPath(); } catch (IOException e) { Logging.errorPrint("Unable to find canonical path for " + dir); } missingDirs.append(" ").append(path).append('\n'); } } if (missingDirs.length() > 0) { String message; message = "This installation of PCGen is missing the following required folders:\n" + missingDirs; Logging.errorPrint(message); if (useGui) { JOptionPane.showMessageDialog(null, message + "\nPlease reinstall PCGen.", Constants.APPLICATION_NAME, JOptionPane.ERROR_MESSAGE); } System.exit(1); } } public static void loadProperties(boolean useGui) { if ((settingsDir == null) && (ConfigurationSettings.getSystemProperty(ConfigurationSettings.SETTINGS_FILES_PATH) == null)) { if (!useGui) { Logging.errorPrint("No settingsDir specified via -s in batch mode and no default exists."); System.exit(1); } String filePath = OptionsPathDialog.promptSettingsPath(); ConfigurationSettings.setSystemProperty(ConfigurationSettings.SETTINGS_FILES_PATH, filePath); } PropertyContextFactory.setDefaultFactory(settingsDir); //Existing PropertyContexts are registered here PropertyContextFactory defaultFactory = PropertyContextFactory.getDefaultFactory(); defaultFactory.registerPropertyContext(PCGenSettings.getInstance()); defaultFactory.registerPropertyContext(UIPropertyContext.getInstance()); defaultFactory.registerPropertyContext(LegacySettings.getInstance()); defaultFactory.loadPropertyContexts(); } /** * Create a task to load all system plugins. * * @return The task to load plugins. */ public static PCGenTask createLoadPluginTask() { String pluginsDir = ConfigurationSettings.getPluginsDir(); PluginClassLoader loader = new PluginClassLoader(new File(pluginsDir)); loader.addPluginLoader(TokenLibrary.getInstance()); loader.addPluginLoader(TokenStore.inst()); try { loader.addPluginLoader(PreParserFactory.getInstance()); } catch (PersistenceLayerException ex) { Logging.errorPrint("createLoadPluginTask failed", ex); } loader.addPluginLoader(PrerequisiteTestFactory.getInstance()); loader.addPluginLoader(PrerequisiteWriterFactory.getInstance()); loader.addPluginLoader(PJEP.getJepPluginLoader()); loader.addPluginLoader(ExportHandler.getPluginLoader()); loader.addPluginLoader(TokenConverter.getPluginLoader()); loader.addPluginLoader(PluginManager.getInstance()); loader.addPluginLoader(PluginFunctionLibrary.getInstance()); return loader; } private static boolean startupWithoutGUI() { loadProperties(false); validateEnvironment(false); PCGenTaskExecutor executor = new PCGenTaskExecutor(); executor.addPCGenTask(createLoadPluginTask()); executor.addPCGenTask(new GameModeFileLoader()); executor.addPCGenTask(new CampaignFileLoader()); executor.execute(); UIDelegate uiDelegate = new ConsoleUIDelegate(); BatchExporter exporter = new BatchExporter(exportSheet, uiDelegate); boolean result = true; if (partyFile != null) { result = exporter.exportParty(partyFile, outputFile); } if (characterFile != null) { result = exporter.exportCharacter(characterFile, outputFile); } return result; } public static void shutdown() { configFactory.savePropertyContexts(); BatchExporter.removeTemporaryFiles(); PropertyContextFactory.getDefaultFactory().savePropertyContexts(); // Need to (possibly) write customEquipment.lst if (PCGenSettings.OPTIONS_CONTEXT.getBoolean(PCGenSettings.OPTION_SAVE_CUSTOM_EQUIPMENT)) { CustomData.writeCustomItems(); } System.exit(0); } private static void initPrintPreviewFonts() { GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); String fontDir = ConfigurationSettings.getOutputSheetsDir() + File.separator + "fonts" + File.separator + "NotoSans" + File.separator; try { ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, new File(fontDir + "NotoSans-Regular.ttf"))); ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, new File(fontDir + "NotoSans-Bold.ttf"))); ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, new File(fontDir + "NotoSans-Italic.ttf"))); ge.registerFont(Font.createFont(Font.TRUETYPE_FONT, new File(fontDir + "NotoSans-BoldItalic.ttf"))); } catch (IOException | FontFormatException ex) { Logging.errorPrint("Unexpected exception loading fonts fo print p", ex); } } /** * @return an ArgumentParser used to perform argument parsing */ private static ArgumentParser getParser() { ArgumentParser parser = ArgumentParsers.newFor(Constants.APPLICATION_NAME).build().defaultHelp(false) .description("RPG Character Generator").version(PCGenPropBundle.getVersionNumber()); parser.addArgument("-v", "--verbose").help("verbose logging").type(Boolean.class).action(Arguments.count()); parser.addArgument("-V", "--version").action(Arguments.version()); MutuallyExclusiveGroup startupMode = parser.addMutuallyExclusiveGroup() .description("start up on a specific mode"); startupMode.addArgument("-G", "--gmgen").help("GMGen mode").type(Boolean.class) .action(Arguments.storeTrue()); startupMode.addArgument("-N", "--npc").help("NPC generation mode").type(Boolean.class) .action(Arguments.storeTrue()); startupMode.addArgument("--name-generator").help("run the name generator").type(Boolean.class) .action(Arguments.storeTrue()); startupMode.addArgument("-D", "--tab").nargs(1); parser.addArgument("-s", "--settingsdir").nargs(1) .type(Arguments.fileType().verifyIsDirectory().verifyCanRead().verifyExists()); parser.addArgument("-m", "--campaignmode").nargs(1).type(String.class); parser.addArgument("-E", "--exportsheet").nargs(1) .type(Arguments.fileType().verifyCanRead().verifyExists().verifyIsFile()); parser.addArgument("-o", "--outputfile").nargs(1) .type(Arguments.fileType().verifyCanCreate().verifyCanWrite().verifyNotExists()); parser.addArgument("-c", "--character").nargs(1) .type(Arguments.fileType().verifyCanRead().verifyExists().verifyIsFile()); parser.addArgument("-p", "--party").nargs(1) .type(Arguments.fileType().verifyCanRead().verifyExists().verifyIsFile()); return parser; } /** * The Class {@code PCGenUncaughtExceptionHandler} reports any * exceptions that are not otherwise handled by the program. */ private static class PCGenUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { Logging.errorPrint("Uncaught error - ignoring", e); } } }