changeset 8914:da5be0935d4b 9-b57

Merge
author kcr
date Tue, 31 Mar 2015 08:15:48 -0700
parents c32419e617d8 96ee85199d13
children de031c9cec1f 9c2e8ff4fa26
files modules/fxpackager/src/test/java/com/oracle/tools/packager/windows/WinAppBundlerTest.java
diffstat 75 files changed, 3669 insertions(+), 867 deletions(-) [+]
line wrap: on
line diff
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/AbstractBundler.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/AbstractBundler.java	Tue Mar 31 08:15:48 2015 -0700
@@ -34,7 +34,6 @@
 import java.net.URL;
 import java.text.MessageFormat;
 import java.util.*;
-import java.util.regex.Pattern;
 
 public abstract class AbstractBundler implements Bundler {
 
@@ -55,23 +54,6 @@
 
     protected Class baseResourceLoader = null;
     
-    //helper method to test if required files are present in the runtime
-    public void testRuntime(RelativeFileSet runtime, String[] file) throws ConfigException {
-        if (runtime == null) {
-            return; //null runtime is ok (request to use system)
-        }
-
-        Pattern[] weave = Arrays.stream(file).map(Pattern::compile).toArray(Pattern[]::new);
-
-        if (!runtime.getIncludedFiles().stream().anyMatch(s ->
-                Arrays.stream(weave).anyMatch(pattern -> pattern.matcher(s).matches())
-        )) {
-            throw new ConfigException(
-                    MessageFormat.format(I18N.getString("error.jre-missing-file"), Arrays.toString(file)),
-                    I18N.getString("error.jre-missing-file.advice"));
-        }
-    }
-
     protected void fetchResource(
             String publicName, String category,
             String defaultName, File result, boolean verbose, File publicRoot)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/AbstractImageBundler.java	Tue Mar 31 08:15:48 2015 -0700
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.tools.packager;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.regex.Pattern;
+
+import static com.oracle.tools.packager.StandardBundlerParam.*;
+import static com.oracle.tools.packager.StandardBundlerParam.ARGUMENTS;
+
+/**
+ * Common utility methods used by app image bundlers.
+ */
+public abstract class AbstractImageBundler extends AbstractBundler {
+
+    private static final ResourceBundle I18N =
+            ResourceBundle.getBundle(AbstractImageBundler.class.getName());
+
+    public static final String CFG_FORMAT_PROPERTIES="prop";
+    public static final String CFG_FORMAT_INI="ini";
+    
+    public static final BundlerParamInfo<String> LAUNCHER_CFG_FORMAT =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.launcher-cfg-format.name"),
+                    I18N.getString("param.launcher-cfg-format.description"),
+                    "launcher-cfg-format",
+                    String.class,
+                    params -> "ini",
+                    (s, p) -> s);
+
+    //helper method to test if required files are present in the runtime
+    public void testRuntime(RelativeFileSet runtime, String[] file) throws ConfigException {
+        if (runtime == null) {
+            return; //null runtime is ok (request to use system)
+        }
+
+        Pattern[] weave = Arrays.stream(file).map(Pattern::compile).toArray(Pattern[]::new);
+
+        if (!runtime.getIncludedFiles().stream().anyMatch(s ->
+                        Arrays.stream(weave).anyMatch(pattern -> pattern.matcher(s).matches())
+        )) {
+            throw new ConfigException(
+                    MessageFormat.format(I18N.getString("error.jre-missing-file"), Arrays.toString(file)),
+                    I18N.getString("error.jre-missing-file.advice"));
+        }
+    }
+
+    public void writeCfgFile(Map<String, ? super Object> params, File cfgFileName, String runtimeLocation) throws IOException {
+        cfgFileName.delete();
+
+        PrintStream out = new PrintStream(cfgFileName);
+        
+        out.println("[Application]");
+        out.println("app.name=" + APP_NAME.fetchFrom(params));
+        out.println("app.mainjar=" + MAIN_JAR.fetchFrom(params).getIncludedFiles().iterator().next());
+        out.println("app.version=" + VERSION.fetchFrom(params));
+        out.println("app.preferences.id=" + PREFERENCES_ID.fetchFrom(params));
+        out.println("app.mainclass=" +
+                MAIN_CLASS.fetchFrom(params).replaceAll("\\.", "/"));
+        out.println("app.classpath=" +
+                String.join(File.pathSeparator, CLASSPATH.fetchFrom(params).split("[ :;]")));
+        out.println("app.runtime=" + runtimeLocation);
+        out.println("app.identifier=" + IDENTIFIER.fetchFrom(params));
+
+
+        out.println();
+        out.println("[JVMOptions]");
+        List<String> jvmargs = JVM_OPTIONS.fetchFrom(params);
+        for (String arg : jvmargs) {
+            out.println(arg);
+        }
+        Map<String, String> jvmProps = JVM_PROPERTIES.fetchFrom(params);
+        for (Map.Entry<String, String> property : jvmProps.entrySet()) {
+            out.println("-D" + property.getKey() + "=" + property.getValue());
+        }
+        String preloader = PRELOADER_CLASS.fetchFrom(params);
+        if (preloader != null) {
+            out.println("-Djavafx.preloader="+preloader);
+        }
+
+        
+        out.println();
+        out.println("[JVMUserOptions]");
+        Map<String, String> overridableJVMOptions = USER_JVM_OPTIONS.fetchFrom(params);
+        for (Map.Entry<String, String> arg: overridableJVMOptions.entrySet()) {
+            if (arg.getKey() == null || arg.getValue() == null) {
+                Log.info(I18N.getString("message.jvm-user-arg-is-null"));
+            } else {
+                out.println(arg.getKey().replaceAll("([\\=])", "\\$1") + "=" + arg.getValue());
+            }
+        }
+
+        
+        if (UNLOCK_COMMERCIAL_FEATURES.fetchFrom(params) && ENABLE_APP_CDS.fetchFrom(params)) {
+            prepareAppCDS(params, out);
+        }
+        
+        out.println();
+        out.println("[ArgOptions]");
+        List<String> args = ARGUMENTS.fetchFrom(params);
+        for (String arg : args) {
+            out.println(arg);
+        }
+
+        
+        out.close();
+    }
+
+    protected abstract String getCacheLocation(Map<String, ? super Object> params);
+    
+    void prepareAppCDS(Map<String, ? super Object> params, PrintStream out) throws IOException {
+        //TODO check 8u40 or later
+
+        File tempDir = Files.createTempDirectory("javapackager").toFile();
+        tempDir.deleteOnExit();
+        File classList = new File(tempDir, APP_FS_NAME.fetchFrom(params)  + ".classlist");
+
+        try (FileOutputStream fos = new FileOutputStream(classList);
+             PrintStream ps = new PrintStream(fos)) {
+            for (String className : APP_CDS_CLASS_ROOTS.fetchFrom(params)) {
+                String slashyName = className.replace(".", "/");
+                ps.println(slashyName);
+            }
+        }
+        APP_RESOURCES_LIST.fetchFrom(params).add(new RelativeFileSet(classList.getParentFile(), Arrays.asList(classList)));
+
+        out.println();
+        out.println("[AppCDSJVMOptions]");
+        out.println("-XX:+UnlockCommercialFeatures");
+        out.print("-XX:SharedArchiveFile=");
+        out.print(getCacheLocation(params));
+        out.print(APP_FS_NAME.fetchFrom(params));
+        out.println(".jpa");
+        out.println("-Xshare:on");
+        out.println("-XX:+UseAppCDS");
+        if (Log.isDebug()) {
+            out.println("-verbose:class");
+            out.println("-XX:+TraceClassPaths");
+            out.println("-XX:+UnlockDiagnosticVMOptions");
+        }
+        out.println("");
+        
+        out.println("[AppCDSGenerateCacheJVMOptions]");
+        out.println("-XX:+UnlockCommercialFeatures");
+        out.println("-Xshare:dump");
+        out.println("-XX:+UseAppCDS");
+        out.print("-XX:SharedArchiveFile=");
+        out.print(getCacheLocation(params));
+        out.print(APP_FS_NAME.fetchFrom(params));
+        out.println(".jpa");
+        out.println("-XX:SharedClassListFile=$PACKAGEDIR/" + APP_FS_NAME.fetchFrom(params) + ".classlist");
+        if (Log.isDebug()) {
+            out.println("-XX:+UnlockDiagnosticVMOptions");
+        }
+    }
+}
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/RelativeFileSet.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/RelativeFileSet.java	Tue Mar 31 08:15:48 2015 -0700
@@ -27,6 +27,7 @@
 
 import java.io.File;
 
+import java.util.Collection;
 import java.util.LinkedHashSet;
 import java.util.Set;
 
@@ -44,7 +45,7 @@
     private File basedir;
     Set<String> files = new LinkedHashSet<>();
 
-    public RelativeFileSet(File base, Set<File> files) {
+    public RelativeFileSet(File base, Collection<File> files) {
         basedir = base;
         String baseAbsolute = basedir.getAbsolutePath();
         for (File f: files) {
@@ -59,6 +60,10 @@
         }
     }
 
+    public RelativeFileSet(File base, Set<File> files) {
+        this(base, (Collection<File>) files);
+    }    
+
     public boolean contains(String[] requiredFiles) {
         boolean result = true;
 
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/StandardBundlerParam.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/StandardBundlerParam.java	Tue Mar 31 08:15:48 2015 -0700
@@ -570,6 +570,37 @@
                     (s, p) -> new File(s)
             );
 
+    public static final StandardBundlerParam<Boolean> UNLOCK_COMMERCIAL_FEATURES =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.commercial-features.name"),
+                    I18N.getString("param.commercial-features.description"),
+                    "commercialFeatures",
+                    Boolean.class,
+                    p -> false,
+                    (s, p) -> Boolean.parseBoolean(s)
+            );
+
+    public static final StandardBundlerParam<Boolean> ENABLE_APP_CDS =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.com-app-cds.name"),
+                    I18N.getString("param.com-app-cds.description"),
+                    "commercial.AppCDS",
+                    Boolean.class,
+                    p -> false,
+                    (s, p) -> Boolean.parseBoolean(s)
+            );
+
+    @SuppressWarnings("unchecked")
+    public static final StandardBundlerParam<List<String>> APP_CDS_CLASS_ROOTS =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.com-app-cds-root.name"),
+                    I18N.getString("param.com-app-cds-root.description"),
+                    "commercial.AppCDS.classRoots",
+                    (Class<List<String>>)((Object)List.class),
+                    p -> Arrays.asList(MAIN_CLASS.fetchFrom(p)),
+                    (s, p) -> Arrays.asList(s.split("[ ,:]"))
+            );
+
     public static void extractMainClassInfoFromAppResources(Map<String, ? super Object> params) {
         boolean hasMainClass = params.containsKey(MAIN_CLASS.getID());
         boolean hasMainJar = params.containsKey(MAIN_JAR.getID());
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/linux/LinuxAppBundler.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/linux/LinuxAppBundler.java	Tue Mar 31 08:15:48 2015 -0700
@@ -25,7 +25,7 @@
 
 package com.oracle.tools.packager.linux;
 
-import com.oracle.tools.packager.AbstractBundler;
+import com.oracle.tools.packager.AbstractImageBundler;
 import com.oracle.tools.packager.BundlerParamInfo;
 import com.oracle.tools.packager.JreUtils;
 import com.oracle.tools.packager.JreUtils.Rule;
@@ -48,7 +48,7 @@
 
 import static com.oracle.tools.packager.StandardBundlerParam.*;
 
-public class LinuxAppBundler extends AbstractBundler {
+public class LinuxAppBundler extends AbstractImageBundler {
 
     private static final ResourceBundle I18N =
             ResourceBundle.getBundle(LinuxAppBundler.class.getName());
@@ -260,8 +260,12 @@
         executableFile.setExecutable(true, false);
         executableFile.setWritable(true, true); //for str
 
-        // Generate PkgInfo
-        writePkgInfo(p, rootDir);
+        // Generate launcher .cfg file
+        if (LAUNCHER_CFG_FORMAT.fetchFrom(p).equals(CFG_FORMAT_PROPERTIES)) {
+            writeCfgFile(p, rootDir);
+        } else {
+            writeCfgFile(p, new File(rootDir, getLauncherCfgName(p)), "$APPDIR/runtime");
+        }
     }
 
     private void copyApplication(Map<String, ? super Object> params, File appDirectory) throws IOException {
@@ -281,11 +285,11 @@
         }
     }
 
-    private void writePkgInfo(Map<String, ? super Object> params, File rootDir) throws FileNotFoundException {
-        File pkgInfoFile = new File(rootDir, getLauncherCfgName(params));
+    private void writeCfgFile(Map<String, ? super Object> params, File rootDir) throws FileNotFoundException {
+        File cfgFile = new File(rootDir, getLauncherCfgName(params));
 
-        pkgInfoFile.delete();
-        PrintStream out = new PrintStream(pkgInfoFile);
+        cfgFile.delete();
+        PrintStream out = new PrintStream(cfgFile);
         if (LINUX_RUNTIME.fetchFrom(params) == null) {
             out.println("app.runtime=");                    
         } else {
@@ -325,6 +329,7 @@
         
         //app.id required for setting user preferences (Java Preferences API)
         out.println("app.preferences.id=" + PREFERENCES_ID.fetchFrom(params));
+        out.println("app.identifier=" + IDENTIFIER.fetchFrom(params));
 
         Map<String, String> overridableJVMOptions = USER_JVM_OPTIONS.fetchFrom(params);
         idx = 1;
@@ -414,4 +419,9 @@
     public File execute(Map<String, ? super Object> params, File outputParentDir) {
         return doBundle(params, outputParentDir, false);
     }
+
+    @Override
+    protected String getCacheLocation(Map<String, ? super Object> params) {
+        return "$APPDIR/";
+    }
 }
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/linux/LinuxDebBundler.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/linux/LinuxDebBundler.java	Tue Mar 31 08:15:48 2015 -0700
@@ -561,6 +561,17 @@
         data.put("SECONDARY_LAUNCHERS_INSTALL", installScripts.toString());
         data.put("SECONDARY_LAUNCHERS_REMOVE", removeScripts.toString());
 
+        StringBuilder cdsScript = new StringBuilder();
+        if (UNLOCK_COMMERCIAL_FEATURES.fetchFrom(params) && ENABLE_APP_CDS.fetchFrom(params)) {
+            cdsScript.append("/opt/");
+            cdsScript.append(data.get("APPLICATION_FS_NAME"));
+            cdsScript.append("/");
+            cdsScript.append(data.get("APPLICATION_LAUNCHER_FILENAME"));
+            cdsScript.append(" -Xappcds:generatecache\n");
+        }
+
+        data.put("APP_CDS_CACHE", cdsScript.toString());
+
         List<Map<String, ? super Object>> associations = FILE_ASSOCIATIONS.fetchFrom(params);
         data.put("FILE_ASSOCIATION_INSTALL", "");
         data.put("FILE_ASSOCIATION_REMOVE", "");
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/linux/LinuxRpmBundler.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/linux/LinuxRpmBundler.java	Tue Mar 31 08:15:48 2015 -0700
@@ -439,6 +439,17 @@
         data.put("SECONDARY_LAUNCHERS_INSTALL", installScripts.toString());
         data.put("SECONDARY_LAUNCHERS_REMOVE", removeScripts.toString());
 
+        StringBuilder cdsScript = new StringBuilder();
+        if (UNLOCK_COMMERCIAL_FEATURES.fetchFrom(params) && ENABLE_APP_CDS.fetchFrom(params)) {
+            cdsScript.append("/opt/");
+            cdsScript.append(data.get("APPLICATION_FS_NAME"));
+            cdsScript.append("/");
+            cdsScript.append(data.get("APPLICATION_LAUNCHER_FILENAME"));
+            cdsScript.append(" -Xappcds:generatecache\n");
+        }
+        
+        data.put("APP_CDS_CACHE", cdsScript.toString());
+        
         List<Map<String, ? super Object>> associations = FILE_ASSOCIATIONS.fetchFrom(params);
         data.put("FILE_ASSOCIATION_INSTALL", "");
         data.put("FILE_ASSOCIATION_REMOVE", "");
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacAppBundler.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacAppBundler.java	Tue Mar 31 08:15:48 2015 -0700
@@ -24,7 +24,7 @@
  */
 package com.oracle.tools.packager.mac;
 
-import com.oracle.tools.packager.AbstractBundler;
+import com.oracle.tools.packager.AbstractImageBundler;
 import com.oracle.tools.packager.BundlerParamInfo;
 import com.oracle.tools.packager.EnumeratedBundlerParam;
 import com.oracle.tools.packager.JreUtils;
@@ -49,7 +49,7 @@
 import static com.oracle.tools.packager.mac.MacBaseInstallerBundler.SIGNING_KEY_USER;
 import static com.oracle.tools.packager.mac.MacBaseInstallerBundler.getPredefinedImage;
 
-public class MacAppBundler extends AbstractBundler {
+public class MacAppBundler extends AbstractImageBundler {
 
     private static final ResourceBundle I18N =
             ResourceBundle.getBundle(MacAppBundler.class.getName());
@@ -61,7 +61,8 @@
     private final static String LIBRARY_NAME         = "libpackager.dylib";
     private static final String TEMPLATE_BUNDLE_ICON = "GenericApp.icns";
     private static final String OS_TYPE_CODE         = "APPL";
-    private static final String TEMPLATE_INFO_PLIST  = "Info.plist.template";
+    private static final String TEMPLATE_INFO_PLIST_LEGACY  = "Info.plist.template";
+    private static final String TEMPLATE_INFO_PLIST_LITE    = "Info-lite.plist.template";
 
     private static Map<String, String> getMacCategories() {
         Map<String, String> map = new HashMap<>();
@@ -110,6 +111,15 @@
         return map;
     }
 
+    public static final BundlerParamInfo<Boolean> MAC_CONFIGURE_LAUNCHER_IN_PLIST =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.configure-launcher-in-plist"),
+                    I18N.getString("param.configure-launcher-in-plist.description"),
+                    "mac.configure-launcher-in-plist",
+                    Boolean.class,
+                    params -> Boolean.FALSE,
+                    (s, p) -> Boolean.valueOf(s));
+
     public static final EnumeratedBundlerParam<String> MAC_CATEGORY =
             new EnumeratedBundlerParam<>(
                     I18N.getString("param.category-name"),
@@ -177,7 +187,7 @@
             URL.class,
             params -> MacResources.class.getResource(EXECUTABLE_NAME),
             (s, p) -> {
-               try {
+                try {
                     return new URL(s);
                 } catch (MalformedURLException e) {
                     Log.info(e.toString());
@@ -273,6 +283,17 @@
         baseResourceLoader = MacResources.class;
     }
 
+    @Override
+    protected String getCacheLocation(Map<String, ? super Object> params) {
+        Boolean systemWide = SYSTEM_WIDE.fetchFrom(params);
+        if (systemWide == null || systemWide) {
+            return "/Library/Application Support/" + IDENTIFIER.fetchFrom(params) + "/cache/";
+        } else {
+            return "$CACHEDIR/";
+        }
+    }
+
+
     public static boolean validCFBundleVersion(String v) {
         // CFBundleVersion (String - iOS, OS X) specifies the build version
         // number of the bundle, which identifies an iteration (released or
@@ -413,6 +434,8 @@
 
     public File doBundle(Map<String, ? super Object> p, File outputDirectory, boolean dependentTask) {
         File rootDirectory = null;
+        Map<String, ? super Object> originalParams = new HashMap<>(p);
+        
         if (!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) {
             throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), outputDirectory.getAbsolutePath()));
         }
@@ -472,6 +495,15 @@
                     MacResources.class.getResource(LIBRARY_NAME),
                     new File(macOSDirectory, LIBRARY_NAME));
 
+            // maybe generate launcher config
+            if (!MAC_CONFIGURE_LAUNCHER_IN_PLIST.fetchFrom(p)) {
+                if (LAUNCHER_CFG_FORMAT.fetchFrom(p).equals(CFG_FORMAT_PROPERTIES)) {
+                    writeCfgFile(p, rootDirectory);
+                } else {
+                    writeCfgFile(p, new File(rootDirectory, getLauncherCfgName(p)), "$APPDIR/PlugIns/Java.runtime");
+                }
+            }
+
             executableFile.setExecutable(true, false);
 
             // Copy runtime to PlugIns folder
@@ -480,7 +512,7 @@
             // Copy class path entries to Java folder
             copyClassPathEntries(javaDirectory, p);
 
-//TODO: Need to support adding native libraries.
+            //TODO: Need to support adding native libraries.
             // Copy library path entries to MacOS folder
             //copyLibraryPathEntries(macOSDirectory);
 
@@ -498,10 +530,17 @@
                 }
             }
 
-
             // Generate Info.plist
             IOUtils.copyFile(getConfig_InfoPlist(p),
                     new File(contentsDirectory, "Info.plist"));
+            
+            // create the secondary launchers, if any
+            List<Map<String, ? super Object>> entryPoints = StandardBundlerParam.SECONDARY_LAUNCHERS.fetchFrom(p);
+            for (Map<String, ? super Object> entryPoint : entryPoints) {
+                Map<String, ? super Object> tmp = new HashMap<>(originalParams);
+                tmp.putAll(entryPoint);
+                createLauncherForEntryPoint(tmp, rootDirectory);
+            }
 
             // maybe sign
             if (Optional.ofNullable(SIGN_BUNDLE.fetchFrom(p)).orElse(Boolean.TRUE)) {
@@ -528,12 +567,8 @@
     public void cleanupConfigFiles(Map<String, ? super Object> params) {
         //Since building the app can be bypassed, make sure configRoot was set
         if (CONFIG_ROOT.fetchFrom(params) != null) {
-            if (getConfig_Icon(params) != null) {
-                getConfig_Icon(params).delete();
-            }
-            if (getConfig_InfoPlist(params) != null) {
-                getConfig_InfoPlist(params).delete();
-            }
+            getConfig_Icon(params).delete();
+            getConfig_InfoPlist(params).delete();
         }
     }
 
@@ -835,8 +870,11 @@
         Writer w = new BufferedWriter(new FileWriter(file));
         w.write(preprocessTextResource(
                 MAC_BUNDLER_PREFIX + getConfig_InfoPlist(params).getName(),
-                I18N.getString("resource.bundle-config-file"), TEMPLATE_INFO_PLIST, data,
-                VERBOSE.fetchFrom(params),
+                I18N.getString("resource.bundle-config-file"),
+                MAC_CONFIGURE_LAUNCHER_IN_PLIST.fetchFrom(params)
+                    ? TEMPLATE_INFO_PLIST_LEGACY
+                    : TEMPLATE_INFO_PLIST_LITE,
+                data, VERBOSE.fetchFrom(params),
                 DROP_IN_RESOURCES_ROOT.fetchFrom(params)));
         w.close();
 
@@ -1049,4 +1087,90 @@
     public File execute(Map<String, ? super Object> params, File outputParentDir) {
         return doBundle(params, outputParentDir, false);
     }
+
+    private void createLauncherForEntryPoint(Map<String, ? super Object> p, File rootDirectory) throws IOException {
+        prepareConfigFiles(p);
+
+        if (LAUNCHER_CFG_FORMAT.fetchFrom(p).equals(CFG_FORMAT_PROPERTIES)) {
+            writeCfgFile(p, rootDirectory);
+        } else {
+            writeCfgFile(p, new File(rootDirectory, getLauncherCfgName(p)), "$APPDIR/PlugIns/Java.runtime");
+        }
+
+        // Copy executable root folder
+        File executableFile = new File(rootDirectory, "Contents/MacOS/" + getLauncherName(p));
+        IOUtils.copyFromURL(
+                RAW_EXECUTABLE_URL.fetchFrom(p),
+                executableFile);
+        executableFile.setExecutable(true, false);
+
+    }
+
+    public static String getLauncherCfgName(Map<String, ? super Object> p) {
+        return "Contents/Java/" + APP_NAME.fetchFrom(p) +".cfg";
+    }
+
+    private void writeCfgFile(Map<String, ? super Object> params, File rootDir) throws FileNotFoundException {
+        File pkgInfoFile = new File(rootDir, getLauncherCfgName(params));
+
+        pkgInfoFile.delete();
+
+        PrintStream out = new PrintStream(pkgInfoFile);
+        if (MAC_RUNTIME.fetchFrom(params) == null) {
+            out.println("app.runtime=");
+        } else {
+            out.println("app.runtime=$APPDIR/PlugIns/Java.runtime");
+        }
+        out.println("app.mainjar=" + MAIN_JAR.fetchFrom(params).getIncludedFiles().iterator().next());
+        out.println("app.version=" + VERSION.fetchFrom(params));
+        //for future AU support (to be able to find app in the registry)
+        out.println("app.id=" + IDENTIFIER.fetchFrom(params));
+        out.println("app.preferences.id=" + PREFERENCES_ID.fetchFrom(params));
+        out.println("app.identifier=" + IDENTIFIER.fetchFrom(params));
+
+        out.println("app.mainclass=" +
+                MAIN_CLASS.fetchFrom(params).replaceAll("\\.", "/"));
+        out.println("app.classpath=" + CLASSPATH.fetchFrom(params));
+
+        List<String> jvmargs = JVM_OPTIONS.fetchFrom(params);
+        int idx = 1;
+        for (String a : jvmargs) {
+            out.println("jvmarg."+idx+"="+a);
+            idx++;
+        }
+        Map<String, String> jvmProps = JVM_PROPERTIES.fetchFrom(params);
+        for (Map.Entry<String, String> entry : jvmProps.entrySet()) {
+            out.println("jvmarg."+idx+"=-D"+entry.getKey()+"="+entry.getValue());
+            idx++;
+        }
+
+        String preloader = PRELOADER_CLASS.fetchFrom(params);
+        if (preloader != null) {
+            out.println("jvmarg."+idx+"=-Djavafx.preloader="+preloader);
+        }
+
+        Map<String, String> overridableJVMOptions = USER_JVM_OPTIONS.fetchFrom(params);
+        idx = 1;
+        for (Map.Entry<String, String> arg: overridableJVMOptions.entrySet()) {
+            if (arg.getKey() == null || arg.getValue() == null) {
+                Log.info(I18N.getString("message.jvm-user-arg-is-null"));
+            }
+            else {
+                out.println("jvmuserarg."+idx+".name="+arg.getKey());
+                out.println("jvmuserarg."+idx+".value="+arg.getValue());
+            }
+            idx++;
+        }
+
+        // add command line args
+        List<String> args = ARGUMENTS.fetchFrom(params);
+        idx = 1;
+        for (String a : args) {
+            out.println("arg."+idx+"="+a);
+            idx++;
+        }
+
+        out.close();
+    }
+    
 }
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/windows/WinAppBundler.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/windows/WinAppBundler.java	Tue Mar 31 08:15:48 2015 -0700
@@ -25,7 +25,7 @@
 
 package com.oracle.tools.packager.windows;
 
-import com.oracle.tools.packager.AbstractBundler;
+import com.oracle.tools.packager.AbstractImageBundler;
 import com.oracle.tools.packager.BundlerParamInfo;
 import com.oracle.tools.packager.StandardBundlerParam;
 import com.oracle.tools.packager.Log;
@@ -51,7 +51,7 @@
 import static com.oracle.tools.packager.windows.WindowsBundlerParam.BIT_ARCH_64_RUNTIME;
 import static com.oracle.tools.packager.windows.WindowsBundlerParam.WIN_RUNTIME;
 
-public class WinAppBundler extends AbstractBundler {
+public class WinAppBundler extends AbstractImageBundler {
 
     private static final ResourceBundle I18N = 
             ResourceBundle.getBundle(WinAppBundler.class.getName());
@@ -226,9 +226,7 @@
 
     //remove
     protected void cleanupConfigFiles(Map<String, ? super Object> params) {
-        if (getConfig_AppIcon(params) != null) {
-            getConfig_AppIcon(params).delete();
-        }
+        getConfig_AppIcon(params).delete();
     }
 
     private void prepareConfigFiles(Map<String, ? super Object> params) throws IOException {
@@ -257,7 +255,7 @@
     }
 
     File doBundle(Map<String, ? super Object> p, File outputDirectory, boolean dependentTask) {
-        Map<String, ? super Object> originalParams = new HashMap<String, Object>(p);
+        Map<String, ? super Object> originalParams = new HashMap<>(p);
         if (!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) {
             throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), outputDirectory.getAbsolutePath()));
         }
@@ -276,11 +274,13 @@
 
             File appDirectory = new File(rootDirectory, "app");
             appDirectory.mkdirs();
-            copyApplication(p, appDirectory);
 
             // create the .exe launchers
             createLauncherForEntryPoint(p, rootDirectory);
 
+            // copy the jars
+            copyApplication(p, appDirectory);
+
             // Copy runtime 
             File runtimeDirectory = new File(rootDirectory, "runtime");
             copyRuntime(p, runtimeDirectory);
@@ -295,7 +295,7 @@
             // create the secondary launchers, if any
             List<Map<String, ? super Object>> entryPoints = StandardBundlerParam.SECONDARY_LAUNCHERS.fetchFrom(p);
             for (Map<String, ? super Object> entryPoint : entryPoints) {
-                Map<String, ? super Object> tmp = new HashMap<String, Object>(originalParams);
+                Map<String, ? super Object> tmp = new HashMap<>(originalParams);
                 tmp.putAll(entryPoint);
                 createLauncherForEntryPoint(tmp, rootDirectory);
             }
@@ -374,7 +374,12 @@
     private void createLauncherForEntryPoint(Map<String, ? super Object> p, File rootDirectory) throws IOException {
         prepareConfigFiles(p);
 
-        writePkgInfo(p, rootDirectory);
+        // Generate launcher .cfg file
+        if (LAUNCHER_CFG_FORMAT.fetchFrom(p).equals(CFG_FORMAT_PROPERTIES)) {
+            writeCfgFile(p, rootDirectory);
+        } else {
+            writeCfgFile(p, new File(rootDirectory, getLauncherCfgName(p)), "$APPDIR\\runtime");
+        }
 
         // Copy executable root folder
         File executableFile = new File(rootDirectory, getLauncherName(p));
@@ -426,12 +431,12 @@
         }
     }
 
-    private void writePkgInfo(Map<String, ? super Object> params, File rootDir) throws FileNotFoundException {
-        File pkgInfoFile = new File(rootDir, getLauncherCfgName(params));
+    private void writeCfgFile(Map<String, ? super Object> params, File rootDir) throws FileNotFoundException {
+        File cfgFile = new File(rootDir, getLauncherCfgName(params));
 
-        pkgInfoFile.delete();
+        cfgFile.delete();
 
-        PrintStream out = new PrintStream(pkgInfoFile);
+        PrintStream out = new PrintStream(cfgFile);
         if (WIN_RUNTIME.fetchFrom(params) == null) {
             out.println("app.runtime=");
         } else {
@@ -442,6 +447,7 @@
         //for future AU support (to be able to find app in the registry)
         out.println("app.id=" + IDENTIFIER.fetchFrom(params));
         out.println("app.preferences.id=" + PREFERENCES_ID.fetchFrom(params));
+        out.println("app.identifier=" + IDENTIFIER.fetchFrom(params));
 
         out.println("app.mainclass=" +
                 MAIN_CLASS.fetchFrom(params).replaceAll("\\.", "/"));
@@ -553,4 +559,9 @@
     public File execute(Map<String, ? super Object> params, File outputParentDir) {
         return doBundle(params, outputParentDir, false);
     }
+
+    @Override
+    protected String getCacheLocation(Map<String, ? super Object> params) {
+        return "$APPDIR/";
+    }
 }
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/windows/WinExeBundler.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/windows/WinExeBundler.java	Tue Mar 31 08:15:48 2015 -0700
@@ -492,6 +492,9 @@
         validateValueAndPut(data, "APPLICATION_DESCRIPTION", DESCRIPTION, params);
         data.put("APPLICATION_SERVICE", SERVICE_HINT.fetchFrom(params) ? "returnTrue" : "returnFalse");
         data.put("APPLICATION_NOT_SERVICE", SERVICE_HINT.fetchFrom(params) ? "returnFalse" : "returnTrue");
+        data.put("APPLICATION_APP_CDS", (UNLOCK_COMMERCIAL_FEATURES.fetchFrom(params) && ENABLE_APP_CDS.fetchFrom(params))
+                ? "returnTrue"
+                : "returnFalse");
         data.put("START_ON_INSTALL", START_ON_INSTALL.fetchFrom(params) ? "-startOnInstall" : "");
         data.put("STOP_ON_UNINSTALL", STOP_ON_UNINSTALL.fetchFrom(params) ? "-stopOnUninstall" : "");
         data.put("RUN_AT_STARTUP", RUN_AT_STARTUP.fetchFrom(params) ? "-runAtStartup" : "");
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/windows/WinMsiBundler.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/windows/WinMsiBundler.java	Tue Mar 31 08:15:48 2015 -0700
@@ -611,6 +611,7 @@
         }
 
         data.put("UI_BLOCK", getUIBlock(params));
+        data.put("APP_CDS_BLOCK", getAppCDSBlock(params));
 
         List<Map<String, ? super Object>> secondaryLaunchers = SECONDARY_LAUNCHERS.fetchFrom(params);
 
@@ -686,6 +687,23 @@
         return uiBlock;
     }
     
+    private String getAppCDSBlock(Map<String, ? super Object> params) {
+        String cdsBlock = "";
+        if (UNLOCK_COMMERCIAL_FEATURES.fetchFrom(params) && ENABLE_APP_CDS.fetchFrom(params)) {
+            cdsBlock = 
+                    "     <CustomAction Id=\"CACHE_CDS\"\n" +
+                    "          Directory=\"APPLICATIONFOLDER\"\n" +
+                    "          ExeCommand=\"[APPLICATIONFOLDER]" + WinAppBundler.getLauncherName(params) +" -Xappcds:generatecache\"\n" +
+                    "          Execute=\"commit\"\n" +
+                    "          Return=\"check\"/>\n" +
+                    "\n" +
+                    "     <InstallExecuteSequence>\n" +
+                    "         <Custom Action=\"CACHE_CDS\" Before=\"InstallFinalize\" />\n" +
+                    "     </InstallExecuteSequence>";
+        }
+        return cdsBlock;
+    }
+    
     private void walkFileTree(Map<String, ? super Object> params, File root, PrintStream out, String prefix) {
         List<File> dirs = new ArrayList<>();
         List<File> files = new ArrayList<>();
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/DeployParams.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/DeployParams.java	Tue Mar 31 08:15:48 2015 -0700
@@ -55,7 +55,7 @@
         WEBSTART, EMBEDDED, STANDALONE, ALL
     }
 
-    final List<DeployResource> resources = new ArrayList<>();
+    final List<RelativeFileSet> resources = new ArrayList<>();
 
     String id;
     String title;
@@ -120,14 +120,14 @@
 
     //list of jvm args (in theory string can contain spaces and need to be escaped
     List<String> jvmargs = new LinkedList<>();
-    Map<String, String> jvmUserArgs = new HashMap<>();
+    Map<String, String> jvmUserArgs = new LinkedHashMap<>();
 
     //list of jvm properties (can also be passed as VM args
     // but keeping them separate make it a bit more convinient for JNLP generation)
-    Map<String, String> properties = new HashMap<>();
+    Map<String, String> properties = new LinkedHashMap<>();
     
     // raw arguments to the bundler
-    Map<String, ? super Object> bundlerArguments = new HashMap<>();
+    Map<String, ? super Object> bundlerArguments = new LinkedHashMap<>();
 
     String fallbackApp = null;
 
@@ -354,16 +354,16 @@
     List<File> expandFileset(File root) {
         List<File> files = new LinkedList<>();
         if (com.oracle.tools.packager.IOUtils.isNotSymbolicLink(root)) {
-           if (root.isDirectory()) {
-               File[] children = root.listFiles();
-               if (children != null) {
-                   for (File f : children) {
-                       files.addAll(expandFileset(f));
-                   }
-               }
-           } else {
-               files.add(root);
-           }
+            if (root.isDirectory()) {
+                File[] children = root.listFiles();
+                if (children != null) {
+                    for (File f : children) {
+                        files.addAll(expandFileset(f));
+                    }
+                }
+            } else {
+                files.add(root);
+            }
         }
         return files;
     }
@@ -371,42 +371,77 @@
     @Override
     public void addResource(File baseDir, String path) {
         File file = new File(baseDir, path);
-        try {
-            //normalize top level dir
-            // to strip things like "." in the path
-            // or it can confuse symlink detection logic
-            file = file.getCanonicalFile();
-        } catch (IOException ignored) {}
-        for (File f: expandFileset(file)) {
-           resources.add(new DeployResource(baseDir, f));
+        //normalize top level dir
+        // to strip things like "." in the path
+        // or it can confuse symlink detection logic
+        file = file.getAbsoluteFile();
+
+        if (baseDir == null) {
+            baseDir = file.getParentFile();
         }
+        resources.add(new RelativeFileSet(baseDir, new LinkedHashSet<>(expandFileset(file))));
     }
 
     @Override
     public void addResource(File baseDir, File file) {
-        try {
-            //normalize initial file
-            // to strip things like "." in the path
-            // or it can confuse symlink detection logic
-            file = file.getCanonicalFile();
-        } catch (IOException ignored) {}
-        for (File f: expandFileset(file)) {
-           resources.add(new DeployResource(baseDir, f));
+        //normalize initial file
+        // to strip things like "." in the path
+        // or it can confuse symlink detection logic
+        file = file.getAbsoluteFile();
+
+        if (baseDir == null) {
+            baseDir = file.getParentFile();
         }
+        resources.add(new RelativeFileSet(baseDir, new LinkedHashSet<>(expandFileset(file))));
     }
 
     public void addResource(File baseDir, String path, String type) {
-        resources.add(new DeployResource(baseDir, path, type));
+        addResource(baseDir, createFile(baseDir, path), type);
     }
 
     public void addResource(File baseDir, File file, String type) {
-        resources.add(new DeployResource(baseDir, file, type));
+        addResource(baseDir, file, "eager", type, null, null);
     }
 
     public void addResource(File baseDir, File file, String mode, String type, String os, String arch) {
-        resources.add(new DeployResource(baseDir, file, mode, type, os, arch));
+        Set<File> singleFile = new LinkedHashSet<>();
+        singleFile.add(file);
+        if (baseDir == null) {
+            baseDir = file.getParentFile();
+        }
+        RelativeFileSet rfs = new RelativeFileSet(baseDir, singleFile);
+        rfs.setArch(arch);
+        rfs.setMode(mode);
+        rfs.setOs(os);
+        rfs.setType(parseTypeFromString(type, file));
+        resources.add(rfs);
     }
 
+    private RelativeFileSet.Type parseTypeFromString(String type, File file) {
+        if (type == null) {
+            if (file.getName().endsWith(".jar")) {
+                return RelativeFileSet.Type.jar;
+            } else if (file.getName().endsWith(".jnlp")) {
+                return RelativeFileSet.Type.jnlp;
+            } else {
+                return RelativeFileSet.Type.UNKNOWN;
+            }
+        } else {
+            return RelativeFileSet.Type.valueOf(type);
+        }
+    }
+    
+    private static File createFile(final File baseDir, final String path) {
+        final File testFile = new File(path);
+        return testFile.isAbsolute()
+                ? testFile
+                : new File(baseDir == null 
+                    ? null
+                    : baseDir.getAbsolutePath(),
+                      path);
+    }
+
+
     @Override
     public void validate() throws PackagerException {
         if (outdir == null) {
@@ -523,30 +558,23 @@
         String currentOS = System.getProperty("os.name").toLowerCase();
         String currentArch = getArch();
 
-        Map<File, Set<File>> fileResources = new LinkedHashMap<>();
-        
-        for (DeployResource r: resources) {
-            String os = r.getOs();
-            String arch = r.getArch();
+        for (RelativeFileSet rfs : resources) {
+            String os = rfs.getOs();
+            String arch = rfs.getArch();
             //skip resources for other OS
             // and nativelib jars (we are including raw libraries)
             if ((os == null || currentOS.contains(os.toLowerCase())) &&
                     (arch == null || currentArch.startsWith(arch.toLowerCase()))
-                    && r.getType() != DeployResource.Type.nativelib) {
-                if (r.getType() == DeployResource.Type.license) {
-                    bundleParams.addLicenseFile(r.getRelativePath());
+                    && rfs.getType() != RelativeFileSet.Type.nativelib) {
+                if (rfs.getType() == RelativeFileSet.Type.license) {
+                    for (String s : rfs.getIncludedFiles()) {
+                        bundleParams.addLicenseFile(s);
+                    }
                 }
-                Set<File> files = fileResources.get(r.getBaseDir());
-                if (files == null) {
-                    fileResources.put(r.getBaseDir(), files = new LinkedHashSet<>());
-                }
-                files.add(new File(r.getBaseDir(), r.getRelativePath()));
             }
         }
         
-        bundleParams.setAppResourcesList(fileResources.entrySet().stream()
-                .map(e -> new RelativeFileSet(e.getKey(), e.getValue()))
-                .collect(Collectors.toList()));
+        bundleParams.setAppResourcesList(resources);
 
         bundleParams.setIdentifier(id);
 
@@ -585,7 +613,8 @@
             // currently everything is marked as webstart internally and runmode
             // is not publicly documented property
             if (/* (ic.mode == RunMode.ALL || ic.mode == RunMode.STANDALONE) && */
-                (ic.kind == null || ic.kind.equals("default"))) {
+                (ic.kind == null || ic.kind.equals("default"))) 
+            {
                 //could be full path or something relative to the output folder
                 appIcon = new File(ic.href);
                 if (!appIcon.exists()) {
--- a/modules/fxpackager/src/main/native/library/common/Exports.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Exports.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -46,19 +46,21 @@
     // This is not a class to create an instance of.
     UserJVMArgsExports();
 
-    static jobjectArray MapKeysToJObjectArray(JNIEnv *env, TOrderedMap map) {
-        JavaStringArray result(env, map.size());
-        unsigned int index = 0;
+    static jobjectArray MapKeysToJObjectArray(JNIEnv *env, OrderedMap<TString, TString> map) {
+        std::vector<TString> keys = map.GetKeys();
+        JavaStringArray result(env, keys.size());
 
-        for (TOrderedMap::iterator iterator = map.begin();
-            iterator != map.end();
-            iterator++) {
+        for (unsigned int index = 0; index < keys.size(); index++) {
+            jstring item = PlatformString(keys[index]).toJString(env);
+            result.SetValue(index, item);
+        }
 
-            jstring item = PlatformString(iterator->first).toJString(env);
-            result.SetValue(index, item);
-
-            index++;
-        }
+//        JavaStringArray result(env, map.Count());
+//
+//        for (map::  iterator = map.begin(); iterator != map.end(); iterator++) {
+//            jstring item = PlatformString(keys[index]).toJString(env);
+//            result.SetValue(index, item);
+//        }
 
         return result.GetData();
     }
@@ -68,18 +70,19 @@
         if (env == NULL || option == NULL)
             return NULL;
 
-        jstring result;
+        jstring result = NULL;
 
         Package& package = Package::GetInstance();
-        TOrderedMap defaultuserargs = package.GetDefaultJVMUserArgs();
+        OrderedMap<TString, TString> defaultuserargs = package.GetDefaultJVMUserArgs();
         TString loption = PlatformString(env, option).toString();
-        PlatformString value = defaultuserargs[loption].value;
 
         try {
+            TString temp;
+            defaultuserargs.GetValue(loption, temp);
+            PlatformString value = temp;
             result = value.toJString(env);
         }
         catch (const JavaException&) {
-            return NULL;
         }
 
         return result;
@@ -89,7 +92,7 @@
         if (env == NULL)
             return NULL;
 
-        jobjectArray result;
+        jobjectArray result = NULL;
 
         Package& package = Package::GetInstance();
 
@@ -97,7 +100,6 @@
             result = MapKeysToJObjectArray(env, package.GetDefaultJVMUserArgs());
         }
         catch (const JavaException&) {
-            return NULL;
         }
 
         return result;
@@ -107,18 +109,19 @@
         if (env == NULL || option == NULL)
             return NULL;
 
-        jstring result;
+        jstring result = NULL;
 
         Package& package = Package::GetInstance();
-        TOrderedMap userargs = package.GetJVMUserArgs();
+        OrderedMap<TString, TString> userargs = package.GetJVMUserArgs();
 
         try {
             TString loption = PlatformString(env, option).toString();
-            PlatformString value = userargs[loption].value;
+            TString temp;
+            userargs.GetValue(loption, temp);
+            PlatformString value = temp;
             result = value.toJString(env);
         }
         catch (const JavaException&) {
-            return NULL;
         }
 
         return result;
@@ -127,9 +130,9 @@
     static void _setUserJvmKeysAndValues(JNIEnv *env, jobjectArray options, jobjectArray values) {
         if (env == NULL || options == NULL || values == NULL)
             return;
-        
+
         Package& package = Package::GetInstance();
-        TOrderedMap newMap;
+        OrderedMap<TString, TString> newMap;
 
         try {
             JavaStringArray loptions(env, options);
@@ -137,10 +140,8 @@
 
             for (unsigned int index = 0; index < loptions.Count(); index++) {
                 TString name = PlatformString(env, loptions.GetValue(index)).toString();
-                TValueIndex value;
-                value.value = PlatformString(env, lvalues.GetValue(index)).toString();
-                value.index = index;
-                newMap.insert(TOrderedMap::value_type(name, value));
+                TString value = PlatformString(env, lvalues.GetValue(index)).toString();
+                newMap.Append(name, value);
             }
         }
         catch (const JavaException&) {
@@ -154,7 +155,7 @@
         if (env == NULL)
             return NULL;
 
-        jobjectArray result;
+        jobjectArray result = NULL;
 
         Package& package = Package::GetInstance();
 
@@ -162,7 +163,6 @@
             result = MapKeysToJObjectArray(env, package.GetJVMUserArgs());
         }
         catch (const JavaException&) {
-            return NULL;
         }
 
         return result;
@@ -228,12 +228,12 @@
     JNIEXPORT jboolean JNICALL Java_com_DebugExports_isdebugged(JNIEnv *env, jclass klass) {
         jboolean result = false;
         Package& package = Package::GetInstance();
-        
+
         if (package.Debugging() == dsNative) {
             Platform& platform = Platform::GetInstance();
             result = platform.GetDebugState() != dsNone;
         }
-        
+
         return result;
     }
 
--- a/modules/fxpackager/src/main/native/library/common/FilePath.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/FilePath.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -36,6 +36,10 @@
 #include <algorithm>
 #include <list>
 
+#ifdef WINDOWS
+#include <ShellAPI.h>
+#endif //WINDOWS
+
 #ifdef POSIX
 #include <sys/stat.h>
 #endif //POSIX
@@ -92,12 +96,41 @@
     return result;
 }
 
+#ifdef WINDOWS
+std::string GetLastErrorAsString() {
+    //Get the error message, if any.
+    DWORD errorMessageID = ::GetLastError();
+
+    if (errorMessageID == 0) {
+        return "No error message has been recorded";
+    }
+
+    LPSTR messageBuffer = NULL;
+    size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+                                 NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
+
+    std::string message(messageBuffer, size);
+
+    // Free the buffer.
+    LocalFree(messageBuffer);
+
+    return message;
+}
+#endif //WINDOWS
+
 bool FilePath::DeleteFile(const TString FileName) {
     bool result = false;
 
     if (FileExists(FileName) == true) {
 #ifdef WINDOWS
-        result = DeleteFile(FileName.data());
+        TString lFileName = FileName;
+        FileAttributes attributes(lFileName);
+
+        if (attributes.Contains(faReadOnly) == true) {
+            attributes.Remove(faReadOnly);
+        }
+
+        result = ::DeleteFile(lFileName.data()) == TRUE;
 #endif //WINDOWS
 #ifdef POSIX
         if (unlink(StringToFileSystemString(FileName)) == 0) {
@@ -109,32 +142,61 @@
     return result;
 }
 
-TString FilePath::IncludeTrailingSlash(const TString value) {
-    TString result = value;
-    TString::iterator i = result.end();
-    i--;
+bool FilePath::DeleteDirectory(const TString DirectoryName) {
+    bool result = false;
 
-    if (*i != TRAILING_SLASH) {
-        result += TRAILING_SLASH;
+    if (DirectoryExists(DirectoryName) == true) {
+#ifdef WINDOWS
+        SHFILEOPSTRUCTW fos = {0};
+        DynamicBuffer<TCHAR> lDirectoryName(DirectoryName.size() + 2);
+        memcpy(lDirectoryName.GetData(), DirectoryName.data(), (DirectoryName.size() + 2) * sizeof(TCHAR));
+        lDirectoryName[DirectoryName.size() + 1] = NULL; // Double null terminate for SHFileOperation.
+
+        // Delete the folder and everything inside.
+        fos.wFunc = FO_DELETE;
+        fos.pFrom = lDirectoryName.GetData();
+        fos.fFlags = FOF_NO_UI;
+        result = SHFileOperation(&fos) == 0;
+#endif //WINDOWS
+#ifdef POSIX
+        if (unlink(StringToFileSystemString(DirectoryName)) == 0) {
+            result = true;
+        }
+#endif //POSIX
     }
 
     return result;
 }
 
-TString FilePath::IncludeTrailingSlash(const char* value) {
-    TString lvalue = PlatformString(value).toString();
-    return IncludeTrailingSlash(lvalue);
+TString FilePath::IncludeTrailingSeparater(const TString value) {
+    TString result = value;
+
+    if (value.size() > 0) {
+        TString::iterator i = result.end();
+        i--;
+
+        if (*i != TRAILING_PATHSEPARATOR) {
+            result += TRAILING_PATHSEPARATOR;
+        }
+    }
+
+    return result;
 }
 
-TString FilePath::IncludeTrailingSlash(const wchar_t* value) {
+TString FilePath::IncludeTrailingSeparater(const char* value) {
     TString lvalue = PlatformString(value).toString();
-    return IncludeTrailingSlash(lvalue);
+    return IncludeTrailingSeparater(lvalue);
+}
+
+TString FilePath::IncludeTrailingSeparater(const wchar_t* value) {
+    TString lvalue = PlatformString(value).toString();
+    return IncludeTrailingSeparater(lvalue);
 }
 
 TString FilePath::ExtractFilePath(TString Path) {
 #ifdef WINDOWS
     TString result;
-    size_t slash = Path.find_last_of(TRAILING_SLASH);
+    size_t slash = Path.find_last_of(TRAILING_PATHSEPARATOR);
     if (slash != TString::npos)
         result = Path.substr(0, slash);
     return result;
@@ -159,7 +221,7 @@
 #ifdef WINDOWS
     TString result;
 
-    size_t slash = Path.find_last_of(TRAILING_SLASH);
+    size_t slash = Path.find_last_of(TRAILING_PATHSEPARATOR);
     if (slash != TString::npos)
         result = Path.substr(slash + 1, Path.size() - slash - 1);
 
@@ -185,9 +247,14 @@
     return result;
 }
 
+TString FilePath::FixPathForPlatform(TString Path) {
+    TString result = Path;
+    std::replace(result.begin(), result.end(), BAD_TRAILING_PATHSEPARATOR, TRAILING_PATHSEPARATOR);
+    return result;
+}
+
 TString FilePath::FixPathSeparatorForPlatform(TString Path) {
     TString result = Path;
-    std::replace(result.begin(), result.end(), ' ', PATH_SEPARATOR);
     std::replace(result.begin(), result.end(), BAD_PATH_SEPARATOR, PATH_SEPARATOR);
     return result;
 }
@@ -234,7 +301,6 @@
 }
 
 void FilePath::ChangePermissions(TString FileName, bool ownerOnly) {
-
 #ifdef POSIX
     mode_t mode = S_IRWXU;
     if (!ownerOnly) {
@@ -242,5 +308,371 @@
     }
     chmod(FileName.data(), mode);
 #endif // POSIX
+}
 
+//--------------------------------------------------------------------------------------------------
+
+#include <algorithm>
+
+FileAttributes::FileAttributes(const TString FileName, bool FollowLink) {
+    FFileName = FileName;
+    FFollowLink = FollowLink;
+    ReadAttributes();
 }
+
+bool FileAttributes::WriteAttributes() {
+    bool result = false;
+
+#ifdef WINDOWS
+    DWORD attributes = 0;
+
+    for (std::vector<FileAttribute>::const_iterator iterator = FAttributes.begin();
+         iterator != FAttributes.end(); iterator++) {
+        switch (*iterator) {
+            case faArchive: {
+                attributes = attributes & FILE_ATTRIBUTE_ARCHIVE;
+                break;
+            }
+            case faCompressed: {
+                attributes = attributes & FILE_ATTRIBUTE_COMPRESSED;
+                break;
+            }
+            case faDevice: {
+                attributes = attributes & FILE_ATTRIBUTE_DEVICE;
+                break;
+            }
+            case faDirectory: {
+                attributes = attributes & FILE_ATTRIBUTE_DIRECTORY;
+                break;
+            }
+            case faEncrypted: {
+                attributes = attributes & FILE_ATTRIBUTE_ENCRYPTED;
+                break;
+            }
+            case faHidden: {
+                attributes = attributes & FILE_ATTRIBUTE_HIDDEN;
+                break;
+            }
+//            case faIntegrityStream: {
+//                attributes = attributes & FILE_ATTRIBUTE_INTEGRITY_STREAM;
+//                break;
+//            }
+            case faNormal: {
+                attributes = attributes & FILE_ATTRIBUTE_NORMAL;
+                break;
+            }
+            case faNotContentIndexed: {
+                attributes = attributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+                break;
+            }
+//            case faNoScrubData: {
+//                attributes = attributes & FILE_ATTRIBUTE_NO_SCRUB_DATA;
+//                break;
+//            }
+            case faOffline: {
+                attributes = attributes & FILE_ATTRIBUTE_OFFLINE;
+                break;
+            }
+            case faSystem: {
+                attributes = attributes & FILE_ATTRIBUTE_SYSTEM;
+                break;
+            }
+            case faSymbolicLink: {
+                attributes = attributes & FILE_ATTRIBUTE_REPARSE_POINT;
+                break;
+            }
+            case faSparceFile: {
+                attributes = attributes & FILE_ATTRIBUTE_SPARSE_FILE;
+                break;
+            }
+            case faReadOnly: {
+                attributes = attributes & FILE_ATTRIBUTE_READONLY;
+                break;
+            }
+            case faTemporary: {
+                attributes = attributes & FILE_ATTRIBUTE_TEMPORARY;
+                break;
+            }
+            case faVirtual: {
+                attributes = attributes & FILE_ATTRIBUTE_VIRTUAL;
+                break;
+            }
+        }
+    }
+
+    if (::SetFileAttributes(FFileName.data(), attributes) != 0) {
+        result = true;
+    }
+#endif // WINDOWS
+#ifdef POSIX
+    mode_t attributes = 0;
+
+    for (std::vector<FileAttribute>::const_iterator iterator = FAttributes.begin();
+         iterator != FAttributes.end(); iterator++) {
+        switch (*iterator) {
+            case faBlockSpecial: {
+                attributes |= S_IFBLK;
+                break;
+            }
+            case faCharacterSpecial: {
+                attributes |= S_IFCHR;
+                break;
+            }
+            case faFIFOSpecial: {
+                attributes |= S_IFIFO;
+                break;
+            }
+            case faNormal: {
+                attributes |= S_IFREG;
+                break;
+            }
+            case faDirectory: {
+                attributes |= S_IFDIR;
+                break;
+            }
+            case faSymbolicLink: {
+                attributes |= S_IFLNK;
+                break;
+            }
+            case faSocket: {
+                attributes |= S_IFSOCK;
+                break;
+            }
+
+            // Owner
+            case faReadOnly: {
+                attributes |= S_IRUSR;
+                break;
+            }
+            case  faWriteOnly: {
+                attributes |= S_IWUSR;
+                break;
+            }
+            case faReadWrite: {
+                attributes |= S_IRUSR;
+                attributes |= S_IWUSR;
+                break;
+            }
+            case faExecute: {
+                attributes |= S_IXUSR;
+                break;
+            }
+
+            // Group
+            case faGroupReadOnly: {
+                attributes |= S_IRGRP;
+                break;
+            }
+            case  faGroupWriteOnly: {
+                attributes |= S_IWGRP;
+                break;
+            }
+            case faGroupReadWrite: {
+                attributes |= S_IRGRP;
+                attributes |= S_IWGRP;
+                break;
+            }
+            case faGroupExecute: {
+                attributes |= S_IXGRP;
+                break;
+            }
+
+            // Others
+            case faOthersReadOnly: {
+                attributes |= S_IROTH;
+                break;
+            }
+            case  faOthersWriteOnly: {
+                attributes |= S_IWOTH;
+                break;
+            }
+            case faOthersReadWrite: {
+                attributes |= S_IROTH;
+                attributes |= S_IWOTH;
+                break;
+            }
+            case faOthersExecute: {
+                attributes |= S_IXOTH;
+                break;
+            }
+        }
+    }
+
+    if (chmod(FFileName.data(), attributes) == 0) {
+        result = true;
+    }
+#endif //POSIX
+
+    return result;
+}
+
+#define S_ISRUSR(m)    (((m) & S_IRWXU) == S_IRUSR)
+#define S_ISWUSR(m)    (((m) & S_IRWXU) == S_IWUSR)
+#define S_ISXUSR(m)    (((m) & S_IRWXU) == S_IXUSR)
+
+#define S_ISRGRP(m)    (((m) & S_IRWXG) == S_IRGRP)
+#define S_ISWGRP(m)    (((m) & S_IRWXG) == S_IWGRP)
+#define S_ISXGRP(m)    (((m) & S_IRWXG) == S_IXGRP)
+
+#define S_ISROTH(m)    (((m) & S_IRWXO) == S_IROTH)
+#define S_ISWOTH(m)    (((m) & S_IRWXO) == S_IWOTH)
+#define S_ISXOTH(m)    (((m) & S_IRWXO) == S_IXOTH)
+
+bool FileAttributes::ReadAttributes() {
+    bool result = false;
+
+#ifdef WINDOWS
+    DWORD attributes = ::GetFileAttributes(FFileName.data());
+
+    if (attributes != INVALID_FILE_ATTRIBUTES) {
+        result = true;
+
+        if (attributes | FILE_ATTRIBUTE_ARCHIVE) { FAttributes.push_back(faArchive); }
+        if (attributes | FILE_ATTRIBUTE_COMPRESSED) { FAttributes.push_back(faCompressed); }
+        if (attributes | FILE_ATTRIBUTE_DEVICE) { FAttributes.push_back(faDevice); }
+        if (attributes | FILE_ATTRIBUTE_DIRECTORY) { FAttributes.push_back(faDirectory); }
+        if (attributes | FILE_ATTRIBUTE_ENCRYPTED) { FAttributes.push_back(faEncrypted); }
+        if (attributes | FILE_ATTRIBUTE_HIDDEN) { FAttributes.push_back(faHidden); }
+        //if (attributes | FILE_ATTRIBUTE_INTEGRITY_STREAM) { FAttributes.push_back(faIntegrityStream); }
+        if (attributes | FILE_ATTRIBUTE_NORMAL) { FAttributes.push_back(faNormal); }
+        if (attributes | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) { FAttributes.push_back(faNotContentIndexed); }
+        //if (attributes | FILE_ATTRIBUTE_NO_SCRUB_DATA) { FAttributes.push_back(faNoScrubData); }
+        if (attributes | FILE_ATTRIBUTE_SYSTEM) { FAttributes.push_back(faSystem); }
+        if (attributes | FILE_ATTRIBUTE_OFFLINE) { FAttributes.push_back(faOffline); }
+        if (attributes | FILE_ATTRIBUTE_REPARSE_POINT) { FAttributes.push_back(faSymbolicLink); }
+        if (attributes | FILE_ATTRIBUTE_SPARSE_FILE) { FAttributes.push_back(faSparceFile); }
+        if (attributes | FILE_ATTRIBUTE_READONLY ) { FAttributes.push_back(faReadOnly); }
+        if (attributes | FILE_ATTRIBUTE_TEMPORARY) { FAttributes.push_back(faTemporary); }
+        if (attributes | FILE_ATTRIBUTE_VIRTUAL) { FAttributes.push_back(faVirtual); }
+    }
+#endif // WINDOWS
+#ifdef POSIX
+    struct stat status;
+
+    if (stat(StringToFileSystemString(FFileName), &status) == 0) {
+        result = true;
+
+        if (S_ISBLK(status.st_mode) != 0) { FAttributes.push_back(faBlockSpecial); }
+        if (S_ISCHR(status.st_mode) != 0) { FAttributes.push_back(faCharacterSpecial); }
+        if (S_ISFIFO(status.st_mode) != 0) { FAttributes.push_back(faFIFOSpecial); }
+        if (S_ISREG(status.st_mode) != 0) { FAttributes.push_back(faNormal); }
+        if (S_ISDIR(status.st_mode) != 0) { FAttributes.push_back(faDirectory); }
+        if (S_ISLNK(status.st_mode) != 0) { FAttributes.push_back(faSymbolicLink); }
+        if (S_ISSOCK(status.st_mode) != 0) { FAttributes.push_back(faSocket); }
+
+        // Owner
+        if (S_ISRUSR(status.st_mode) != 0) {
+            if (S_ISWUSR(status.st_mode) != 0) { FAttributes.push_back(faReadWrite); }
+            else { FAttributes.push_back(faReadOnly); }
+        }
+        else if (S_ISWUSR(status.st_mode) != 0) { FAttributes.push_back(faWriteOnly); }
+
+        if (S_ISXUSR(status.st_mode) != 0) { FAttributes.push_back(faExecute); }
+
+        // Group
+        if (S_ISRGRP(status.st_mode) != 0) {
+            if (S_ISWGRP(status.st_mode) != 0) { FAttributes.push_back(faGroupReadWrite); }
+            else { FAttributes.push_back(faGroupReadOnly); }
+        }
+        else if (S_ISWGRP(status.st_mode) != 0) { FAttributes.push_back(faGroupWriteOnly); }
+
+        if (S_ISXGRP(status.st_mode) != 0) { FAttributes.push_back(faGroupExecute); }
+
+
+        // Others
+        if (S_ISROTH(status.st_mode) != 0) {
+            if (S_ISWOTH(status.st_mode) != 0) { FAttributes.push_back(faOthersReadWrite); }
+            else { FAttributes.push_back(faOthersReadOnly); }
+        }
+        else if (S_ISWOTH(status.st_mode) != 0) { FAttributes.push_back(faOthersWriteOnly); }
+
+        if (S_ISXOTH(status.st_mode) != 0) { FAttributes.push_back(faOthersExecute); }
+
+        if (FFileName.size() > 0 && FFileName[0] == '.') {
+            FAttributes.push_back(faHidden);
+        }
+    }
+#endif //POSIX
+
+    return result;
+}
+
+bool FileAttributes::Valid(const FileAttribute Value) {
+    bool result = false;
+
+    switch (Value) {
+#ifdef WINDOWS
+        case faHidden:
+#endif // WINDOWS
+#ifdef POSIX
+        case faReadWrite:
+        case faWriteOnly:
+        case faExecute:
+
+        case faGroupReadWrite:
+        case faGroupWriteOnly:
+        case faGroupReadOnly:
+        case faGroupExecute:
+
+        case faOthersReadWrite:
+        case faOthersWriteOnly:
+        case faOthersReadOnly:
+        case faOthersExecute:
+#endif //POSIX
+
+        case faReadOnly: {
+            result = true;
+            break;
+        }
+    }
+
+    return result;
+}
+
+void FileAttributes::Append(FileAttribute Value) {
+    if (Valid(Value) == true) {
+#ifdef POSIX
+        if ((Value == faReadOnly && Contains(faWriteOnly) == true) ||
+            (Value == faWriteOnly && Contains(faReadOnly) == true)) {
+            Value = faReadWrite;
+        }
+#endif //POSIX
+
+        FAttributes.push_back(Value);
+        WriteAttributes();
+    }
+}
+
+bool FileAttributes::Contains(FileAttribute Value) {
+    bool result = false;
+
+    std::vector<FileAttribute>::const_iterator iterator = std::find(FAttributes.begin(), FAttributes.end(), Value);
+
+    if (iterator != FAttributes.end()) {
+        result = true;
+    }
+
+    return result;
+}
+
+void FileAttributes::Remove(FileAttribute Value) {
+    if (Valid(Value) == true) {
+#ifdef POSIX
+        if (Value == faReadOnly && Contains(faReadWrite) == true) {
+            Append(faWriteOnly);
+            Remove(faReadWrite);
+        }
+        else if (Value == faWriteOnly && Contains(faReadWrite) == true) {
+            Append(faReadOnly);
+            Remove(faReadWrite);
+        }
+#endif //POSIX
+
+        std::vector<FileAttribute>::iterator iterator = std::find(FAttributes.begin(), FAttributes.end(), Value);
+
+        if (iterator != FAttributes.end()) {
+            FAttributes.erase(iterator);
+            WriteAttributes();
+        }
+    }
+}
--- a/modules/fxpackager/src/main/native/library/common/FilePath.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/FilePath.h	Tue Mar 31 08:15:48 2015 -0700
@@ -37,6 +37,76 @@
 #include "Platform.h"
 #include "PlatformString.h"
 
+#include <vector>
+
+enum FileAttribute {
+#ifdef WINDOWS
+    faArchive = FILE_ATTRIBUTE_ARCHIVE,
+    faCompressed = FILE_ATTRIBUTE_COMPRESSED,
+    faDevice = FILE_ATTRIBUTE_DEVICE,
+    faDirectory = FILE_ATTRIBUTE_DIRECTORY,
+    faEncrypted = FILE_ATTRIBUTE_ENCRYPTED,
+    faHidden = FILE_ATTRIBUTE_HIDDEN,
+    //faIntegrityStream = FILE_ATTRIBUTE_INTEGRITY_STREAM,
+    faNormal = FILE_ATTRIBUTE_NORMAL,
+    faNotContentIndexed = FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
+    //faNoScrubData = FILE_ATTRIBUTE_NO_SCRUB_DATA,
+    faOffline = FILE_ATTRIBUTE_OFFLINE,
+    faSystem = FILE_ATTRIBUTE_SYSTEM,
+    faSymbolicLink = FILE_ATTRIBUTE_REPARSE_POINT,
+    faSparceFile = FILE_ATTRIBUTE_SPARSE_FILE,
+    faReadOnly = FILE_ATTRIBUTE_READONLY,
+    faTemporary = FILE_ATTRIBUTE_TEMPORARY,
+    faVirtual = FILE_ATTRIBUTE_VIRTUAL
+#endif //WINDOWS
+#ifdef POSIX
+    faBlockSpecial,
+    faCharacterSpecial,
+    faFIFOSpecial,
+    faNormal,
+    faDirectory,
+    faSymbolicLink,
+    faSocket,
+
+    // Owner
+    faReadOnly,
+    faWriteOnly,
+    faReadWrite,
+    faExecute,
+
+    // Group
+    faGroupReadOnly,
+    faGroupWriteOnly,
+    faGroupReadWrite,
+    faGroupExecute,
+
+    // Others
+    faOthersReadOnly,
+    faOthersWriteOnly,
+    faOthersReadWrite,
+    faOthersExecute,
+
+    faHidden
+#endif //POSIX
+};
+
+class FileAttributes {
+private:
+    TString FFileName;
+    bool FFollowLink;
+    std::vector<FileAttribute> FAttributes;
+
+    bool WriteAttributes();
+    bool ReadAttributes();
+    bool Valid(const FileAttribute Value);
+
+public:
+    FileAttributes(const TString FileName, bool FollowLink = true);
+
+    void Append(const FileAttribute Value);
+    bool Contains(const FileAttribute Value);
+    void Remove(const FileAttribute Value);
+};
 
 class FilePath {
 private:
@@ -48,15 +118,17 @@
     static bool DirectoryExists(const TString DirectoryName);
 
     static bool DeleteFile(const TString FileName);
+    static bool DeleteDirectory(const TString DirectoryName);
 
     static TString ExtractFilePath(TString Path);
     static TString ExtractFileExt(TString Path);
     static TString ExtractFileName(TString Path);
     static TString ChangeFileExt(TString Path, TString Extension);
 
-    static TString IncludeTrailingSlash(const TString value);
-    static TString IncludeTrailingSlash(const char* value);
-    static TString IncludeTrailingSlash(const wchar_t* value);
+    static TString IncludeTrailingSeparater(const TString value);
+    static TString IncludeTrailingSeparater(const char* value);
+    static TString IncludeTrailingSeparater(const wchar_t* value);
+    static TString FixPathForPlatform(TString Path);
     static TString FixPathSeparatorForPlatform(TString Path);
     static TString PathSeparator();
 
--- a/modules/fxpackager/src/main/native/library/common/GenericPlatform.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/GenericPlatform.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -33,7 +33,6 @@
 
 #include "GenericPlatform.h"
 
-
 #include <fstream>
 #include <locale>
 
@@ -51,32 +50,32 @@
 TString GenericPlatform::GetConfigFileName() {
     TString result;
     TString basedir = GetPackageAppDirectory();
-    
+
     if (basedir.empty() == false) {
-        basedir = FilePath::IncludeTrailingSlash(basedir);
+        basedir = FilePath::IncludeTrailingSeparater(basedir);
         TString appConfig = basedir + GetAppName() + _T(".cfg");
-        
+
         if (FilePath::FileExists(appConfig) == true) {
             result = appConfig;
         }
         else {
             result = basedir + _T("package.cfg");
-            
+
             if (FilePath::FileExists(result) == false) {
                 result = _T("");
             }
         }
     }
-    
+
     return result;
 }
 
 TString GenericPlatform::GetPackageAppDirectory() {
 #if defined(WINDOWS) || defined(LINUX)
-    return FilePath::IncludeTrailingSlash(GetPackageRootDirectory()) + _T("app");
+    return FilePath::IncludeTrailingSeparater(GetPackageRootDirectory()) + _T("app");
 #endif //WINDOWS || LINUX
 #ifdef MAC
-    return FilePath::IncludeTrailingSlash(GetPackageRootDirectory()) + _T("Java");
+    return FilePath::IncludeTrailingSeparater(GetPackageRootDirectory()) + _T("Java");
 #endif
 }
 
@@ -85,7 +84,7 @@
     return GetPackageRootDirectory();
 #endif //WINDOWS || LINUX
 #ifdef MAC
-    return FilePath::IncludeTrailingSlash(GetPackageRootDirectory()) + _T("MacOS");
+    return FilePath::IncludeTrailingSeparater(GetPackageRootDirectory()) + _T("MacOS");
 #endif
 }
 
@@ -163,26 +162,37 @@
 
 std::map<TString, TString> GenericPlatform::GetKeys() {
     std::map<TString, TString> keys;
+    keys.insert(std::map<TString, TString>::value_type(CONFIG_VERSION,           _T("app.version")));
     keys.insert(std::map<TString, TString>::value_type(CONFIG_MAINJAR_KEY,       _T("app.mainjar")));
     keys.insert(std::map<TString, TString>::value_type(CONFIG_MAINCLASSNAME_KEY, _T("app.mainclass")));
     keys.insert(std::map<TString, TString>::value_type(CONFIG_CLASSPATH_KEY,     _T("app.classpath")));
     keys.insert(std::map<TString, TString>::value_type(APP_NAME_KEY,             _T("app.name")));
+    keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_ID_KEY,        _T("app.preferences.id")));
+    keys.insert(std::map<TString, TString>::value_type(JVM_RUNTIME_KEY,          _T("app.runtime")));
+    keys.insert(std::map<TString, TString>::value_type(PACKAGER_APP_DATA_DIR,    _T("app.identifier")));
+
+    keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_MEMORY,        _T("app.memory")));
     keys.insert(std::map<TString, TString>::value_type(CONFIG_SPLASH_KEY,        _T("app.splash")));
-    keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_ID_KEY,        _T("app.preferences.id")));
-    keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_MEMORY,        _T("app.memory")));
-    keys.insert(std::map<TString, TString>::value_type(JVM_RUNTIME_KEY,          _T("app.runtime")));
-    keys.insert(std::map<TString, TString>::value_type(PACKAGER_APP_DATA_DIR,    _T("app.preferences.id")));
+
+    keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_APPLICATION,    _T("Application")));
+    keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_JVMOPTIONS,     _T("JVMOptions")));
+    keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_JVMUSEROPTIONS, _T("JVMUserOptions")));
+    keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS, _T("JVMUserOverrideOptions")));
+    keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_APPCDSJVMOPTIONS, _T("AppCDSJVMOptions")));
+    keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS, _T("AppCDSGenerateCacheJVMOptions")));
+    keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_ARGOPTIONS,     _T("ArgOptions")));
+
     return keys;
 }
 
 #ifdef DEBUG
 DebugState GenericPlatform::GetDebugState() {
     DebugState result = dsNone;
-    
+
     if (IsNativeDebuggerPresent() == true) {
         result = dsNative;
     }
-    
+
     return result;
 }
 #endif //DEBUG
--- a/modules/fxpackager/src/main/native/library/common/GenericPlatform.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/GenericPlatform.h	Tue Mar 31 08:15:48 2015 -0700
@@ -35,7 +35,7 @@
 #define GENERICPLATFORM_H
 
 #include "FilePath.h"
-#include "Platform.h"
+//#include "Platform.h"
 
 
 #pragma warning( push )
@@ -48,7 +48,7 @@
 
     virtual TString GetPackageAppDirectory();
     virtual TString GetPackageLauncherDirectory();
-    
+
     virtual TString GetConfigFileName();
 
     virtual std::list<TString> LoadFromFile(TString FileName);
@@ -59,7 +59,7 @@
 #endif //WINDOWS || LINUX
 
     virtual std::map<TString, TString> GetKeys();
-    
+
 #ifdef DEBUG
     virtual DebugState GetDebugState();
 #endif //DEBUG
--- a/modules/fxpackager/src/main/native/library/common/Helpers.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Helpers.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -33,24 +33,65 @@
 
 #include "Helpers.h"
 #include "PlatformString.h"
+#include "PropertyFile.h"
 
 
 bool Helpers::SplitOptionIntoNameValue(TString option, TString& Name, TString& Value) {
     bool result = false;
-    size_t position = option.find('=');
+    Name = _T("");
+    Value = _T("");
+    unsigned int index = 0;
 
-    if (position != TString::npos) {
-        Name = option.substr(0, position);
-        Value = option.substr(position + 1, option.length() - position + 1);
-        result = true;
-    }
-    else {
-        Name = option;
+    for (; index < option.length(); index++) {
+        TCHAR c = option[index];
+
+        switch (c) {
+            case '=': {
+                index++;
+                result = true;
+                break;
+            }
+
+            case '\\': {
+                if (index + 1 < option.length()) {
+                    c = option[index + 1];
+
+                    switch (c) {
+                        case '\\': {
+                            index++;
+                            Name += '\\';
+                            break;
+                        }
+
+                        case '=': {
+                            index++;
+                            Name += '=';
+                            break;
+                        }
+                    }
+
+                }
+
+                continue;
+            }
+
+            default: {
+                Name += c;
+                continue;
+            }
+        }
+
+        break;
     }
 
-    return result;
+    if (result) {
+        Value = option.substr(index, index - option.length());
+    }
+
+    return true;
 }
 
+
 TString Helpers::ReplaceString(TString subject, const TString& search,
                             const TString& replace) {
     size_t pos = 0;
@@ -83,15 +124,15 @@
 
 TString Helpers::ConvertPathToId(TString Value) {
     TString search;
-    search = TRAILING_SLASH;
+    search = TRAILING_PATHSEPARATOR;
     TString replace;
     replace = '.';
     TString result = ReplaceString(Value, search, replace);
     return result;
 }
 
-TOrderedMap Helpers::GetJVMArgsFromConfig(PropertyContainer* config) {
-    TOrderedMap result;
+OrderedMap<TString, TString> Helpers::GetJVMArgsFromConfig(IPropertyContainer* config) {
+    OrderedMap<TString, TString> result;
 
     for (unsigned int index = 0; index < config->GetCount(); index++) {
         TString argname = TString(_T("jvmarg.")) + PlatformString(index + 1).toString();
@@ -102,58 +143,58 @@
         }
         else if (argvalue.empty() == false) {
             TString name;
-            TValueIndex value;
-            Helpers::SplitOptionIntoNameValue(argvalue, name, value.value);
-            result.insert(TOrderedMap::value_type(name, value));
+            TString value;
+            Helpers::SplitOptionIntoNameValue(argvalue, name, value);
+            result.Append(name, value);
         }
     }
 
     return result;
 }
 
-TOrderedMap Helpers::GetJVMUserArgsFromConfig(PropertyContainer* config) {
-    TOrderedMap result;
+OrderedMap<TString, TString> Helpers::GetJVMUserArgsFromConfig(IPropertyContainer* config) {
+    OrderedMap<TString, TString> result;
 
     for (unsigned int index = 0; index < config->GetCount(); index++) {
         TString prefix = TString(_T("jvmuserarg.")) + PlatformString(index + 1).toString();
         TString argname = prefix + _T(".name");
         TString argvalue = prefix + _T(".value");
         TString name;
-        TValueIndex value;
+        TString value;
 
-        if ((config->GetValue(argname, name) == false) || (config->GetValue(argvalue, value.value) == false)) {
+        if ((config->GetValue(argname, name) == false) || (config->GetValue(argvalue, value) == false)) {
             break;
         }
-        else if ((name.empty() == false) && (value.value.empty() == false)) {
-            result.insert(TOrderedMap::value_type(name, value));
+        else if ((name.empty() == false) && (value.empty() == false)) {
+            result.Append(name, value);
         }
     }
 
     return result;
 }
 
-std::map<TString, TString> Helpers::GetConfigFromJVMUserArgs(TOrderedMap OrderedMap) {
-    std::map<TString, TString> result;
-    size_t index = 0;
-    
-    for (TOrderedMap::iterator iterator = OrderedMap.begin();
-         iterator != OrderedMap.end();
-         iterator++) {
-        TString prefix = TString(_T("jvmuserarg.")) + PlatformString(index + 1).toString();
-        TString argname = prefix + _T(".name");
-        TString argvalue = prefix + _T(".value");
-        TString name = iterator->first;
-        TString value = iterator->second.value;
-        
-        result.insert(std::map<TString, TString>::value_type(argname, name));
-        result.insert(std::map<TString, TString>::value_type(argvalue, value));
-        index++;
+/*OrderedMap<TString, TString> Helpers::GetConfigFromJVMUserArgs(OrderedMap<TString, TString> Map) {
+    OrderedMap<TString, TString> result;
+    std::vector<TString> keys = Map.GetKeys();
+
+    for (unsigned int index = 0; index < keys.size(); index++) {
+        TString key = keys[index];
+        TString value;
+
+        if (Map.GetValue(key, value) == true) {
+            TString prefix = TString(_T("jvmuserarg.")) + PlatformString(index + 1).toString();
+            TString argname = prefix + _T(".name");
+            TString argvalue = prefix + _T(".value");
+
+            result.Append(argname, key);
+            result.Append(argvalue, value);
+        }
     }
-    
+
     return result;
-}
+}*/
 
-std::list<TString> Helpers::GetArgsFromConfig(PropertyContainer* config) {
+std::list<TString> Helpers::GetArgsFromConfig(IPropertyContainer* config) {
     std::list<TString> result;
 
     for (unsigned int index = 0; index < config->GetCount(); index++) {
@@ -171,42 +212,104 @@
     return result;
 }
 
-bool comp(const TValueIndex& a, const TValueIndex& b) {
-    return a.index < b.index;
+void AppendToIni(PropertyFile &Source, IniFile* Destination, TString Key) {
+    TString value;
+
+    if (Source.GetValue(Key, value) == true) {
+        Platform& platform = Platform::GetInstance();
+        std::map<TString, TString> keys = platform.GetKeys();
+        Destination->Append(keys[CONFIG_SECTION_APPLICATION], Key, value);
+    }
 }
 
-std::list<TString> Helpers::GetOrderedKeysFromMap(TOrderedMap OrderedMap) {
+void Helpers::LoadOldConfigFile(TString FileName, IniFile* Container) {
+    PropertyFile propertyFile;
+
+    if (propertyFile.LoadFromFile(FileName) == true) {
+        Platform& platform = Platform::GetInstance();
+
+        std::map<TString, TString> keys = platform.GetKeys();
+
+        // Application Section
+        AppendToIni(propertyFile, Container, keys[CONFIG_MAINJAR_KEY]);
+        AppendToIni(propertyFile, Container, keys[CONFIG_MAINCLASSNAME_KEY]);
+        AppendToIni(propertyFile, Container, keys[CONFIG_CLASSPATH_KEY]);
+        AppendToIni(propertyFile, Container, keys[APP_NAME_KEY]);
+        AppendToIni(propertyFile, Container, keys[CONFIG_APP_ID_KEY]);
+        AppendToIni(propertyFile, Container, keys[JVM_RUNTIME_KEY]);
+        AppendToIni(propertyFile, Container, keys[PACKAGER_APP_DATA_DIR]);
+
+        AppendToIni(propertyFile, Container, keys[CONFIG_APP_MEMORY]);
+        AppendToIni(propertyFile, Container, keys[CONFIG_SPLASH_KEY]);
+
+        // JVMOptions Section
+        OrderedMap<TString, TString> JVMArgs = Helpers::GetJVMArgsFromConfig(&propertyFile);
+        Container->AppendSection(keys[CONFIG_SECTION_JVMOPTIONS], JVMArgs);
+
+        // JVMUserOptions Section
+        OrderedMap<TString, TString> defaultJVMUserArgs = Helpers::GetJVMUserArgsFromConfig(&propertyFile);
+        Container->AppendSection(keys[CONFIG_SECTION_JVMUSEROPTIONS], defaultJVMUserArgs);
+
+        // ArgOptions Section
+        std::list<TString> args = Helpers::GetArgsFromConfig(&propertyFile);
+        OrderedMap<TString, TString> convertedArgs;
+
+        for (std::list<TString>::iterator iterator = args.begin(); iterator != args.end(); iterator++) {
+            TString arg = *iterator;
+            TString name;
+            TString value;
+
+            if (Helpers::SplitOptionIntoNameValue(arg, name, value) == true) {
+                convertedArgs.Append(name, value);
+            }
+        }
+
+        Container->AppendSection(keys[CONFIG_SECTION_ARGOPTIONS], convertedArgs);
+    }
+}
+
+void Helpers::LoadOldUserConfigFile(TString FileName, IniFile* Container) {
+    PropertyFile propertyFile;
+    Container = NULL;
+
+    if (propertyFile.LoadFromFile(FileName) == true) {
+        Container = new IniFile();
+        Platform& platform = Platform::GetInstance();
+
+        std::map<TString, TString> keys = platform.GetKeys();
+
+        // JVMUserOverridesOptions Section
+        OrderedMap<TString, TString> defaultJVMUserArgs = Helpers::GetJVMUserArgsFromConfig(&propertyFile);
+        Container->AppendSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], defaultJVMUserArgs);
+    }
+}
+
+std::list<TString> Helpers::MapToNameValueList(OrderedMap<TString, TString> Map) {
     std::list<TString> result;
-    std::list<TValueIndex> indexedList;
-    
-    for (TOrderedMap::iterator iterator = OrderedMap.begin();
-         iterator != OrderedMap.end();
-         iterator++) {
-        TValueIndex item;
-        item.value = iterator->first;
-        item.index = iterator->second.index;
-        indexedList.push_back(item);
+    std::vector<TString> keys = Map.GetKeys();
+
+    for (size_t index = 0; index < keys.size(); index++) {
+        TString key = keys[index];
+        TString value;
+
+        if (Map.GetValue(key, value) == true) {
+            result.push_back(key + _T('=') + value);
+        }
     }
-    
-    indexedList.sort(comp);
-    
-    for (std::list<TValueIndex>::const_iterator iterator = indexedList.begin(); iterator != indexedList.end(); iterator++) {
-        TString name = iterator->value;
-        result.push_back(name);
-    }
-    
+
     return result;
 }
 
+
 TString Helpers::NameValueToString(TString name, TString value) {
     TString result;
-    
+
     if (value.empty() == true) {
         result = name;
     }
     else {
         result = name + TString(_T("=")) + value;
     }
-    
+
     return result;
 }
--- a/modules/fxpackager/src/main/native/library/common/Helpers.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Helpers.h	Tue Mar 31 08:15:48 2015 -0700
@@ -35,7 +35,8 @@
 #define HELPERS_H
 
 #include "Platform.h"
-#include "PropertyFile.h"
+#include "OrderedMap.h"
+#include "IniFile.h"
 
 
 class Helpers {
@@ -44,6 +45,12 @@
     ~Helpers(void) {}
 
 public:
+    // Supports two formats for option:
+    // Example 1:
+    // foo=bar
+    //
+    // Example 2:
+    // <name=foo=, value=goo>
     static bool SplitOptionIntoNameValue(TString option, TString& Name, TString& Value);
     static TString ReplaceString(TString subject, const TString& search,
                                  const TString& replace);
@@ -51,52 +58,17 @@
     static TString ConvertIdToJavaPath(TString Value);
     static TString ConvertPathToId(TString Value);
 
-    static std::map<TString, TValueIndex> GetJVMArgsFromConfig(PropertyContainer* config);
-    static std::map<TString, TValueIndex> GetJVMUserArgsFromConfig(PropertyContainer* config);
-    static std::map<TString, TString> GetConfigFromJVMUserArgs(std::map<TString, TValueIndex> OrderedMap);
-    static std::list<TString> GetArgsFromConfig(PropertyContainer* config);
-    
-    static std::list<TString> GetOrderedKeysFromMap(std::map<TString, TValueIndex> OrderedMap);
-    
+    static OrderedMap<TString, TString> GetJVMArgsFromConfig(IPropertyContainer* config);
+    static OrderedMap<TString, TString> GetJVMUserArgsFromConfig(IPropertyContainer* config);
+    //static OrderedMap<TString, TString> GetConfigFromJVMUserArgs(OrderedMap<TString, TString> Value);
+    static std::list<TString> GetArgsFromConfig(IPropertyContainer* config);
+
+    static void LoadOldConfigFile(TString FileName, IniFile* Container);
+    static void LoadOldUserConfigFile(TString FileName, IniFile* Container);
+
+    static std::list<TString> MapToNameValueList(OrderedMap<TString, TString> Map);
+
     static TString NameValueToString(TString name, TString value);
 };
 
-template <typename T>
-class AutoFreePtr {
-private:
-    T* FObject;
-    
-public:
-    AutoFreePtr(T* Value) {
-        FObject = Value;
-    }
-    
-    ~AutoFreePtr() {
-        if (FObject != NULL) {
-            delete FObject;
-        }
-    }
-    
-    operator T* () const {
-        return FObject;
-    }
-    
-    T& operator* () const {
-        return *FObject;
-    }
-    
-    T* operator->() const {
-        return FObject;
-    }
-    
-    T** operator&() {
-        return &FObject;
-    }
-    
-    T* operator=(const T * rhs) {
-        FObject = rhs;
-        return FObject;
-    }
-};
-
 #endif //HELPERS_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/native/library/common/IniFile.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "IniFile.h"
+#include "Helpers.h"
+
+#include <string>
+
+
+IniFile::IniFile() : ISectionalPropertyContainer() {
+}
+
+IniFile::~IniFile() {
+    std::vector<TString> keys = FMap.GetKeys();
+
+    for (size_t index = 0; index < keys.size(); index++) {
+        TString key = keys[index];
+
+        IniSectionData* item;
+
+        if (FMap.GetValue(key, item) == true) {
+            if (item != NULL) {
+                delete item;
+                item = NULL;
+            }
+        }
+    }
+}
+
+bool IniFile::LoadFromFile(const TString FileName) {
+    bool result = false;
+    Platform& platform = Platform::GetInstance();
+
+    std::list<TString> contents = platform.LoadFromFile(FileName);
+
+    if (contents.empty() == false) {
+        bool found = false;
+
+        // Determine the if file is an INI file or property file. Assign FDefaultSection if it is
+        // an INI file. Otherwise FDefaultSection is NULL.
+        for (std::list<TString>::const_iterator iterator = contents.begin(); iterator != contents.end(); iterator++) {
+            TString line = *iterator;
+
+            if (line[0] == ';') {
+                // Semicolon is a comment so ignore the line.
+                continue;
+            }
+            else {
+                if (line[0] == '[') {
+                    found = true;
+                }
+
+                break;
+            }
+        }
+
+        if (found == true) {
+            TString sectionName;
+
+            for (std::list<TString>::const_iterator iterator = contents.begin(); iterator != contents.end(); iterator++) {
+                TString line = *iterator;
+
+                if (line[0] == ';') {
+                    // Semicolon is a comment so ignore the line.
+                    continue;
+                }
+                else if (line[0] == '[' && line[line.length() - 1] == ']') {
+                    sectionName = line.substr(1, line.size() - 2);
+                }
+                else if (sectionName.empty() == false) {
+                    TString name;
+                    TString value;
+
+                    if (Helpers::SplitOptionIntoNameValue(line, name, value) == true) {
+                        Append(sectionName, name, value);
+                    }
+                }
+            }
+
+            result = true;
+        }
+    }
+
+    return result;
+}
+
+bool IniFile::SaveToFile(const TString FileName, bool ownerOnly) {
+    bool result = false;
+
+    //if (GetReadOnly() == false && IsModified()) {
+        std::list<TString> contents;
+        std::vector<TString> keys = FMap.GetKeys();
+
+        for (unsigned int index = 0; index < keys.size(); index++) {
+            TString name = keys[index];
+
+            //try {
+                IniSectionData *section;// = FMap[index];
+
+                if (FMap.GetValue(name, section) == true) {
+                    contents.push_back(_T("[") + name + _T("]"));
+                    std::list<TString> lines = section->GetLines();
+                    contents.insert(contents.end(), lines.begin(), lines.end());
+                    contents.push_back(_T(""));
+                }
+//            }
+//            catch (std::out_of_range) {
+//            }
+        }
+
+        Platform& platform = Platform::GetInstance();
+        platform.SaveToFile(FileName, contents, ownerOnly);
+
+        //SetModified(false);
+        result = true;
+    //}
+
+    return result;
+}
+
+void IniFile::Append(const TString SectionName, const TString Key, TString Value) {
+    if (FMap.ContainsKey(SectionName) == true) {
+        IniSectionData* section;
+
+        if (FMap.GetValue(SectionName, section) == true && section != NULL) {
+            section->SetValue(Key, Value);
+        }
+    }
+    else {
+        IniSectionData *section = new IniSectionData();
+        section->SetValue(Key, Value);
+        FMap.Append(SectionName, section);
+    }
+}
+
+void IniFile::AppendSection(const TString SectionName, OrderedMap<TString, TString> Values) {
+    if (FMap.ContainsKey(SectionName) == true) {
+        IniSectionData* section;
+
+        if (FMap.GetValue(SectionName, section) == true && section != NULL) {
+            section->Append(Values);
+        }
+    }
+    else {
+        IniSectionData *section = new IniSectionData(Values);
+        FMap.Append(SectionName, section);
+    }
+}
+
+bool IniFile::GetValue(const TString SectionName, const TString Key, TString& Value) {
+    bool result = false;
+    IniSectionData* section;
+
+    if (FMap.GetValue(SectionName, section) == true && section != NULL) {
+        result = section->GetValue(Key, Value);
+    }
+
+    return result;
+}
+
+bool IniFile::SetValue(const TString SectionName, const TString Key, TString Value) {
+    bool result = false;
+    IniSectionData* section;
+
+    if (FMap.GetValue(SectionName, section) && section != NULL) {
+        result = section->SetValue(Key, Value);
+    }
+    else {
+        Append(SectionName, Key, Value);
+    }
+
+
+    return result;
+}
+
+bool IniFile::GetSection(const TString SectionName, OrderedMap<TString, TString> &Data) {
+    bool result = false;
+
+    if (FMap.ContainsKey(SectionName) == true) {
+        IniSectionData* section;
+
+        if (FMap.GetValue(SectionName, section) == true && section != NULL) {
+            OrderedMap<TString, TString> data = section->GetData();
+            Data.Append(data);
+        }
+    }
+
+    return result;
+}
+
+bool IniFile::ContainsSection(const TString SectionName) {
+    return FMap.ContainsKey(SectionName);
+}
+
+//--------------------------------------------------------------------------------------------------
+
+IniSectionData::IniSectionData() {
+}
+
+IniSectionData::IniSectionData(OrderedMap<TString, TString> Values) {
+    FMap = Values;
+}
+
+std::vector<TString> IniSectionData::GetKeys() {
+    return FMap.GetKeys();
+}
+
+std::list<TString> IniSectionData::GetLines() {
+    std::list<TString> result;
+    std::vector<TString> keys = FMap.GetKeys();
+
+    for (unsigned int index = 0; index < keys.size(); index++) {
+        TString name = keys[index];
+        TString value;
+
+        if (FMap.GetValue(name, value) == true) {
+            TString line = name + _T('=') + value;
+            result.push_back(line);
+        }
+    }
+
+    return result;
+}
+
+OrderedMap<TString, TString> IniSectionData::GetData() {
+    OrderedMap<TString, TString> result = FMap;
+    return result;
+}
+
+bool IniSectionData::GetValue(const TString Key, TString& Value) {
+    return FMap.GetValue(Key, Value);
+}
+
+bool IniSectionData::SetValue(const TString Key, TString Value) {
+    return FMap.SetValue(Key, Value);
+}
+
+void IniSectionData::Append(OrderedMap<TString, TString> Values) {
+    FMap.Append(Values);
+}
+
+size_t IniSectionData::GetCount() {
+    return FMap.Count();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/native/library/common/IniFile.h	Tue Mar 31 08:15:48 2015 -0700
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef INIFILE_H
+#define INIFILE_H
+
+#include "Platform.h"
+#include "OrderedMap.h"
+
+#include <map>
+
+
+class IniSectionData : public IPropertyContainer {
+private:
+    OrderedMap<TString, TString> FMap;
+
+public:
+    IniSectionData();
+    IniSectionData(OrderedMap<TString, TString> Values);
+
+    std::vector<TString> GetKeys();
+    std::list<TString> GetLines();
+    OrderedMap<TString, TString> GetData();
+
+    bool SetValue(const TString Key, TString Value);
+    void Append(OrderedMap<TString, TString> Values);
+
+    virtual bool GetValue(const TString Key, TString& Value);
+    virtual size_t GetCount();
+};
+
+
+class IniFile : public ISectionalPropertyContainer {
+private:
+    OrderedMap<TString, IniSectionData*> FMap;
+
+public:
+    IniFile();
+    virtual ~IniFile();
+
+    void internalTest();
+
+    bool LoadFromFile(const TString FileName);
+    bool SaveToFile(const TString FileName, bool ownerOnly = true);
+
+    void Append(const TString SectionName, const TString Key, TString Value);
+    void AppendSection(const TString SectionName, OrderedMap<TString, TString> Values);
+    bool SetValue(const TString SectionName, const TString Key, TString Value);
+
+    // ISectionalPropertyContainer
+    virtual bool GetSection(const TString SectionName, OrderedMap<TString, TString> &Data);
+    virtual bool ContainsSection(const TString SectionName);
+    virtual bool GetValue(const TString SectionName, const TString Key, TString& Value);
+};
+
+#endif //INIFILE_H
--- a/modules/fxpackager/src/main/native/library/common/Java.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Java.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -40,18 +40,18 @@
 //--------------------------------------------------------------------------------------------------
 
 #ifdef DEBUG
-std::string JavaException::CreateExceptionMessage(JNIEnv* Env, jthrowable Exception,
+TString JavaException::CreateExceptionMessage(JNIEnv* Env, jthrowable Exception,
     jmethodID GetCauseMethod, jmethodID GetStackTraceMethod, jmethodID ThrowableToTStringMethod,
     jmethodID FrameToTStringMethod) {
 
-    std::string result;
+    TString result;
     jobjectArray frames = (jobjectArray)Env->CallObjectMethod(Exception, GetStackTraceMethod);
 
     // Append Throwable.toTString().
     if (0 != frames) {
         jstring jstr = (jstring)Env->CallObjectMethod(Exception, ThrowableToTStringMethod);
         const char* str = Env->GetStringUTFChars(jstr, 0);
-        result += str;
+        result += PlatformString(str).toPlatformString();
         Env->ReleaseStringUTFChars(jstr, str);
         Env->DeleteLocalRef(jstr);
     }
@@ -66,8 +66,8 @@
             jobject frame = Env->GetObjectArrayElement(frames, i);
             jstring obj = (jstring)Env->CallObjectMethod(frame, FrameToTStringMethod);
             const char* str = Env->GetStringUTFChars(obj, 0);
-            result += "\n  ";
-            result += str;
+            result += _T("\n  ");
+            result += PlatformString(str).toPlatformString();
             Env->ReleaseStringUTFChars(obj, str);
             Env->DeleteLocalRef(obj);
             Env->DeleteLocalRef(frame);
@@ -89,27 +89,18 @@
 }
 #endif //DEBUG
 
-JavaException::JavaException() : std::exception() {}
+JavaException::JavaException() : Exception() {}
 
-//TODO Fix JavaException for all platforms.
-#ifdef WINDOWS
-JavaException::JavaException(const char* const message) : std::exception(message) {}
-#endif //WINDOWS
-#ifdef MAC
-JavaException::JavaException(const char* const message) {}
-#endif //MAC
-
-#ifdef WINDOWS
-JavaException::JavaException(JNIEnv *Env, const char* const message) : std::exception(message) {
-#endif //WINDOWS
-#ifdef POSIX
-JavaException::JavaException(JNIEnv *Env, const char* const message) {
-#endif //POSIX
+//#ifdef WINDOWS
+JavaException::JavaException(JNIEnv *Env, const TString Message) : Exception(Message) {
+//#endif //WINDOWS
+//#ifdef POSIX
+//JavaException::JavaException(JNIEnv *Env, TString message) {
+//#endif //POSIX
 
     FEnv = Env;
     FException = Env->ExceptionOccurred();
     Env->ExceptionClear();
-    FMessage = message;
 
 #ifdef DEBUG
     Platform& platform = Platform::GetInstance();
@@ -165,22 +156,13 @@
             return;
         }
 
-        std::string lmessage = CreateExceptionMessage(Env, FException, GetCauseMethod,
+        TString lmessage = CreateExceptionMessage(Env, FException, GetCauseMethod,
             GetStackTraceMethod, ThrowableToTStringMethod, FrameToTStringMethod);
-        FMessage = lmessage.c_str();
+        SetMessage(lmessage);
     }
 #endif //DEBUG
 }
 
-const char* JavaException::what() {
-    if (FMessage.empty() == true) {
-        return std::exception::what();
-    }
-    else {
-        return FMessage.c_str();
-    }
-}
-
 void JavaException::Rethrow() {
     FEnv->Throw(FException);
 }
@@ -201,8 +183,7 @@
 
     if (FEnv->ExceptionCheck() == JNI_TRUE) {
         Messages& messages = Messages::GetInstance();
-        std::string message = PlatformString(messages.GetMessage(ERROR_INVOKING_METHOD)).toStdString();
-        throw JavaException(FEnv, message.c_str());
+        throw JavaException(FEnv, messages.GetMessage(ERROR_INVOKING_METHOD));
     }
 }
 
@@ -226,8 +207,7 @@
 
     if (FEnv->ExceptionCheck() == JNI_TRUE) {
         Messages& messages = Messages::GetInstance();
-        std::string message = PlatformString(messages.GetMessage(ERROR_INVOKING_METHOD)).toStdString();
-        throw JavaException(FEnv, message.c_str());
+        throw JavaException(FEnv, messages.GetMessage(ERROR_INVOKING_METHOD));
     }
 }
 
@@ -244,10 +224,9 @@
 
     if (FClass == NULL || FEnv->ExceptionCheck() == JNI_TRUE) {
         Messages& messages = Messages::GetInstance();
-        std::string message = PlatformString(messages.GetMessage(CLASS_NOT_FOUND)).toStdString();
-        message = PlatformString::Format(message,
-            PlatformString(FClassName).c_str());
-        throw JavaException(FEnv, message.c_str());
+        TString message = messages.GetMessage(CLASS_NOT_FOUND);
+        message = PlatformString::Format(message, FClassName.data());
+        throw JavaException(FEnv, message);
     }
 }
 
@@ -255,7 +234,7 @@
     FEnv->DeleteLocalRef(FClass);
 
     if (FEnv->ExceptionCheck() == JNI_TRUE) {
-        throw JavaException(FEnv, "Error");
+        throw JavaException(FEnv, _T("Error"));
     }
 }
 
@@ -264,11 +243,9 @@
 
     if (method == NULL || FEnv->ExceptionCheck() == JNI_TRUE) {
         Messages& messages = Messages::GetInstance();
-        std::string message = PlatformString(messages.GetMessage(METHOD_NOT_FOUND)).toStdString();
-        message = PlatformString::Format(message,
-            PlatformString(Name).c_str(),
-            PlatformString(FClassName).c_str());
-        throw JavaException(FEnv, message.c_str());
+        TString message = messages.GetMessage(METHOD_NOT_FOUND);
+        message = PlatformString::Format(message, Name.data(), FClassName.data());
+        throw JavaException(FEnv, message);
     }
 
     return JavaStaticMethod(FEnv, FClass, method);
@@ -285,16 +262,16 @@
 
     if (FEnv->ExceptionCheck() == JNI_TRUE) {
         Messages& messages = Messages::GetInstance();
-        std::string message = PlatformString(messages.GetMessage(CLASS_NOT_FOUND)).toStdString();
-        message = PlatformString::Format(message, "String");
-        throw JavaException(FEnv, message.c_str());
+        TString message = messages.GetMessage(CLASS_NOT_FOUND);
+        message = PlatformString::Format(message, _T("String"));
+        throw JavaException(FEnv, message.data());
     }
 
     jstring str = PlatformString("").toJString(FEnv);
     FData = (jobjectArray)FEnv->NewObjectArray((jsize)Size, jstringClass, str);
 
     if (FEnv->ExceptionCheck() == JNI_TRUE) {
-        throw JavaException(FEnv, "Error");
+        throw JavaException(FEnv, _T("Error"));
     }
 }
 
@@ -328,7 +305,7 @@
     FEnv->SetObjectArrayElement(FData, Index, Item);
 
     if (FEnv->ExceptionCheck() == JNI_TRUE) {
-        throw JavaException(FEnv, "Error");
+        throw JavaException(FEnv, _T("Error"));
     }
 }
 
@@ -336,7 +313,7 @@
     jstring result = (jstring)FEnv->GetObjectArrayElement(FData, Index);
 
     if (FEnv->ExceptionCheck() == JNI_TRUE) {
-        throw JavaException(FEnv, "Error");
+        throw JavaException(FEnv, _T("Error"));
     }
 
     return result;
@@ -346,7 +323,7 @@
     unsigned int result = FEnv->GetArrayLength(FData);
 
     if (FEnv->ExceptionCheck() == JNI_TRUE) {
-        throw JavaException(FEnv, "Error");
+        throw JavaException(FEnv, _T("Error"));
     }
 
     return result;
--- a/modules/fxpackager/src/main/native/library/common/Java.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Java.h	Tue Mar 31 08:15:48 2015 -0700
@@ -46,29 +46,26 @@
 class JavaStringArray;
 
 
-class JavaException : public std::exception {
+class JavaException : public Exception {
 // Prohibit Heap-Based Classes.
 private:
     static void *operator new(size_t size);
 
 private:
 #ifdef DEBUG
-    static std::string CreateExceptionMessage(JNIEnv* Env, jthrowable Exception,
+    static TString CreateExceptionMessage(JNIEnv* Env, jthrowable Exception,
         jmethodID GetCauseMethod, jmethodID GetStackTraceMethod, jmethodID ThrowableToStringMethod,
         jmethodID FrameToStringMethod);
 #endif //DEBUG
 
-    std::string FMessage;
     jthrowable FException;
     JNIEnv *FEnv;
 
 public:
     explicit JavaException();
-    explicit JavaException(const char* const message);
-    explicit JavaException(JNIEnv *Env, const char* const message);
+    explicit JavaException(JNIEnv *Env, const TString message);
     virtual ~JavaException() throw() {}
 
-    virtual const char* what();
     void Rethrow();
 };
 
@@ -147,7 +144,7 @@
 private:
     JNIEnv *FEnv;
     jobjectArray FData;
-    
+
     void Initialize(size_t Size);
 
 public:
--- a/modules/fxpackager/src/main/native/library/common/JavaUserPreferences.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/JavaUserPreferences.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -59,6 +59,6 @@
 JavaUserPreferences::~JavaUserPreferences(void){
 }
 
-TOrderedMap JavaUserPreferences::GetData() {
+OrderedMap<TString, TString> JavaUserPreferences::GetData() {
     return FMap;
 }
--- a/modules/fxpackager/src/main/native/library/common/JavaUserPreferences.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/JavaUserPreferences.h	Tue Mar 31 08:15:48 2015 -0700
@@ -35,7 +35,7 @@
 #define JAVAUSERPREFERENCES_H
 
 
-#include "PropertyFile.h"
+#include "Helpers.h"
 
 #include <map>
 
@@ -43,14 +43,14 @@
 class JavaUserPreferences {
 protected:
     TString FAppid;
-    TOrderedMap FMap;
+    OrderedMap<TString, TString> FMap;
 
 public:
     static JavaUserPreferences* CreateInstance(void);
     JavaUserPreferences(void);
     virtual ~JavaUserPreferences(void);
 
-    TOrderedMap GetData();
+    OrderedMap<TString, TString> GetData();
 
 public:
     virtual bool Load(TString Appid) = 0;
--- a/modules/fxpackager/src/main/native/library/common/JavaVirtualMachine.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/JavaVirtualMachine.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -48,6 +48,23 @@
 #include <list>
 
 
+bool RunVM() {
+    bool result = false;
+    JavaVirtualMachine javavm;
+
+    if (javavm.StartJVM() == true) {
+        result = true;
+        javavm.ShutdownJVM();
+    }
+    else {
+        Platform& platform = Platform::GetInstance();
+        platform.ShowMessage(_T("Failed to launch JVM\n"));
+    }
+
+    return result;
+}
+
+
 // Private typedef for function pointer casting
 #ifndef USE_JLI_LAUNCH
 #define LAUNCH_FUNC "JNI_CreateJavaVM"
@@ -200,10 +217,6 @@
         }
     }
 
-    void AppendValue(const TString Key, TString Value) {
-        AppendValue(Key, Value, NULL);
-    }
-
     void AppendValue(const TString Key, TString Value, void* Extra) {
         JavaOptionItem item;
         item.name = Key;
@@ -212,22 +225,29 @@
         FItems.push_back(item);
     }
 
-    void AppendValues(TOrderedMap Values) {
-        std::list<TString> orderedKeys = Helpers::GetOrderedKeysFromMap(Values);
-        
-        for (std::list<TString>::const_iterator iterator = orderedKeys.begin(); iterator != orderedKeys.end(); iterator++) {
+    void AppendValue(const TString Key, TString Value) {
+        AppendValue(Key, Value, NULL);
+    }
+
+    void AppendValues(OrderedMap<TString, TString> Values) {
+        std::vector<TString> orderedKeys = Values.GetKeys();
+
+        for (std::vector<TString>::const_iterator iterator = orderedKeys.begin(); iterator != orderedKeys.end(); iterator++) {
             TString name = *iterator;
-            TValueIndex value = Values[name];
-            AppendValue(name, value.value);
+            TString value;
+
+            if (Values.GetValue(name, value) == true) {
+                AppendValue(name, value);
+            }
         }
     }
-    
+
     void ReplaceValue(const TString Key, TString Value) {
         for (std::list<JavaOptionItem>::iterator iterator = FItems.begin();
              iterator != FItems.end(); iterator++) {
-            
+
             TString lkey = iterator->name;
-            
+
             if (lkey == Key) {
                 JavaOptionItem item = *iterator;
                 item.value = Value;
@@ -244,7 +264,7 @@
         memset(FOptions, 0, sizeof(JavaVMOption) * FItems.size());
         Macros& macros = Macros::GetInstance();
         unsigned int index = 0;
-        
+
         for (std::list<JavaOptionItem>::const_iterator iterator = FItems.begin();
              iterator != FItems.end(); iterator++) {
             TString key = iterator->name;
@@ -265,7 +285,7 @@
     std::list<TString> ToList() {
         std::list<TString> result;
         Macros& macros = Macros::GetInstance();
-        
+
         for (std::list<JavaOptionItem>::const_iterator iterator = FItems.begin();
              iterator != FItems.end(); iterator++) {
             TString key = iterator->name;
@@ -286,34 +306,38 @@
 
 // jvmuserargs can have a trailing equals in the key. This needs to be removed to use
 // other parts of the launcher.
-TOrderedMap RemoveTrailingEquals(TOrderedMap Map) {
-    TOrderedMap result;
+OrderedMap<TString, TString> RemoveTrailingEquals(OrderedMap<TString, TString> Map) {
+    OrderedMap<TString, TString> result;
 
-    for (TOrderedMap::const_iterator iterator = Map.begin(); iterator != Map.end(); iterator++) {
-        TString name = iterator->first;
-        TValueIndex value = iterator->second;
+    std::vector<TString> keys = Map.GetKeys();
 
-        // If the last character of the key is an equals, then remove it. If there is no
-        // equals then combine the two as a key.
-        TString::iterator i = name.end();
-        i--;
+    for (size_t index = 0; index < keys.size(); index++) {
+        TString name = keys[index];
+        TString value;
 
-        if (*i == '=') {
-            name = name.substr(0, name.size() - 1);
-        }
-        else {
-            i = value.value.begin();
-            
+        if (Map.GetValue(name, value) == true) {
+            // If the last character of the key is an equals, then remove it. If there is no
+            // equals then combine the two as a key.
+            TString::iterator i = name.end();
+            i--;
+
             if (*i == '=') {
-                value.value = value.value.substr(1, value.value.size() - 1);
+                name = name.substr(0, name.size() - 1);
             }
             else {
-                name = name + value.value;
-                value.value = _T("");
+                i = value.begin();
+
+                if (*i == '=') {
+                    value = value.substr(1, value.size() - 1);
+                }
+                else {
+                    name = name + value;
+                    value = _T("");
+                }
             }
+
+            result.Append(name, value);
         }
-
-        result.insert(TOrderedMap::value_type(name, value));
     }
 
     return result;
@@ -344,7 +368,7 @@
     options.AppendValue(_T("-Dapp.preferences.id"), package.GetAppID());
     options.AppendValues(package.GetJVMArgs());
     options.AppendValues(RemoveTrailingEquals(package.GetJVMUserArgs()));
- 
+
 #ifdef DEBUG
     if (package.Debugging() == dsJava) {
         options.AppendValue(_T("-Xdebug"), _T(""));
@@ -382,7 +406,7 @@
     JavaLibrary javaLibrary;
     javaLibrary.AddDependencies(platform.FilterOutRuntimeDependenciesForPlatform(platform.GetLibraryImports(package.GetJVMLibraryFileName())));
     javaLibrary.Load(package.GetJVMLibraryFileName());
-    
+
 #ifndef USE_JLI_LAUNCH
     if (package.HasSplashScreen() == true) {
         options.AppendValue(TString(_T("-splash:")) + package.GetSplashScreenFileName(), _T(""));
@@ -402,14 +426,14 @@
             JavaStaticMethod mainMethod = mainClass.GetStaticMethod(_T("main"), _T("([Ljava/lang/String;)V"));
             std::list<TString> appargs = package.GetArgs();
             JavaStringArray largs(FEnv, appargs);
-            
+
             package.FreeBootFields();
-            
+
             mainMethod.CallVoidMethod(1, largs.GetData());
             return true;
         }
         catch (JavaException& exception) {
-            platform.ShowMessage(PlatformString(exception.what()).toString());
+            platform.ShowMessage(exception.GetMessage());
             return false;
         }
     }
@@ -446,7 +470,7 @@
     std::list<TString> largs = package.GetArgs();
     vmargs.splice(vmargs.end(), largs, largs.begin(), largs.end());
     size_t argc = vmargs.size();
-    DynamicBuffer<char*> argv(argc+1);
+    DynamicBuffer<char*> argv(argc + 1);
     unsigned int index = 0;
 
     for (std::list<TString>::const_iterator iterator = vmargs.begin();
@@ -463,11 +487,13 @@
     argv[argc] = NULL;
 
     // On Mac we can only free the boot fields if the calling thread is not the main thread.
-#ifdef MAC
+    #ifdef MAC
     if (platform.IsMainThread() == false) {
         package.FreeBootFields();
     }
-#endif //MAC
+    #else
+    package.FreeBootFields();
+    #endif //MAC
 
     if (javaLibrary.JavaVMCreate(argc, argv.GetData()) == true) {
         return true;
--- a/modules/fxpackager/src/main/native/library/common/JavaVirtualMachine.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/JavaVirtualMachine.h	Tue Mar 31 08:15:48 2015 -0700
@@ -67,4 +67,6 @@
     void ShutdownJVM();
 };
 
+bool RunVM();
+
 #endif //JAVAVIRTUALMACHINE_H
--- a/modules/fxpackager/src/main/native/library/common/LinuxPlatform.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/LinuxPlatform.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -108,32 +108,39 @@
     TString home = GetEnv(_T("HOME"));
 
     if (home.empty() == false) {
-        result += FilePath::IncludeTrailingSlash(home) + _T(".local");
+        result += FilePath::IncludeTrailingSeparater(home) + _T(".local");
     }
 
     return result;
 }
 
-PropertyContainer* LinuxPlatform::GetConfigFile(TString FileName) {
-    return new PropertyFile(FileName);
+ISectionalPropertyContainer* LinuxPlatform::GetConfigFile(TString FileName) {
+    IniFile *result = new IniFile();
+
+    if (result->LoadFromFile(FileName) == false) {
+        // New property file format was not found, attempt to load old property file format.
+        Helpers::LoadOldConfigFile(FileName, result);
+    }
+
+    return result;
 }
 
 TString LinuxPlatform::GetBundledJVMLibraryFileName(TString RuntimePath) {
-    TString result = FilePath::IncludeTrailingSlash(RuntimePath) +
+    TString result = FilePath::IncludeTrailingSeparater(RuntimePath) +
         "jre/lib/"JAVAARCH"/client/libjvm.so";
 
     if (FilePath::FileExists(result) == false) {
-        result = FilePath::IncludeTrailingSlash(RuntimePath) +
+        result = FilePath::IncludeTrailingSeparater(RuntimePath) +
             "jre/lib/"JAVAARCH"/server/libjvm.so";
     }
 
     if (FilePath::FileExists(result) == false) {
-        result = FilePath::IncludeTrailingSlash(RuntimePath) +
+        result = FilePath::IncludeTrailingSeparater(RuntimePath) +
             "lib/"JAVAARCH"/server/libjvm.so";
     }
 
     if (FilePath::FileExists(result) == false) {
-        result = FilePath::IncludeTrailingSlash(RuntimePath) +
+        result = FilePath::IncludeTrailingSeparater(RuntimePath) +
             "lib/"JAVAARCH"/server/libjvm.so";
     }
 
@@ -141,14 +148,19 @@
 }
 
 TString LinuxPlatform::GetSystemJRE() {
+    if (GetAppCDSState() == cdsOn || GetAppCDSState() == cdsGenCache) {
+        //TODO throw exception
+        return _T("");
+    }
+
     TString result;
     TString jreHome = GetEnv("JRE_HOME");
 
     if (jreHome.empty() == false) {
-        result = FilePath::IncludeTrailingSlash(jreHome);
+        result = FilePath::IncludeTrailingSeparater(jreHome);
 
         if (FilePath::FileExists(result + _T("lib/rt.jar")) == false) {
-            result = FilePath::IncludeTrailingSlash(jreHome) + _T("jre");
+            result = FilePath::IncludeTrailingSeparater(jreHome) + _T("jre");
 
             if (FilePath::FileExists(result + _T("/lib/rt.jar")) == false) {
                 //check redhat location
@@ -173,11 +185,11 @@
     TString jreHome = GetSystemJRE();
 
     if (jreHome.empty() == false && FilePath::DirectoryExists(jreHome) == true) {
-        result = FilePath::IncludeTrailingSlash(jreHome) +
+        result = FilePath::IncludeTrailingSeparater(jreHome) +
             _T("/lib/"JAVAARCH"/client/libjvm.so");
 
         if (FilePath::FileExists(result) == false) {
-            result = FilePath::IncludeTrailingSlash(jreHome) +
+            result = FilePath::IncludeTrailingSeparater(jreHome) +
                 _T("/lib/"JAVAARCH"/server/libjvm.so");
         }
     }
@@ -204,11 +216,11 @@
     // a typical prog uses only stdin=0, stdout=1, stderr=2.
     bool result = false;
     FILE *fd = fopen("/tmp", "r");
-    
+
     if (fileno(fd) > 5) {
         result = true;
     }
-    
+
     fclose(fd);
     return result;
 }
@@ -1025,9 +1037,9 @@
     TString result;
     struct passwd *pw = getpwuid(getuid());
     TString homedir = pw->pw_dir;
-    TString userOverrideFileName = FilePath::IncludeTrailingSlash(homedir) +
-        FilePath::IncludeTrailingSlash(_T(".java/.userPrefs")) +
-        FilePath::IncludeTrailingSlash(Appid) +
+    TString userOverrideFileName = FilePath::IncludeTrailingSeparater(homedir) +
+        FilePath::IncludeTrailingSeparater(_T(".java/.userPrefs")) +
+        FilePath::IncludeTrailingSeparater(Appid) +
         _T("JVMUserOptions/prefs.xml");
 
     if (FilePath::FileExists(userOverrideFileName) == true) {
@@ -1037,10 +1049,9 @@
     return result;
 }
 
-TOrderedMap ReadNode(XMLNode* node) {
-    TOrderedMap result;
+OrderedMap<TString, TString> ReadNode(XMLNode* node) {
+    OrderedMap<TString, TString> result;
     XMLNode* keyNode = FindXMLChild(node->_sub, _T("entry"));
-    int index = 1;
 
     while (keyNode != NULL) {
         TString key = FindXMLAttribute(keyNode->_attributes, _T("key"));
@@ -1048,19 +1059,15 @@
         keyNode = keyNode->_next;
 
         if (key.empty() == false) {
-            TValueIndex item;
-            item.value = value;
-            item.index = index;
-            result.insert(TOrderedMap::value_type(key, item));
-            index++;
+            result.Append(key, value);
         }
     }
 
     return result;
 }
 
-TOrderedMap GetJvmUserArgs(TString filename) {
-    TOrderedMap result;
+OrderedMap<TString, TString> GetJvmUserArgs(TString filename) {
+    OrderedMap<TString, TString> result;
 
     if (FilePath::FileExists(filename) == true) {
         //scan file for the key
--- a/modules/fxpackager/src/main/native/library/common/LinuxPlatform.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/LinuxPlatform.h	Tue Mar 31 08:15:48 2015 -0700
@@ -58,7 +58,7 @@
 
     virtual void ShowMessage(TString title, TString description);
     virtual void ShowMessage(TString description);
-    
+
     virtual TCHAR* ConvertStringToFileSystemString(TCHAR* Source, bool &release);
     virtual TCHAR* ConvertFileSystemStringToString(TCHAR* Source, bool &release);
 
@@ -72,7 +72,7 @@
     virtual TString GetSystemJVMLibraryFileName();
     virtual TString GetSystemJRE();
 
-    virtual PropertyContainer* GetConfigFile(TString FileName);
+    virtual ISectionalPropertyContainer* GetConfigFile(TString FileName);
 
     virtual bool IsMainThread();
     virtual TPlatformNumber GetMemorySize();
--- a/modules/fxpackager/src/main/native/library/common/Lock.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Lock.h	Tue Mar 31 08:15:48 2015 -0700
@@ -49,7 +49,7 @@
 #ifdef POSIX
     pthread_mutex_t FMutex;
 #endif //POSIX
-    
+
     void Initialize();
 
 public:
--- a/modules/fxpackager/src/main/native/library/common/MacPlatform.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/MacPlatform.h	Tue Mar 31 08:15:48 2015 -0700
@@ -54,7 +54,7 @@
 public:
     virtual void ShowMessage(TString title, TString description);
     virtual void ShowMessage(TString description);
-    
+
     virtual TCHAR* ConvertStringToFileSystemString(TCHAR* Source, bool &release);
     virtual TCHAR* ConvertFileSystemStringToString(TCHAR* Source, bool &release);
 
@@ -66,14 +66,14 @@
     virtual TString GetSystemJRE();
     virtual TString GetAppName();
 
-    virtual PropertyContainer* GetConfigFile(TString FileName);
+    virtual ISectionalPropertyContainer* GetConfigFile(TString FileName);
     virtual TString GetModuleFileName();
 
     virtual bool IsMainThread();
     virtual TPlatformNumber GetMemorySize();
 
     virtual std::map<TString, TString> GetKeys();
-    
+
 #ifdef DEBUG
     virtual bool IsNativeDebuggerPresent();
     virtual int GetProcessID();
@@ -84,7 +84,7 @@
 class MacJavaUserPreferences : public JavaUserPreferences {
 public:
   MacJavaUserPreferences(void);
-    
+
   virtual bool Load(TString Appid);
 };
 
--- a/modules/fxpackager/src/main/native/library/common/MacPlatform.mm	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/MacPlatform.mm	Tue Mar 31 08:15:48 2015 -0700
@@ -38,6 +38,8 @@
 #include "MacPlatform.h"
 #include "Helpers.h"
 #include "Package.h"
+#include "PropertyFile.h"
+#include "IniFile.h"
 
 #include <sys/sysctl.h>
 #include <pthread.h>
@@ -90,12 +92,12 @@
     TCHAR* result = NULL;
     release = false;
     CFStringRef StringRef = CFStringCreateWithCString(kCFAllocatorDefault, Source, kCFStringEncodingUTF8);
-    
+
     if (StringRef != NULL) {
         @try {
             CFIndex length = CFStringGetMaximumSizeOfFileSystemRepresentation(StringRef);
             result = new char[length + 1];
-            
+
             if (CFStringGetFileSystemRepresentation(StringRef, result, length)) {
                 release = true;
             }
@@ -108,7 +110,7 @@
             CFRelease(StringRef);
         }
     }
-    
+
     return result;
 }
 
@@ -116,16 +118,16 @@
     TCHAR* result = NULL;
     release = false;
     CFStringRef StringRef = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, Source);
-    
+
     if (StringRef != NULL) {
         @try {
             CFIndex length = CFStringGetLength(StringRef);
-            
+
             if (length > 0) {
                 CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
-                
+
                 result = new char[maxSize + 1];
-                
+
                 if (CFStringGetCString(StringRef, result, maxSize, kCFStringEncodingUTF8) == true) {
                     release = true;
                 }
@@ -139,7 +141,7 @@
             CFRelease(StringRef);
         }
     }
-    
+
     return result;
 }
 
@@ -166,10 +168,10 @@
 TString MacPlatform::GetBundledJVMLibraryFileName(TString RuntimePath) {
     TString result;
 
-    result = FilePath::IncludeTrailingSlash(RuntimePath) + _T("Contents/Home/jre/lib/jli/libjli.dylib");
+    result = FilePath::IncludeTrailingSeparater(RuntimePath) + _T("Contents/Home/jre/lib/jli/libjli.dylib");
 
     if (FilePath::FileExists(result) == false) {
-        result = FilePath::IncludeTrailingSlash(RuntimePath) + _T("Contents/Home/lib/jli/libjli.dylib");
+        result = FilePath::IncludeTrailingSeparater(RuntimePath) + _T("Contents/Home/lib/jli/libjli.dylib");
 
         if (FilePath::FileExists(result) == false) {
             result = _T("");
@@ -181,6 +183,11 @@
 
 
 TString MacPlatform::GetSystemJRE() {
+    if (GetAppCDSState() == cdsOn || GetAppCDSState() == cdsGenCache) {
+        //TODO throw exception
+        return _T("");
+    }
+
     return _T("/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/jli/libjli.dylib");
 }
 
@@ -200,79 +207,138 @@
     return result;
 }
 
-// Convert parts of the info.plist to the INI format the rest of the packager uses unless
-// a packager config file exists.
-PropertyContainer* MacPlatform::GetConfigFile(TString FileName) {
-    if (UsePListForConfigFile() == false) {
-        return new PropertyFile(FileName);
+void AppendPListArrayToIniFile(NSDictionary *infoDictionary, IniFile *result, TString Section) {
+    NSString *sectionKey = [NSString stringWithUTF8String:PlatformString(Section).toMultibyte()];
+    NSDictionary *array = [infoDictionary objectForKey:sectionKey];
+
+    for (id option in array) {
+        if ([option isKindOfClass:[NSString class]]) {
+            TString arg = [option UTF8String];
+
+            TString name;
+            TString value;
+
+            if (Helpers::SplitOptionIntoNameValue(arg, name, value) == true) {
+                result->Append(Section, name, value);
+            }
+        }
+    }
+}
+
+void AppendPListDictionaryToIniFile(NSDictionary *infoDictionary, IniFile *result, TString Section, bool FollowSection = true) {
+    NSDictionary *dictionary = NULL;
+
+    if (FollowSection == true) {
+        NSString *sectionKey = [NSString stringWithUTF8String:PlatformString(Section).toMultibyte()];
+        dictionary = [infoDictionary objectForKey:sectionKey];
+    }
+    else {
+        dictionary = infoDictionary;
     }
 
-    NSBundle *mainBundle = [NSBundle mainBundle];
-    NSDictionary *infoDictionary = [mainBundle infoDictionary];
-
-    std::map<TString, TString> data;
-
-    // Packager options.
-    for (id key in [infoDictionary allKeys]) {
-        id option = [infoDictionary valueForKey:key];
+    for (id key in dictionary) {
+        id option = [dictionary valueForKey:key];
 
         if ([key isKindOfClass:[NSString class]] && [option isKindOfClass:[NSString class]]) {
             TString name = [key UTF8String];
             TString value = [option UTF8String];
-            data.insert(std::map<TString, TString>::value_type(name, value));
+            result->Append(Section, name, value);
         }
     }
+}
 
-    // jvmargs
-    NSArray *options = [infoDictionary objectForKey:@"JVMOptions"];
-    int index = 1;
+// Convert parts of the info.plist to the INI format the rest of the packager uses unless
+// a packager config file exists.
+ISectionalPropertyContainer* MacPlatform::GetConfigFile(TString FileName) {
+    IniFile* result = new IniFile();
 
-    for (id option in options) {
-        if ([option isKindOfClass:[NSString class]]) {
-            TString value = [option UTF8String];
-            TString argname = TString(_T("jvmarg.")) + PlatformString(index).toString();
-            data.insert(std::map<TString, TString>::value_type(argname, value));
-            index++;
+    if (UsePListForConfigFile() == false) {
+        if (result->LoadFromFile(FileName) == false) {
+            // New property file format was not found, attempt to load old property file format.
+            Helpers::LoadOldConfigFile(FileName, result);
         }
     }
+    else {
+        NSBundle *mainBundle = [NSBundle mainBundle];
+        NSDictionary *infoDictionary = [mainBundle infoDictionary];
+        std::map<TString, TString> keys = GetKeys();
 
-    // jvmuserargs
-    NSDictionary *defaultOverrides = [infoDictionary objectForKey:@"JVMUserOptions"];
-    index = 1;
+        // Packager options.
+        AppendPListDictionaryToIniFile(infoDictionary, result, keys[CONFIG_SECTION_APPLICATION], false);
 
-    for (id key in defaultOverrides) {
-        id option = [defaultOverrides valueForKey:key];
+        // jvmargs
+        AppendPListArrayToIniFile(infoDictionary, result, keys[CONFIG_SECTION_JVMOPTIONS]);
 
-        if ([key isKindOfClass:[NSString class]] && [option isKindOfClass:[NSString class]]) {
-            TString name = [key UTF8String];
-            TString value = [option UTF8String];
-            TString prefix = TString(_T("jvmuserarg.")) + PlatformString(index).toString();
-            TString argname = prefix + _T(".name");
-            TString argvalue = prefix + _T(".value");
-            data.insert(std::map<TString, TString>::value_type(argname, name));
-            data.insert(std::map<TString, TString>::value_type(argvalue, value));
-            index++;
+        // jvmuserargs
+        AppendPListDictionaryToIniFile(infoDictionary, result, keys[CONFIG_SECTION_JVMUSEROPTIONS]);
+
+        // Generate AppCDS Cache
+        AppendPListDictionaryToIniFile(infoDictionary, result, keys[CONFIG_SECTION_APPCDSJVMOPTIONS]);
+        AppendPListDictionaryToIniFile(infoDictionary, result, keys[CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS]);
+
+        // args
+        AppendPListArrayToIniFile(infoDictionary, result, keys[CONFIG_SECTION_ARGOPTIONS]);
+    }
+
+    return result;
+}
+/*
+#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
+#include <dlfcn.h>
+#include <string>
+
+std::string GetModuleFileName(const void *module)
+{
+    if (!module) { return std::string(); }
+    uint32_t count = _dyld_image_count();
+    for (uint32_t i = 0; i < count; ++i) {
+        const mach_header *header = _dyld_get_image_header(i);
+        if (!header) { break; }
+        char *code_ptr = NULL;
+        if ((header->magic & MH_MAGIC_64) == MH_MAGIC_64) {
+            uint64_t size;
+            code_ptr = getsectdatafromheader_64((const mach_header_64 *)header, SEG_TEXT, SECT_TEXT, &size);
+        } else {
+            uint32_t size;
+            code_ptr = getsectdatafromheader(header, SEG_TEXT, SECT_TEXT, &size);
+        }
+        if (!code_ptr) { continue; }
+        const uintptr_t slide = _dyld_get_image_vmaddr_slide(i);
+        const uintptr_t start = (const uintptr_t)code_ptr + slide;
+        Dl_info info;
+        if (dladdr((const void *)start, &info)) {
+            if (dlopen(info.dli_fname, RTLD_NOW) == module) {
+                return std::string(info.dli_fname);
+            }
         }
     }
+    return std::string();
+}*/
 
-    // args
-    NSDictionary *args = [infoDictionary objectForKey:@"ArgOptions"];
-    index = 1;
+TString GetModuleFileNameOSX() {
+    Dl_info module_info;
+    if (dladdr(reinterpret_cast<void*>(GetModuleFileNameOSX), &module_info) == 0) {
+        // Failed to find the symbol we asked for.
+        return std::string();
+    }
+    return TString(module_info.dli_fname);
+}
 
-    for (id option in args) {
-        if ([option isKindOfClass:[NSString class]]) {
-            TString value = [option UTF8String];
-            TString argname = TString(_T("arg.")) + PlatformString(index).toString();
-            data.insert(std::map<TString, TString>::value_type(argname, value));
-            index++;
-        }
+#include <mach-o/dyld.h>
+
+TString MacPlatform::GetModuleFileName() {
+    //return GetModuleFileNameOSX();
+
+    TString result;
+    DynamicBuffer<TCHAR> buffer(MAX_PATH);
+    uint32_t size = buffer.GetSize();
+
+    if (_NSGetExecutablePath(buffer.GetData(), &size) == 0) {
+        result = FileSystemStringToString(buffer.GetData());
     }
 
-    return new PropertyFile(data);
-}
-
-TString MacPlatform::GetModuleFileName() {
-    return "";
+    return result;
 }
 
 bool MacPlatform::IsMainThread() {
@@ -293,34 +359,44 @@
         return GenericPlatform::GetKeys();
     }
     else {
+        keys.insert(std::map<TString, TString>::value_type(CONFIG_VERSION,            _T("app.version")));
         keys.insert(std::map<TString, TString>::value_type(CONFIG_MAINJAR_KEY,        _T("JVMMainJarName")));
         keys.insert(std::map<TString, TString>::value_type(CONFIG_MAINCLASSNAME_KEY,  _T("JVMMainClassName")));
         keys.insert(std::map<TString, TString>::value_type(CONFIG_CLASSPATH_KEY,      _T("JVMAppClasspath")));
         keys.insert(std::map<TString, TString>::value_type(APP_NAME_KEY,              _T("CFBundleName")));
-        keys.insert(std::map<TString, TString>::value_type(CONFIG_SPLASH_KEY,         _T("app.splash")));
         keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_ID_KEY,         _T("JVMPreferencesID")));
         keys.insert(std::map<TString, TString>::value_type(JVM_RUNTIME_KEY,           _T("JVMRuntime")));
         keys.insert(std::map<TString, TString>::value_type(PACKAGER_APP_DATA_DIR,     _T("CFBundleIdentifier")));
+
+        keys.insert(std::map<TString, TString>::value_type(CONFIG_SPLASH_KEY,         _T("app.splash")));
         keys.insert(std::map<TString, TString>::value_type(CONFIG_APP_MEMORY,         _T("app.memory")));
+
+        keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_APPLICATION,    _T("Application")));
+        keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_JVMOPTIONS,     _T("JVMOptions")));
+        keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_JVMUSEROPTIONS, _T("JVMUserOptions")));
+        keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS, _T("JVMUserOverrideOptions")));
+        keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_APPCDSJVMOPTIONS, _T("AppCDSJVMOptions")));
+        keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS, _T("AppCDSGenerateCacheJVMOptions")));
+        keys.insert(std::map<TString, TString>::value_type(CONFIG_SECTION_ARGOPTIONS,     _T("ArgOptions")));
     }
 
     return keys;
 }
 
-#ifdef DEBUG 
+#ifdef DEBUG
 bool MacPlatform::IsNativeDebuggerPresent() {
     int state;
     int mib[4];
     struct kinfo_proc info;
     size_t size;
-    
+
     info.kp_proc.p_flag = 0;
-    
+
     mib[0] = CTL_KERN;
     mib[1] = KERN_PROC;
     mib[2] = KERN_PROC_PID;
     mib[3] = getpid();
-    
+
     size = sizeof(info);
     state = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
     assert(state == 0);
@@ -337,87 +413,80 @@
 
 class UserDefaults {
 private:
-    TOrderedMap FData;
+    OrderedMap<TString, TString> FData;
     TString FDomainName;
-    
-    bool ReadDictionary(NSDictionary *Items, TOrderedMap &Data) {
+
+    bool ReadDictionary(NSDictionary *Items, OrderedMap<TString, TString> &Data) {
         bool result = false;
-        int index = 1;
-        
+
         for (id key in Items) {
             id option = [Items valueForKey:key];
-            
+
             if ([key isKindOfClass:[NSString class]] && [option isKindOfClass:[NSString class]]) {
                 TString name = [key UTF8String];
                 TString value = [option UTF8String];
-                
+
                 if (name.empty() == false) {
-                    TValueIndex item;
-                    item.value = value;
-                    item.index = index;
-                    
-                    Data.insert(TOrderedMap::value_type(name, item));
-                    result = true;
-                    index++;
+                    Data.Append(name, value);
                 }
             }
         }
-        
+
         return result;
     }
-    
+
     // Open and read the defaults file specified by domain.
-    bool ReadPreferences(NSDictionary *Defaults, std::list<TString> Keys, TOrderedMap &Data) {
+    bool ReadPreferences(NSDictionary *Defaults, std::list<TString> Keys, OrderedMap<TString, TString> &Data) {
         bool result = false;
-        
+
         if (Keys.size() > 0 && Defaults != NULL) {
             NSDictionary *node = Defaults;
-            
+
             while (Keys.size() > 0 && node != NULL) {
                 TString key = Keys.front();
                 Keys.pop_front();
                 NSString *tempKey = StringToNSString(key);
                 node = [node valueForKey:tempKey];
-                
+
                 if (Keys.size() == 0) {
                     break;
                 }
             }
-            
+
             if (node != NULL) {
                 result = ReadDictionary(node, Data);
             }
         }
-        
+
         return result;
     }
-    
+
     NSDictionary* LoadPreferences(TString DomainName) {
         NSDictionary *result = NULL;
-        
+
         if (DomainName.empty() == false) {
             NSUserDefaults *prefs = [[NSUserDefaults alloc] init];
-            
+
             if (prefs != NULL) {
                 NSString *lDomainName = StringToNSString(DomainName);
                 result = [prefs persistentDomainForName: lDomainName];
             }
         }
-        
+
         return result;
     }
-    
+
 public:
     UserDefaults(TString DomainName) {
         FDomainName = DomainName;
     }
-    
+
     bool Read(std::list<TString> Keys) {
         NSDictionary *defaults = LoadPreferences(FDomainName);
         return ReadPreferences(defaults, Keys, FData);
     }
-    
-    TOrderedMap GetData() {
+
+    OrderedMap<TString, TString> GetData() {
         return FData;
     }
 };
@@ -440,13 +509,13 @@
     std::list<TString> result;
     std::vector<char> buffer(Value.c_str(), Value.c_str() + Value.size() + 1);
     char *p = strtok(&buffer[0], Delimiter.data());
-    
+
     while (p != NULL) {
         TString token = p;
         result.push_back(token);
         p = strtok(NULL, Delimiter.data());
     }
-    
+
     return result;
 }
 
@@ -502,17 +571,17 @@
 // Since OS 10.9 Mavericks the defaults are cashed so directly modifying the files is not recommended.
 bool MacJavaUserPreferences::Load(TString Appid) {
     bool result = false;
-    
+
     if (Appid.empty() == false) {
         // This is for backwards compatability. Older packaged applications have an
         // app.preferences.id that is delimited by period (".") rather than
         // slash ("/") so convert to newer style.
         TString path = Helpers::ReplaceString(Appid, _T("."), _T("/"));
-        
+
         path = path + _T("/JVMUserOptions");
         TString domainName;
         std::list<TString> keys = Split(path, _T("/"));
-        
+
         // If there are less than three parts to the path then use the default preferences file.
         if (keys.size() < 3) {
             domainName = _T("com.apple.java.util.prefs");
@@ -523,7 +592,7 @@
                 item = item + _T("/");
                 *iterator = item;
             }
-            
+
             // The root key is /.
             keys.push_front(_T("/"));
         }
@@ -537,27 +606,27 @@
             keys.pop_front();
             domainName = one + TString(".") + two + TString(".") + three;
             domainName = toLowerCase(domainName);
-            
+
             // Append slash to the end of each key.
             for (std::list<TString>::iterator iterator = keys.begin(); iterator != keys.end(); iterator++) {
                 TString item = *iterator;
                 item = item + _T("/");
                 *iterator = item;
             }
-            
+
             // The root key is /one/two/three/
             TString key = TString("/") + one + TString("/") + two + TString("/") + three + TString("/");
             keys.push_front(key);
         }
 
         UserDefaults userDefaults(domainName);
-        
+
         if (userDefaults.Read(keys) == true) {
             result = true;
             FMap = userDefaults.GetData();
         }
     }
-    
+
     return result;
 }
 
--- a/modules/fxpackager/src/main/native/library/common/Macros.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Macros.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -45,15 +45,19 @@
 void Macros::Initialize() {
     Package& package = Package::GetInstance();
     Macros& macros = Macros::GetInstance();
-    
+
     // Public macros.
     macros.AddMacro(_T("$APPDIR"), package.GetPackageRootDirectory());
     macros.AddMacro(_T("$PACKAGEDIR"), package.GetPackageAppDirectory());
     macros.AddMacro(_T("$LAUNCHERDIR"), package.GetPackageLauncherDirectory());
-    
+    macros.AddMacro(_T("$APPDATADIR"), package.GetAppDataDirectory());
+
     TString javaHome = FilePath::ExtractFilePath(package.GetJVMLibraryFileName());
     macros.AddMacro(_T("$JREHOME"), javaHome);
-    
+
+    // App CDS Macros
+    macros.AddMacro(_T("$CACHEDIR"), package.GetAppCDSCacheDirectory());
+
     // Private macros.
     TString javaVMLibraryName = FilePath::ExtractFileName(javaHome);
     macros.AddMacro(_T("$JAVAVMLIBRARYNAME"), javaVMLibraryName);
--- a/modules/fxpackager/src/main/native/library/common/Messages.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Messages.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -50,10 +50,11 @@
     FMessages.SetValue(ERROR_INVOKING_METHOD, _T("Error invoking method."));
     //FMessages.SetValue(CONFIG_FILE_NOT_FOUND, _T("Configuration file %s is not found."));
     //FMessages.SetValue(BUNDLED_JVM_NOT_FOUND, _T("$JAVAVMLIBRARYNAME is not found in the bundled runtime."));
+    FMessages.SetValue(APPCDS_CACHE_FILE_NOT_FOUND, _T("Error: AppCDS cache does not exists:\n\n%s"));
 }
 
 Messages& Messages::GetInstance() {
-    Lock lock;
+    //Lock lock;
     static Messages instance; // Guaranteed to be destroyed. Instantiated on first use.
     return instance;
 }
--- a/modules/fxpackager/src/main/native/library/common/Messages.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Messages.h	Tue Mar 31 08:15:48 2015 -0700
@@ -49,6 +49,7 @@
 
 #define BUNDLED_JVM_NOT_FOUND _T("bundled.jvm.not.found")
 
+#define APPCDS_CACHE_FILE_NOT_FOUND _T("appcds.cache.file.not.found")
 
 class Messages {
 private:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/native/library/common/OrderedMap.h	Tue Mar 31 08:15:48 2015 -0700
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates.
+ * All rights reserved. Use is subject to license terms.
+ *
+ * This file is available and licensed under the following license:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  - Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the distribution.
+ *  - Neither the name of Oracle Corporation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ORDEREDMAP_H
+#define ORDEREDMAP_H
+
+#include <map>
+#include <vector>
+#include <assert.h>
+#include <stdexcept>
+
+#include <iostream>
+
+
+template <typename _T1, typename _T2>
+struct pair
+{
+    typedef _T1 first_type;
+    typedef _T2 second_type;
+
+    first_type first;
+    second_type second;
+
+    pair(first_type Value1, second_type Value2) {
+        first = Value1;
+        second = Value2;
+    }
+};
+
+
+template <typename TKey, typename TValue>
+class OrderedMap {
+public:
+    typedef TKey key_type;
+    typedef TValue mapped_type;
+    typedef pair<key_type, mapped_type> container_type;
+
+private:
+    typedef std::map<key_type, container_type*> map_type;
+    typedef std::vector<container_type*> list_type;
+
+public:
+    typedef typename list_type::const_iterator const_iterator;
+
+private:
+    map_type FMap;
+    list_type FList;
+
+    typename list_type::iterator FindListItem(const key_type Key) {
+        typename list_type::iterator result = FList.end();
+
+        for (typename list_type::iterator iterator = FList.begin(); iterator != FList.end(); iterator++) {
+            container_type *item = *iterator;
+
+            if (item->first == Key) {
+                result = iterator;
+                break;
+            }
+        }
+
+        return result;
+    }
+
+public:
+    OrderedMap() {
+    }
+
+    OrderedMap(const OrderedMap<key_type, mapped_type> &Value) {
+        Append(Value);
+    }
+
+    ~OrderedMap() {
+        Clear();
+    }
+
+    void Clear() {
+        for (typename list_type::iterator iterator = FList.begin(); iterator != FList.end(); iterator++) {
+            container_type *item = *iterator;
+
+            if (item != NULL) {
+                delete item;
+                item = NULL;
+            }
+        }
+
+        FMap.clear();
+        FList.clear();
+    }
+
+    bool ContainsKey(key_type Key) {
+        bool result = false;
+
+        if (FMap.find(Key) != FMap.end()) {
+            result = true;
+        }
+
+        return result;
+    }
+
+    std::vector<key_type> GetKeys() {
+        std::vector<key_type> result;
+
+        for (typename list_type::const_iterator iterator = FList.begin();
+             iterator != FList.end(); iterator++) {
+            container_type *item = *iterator;
+            result.push_back(item->first);
+        }
+
+        return result;
+    }
+
+    void Assign(const OrderedMap<key_type, mapped_type> &Value) {
+        Clear();
+        Append(Value);
+    }
+
+    void Append(const OrderedMap<key_type, mapped_type> &Value) {
+        for (size_t index = 0; index < Value.FList.size(); index++) {
+            container_type *item = Value.FList[index];
+            Append(item->first, item->second);
+        }
+    }
+
+    void Append(key_type Key, mapped_type Value) {
+        container_type *item = new container_type(Key, Value);
+        FMap.insert(std::pair<key_type, container_type*>(Key, item));
+        FList.push_back(item);
+    }
+
+    bool RemoveByKey(key_type Key) {
+        bool result = false;
+        typename list_type::iterator iterator = FindListItem(Key);
+
+        if (iterator != FList.end()) {
+            FMap.erase(Key);
+            FList.erase(iterator);
+            result = true;
+        }
+
+        return result;
+    }
+
+    bool GetValue(key_type Key, mapped_type &Value) {
+        bool result = false;
+        container_type* item = FMap[Key];
+
+        if (item != NULL) {
+            Value = item->second;
+            result = true;
+        }
+
+        return result;
+    }
+
+    bool SetValue(key_type Key, mapped_type &Value) {
+        bool result = false;
+
+        if (ContainsKey(Key) == true) {
+            container_type *item = FMap[Key];
+
+            if (item != NULL) {
+                item->second = Value;
+                result = true;
+            }
+        }
+        else {
+            Append(Key, Value);
+            result = true;
+        }
+
+        return result;
+    }
+
+    mapped_type &operator[](key_type Key) {
+        container_type* item = FMap[Key];
+        assert(item != NULL);
+
+        if (item != NULL) {
+            return item->second;
+        }
+
+        throw std::invalid_argument("Key not found");
+    }
+
+    size_t Count() {
+        return FList.size();
+    }
+
+    typename OrderedMap::const_iterator begin() {
+        return FList.begin();
+    }
+
+    typename OrderedMap::const_iterator end() {
+        return FList.end();
+    }
+};
+
+#endif //ORDEREDMAP_H
--- a/modules/fxpackager/src/main/native/library/common/Package.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Package.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -1,4 +1,4 @@
- /*
+/*
  * Copyright (c) 2014, 2015, Oracle and/or its affiliates.
  * All rights reserved. Use is subject to license terms.
  *
@@ -36,11 +36,13 @@
 #include "Helpers.h"
 #include "JavaUserPreferences.h"
 #include "Macros.h"
+#include "IniFile.h"
 
 #include <assert.h>
 
 
 Package::Package(void) {
+    FInitialized = false;
     Initialize();
 }
 
@@ -56,117 +58,206 @@
 }
 
 void Package::Initialize() {
+    if (FInitialized == true) {
+        return;
+    }
+
     Platform& platform = Platform::GetInstance();
 
     FBootFields = new PackageBootFields();
     FDebugging = dsNone;
-    std::map<TString, TString> keys = platform.GetKeys();
 
     FBootFields->FPackageRootDirectory = platform.GetPackageRootDirectory();
     FBootFields->FPackageAppDirectory = platform.GetPackageAppDirectory();
     FBootFields->FPackageLauncherDirectory = platform.GetPackageLauncherDirectory();
+    FBootFields->FAppDataDirectory = platform.GetAppDataDirectory();
+
+    std::map<TString, TString> keys = platform.GetKeys();
 
     // Read from configure.cfg/Info.plist
+    AutoFreePtr<ISectionalPropertyContainer> config = platform.GetConfigFile(platform.GetConfigFileName());
 
-    AutoFreePtr<PropertyContainer> config = platform.GetConfigFile(platform.GetConfigFileName());
-    config->GetValue(keys[CONFIG_APP_ID_KEY], FBootFields->FAppID);
-    config->GetValue(keys[PACKAGER_APP_DATA_DIR], FBootFields->FPackageAppDataDirectory);
-    
-    // Auto Memory.
-    TString temp;
-    config->GetValue(keys[CONFIG_APP_MEMORY], temp);
-    
-    if (temp == _T("auto") || temp == _T("100%")) {
-        FBootFields->FMemoryState = PackageBootFields::msAuto;
-        FBootFields->FMemorySize = platform.GetMemorySize();
-    }
-    else if (temp.length() == 2 && isdigit(temp[0]) && temp[1] == '%') {
-        FBootFields->FMemoryState = PackageBootFields::msAuto;
-        FBootFields->FMemorySize = StringToPercentageOfNumber(temp.substr(0, 1), platform.GetMemorySize());
-    }
-    else if (temp.length() == 3 && isdigit(temp[0]) && isdigit(temp[1]) && temp[2] == '%') {
-        FBootFields->FMemoryState = PackageBootFields::msAuto;
-        FBootFields->FMemorySize = StringToPercentageOfNumber(temp.substr(0, 2), platform.GetMemorySize());
-    }
-    else {
-        FBootFields->FMemoryState = PackageBootFields::msManual;
-        FBootFields->FMemorySize = 0;
-    }
+//    //config->SaveToFile("/Users/cbensen/Desktop/foo.txt");
+//    OrderedMap<TString, TString> m;
+//    IniFile temp;
+//    //temp.Append("Foo", m);
+//    temp.SaveToFile("/Users/cbensen/Desktop/foo.txt");
+
+
+    config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_APP_ID_KEY], FBootFields->FAppID);
+    config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[PACKAGER_APP_DATA_DIR], FBootFields->FPackageAppDataDirectory);
+    FBootFields->FPackageAppDataDirectory = FilePath::FixPathForPlatform(FBootFields->FPackageAppDataDirectory);
 
     // Main JAR.
-    config->GetValue(keys[CONFIG_MAINJAR_KEY], FBootFields->FMainJar);
-    FBootFields->FMainJar = FilePath::IncludeTrailingSlash(GetPackageAppDirectory()) + FBootFields->FMainJar;
+    config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_MAINJAR_KEY], FBootFields->FMainJar);
+    FBootFields->FMainJar = FilePath::IncludeTrailingSeparater(GetPackageAppDirectory()) +
+                            FilePath::FixPathForPlatform(FBootFields->FMainJar);
 
     // Classpath.
-    config->GetValue(keys[CONFIG_CLASSPATH_KEY], FBootFields->FClassPath);
+    // 1. If the provided class path contains main jar then only use provided class path.
+    // 2. If class path provided by config file is empty then add main jar.
+    // 3. If main jar is not in provided class path then add it.
+    config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_CLASSPATH_KEY], FBootFields->FClassPath);
+    FBootFields->FClassPath = FilePath::FixPathSeparatorForPlatform(FBootFields->FClassPath);
 
-    // 1. If class path provided by config file is empty then add main jar.
-    // 2. If the provided class path contains main jar then only use provided class path.
-    // 3. If main jar is not in provided class path then add it.
     if (FBootFields->FClassPath.empty() == true) {
         FBootFields->FClassPath = GetMainJar();
     }
-    else {
-        TString mainJarFileName = FilePath::ExtractFileName(GetMainJar());
-
-        if (FBootFields->FClassPath.find(mainJarFileName) != TString::npos) {
-            FBootFields->FClassPath = FilePath::FixPathSeparatorForPlatform(FBootFields->FClassPath);
-        }
-        else {
-            FBootFields->FClassPath = GetMainJar() + FilePath::PathSeparator() +
-                FilePath::FixPathSeparatorForPlatform(FBootFields->FClassPath);
-        }
+    else if (FBootFields->FClassPath.find(GetMainJar()) == TString::npos) {
+        FBootFields->FClassPath = GetMainJar() + FilePath::PathSeparator() + FBootFields->FClassPath;
     }
 
-    config->GetValue(keys[CONFIG_MAINCLASSNAME_KEY], FBootFields->FMainClassName);
+    // Main Class.
+    config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_MAINCLASSNAME_KEY], FBootFields->FMainClassName);
 
-    if (config->GetValue(keys[CONFIG_SPLASH_KEY], FBootFields->FSplashScreenFileName) == true) {
-        FBootFields->FSplashScreenFileName = FilePath::IncludeTrailingSlash(GetPackageAppDirectory()) + FBootFields->FSplashScreenFileName;
+    // Splash Screen.
+    if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_SPLASH_KEY], FBootFields->FSplashScreenFileName) == true) {
+        FBootFields->FSplashScreenFileName = FilePath::IncludeTrailingSeparater(GetPackageAppDirectory()) +
+                                             FilePath::FixPathForPlatform(FBootFields->FSplashScreenFileName);
 
         if (FilePath::FileExists(FBootFields->FSplashScreenFileName) == false) {
             FBootFields->FSplashScreenFileName = _T("");
         }
     }
 
+    // Runtime.
     FBootFields->FIsRuntimeBundled = true;
-    config->GetValue(keys[JVM_RUNTIME_KEY], FBootFields->FJVMRuntimeDirectory);
-    
+    config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[JVM_RUNTIME_KEY], FBootFields->FJVMRuntimeDirectory);
+
     if (FBootFields->FJVMRuntimeDirectory.empty()) {
         FBootFields->FIsRuntimeBundled = false;
         FBootFields->FJVMRuntimeDirectory = platform.GetSystemJRE();
     }
 
+    // Special
+    // If running with AppCDS on, and the configuration has been setup so "auto" is enabled, then
+    // the launcher will attempt to generate the cache file automatically and run the application. If the app fails
+    // to launch, this is saved and AppCDS is disabled for subsequent runs.
+    if (platform.GetAppCDSState() == cdsOn) {
+        TString appCDSCacheValue;
+
+        if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], _T("app.appcds.cache"), appCDSCacheValue) == true &&
+            appCDSCacheValue == _T("auto")) {
+            platform.SetAppCDSState(cdsAuto);
+        }
+    }
+
     // Read args if none were passed in.
     if (FBootFields->FArgs.size() == 0) {
-        FBootFields->FArgs = Helpers::GetArgsFromConfig(config);
-    }  
+        OrderedMap<TString, TString> args;
 
-    // Read all jvmargs.
-    FBootFields->FJVMArgs = Helpers::GetJVMArgsFromConfig(config);
+        if (config->GetSection(keys[CONFIG_SECTION_ARGOPTIONS], args) == true) {
+            FBootFields->FArgs = Helpers::MapToNameValueList(args);
+        }
+    }
 
-    // Read all jvmuserarg defaults.
-    FDefaultJVMUserArgs = Helpers::GetJVMUserArgsFromConfig(config);
+    // Read jvmargs.
+
+    ReadJVMArgs(config);
+
+    // Read jvmuserarg defaults.
+    config->GetSection(keys[CONFIG_SECTION_JVMUSEROPTIONS], FDefaultJVMUserArgs);
 
     // Load JVM user overrides.
     TString jvmUserArgsConfigFileName = GetJVMUserArgsConfigFileName();
 
     if (FilePath::FileExists(jvmUserArgsConfigFileName) == true) {
         // Load new location for user VM overrides.
-        AutoFreePtr<PropertyFile> userConfig = new PropertyFile(jvmUserArgsConfigFileName);
-        FJVMUserArgsOverrides = Helpers::GetJVMUserArgsFromConfig(userConfig);
+        IniFile userConfig;
+
+        if (userConfig.LoadFromFile(jvmUserArgsConfigFileName) == false) {
+            // New property file format was not found, attempt to load old property file format.
+            userConfig.GetSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], FJVMUserArgsOverrides);
+        }
+
+        userConfig.GetSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], FJVMUserArgsOverrides);
     }
     else {
         // Attemp to load java.util.prefs for legacy JVM user overrides.
-        AutoFreePtr<JavaUserPreferences> javaPreferences = JavaUserPreferences::CreateInstance();
+        AutoFreePtr<JavaUserPreferences> javaPreferences(JavaUserPreferences::CreateInstance());
 
         if (javaPreferences->Load(GetAppID()) == true) {
             FJVMUserArgsOverrides = javaPreferences->GetData();
         }
     }
 
+    // Auto Memory.
+    TString autoMemory;
+
+    if (config->GetValue(keys[CONFIG_SECTION_APPLICATION], keys[CONFIG_APP_MEMORY], autoMemory) == true) {
+        if (autoMemory == _T("auto") || autoMemory == _T("100%")) {
+            FBootFields->FMemoryState = PackageBootFields::msAuto;
+            FBootFields->FMemorySize = platform.GetMemorySize();
+        }
+        else if (autoMemory.length() == 2 && isdigit(autoMemory[0]) && autoMemory[1] == '%') {
+            FBootFields->FMemoryState = PackageBootFields::msAuto;
+            FBootFields->FMemorySize = StringToPercentageOfNumber(autoMemory.substr(0, 1), platform.GetMemorySize());
+        }
+        else if (autoMemory.length() == 3 && isdigit(autoMemory[0]) && isdigit(autoMemory[1]) && autoMemory[2] == '%') {
+            FBootFields->FMemoryState = PackageBootFields::msAuto;
+            FBootFields->FMemorySize = StringToPercentageOfNumber(autoMemory.substr(0, 2), platform.GetMemorySize());
+        }
+        else {
+            FBootFields->FMemoryState = PackageBootFields::msManual;
+            FBootFields->FMemorySize = 0;
+        }
+    }
+
     MergeJVMDefaultsWithOverrides();
 }
 
+void Package::Clear() {
+    FreeBootFields();
+    FJVMUserArgsOverrides.Clear();
+    FDefaultJVMUserArgs.Clear();
+    FJVMUserArgs.Clear();
+    FInitialized = false;
+}
+
+void Package::ReadJVMArgs(ISectionalPropertyContainer* Config) {
+    Platform& platform = Platform::GetInstance();
+    std::map<TString, TString> keys = platform.GetKeys();
+
+    if (Config->ContainsSection(keys[CONFIG_SECTION_APPCDSJVMOPTIONS]) == false) {
+        // If the AppCDS section is not present then disable AppCDS.
+        platform.SetAppCDSState(cdsNone);
+    }
+
+    switch (platform.GetAppCDSState()) {
+        case cdsNone: {
+            Config->GetSection(keys[CONFIG_SECTION_JVMOPTIONS], FBootFields->FJVMArgs);
+            break;
+        }
+
+        case cdsGenCache: {
+            Config->GetSection(keys[CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS], FBootFields->FJVMArgs);
+            break;
+        }
+
+        case cdsAuto:
+        case cdsOn: {
+            if (Config->GetValue(keys[CONFIG_SECTION_APPCDSJVMOPTIONS],
+                                 _T( "-XX:SharedArchiveFile"), FBootFields->FAppCDSCacheFileName) == true) {
+                // File names may contain the incorrect path separators. The cache file name must be
+                // corrected at this point.
+                if (FBootFields->FAppCDSCacheFileName.empty() == false) {
+                    IniFile* iniConfig = dynamic_cast<IniFile*>(Config);
+
+                    if (iniConfig != NULL) {
+                        FBootFields->FAppCDSCacheFileName = FilePath::FixPathForPlatform(FBootFields->FAppCDSCacheFileName);
+                        iniConfig->SetValue(keys[CONFIG_SECTION_APPCDSJVMOPTIONS],
+                                     _T( "-XX:SharedArchiveFile"), FBootFields->FAppCDSCacheFileName);
+                    }
+                }
+
+                Config->GetSection(keys[CONFIG_SECTION_APPCDSJVMOPTIONS], FBootFields->FJVMArgs);
+            }
+
+            break;
+        }
+    }
+}
+
 void Package::SetCommandLineArguments(int argc, TCHAR* argv[]) {
     if (argc > 0) {
         std::list<TString> args;
@@ -182,7 +273,7 @@
             if (arg == _T("-debug")) {
                 FDebugging = dsNative;
             }
-            
+
             if (arg == _T("-javadebug")) {
                 FDebugging = dsJava;
             }
@@ -221,85 +312,117 @@
 }
 
 Package::~Package(void) {
+    FreeBootFields();
 }
 
 void Package::FreeBootFields() {
-    delete FBootFields;
-    FBootFields = NULL;
+    if (FBootFields != NULL) {
+        delete FBootFields;
+        FBootFields = NULL;
+    }
 }
 
-TOrderedMap Package::GetJVMArgs() {
-    assert(FBootFields != NULL);
+OrderedMap<TString, TString> Package::GetJVMArgs() {
     return FBootFields->FJVMArgs;
 }
 
-TOrderedMap Package::GetDefaultJVMUserArgs() {
+OrderedMap<TString, TString> Package::GetDefaultJVMUserArgs() {
     return FDefaultJVMUserArgs;
 }
 
-TOrderedMap Package::GetJVMUserArgOverrides() {
-    return FJVMUserArgsOverrides;//Helpers::GetJVMUserArgsFromConfig(FJVMUserConfig);
+OrderedMap<TString, TString> Package::GetJVMUserArgOverrides() {
+    return FJVMUserArgsOverrides;
 }
 
-void Package::SetJVMUserArgOverrides(TOrderedMap Value) {
-    TOrderedMap defaults = GetDefaultJVMUserArgs();
-    TOrderedMap overrides = Value;
-    std::list<TString> overrideKeys = Helpers::GetOrderedKeysFromMap(overrides);
+std::vector<TString> GetKeysThatAreNotDuplicates(OrderedMap<TString, TString> &Defaults,
+                                               OrderedMap<TString, TString> &Overrides) {
+    std::vector<TString> result;
+    std::vector<TString> overrideKeys = Overrides.GetKeys();
 
-    // 1. Remove entries in the overrides that are the same as the defaults.
-    for (TOrderedMap::const_iterator iterator = overrides.begin();
-        iterator != overrides.end();
-        iterator++) {
+    for (size_t index = 0; index < overrideKeys.size(); index++) {
+        TString overridesKey = overrideKeys[index];
+        TString overridesValue;
+        TString defaultValue;
 
-        TString overridesKey = iterator->first;
-        TString overridesValue = iterator->second.value;
-        
-        if (defaults.find(overridesKey) != defaults.end()) {
-            TString defaultValue = defaults[overridesKey].value;
-            
-            if (defaultValue == overridesValue) {
-                overrideKeys.remove(overridesKey);
-            }
+        if (Defaults.GetValue(overridesKey, defaultValue) == true &&
+            Overrides.GetValue(overridesKey, overridesValue) == true &&
+            defaultValue != overridesValue) {
+            result.push_back(overridesKey);
         }
     }
 
+    return result;
+}
+
+OrderedMap<TString, TString> CreateOrderedMapFromKeyList(OrderedMap<TString, TString> &Map,
+                                                         std::vector<TString> &Keys) {
+    OrderedMap<TString, TString> result;
+
+    for (size_t index = 0; index < Keys.size(); index++) {
+        TString key = Keys[index];
+        TString value;
+
+        if (Map.GetValue(key, value) == true) {
+            result.Append(key, value);
+        }
+    }
+
+    return result;
+}
+
+void Package::SetJVMUserArgOverrides(OrderedMap<TString, TString> Value) {
+    OrderedMap<TString, TString> defaults = GetDefaultJVMUserArgs();
+    OrderedMap<TString, TString> overrides = Value;
+
+    // 1. Remove entries in the overrides that are the same as the defaults.
+    std::vector<TString> overrideKeys = GetKeysThatAreNotDuplicates(defaults, overrides);
+
     // 2. Create an ordered map from the overrides that weren't removed.
-    TOrderedMap orderedOverrides;
-    size_t index = 1;
-
-    for (std::list<TString>::const_iterator iterator = overrideKeys.begin();
-         iterator != overrideKeys.end(); iterator++) {
-        TString key = *iterator;
-        TValueIndex item;
-        item.value = overrides[key].value;
-        item.index = index;
-
-        orderedOverrides.insert(TOrderedMap::value_type(key, item));
-        index++;
-    }
-    
-    FJVMUserArgsOverrides = orderedOverrides;
-
-    FJVMUserArgsOverrides = orderedOverrides;
+    FJVMUserArgsOverrides = CreateOrderedMapFromKeyList(overrides, overrideKeys);
 
     // 3. Overwrite JVM user config overrides with provided key/value pair.
-    SaveJVMUserArgOverrides(orderedOverrides);
+    SaveJVMUserArgOverrides(FJVMUserArgsOverrides);
 
     // 4. Merge defaults and overrides to produce FJVMUserArgs.
     MergeJVMDefaultsWithOverrides();
 }
 
-void Package::SaveJVMUserArgOverrides(TOrderedMap Data) {
-    AutoFreePtr<PropertyFile> userConfig = new PropertyFile();
-    userConfig->Assign(Helpers::GetConfigFromJVMUserArgs(Data));
-    userConfig->SetReadOnly(false);
-    userConfig->SaveToFile(GetJVMUserArgsConfigFileName(), true);
+void Package::SaveJVMUserArgOverrides(OrderedMap<TString, TString> Data) {
+    IniFile userConfig;
+    Platform& platform = Platform::GetInstance();
+    std::map<TString, TString> keys = platform.GetKeys();
+    userConfig.AppendSection(keys[CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS], Data);
+    userConfig.SaveToFile(GetJVMUserArgsConfigFileName());
 }
 
-TOrderedMap Package::GetJVMUserArgs() {
+OrderedMap<TString, TString> Package::GetJVMUserArgs() {
     return FJVMUserArgs;
 }
 
+std::vector<TString> GetKeysThatAreNotOverridesOfDefaultValues(OrderedMap<TString, TString> &Defaults,
+                                                               OrderedMap<TString, TString> &Overrides) {
+    std::vector<TString> result;
+    std::vector<TString> keys = Overrides.GetKeys();
+
+    for (unsigned int index = 0; index< keys.size(); index++) {
+        TString key = keys[index];
+
+        if (Defaults.ContainsKey(key) == true) {
+            try {
+                TString value = Overrides[key];
+                Defaults[key] = value;
+            }
+            catch (std::out_of_range) {
+            }
+        }
+        else {
+            result.push_back(key);
+        }
+    }
+
+    return result;
+}
+
 void Package::MergeJVMDefaultsWithOverrides() {
     // Merge jvmuserarg defaults and jvmuserarg overrides to populate FJVMUserArgs.
     // 1. If the key is in the config file and not the java.user.preferences the default value is used,
@@ -308,42 +431,25 @@
     //    the config file value is ignored.
     // 3. If the key is not in the config file but it is in the java.user.preferences then it is added anyway.
     //    And if it is removed it won't show back up.
-    FJVMUserArgs.clear();
-    FJVMUserArgs.insert(FDefaultJVMUserArgs.begin(), FDefaultJVMUserArgs.end());
+    FJVMUserArgs.Clear();
+    FJVMUserArgs.Append(FDefaultJVMUserArgs);
 
-    TOrderedMap overrides = GetJVMUserArgOverrides();
-    std::list<TString> indexedKeys = Helpers::GetOrderedKeysFromMap(overrides);
+    OrderedMap<TString, TString> overrides = GetJVMUserArgOverrides();
 
     // 1. Iterate over all elements in overrides to see if any items
     //    override a default value.
-    for (TOrderedMap::iterator iterator = overrides.begin();
-         iterator != overrides.end();
-         iterator++) {
+    std::vector<TString> keys = GetKeysThatAreNotOverridesOfDefaultValues(FJVMUserArgs, overrides);
 
-        TString name = iterator->first;
-        TString value = iterator->second.value;
-        TValueIndex item;
 
-        if (FJVMUserArgs.find(name) != FJVMUserArgs.end()) {
-            item = FJVMUserArgs[name];
-            item.value = value;
-            FJVMUserArgs[name] = item;
-            indexedKeys.remove(name);
+    // 2. All remaining items in overrides are appended to the end.
+    for (unsigned int index = 0; index< keys.size(); index++) {
+        TString key = keys[index];
+        TString value;
+
+        if (overrides.GetValue(key, value) == true) {
+            FJVMUserArgs.Append(key, value);
         }
     }
-    
-    // 2. All remaining items in overrides are appended to the end.
-    size_t index = FDefaultJVMUserArgs.size();
-    
-    for (std::list<TString>::const_iterator iterator = indexedKeys.begin();
-         iterator != indexedKeys.end(); iterator++) {
-        
-        TString name = *iterator;
-        TValueIndex item = overrides[name];
-        item.index = index;
-        index++;
-        FJVMUserArgs[name] = item;
-    }
 }
 
 std::list<TString> Package::GetArgs() {
@@ -366,19 +472,51 @@
     return FBootFields->FPackageLauncherDirectory;
 }
 
+TString Package::GetAppDataDirectory() {
+    assert(FBootFields != NULL);
+    return FBootFields->FAppDataDirectory;
+}
+
 TString Package::GetJVMUserArgsConfigFileName() {
     if (FJVMUserArgsConfigFileName.empty()) {
         Platform& platform = Platform::GetInstance();
 
-        FJVMUserArgsConfigFileName = FilePath::IncludeTrailingSlash(platform.GetAppDataDirectory()) +
-                                        FilePath::IncludeTrailingSlash(GetPackageAppDataDirectory()) +
-                                        FilePath::IncludeTrailingSlash(_T("packager")) +
+        FJVMUserArgsConfigFileName = FilePath::IncludeTrailingSeparater(platform.GetAppDataDirectory()) +
+                                        FilePath::IncludeTrailingSeparater(GetPackageAppDataDirectory()) +
+                                        FilePath::IncludeTrailingSeparater(_T("packager")) +
                                         _T("jvmuserargs.cfg");
     }
-    
+
     return FJVMUserArgsConfigFileName;
 }
 
+TString Package::GetAppCDSCacheDirectory() {
+    if (FAppCDSCacheDirectory.empty()) {
+        Platform& platform = Platform::GetInstance();
+        FAppCDSCacheDirectory = FilePath::IncludeTrailingSeparater(platform.GetAppDataDirectory()) +
+                                FilePath::IncludeTrailingSeparater(GetPackageAppDataDirectory()) +
+                                _T("cache");
+
+        Macros& macros = Macros::GetInstance();
+        FAppCDSCacheDirectory = macros.ExpandMacros(FAppCDSCacheDirectory);
+        FAppCDSCacheDirectory = FilePath::FixPathForPlatform(FAppCDSCacheDirectory);
+    }
+
+    return FAppCDSCacheDirectory;
+}
+
+TString Package::GetAppCDSCacheFileName() {
+    assert(FBootFields != NULL);
+
+    if (FBootFields->FAppCDSCacheFileName.empty() == false) {
+        Macros& macros = Macros::GetInstance();
+        FBootFields->FAppCDSCacheFileName = macros.ExpandMacros(FBootFields->FAppCDSCacheFileName);
+        FBootFields->FAppCDSCacheFileName = FilePath::FixPathForPlatform(FBootFields->FAppCDSCacheFileName);
+    }
+
+    return FBootFields->FAppCDSCacheFileName;
+}
+
 TString Package::GetAppID() {
     assert(FBootFields != NULL);
     return FBootFields->FAppID;
@@ -411,7 +549,7 @@
 
 TString Package::GetJVMLibraryFileName() {
     assert(FBootFields != NULL);
-    
+
     if (FBootFields->FJVMLibraryFileName.empty() == true) {
         Platform& platform = Platform::GetInstance();
         if (IsRuntimeBundled() == true) {
--- a/modules/fxpackager/src/main/native/library/common/Package.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Package.h	Tue Mar 31 08:15:48 2015 -0700
@@ -46,14 +46,15 @@
 class PackageBootFields {
 public:
     enum MemoryState {msManual, msAuto};
-    
+
 public:
-    TOrderedMap FJVMArgs;
+    OrderedMap<TString, TString> FJVMArgs;
     std::list<TString> FArgs;
-    
+
     TString FPackageRootDirectory;
     TString FPackageAppDirectory;
     TString FPackageLauncherDirectory;
+    TString FAppDataDirectory;
     TString FAppID;
     TString FPackageAppDataDirectory;
     TString FClassPath;
@@ -65,7 +66,9 @@
     TString FSplashScreenFileName;
     bool FUseJavaPreferences;
     TString FCommandName;
-    
+
+    TString FAppCDSCacheFileName;
+
     TPlatformNumber FMemorySize;
     MemoryState FMemoryState;
 };
@@ -77,45 +80,52 @@
     void operator=(Package const&); // Don't implement
 
 private:
+    bool FInitialized;
     PackageBootFields* FBootFields;
     TString FJVMUserArgsConfigFileName;
-    
+    TString FAppCDSCacheDirectory;
+
     DebugState FDebugging;
 
-    //PropertyFile* FJVMUserConfig; // Contains JVM user overrides
-    TOrderedMap FJVMUserArgsOverrides;
-    TOrderedMap FDefaultJVMUserArgs; // Contains JVM user defaults
-    TOrderedMap FJVMUserArgs; // Contains a merge of JVM defaults and user overrides
+    OrderedMap<TString, TString> FJVMUserArgsOverrides;
+    OrderedMap<TString, TString> FDefaultJVMUserArgs; // Contains JVM user defaults
+    OrderedMap<TString, TString> FJVMUserArgs; // Contains a merge of JVM defaults and user overrides
 
 
     Package(void);
 
-    void Initialize();
+    //void Initialize();
     void MergeJVMDefaultsWithOverrides();
     TString GetMainJar();
-    void SaveJVMUserArgOverrides(TOrderedMap Data);
-    
+    void SaveJVMUserArgOverrides(OrderedMap<TString, TString> Data);
+    void ReadJVMArgs(ISectionalPropertyContainer* Config);
+
 public:
     static Package& GetInstance();
     ~Package(void);
 
+    void Initialize();
+    void Clear();
     void FreeBootFields();
 
     void SetCommandLineArguments(int argc, TCHAR* argv[]);
 
-    TOrderedMap GetJVMArgs();
-    TOrderedMap GetDefaultJVMUserArgs();
-    TOrderedMap GetJVMUserArgOverrides();
-    void SetJVMUserArgOverrides(TOrderedMap Value);
-    TOrderedMap GetJVMUserArgs();
+    OrderedMap<TString, TString> GetJVMArgs();
+    OrderedMap<TString, TString> GetDefaultJVMUserArgs();
+    OrderedMap<TString, TString> GetJVMUserArgOverrides();
+    void SetJVMUserArgOverrides(OrderedMap<TString, TString> Value);
+    OrderedMap<TString, TString> GetJVMUserArgs();
 
     std::list<TString> GetArgs();
 
     TString GetPackageRootDirectory();
     TString GetPackageAppDirectory();
     TString GetPackageLauncherDirectory();
-    
+    TString GetAppDataDirectory();
+
     TString GetJVMUserArgsConfigFileName();
+    TString GetAppCDSCacheDirectory();
+    TString GetAppCDSCacheFileName();
 
     TString GetAppID();
     TString GetPackageAppDataDirectory();
@@ -127,10 +137,10 @@
     TString GetSplashScreenFileName();
     bool HasSplashScreen();
     TString GetCommandName();
-    
+
     TPlatformNumber GetMemorySize();
     PackageBootFields::MemoryState GetMemoryState();
-    
+
     DebugState Debugging();
 };
 
--- a/modules/fxpackager/src/main/native/library/common/Platform.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Platform.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -93,7 +93,7 @@
         for (std::vector<TString>::const_iterator iterator = FDependentLibraryNames->begin();
                 iterator != FDependentLibraryNames->end(); iterator++) {
             Library* library = new Library();
-            
+
             if (library->Load(*iterator) == true) {
                 FDependenciesLibraries->push_back(library);
             }
@@ -179,4 +179,4 @@
         }
     }
 }
-//--------------------------------------------------------------------------------------------------
\ No newline at end of file
+//--------------------------------------------------------------------------------------------------
--- a/modules/fxpackager/src/main/native/library/common/Platform.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/Platform.h	Tue Mar 31 08:15:48 2015 -0700
@@ -34,6 +34,7 @@
 #ifndef PLATFORM_H
 #define PLATFORM_H
 
+#include "OrderedMap.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -47,7 +48,6 @@
 #ifdef WIN32
 #define WINDOWS
 #endif //WIN32
-//TODO Win64?
 
 #ifdef __APPLE__
 #define MAC
@@ -78,12 +78,15 @@
 #include <malloc.h>
 
 typedef std::wstring TString;
+#define StringLength wcslen
 
-#define TRAILING_SLASH '\\'
+#define TRAILING_PATHSEPARATOR '\\'
+#define BAD_TRAILING_PATHSEPARATOR '/'
 #define PATH_SEPARATOR ';'
 #define BAD_PATH_SEPARATOR ':'
 
 typedef ULONGLONG TPlatformNumber;
+typedef DWORD TProcessID;
 
 #if defined _DEBUG && !defined DEBUG
     #define DEBUG
@@ -103,18 +106,34 @@
 
 typedef char TCHAR;
 typedef std::string TString;
+#define StringLength strlen
 
-#define TRAILING_SLASH '/'
+typedef unsigned long DWORD;
+
+#define TRAILING_PATHSEPARATOR '/'
+#define BAD_TRAILING_PATHSEPARATOR '\\'
 #define PATH_SEPARATOR ':'
 #define BAD_PATH_SEPARATOR ';'
 #define MAX_PATH 1000
 
 typedef long TPlatformNumber;
+typedef pid_t TProcessID;
 
 #define HMODULE void*
 #endif //POSIX
 
 
+// Config file sections
+#define CONFIG_SECTION_APPLICATION            _T("CONFIG_SECTION_APPLICATION")
+#define CONFIG_SECTION_JVMOPTIONS             _T("CONFIG_SECTION_JVMOPTIONS")
+#define CONFIG_SECTION_JVMUSEROPTIONS         _T("CONFIG_SECTION_JVMUSEROPTIONS")
+#define CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS         _T("CONFIG_SECTION_JVMUSEROVERRIDESOPTIONS")
+#define CONFIG_SECTION_APPCDSJVMOPTIONS       _T("CONFIG_SECTION_APPCDSJVMOPTIONS")
+#define CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS _T("CONFIG_SECTION_APPCDSGENERATECACHEJVMOPTIONS")
+#define CONFIG_SECTION_ARGOPTIONS             _T("CONFIG_SECTION_ARGOPTIONS")
+
+// Config file keys.
+#define CONFIG_VERSION            _T("CONFIG_VERSION")
 #define CONFIG_MAINJAR_KEY        _T("CONFIG_MAINJAR_KEY")
 #define CONFIG_MAINCLASSNAME_KEY  _T("CONFIG_MAINCLASSNAME_KEY")
 #define CONFIG_CLASSPATH_KEY      _T("CONFIG_CLASSPATH_KEY")
@@ -123,44 +142,109 @@
 #define CONFIG_APP_ID_KEY         _T("CONFIG_APP_ID_KEY")
 #define CONFIG_APP_MEMORY         _T("CONFIG_APP_MEMORY")
 
-#if defined(WINDOWS) || defined(LINUX)
 #define JVM_RUNTIME_KEY           _T("JVM_RUNTIME_KEY")
-#define PACKAGER_APP_DATA_DIR     _T("CONFIG_APP_ID_KEY")
-#endif //WINDOWS || LINUX
+#define PACKAGER_APP_DATA_DIR     _T("CONFIG_APP_IDENTIFIER")
 
-#ifdef MAC
-#define JVM_RUNTIME_KEY           _T("JVMRuntime")
-#define PACKAGER_APP_DATA_DIR     _T("CFBundleIdentifier")
-#endif //MAC
 
 
 typedef void* Module;
 typedef void* Procedure;
 
-struct TValueIndex {
-    TString value;
-    size_t index;
+
+class Process {
+public:
+    Process() {}
+    virtual ~Process() {}
+
+    virtual bool IsRunning() = 0;
+    virtual bool Terminate() = 0;
+    virtual bool Execute(const TString Application, const std::vector<TString> Arguments,
+        bool AWait = false) = 0;
+    virtual bool Wait() = 0;
+    virtual TProcessID GetProcessID() = 0;
 };
 
-typedef std::map<TString, TValueIndex> TOrderedMap;
 
+template <typename T>
+class AutoFreePtr {
+private:
+    T* FObject;
 
-class PropertyContainer {
 public:
-    PropertyContainer(void) {}
-    virtual ~PropertyContainer(void) {}
+    AutoFreePtr() {
+        FObject = NULL;
+    }
+
+    AutoFreePtr(T* Value) {
+        FObject = Value;
+    }
+
+    ~AutoFreePtr() {
+        if (FObject != NULL) {
+            delete FObject;
+        }
+    }
+
+    operator T* () const {
+        return FObject;
+    }
+
+    T& operator* () const {
+        return *FObject;
+    }
+
+    T* operator->() const {
+        return FObject;
+    }
+
+    T** operator&() {
+        return &FObject;
+    }
+
+    T* operator=(const T * rhs) {
+        FObject = rhs;
+        return FObject;
+    }
+};
+
+
+class IPropertyContainer {
+public:
+    IPropertyContainer(void) {}
+    virtual ~IPropertyContainer(void) {}
 
     virtual bool GetValue(const TString Key, TString& Value) = 0;
     virtual size_t GetCount() = 0;
 };
 
+class ISectionalPropertyContainer {
+public:
+    ISectionalPropertyContainer(void) {}
+    virtual ~ISectionalPropertyContainer(void) {}
+
+    virtual bool GetValue(const TString SectionName, const TString Key, TString& Value) = 0;
+    virtual bool ContainsSection(const TString SectionName) = 0;
+    virtual bool GetSection(const TString SectionName, OrderedMap<TString, TString> &Data) = 0;
+};
+
+
 enum DebugState {dsNone, dsNative, dsJava};
+enum MessageResponse {mrOK, mrCancel};
+enum AppCDSState {cdsNone, cdsOn, cdsGenCache, cdsAuto, cdsInteractive};
 
 class Platform {
+private:
+    AppCDSState FAppCDSState;
+
 protected:
-    Platform(void) {}
+    Platform(void) {
+        FAppCDSState = cdsNone;
+    }
 
 public:
+    AppCDSState GetAppCDSState() { return FAppCDSState; }
+    void SetAppCDSState(AppCDSState Value) { FAppCDSState = Value; }
+
     static Platform& GetInstance();
 
     virtual ~Platform(void) {}
@@ -168,25 +252,27 @@
 public:
     virtual void ShowMessage(TString title, TString description) = 0;
     virtual void ShowMessage(TString description) = 0;
+    virtual MessageResponse ShowResponseMessage(TString title, TString description) = 0;
+//    virtual MessageResponse ShowResponseMessage(TString description) = 0;
 
     virtual void SetCurrentDirectory(TString Value) = 0;
-    
+
     // Caller must free result using delete[].
     virtual TCHAR* ConvertStringToFileSystemString(TCHAR* Source, bool &release) = 0;
-    
+
     // Caller must free result using delete[].
     virtual TCHAR* ConvertFileSystemStringToString(TCHAR* Source, bool &release) = 0;
 
     // Returns:
-    // Windows=C:\Users\<username>\AppData\Local\<app.preferences.id>\packager\jvmuserargs.cfg
-    // Linux=~/.local/<app.preferences.id>/packager/jvmuserargs.cfg
-    // Mac=~/Library/Application Support/<app.preferences.id>/packager/jvmuserargs.cfg
+    // Windows=C:\Users\<username>\AppData\Local\<app.identifier>\packager\jvmuserargs.cfg
+    // Linux=~/.local/<app.identifier>/packager/jvmuserargs.cfg
+    // Mac=~/Library/Application Support/<app.identifier>/packager/jvmuserargs.cfg
     virtual TString GetAppDataDirectory() = 0;
 
     virtual TString GetPackageAppDirectory() = 0;
     virtual TString GetPackageLauncherDirectory() = 0;
     virtual TString GetAppName() = 0;
-    
+
     virtual TString GetConfigFileName() = 0;
 
     virtual TString GetBundledJVMLibraryFileName(TString RuntimePath) = 0;
@@ -194,7 +280,7 @@
     virtual TString GetSystemJRE() = 0;
 
     // Caller must free result.
-    virtual PropertyContainer* GetConfigFile(TString FileName) = 0;
+    virtual ISectionalPropertyContainer* GetConfigFile(TString FileName) = 0;
 
     virtual TString GetModuleFileName() = 0;
     virtual TString GetPackageRootDirectory() = 0;
@@ -204,12 +290,15 @@
     virtual Procedure GetProcAddress(Module Module, std::string MethodName) = 0;
     virtual std::vector<TString> GetLibraryImports(const TString FileName) = 0;
     virtual std::vector<TString> FilterOutRuntimeDependenciesForPlatform(std::vector<TString> Imports) = 0;
-    
+
+    // Caller must free result.
+    virtual Process* CreateProcess() = 0;
+
     virtual bool IsMainThread() = 0;
 
     // Returns megabytes.
     virtual TPlatformNumber GetMemorySize() = 0;
-    
+
     virtual std::map<TString, TString> GetKeys() = 0;
 
     virtual std::list<TString> LoadFromFile(TString FileName) = 0;
@@ -249,4 +338,29 @@
     void AddDependencies(const std::vector<TString> &Dependencies);
 };
 
+
+class Exception: public std::exception {
+private:
+    TString FMessage;
+
+protected:
+    void SetMessage(const TString Message) {
+        FMessage = Message;
+    }
+
+public:
+    explicit Exception() : exception() {}
+    explicit Exception(const TString Message) : exception() {
+        SetMessage(Message);
+    }
+    virtual ~Exception() throw() {}
+
+    TString GetMessage() { return FMessage; }
+};
+
+class FileNotFoundException: public Exception {
+public:
+    explicit FileNotFoundException(const TString Message) : Exception(Message) {}
+};
+
 #endif //PLATFORM_H
--- a/modules/fxpackager/src/main/native/library/common/PlatformString.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/PlatformString.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -75,7 +75,7 @@
     Platform& platform = Platform::GetInstance();
     TCHAR* buffer = platform.ConvertFileSystemStringToString(lvalue, release);
     FData = buffer;
-    
+
     if (buffer != NULL && release == true) {
         delete[] buffer;
     }
@@ -116,7 +116,7 @@
 #ifdef POSIX
     wcsncpy(Destination, Source, NumberOfElements);
 #endif //POSIX
-    
+
     if (NumberOfElements > 0) {
         Destination[NumberOfElements - 1] = '\0';
     }
@@ -205,17 +205,17 @@
 
 PlatformString::PlatformString(size_t Value) {
     initialize();
-    
+
     std::stringstream ss;
     std::string s;
     ss << Value;
     s = ss.str();
-    
+
     FLength = strlen(s.c_str());
     FData = new char[FLength + 1];
     PlatformString::CopyString(FData, FLength + 1, s.c_str());
 }
-    
+
 PlatformString::PlatformString(const wchar_t* value) {
     initialize();
     MultibyteString temp = WideStringToMultibyteString(value);
@@ -268,26 +268,27 @@
     }
 }
 
-std::string PlatformString::Format(std::string value, ...) {
-    std::string result = value;
+TString PlatformString::Format(const TString value, ...) {
+//std::string PlatformString::Format(std::string value, ...) {
+    TString result = value;
 
     va_list arglist;
     va_start(arglist, value);
 
     while (1) {
-        size_t pos = result.find("%s", 0);
+        size_t pos = result.find(_T("%s"), 0);
 
         if (pos == TString::npos) {
             break;
         }
         else {
-            char* arg = va_arg(arglist, char*);
+            TCHAR* arg = va_arg(arglist, TCHAR*);
 
             if (arg == NULL) {
                 break;
             }
             else {
-                result.replace(pos, strlen("%s"), arg);
+                result.replace(pos, StringLength(_T("%s")), arg);
             }
         }
     }
--- a/modules/fxpackager/src/main/native/library/common/PlatformString.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/PlatformString.h	Tue Mar 31 08:15:48 2015 -0700
@@ -114,15 +114,15 @@
 private:
     static void *operator new(size_t size);
     static void operator delete(void *ptr);
-    
+
 private:
     TCHAR* FData;
     bool FRelease;
-    
+
 public:
     StringToFileSystemString(const TString &value);
     ~StringToFileSystemString();
-    
+
     operator TCHAR* ();
 };
 
@@ -139,13 +139,13 @@
 private:
     static void *operator new(size_t size);
     static void operator delete(void *ptr);
-    
+
 private:
     TString FData;
-    
+
 public:
     FileSystemStringToString(const TCHAR* value);
-    
+
     operator TString ();
 };
 #endif //MAC
@@ -166,10 +166,10 @@
 
     // Caller must free result using delete[].
     static void CopyString(char *Destination, size_t NumberOfElements, const char *Source);
-    
+
     // Caller must free result using delete[].
     static void CopyString(wchar_t *Destination, size_t NumberOfElements, const wchar_t *Source);
-    
+
     static WideString MultibyteStringToWideString(const char* value);
     static MultibyteString WideStringToMultibyteString(const wchar_t* value);
 
@@ -188,7 +188,7 @@
     PlatformString(JNIEnv *env, jstring value);
     PlatformString(size_t Value);
 
-    static std::string Format(std::string value, ...);
+    static TString Format(const TString value, ...);
 
     ~PlatformString(void);
 
@@ -209,7 +209,7 @@
 
     // Caller must free result using delete[].
     static char* duplicate(const char* Value);
-    
+
     // Caller must free result using delete[].
     static wchar_t* duplicate(const wchar_t* Value);
 };
--- a/modules/fxpackager/src/main/native/library/common/PosixPlatform.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/PosixPlatform.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -36,14 +36,16 @@
 #ifdef POSIX
 
 #include "PlatformString.h"
+#include "FilePath.h"
 
 #include <assert.h>
 #include <stdbool.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <sys/sysctl.h>
-
+#include <iostream>
 #include <dlfcn.h>
+#include <signal.h>
 
 
 PosixPlatform::PosixPlatform(void) {
@@ -52,6 +54,28 @@
 PosixPlatform::~PosixPlatform(void) {
 }
 
+MessageResponse PosixPlatform::ShowResponseMessage(TString title, TString description) {
+    MessageResponse result = mrCancel;
+
+    printf("%s %s (Y/N)\n", PlatformString(title).toPlatformString(), PlatformString(description).toPlatformString());
+    fflush(stdout);
+
+    std::string input;
+    std::cin >> input;
+
+    if (input == "Y") {
+        result = mrOK;
+    }
+
+    return result;
+}
+
+//MessageResponse PosixPlatform::ShowResponseMessageB(TString description) {
+//    TString appname = GetModuleFileName();
+//    appname = FilePath::ExtractFileName(appname);
+//    return ShowResponseMessage(appname, description);
+//}
+
 void PosixPlatform::SetCurrentDirectory(TString Value) {
     chdir(StringToFileSystemString(Value));
 }
@@ -69,13 +93,182 @@
 }
 
 std::vector<std::string> PosixPlatform::GetLibraryImports(const TString FileName) {
-	std::vector<TString> result;
-	return result;
+ std::vector<TString> result;
+ return result;
 }
 
 std::vector<TString> PosixPlatform::FilterOutRuntimeDependenciesForPlatform(std::vector<TString> Imports) {
-	std::vector<TString> result;
-	return result;
+ std::vector<TString> result;
+ return result;
+}
+
+Process* PosixPlatform::CreateProcess() {
+    return new PosixProcess();
+}
+
+//--------------------------------------------------------------------------------------------------
+
+
+PosixProcess::PosixProcess() : Process() {
+    FChildPID = 0;
+    FRunning = false;
+}
+
+PosixProcess::~PosixProcess() {
+    Terminate();
+}
+
+void PosixProcess::Cleanup() {
+#ifdef MAC
+    sigaction(SIGINT, &savintr, (struct sigaction *)0);
+    sigaction(SIGQUIT, &savequit, (struct sigaction *)0);
+    sigprocmask(SIG_SETMASK, &saveblock, (sigset_t *)0);
+#endif //MAC
+}
+
+bool PosixProcess::IsRunning() {
+    bool result = false;
+
+    if (kill(FChildPID, 0) == 0) {
+        result = true;
+    }
+
+    return result;
+}
+
+bool PosixProcess::Terminate() {
+    bool result = false;
+
+    if (IsRunning() == true && FRunning == true) {
+        FRunning = false;
+        Cleanup();
+        int status = kill(FChildPID, SIGTERM);
+
+        if (status == 0) {
+            result = true;
+        }
+        else {
+#ifdef DEBUG
+            if (errno == EINVAL)
+                printf("Kill error: The value of the sig argument is an invalid or unsupported signal number.");
+            else if (errno == EPERM)
+                printf("Kill error: The process does not have permission to send the signal to any receiving process.");
+            else if (errno == ESRCH)
+                printf("Kill error: No process or process group can be found corresponding to that specified by pid.");
+#endif //DEBUG
+            if (IsRunning() == true) {
+                status = kill(FChildPID, SIGKILL);
+
+                if (status == 0) {
+                    result = true;
+                }
+            }
+        }
+    }
+
+    return result;
+}
+
+bool PosixProcess::Execute(const TString Application, const std::vector<TString> Arguments, bool AWait) {
+    bool result = false;
+
+    if (FRunning == false) {
+        FRunning = true;
+
+        struct sigaction sa;
+        sa.sa_handler = SIG_IGN;
+        sigemptyset(&sa.sa_mask);
+        sa.sa_flags = 0;
+#ifdef MAC
+        sigemptyset(&savintr.sa_mask);
+        sigemptyset(&savequit.sa_mask);
+        sigaction(SIGINT, &sa, &savintr);
+        sigaction(SIGQUIT, &sa, &savequit);
+        sigaddset(&sa.sa_mask, SIGCHLD);
+        sigprocmask(SIG_BLOCK, &sa.sa_mask, &saveblock);
+#endif //MAC
+        FChildPID = fork();
+
+        // PID returned by vfork is 0 for the child process and the PID of the child
+        // process for the parent.
+        if (FChildPID == -1) {
+            // Error
+            TString message = PlatformString::Format(_T("Error: Unable to create process %s"), Application.data());
+            throw Exception(message);
+        }
+        else if (FChildPID == 0) {
+            Cleanup();
+            TString command = Application;
+
+            for (std::vector<TString>::const_iterator iterator = Arguments.begin(); iterator != Arguments.end(); iterator++) {
+                command += TString(_T(" ")) + *iterator;
+            }
+#ifdef DEBUG
+            printf("%s\n", command.data());
+#endif //DEBUG
+            execl("/bin/sh", "sh", "-c", command.data(), (char *)0);
+            _exit(127);
+        } else {
+            if (AWait == true) {
+                Wait();
+                Cleanup();
+                FRunning = false;
+                result = true;
+            }
+            else {
+                result = true;
+            }
+        }
+    }
+
+    return result;
+}
+
+bool PosixProcess::Wait() {
+    bool result = false;
+
+    int status;
+    pid_t wpid;
+
+    //TODO Use waitpid instead of wait
+#ifdef LINUX
+    wait();
+#endif
+#ifdef MAC
+    wpid = wait(&status);
+#endif
+
+    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+        if (errno != EINTR){
+            status = -1;
+        }
+    }
+
+#ifdef DEBUG
+    if (WIFEXITED(status)) {
+        printf("child exited, status=%d\n", WEXITSTATUS(status));
+    } else if (WIFSIGNALED(status)) {
+        printf("child killed (signal %d)\n", WTERMSIG(status));
+    } else if (WIFSTOPPED(status)) {
+        printf("child stopped (signal %d)\n", WSTOPSIG(status));
+#ifdef WIFCONTINUED // Not all implementations support this
+    } else if (WIFCONTINUED(status)) {
+        printf("child continued\n");
+#endif //WIFCONTINUED
+    } else { // Non-standard case -- may never happen
+        printf("Unexpected status (0x%x)\n", status);
+    }
+#endif //DEBUG
+
+    if (wpid != -1) {
+        result = true;
+    }
+
+    return result;
+}
+
+TProcessID PosixProcess::GetProcessID() {
+    return FChildPID;
 }
 
 #endif //POSIX
--- a/modules/fxpackager/src/main/native/library/common/PosixPlatform.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/PosixPlatform.h	Tue Mar 31 08:15:48 2015 -0700
@@ -45,6 +45,9 @@
     virtual ~PosixPlatform(void);
 
 public:
+    virtual MessageResponse ShowResponseMessage(TString title, TString description);
+    //virtual MessageResponse ShowResponseMessageB(TString description);
+
     virtual void SetCurrentDirectory(TString Value);
 
     virtual Module LoadLibrary(TString FileName);
@@ -52,6 +55,32 @@
     virtual Procedure GetProcAddress(Module AModule, std::string MethodName);
     virtual std::vector<TString> GetLibraryImports(const TString FileName);
     virtual std::vector<TString> FilterOutRuntimeDependenciesForPlatform(std::vector<TString> Imports);
+
+    virtual Process* CreateProcess();
+};
+
+
+class PosixProcess : public Process {
+private:
+    pid_t FChildPID;
+    sigset_t saveblock;
+#ifdef MAC
+    struct sigaction savintr, savequit;
+#endif //MAC
+    bool FRunning;
+
+    void Cleanup();
+
+public:
+    PosixProcess();
+    virtual ~PosixProcess();
+
+    virtual bool IsRunning();
+    virtual bool Terminate();
+    virtual bool Execute(const TString Application, const std::vector<TString> Arguments,
+        bool AWait = false);
+    virtual bool Wait();
+    virtual TProcessID GetProcessID();
 };
 
 #endif //POSIXPLATFORM_H
--- a/modules/fxpackager/src/main/native/library/common/PropertyFile.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/PropertyFile.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -39,22 +39,33 @@
 #include <string>
 
 
-PropertyFile::PropertyFile(void) : PropertyContainer() {
+PropertyFile::PropertyFile(void) : IPropertyContainer() {
     FReadOnly = false;
     FModified = false;
 }
 
-PropertyFile::PropertyFile(const TString FileName) : PropertyContainer() {
+PropertyFile::PropertyFile(const TString FileName) : IPropertyContainer() {
     FReadOnly = true;
     FModified = false;
     LoadFromFile(FileName);
 }
 
-PropertyFile::PropertyFile(std::map<TString, TString> Value) : PropertyContainer() {
-    FData.insert(Value.begin(), Value.end());
+PropertyFile::PropertyFile(OrderedMap<TString, TString> Value) {
+    FData.Append(Value);
+}
+
+//PropertyFile::PropertyFile(std::map<TString, TString> Value) : PropertyContainer() {
+//    FData.Append(Value);
+//}
+
+PropertyFile::PropertyFile(const PropertyFile &Value) {
+    FData = Value.FData;
+    FReadOnly = Value.FReadOnly;
+    FModified = Value.FModified;
 }
 
 PropertyFile::~PropertyFile(void) {
+    FData.Clear();
 }
 
 void PropertyFile::SetModified(bool Value) {
@@ -73,11 +84,11 @@
     FReadOnly = Value;
 }
 
-void PropertyFile::Assign(std::map<TString, TString> Value) {
-    FData.clear();
-    FData.insert(Value.begin(), Value.end());
-    SetModified(true);
-}
+//void PropertyFile::Assign(std::map<TString, TString> Value) {
+//    FData.Clear();
+//    FData.Assign(Value);
+//    SetModified(true);
+//}
 
 bool PropertyFile::LoadFromFile(const TString FileName) {
     bool result = false;
@@ -92,7 +103,7 @@
             TString value;
 
             if (Helpers::SplitOptionIntoNameValue(line, name, value) == true) {
-                FData.insert(std::map<TString, TString>::value_type(name, value));
+                FData.Append(name, value);
             }
         }
 
@@ -108,15 +119,21 @@
 
     if (GetReadOnly() == false && IsModified()) {
         std::list<TString> contents;
+        std::vector<TString> keys = FData.GetKeys();
 
-        for (std::map<TString, TString>::iterator iterator = FData.begin();
-            iterator != FData.end();
-            iterator++) {
+        for (size_t index = 0; index < keys.size(); index++) {
+            TString name = keys[index];
 
-            TString name = iterator->first;
-            TString value = iterator->second;
-            TString line = name + _T('=') + value;
-            contents.push_back(line);
+            try {
+                TString value;// = FData[index];
+
+                if (FData.GetValue(name, value) == true) {
+                    TString line = name + _T('=') + value;
+                    contents.push_back(line);
+                }
+            }
+            catch (std::out_of_range) {
+            }
         }
 
         Platform& platform = Platform::GetInstance();
@@ -130,22 +147,14 @@
 }
 
 bool PropertyFile::GetValue(const TString Key, TString& Value) {
-    bool result = false;
-    std::map<TString, TString>::const_iterator iterator = FData.find(Key);
-
-    if (iterator != FData.end()) {
-        Value = iterator->second;
-        result = true;
-    }
-
-    return result;
+    return FData.GetValue(Key, Value);
 }
 
 bool PropertyFile::SetValue(const TString Key, TString Value) {
     bool result = false;
 
     if (GetReadOnly() == false) {
-        FData[Key] = Value;
+        FData.SetValue(Key, Value);
         SetModified(true);
         result = true;
     }
@@ -157,12 +166,10 @@
     bool result = false;
 
     if (GetReadOnly() == false) {
-        std::map<TString, TString>::iterator iterator = FData.find(Key);
+        result = FData.RemoveByKey(Key);
 
-        if (iterator != FData.end()) {
-            FData.erase(iterator);
+        if (result == true) {
             SetModified(true);
-            result = true;
         }
     }
 
@@ -170,9 +177,13 @@
 }
 
 size_t PropertyFile::GetCount() {
-    return FData.size();
+    return FData.Count();
 }
 
-std::map<TString, TString> PropertyFile::GetData() {
+//std::vector<TString> PropertyFile::GetKeys() {
+//    return FData.GetKeys();
+//}
+
+OrderedMap<TString, TString> PropertyFile::GetData() {
     return FData;
 }
--- a/modules/fxpackager/src/main/native/library/common/PropertyFile.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/PropertyFile.h	Tue Mar 31 08:15:48 2015 -0700
@@ -35,39 +35,42 @@
 #define PROPERTYFILE_H
 
 #include "Platform.h"
+#include "Helpers.h"
 
-#include <map>
 
-
-class PropertyFile : public PropertyContainer {
+class PropertyFile : public IPropertyContainer {
 private:
-    std::map<TString, TString> FData;
     bool FReadOnly;
     bool FModified;
+    OrderedMap<TString, TString> FData;
 
     void SetModified(bool Value);
 
 public:
     PropertyFile(void);
     PropertyFile(const TString FileName);
-    PropertyFile(std::map<TString, TString> Value);
+    PropertyFile(OrderedMap<TString, TString> Value);
+    PropertyFile(const PropertyFile &Value);
     virtual ~PropertyFile(void);
 
     bool IsModified();
     bool GetReadOnly();
     void SetReadOnly(bool Value);
 
-    void Assign(std::map<TString, TString> Value);
+    //void Assign(std::map<TString, TString> Value);
 
     bool LoadFromFile(const TString FileName);
-    bool SaveToFile(const TString FileName, bool ownerOnly);
+    bool SaveToFile(const TString FileName, bool ownerOnly = true);
 
-    virtual bool GetValue(const TString Key, TString& Value);
     bool SetValue(const TString Key, TString Value);
     bool RemoveKey(const TString Key);
 
+    OrderedMap<TString, TString> GetData();
+
+    // IPropertyContainer
+    virtual bool GetValue(const TString Key, TString& Value);
     virtual size_t GetCount();
-    std::map<TString, TString> GetData();
+    //virtual std::vector<TString> GetKeys();
 };
 
 #endif //PROPERTYFILE_H
--- a/modules/fxpackager/src/main/native/library/common/WindowsPlatform.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/WindowsPlatform.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -162,11 +162,11 @@
 TString WindowsPlatform::GetAppDataDirectory() {
     TString result;
     TCHAR path[MAX_PATH];
-    
+
     if (SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, path) == S_OK) {
         result = path;
     }
-    
+
     return result;
 }
 
@@ -179,6 +179,11 @@
 // return TRUE if found, and path is set in lpszJavaHome
 // return FALSE otherwise
 TString WindowsPlatform::GetSystemJRE() {
+    if (GetAppCDSState() == cdsOn || GetAppCDSState() == cdsGenCache) {
+        //TODO throw exception
+        return _T("");
+    }
+
     TString result;
     Registry registry(HKEY_LOCAL_MACHINE);
 
@@ -206,26 +211,42 @@
 void WindowsPlatform::ShowMessage(TString description) {
     TString appname = GetModuleFileName();
     appname = FilePath::ExtractFileName(appname);
-    MessageBox(NULL, appname.data(), description.data(), MB_ICONERROR | MB_OK);
+    MessageBox(NULL, description.data(), appname.data(), MB_ICONERROR | MB_OK);
 }
 
+MessageResponse WindowsPlatform::ShowResponseMessage(TString title, TString description) {
+    MessageResponse result = mrCancel;
+
+    if (::MessageBox(NULL, description.data(), title.data(), MB_OKCANCEL) == IDOK) {
+        result = mrOK;
+    }
+
+    return result;
+}
+
+//MessageResponse WindowsPlatform::ShowResponseMessage(TString description) {
+//    TString appname = GetModuleFileName();
+//    appname = FilePath::ExtractFileName(appname);
+//    return ShowResponseMessage(appname, description);
+//}
+
 TString WindowsPlatform::GetBundledJVMLibraryFileName(TString RuntimePath) {
 
-    TString result = FilePath::IncludeTrailingSlash(RuntimePath) +
+    TString result = FilePath::IncludeTrailingSeparater(RuntimePath) +
         _T("jre\\bin\\client\\jvm.dll");
 
     if (FilePath::FileExists(result) == false) {
-        result = FilePath::IncludeTrailingSlash(RuntimePath) +
+        result = FilePath::IncludeTrailingSeparater(RuntimePath) +
             _T("jre\\bin\\server\\jvm.dll");
     }
 
     if (FilePath::FileExists(result) == false) {
-        result = FilePath::IncludeTrailingSlash(RuntimePath) +
+        result = FilePath::IncludeTrailingSeparater(RuntimePath) +
             _T("bin\\client\\jvm.dll");
     }
 
     if (FilePath::FileExists(result) == false) {
-        result = FilePath::IncludeTrailingSlash(RuntimePath) +
+        result = FilePath::IncludeTrailingSeparater(RuntimePath) +
             _T("bin\\server\\jvm.dll");
     }
 
@@ -243,8 +264,15 @@
     return result;
 }
 
-PropertyContainer* WindowsPlatform::GetConfigFile(TString FileName) {
-    return new PropertyFile(FileName);
+ISectionalPropertyContainer* WindowsPlatform::GetConfigFile(TString FileName) {
+    IniFile *result = new IniFile();
+
+    if (result->LoadFromFile(FileName) == false) {
+        // New property file format was not found, attempt to load old property file format.
+        Helpers::LoadOldConfigFile(FileName, result);
+    }
+
+    return result;
 }
 
 TString WindowsPlatform::GetModuleFileName() {
@@ -287,15 +315,15 @@
 }
 
 std::vector<TString> WindowsPlatform::GetLibraryImports(const TString FileName) {
-	std::vector<TString> result;
+ std::vector<TString> result;
     WindowsLibrary library(FileName);
     result = library.GetImports();
-	return result;
+ return result;
 }
 
 std::vector<TString> FilterList(std::vector<TString> &Items, std::wregex Pattern) {
     std::vector<TString> result;
- 
+
     for (std::vector<TString>::iterator it = Items.begin(); it != Items.end(); ++it) {
         TString item = *it;
         std::wsmatch match;
@@ -308,7 +336,7 @@
 }
 
 std::vector<TString> WindowsPlatform::FilterOutRuntimeDependenciesForPlatform(std::vector<TString> Imports) {
-	std::vector<TString> result;
+ std::vector<TString> result;
 
     Package& package = Package::GetInstance();
     Macros& macros = Macros::GetInstance();
@@ -317,14 +345,14 @@
 
     for (std::vector<TString>::iterator it = filelist.begin(); it != filelist.end(); ++it) {
         TString filename = *it;
-        TString msvcr100FileName = FilePath::IncludeTrailingSlash(runtimeDir) + _T("jre\\bin\\") + filename;
+        TString msvcr100FileName = FilePath::IncludeTrailingSeparater(runtimeDir) + _T("jre\\bin\\") + filename;
 
         if (FilePath::FileExists(msvcr100FileName) == true) {
             result.push_back(msvcr100FileName);
             break;
         }
         else {
-            msvcr100FileName = FilePath::IncludeTrailingSlash(runtimeDir) + _T("bin\\") + filename;
+            msvcr100FileName = FilePath::IncludeTrailingSeparater(runtimeDir) + _T("bin\\") + filename;
 
             if (FilePath::FileExists(msvcr100FileName) == true) {
                 result.push_back(msvcr100FileName);
@@ -333,17 +361,21 @@
         }
     }
 
-	return result;
+ return result;
+}
+
+Process* WindowsPlatform::CreateProcess() {
+    return new WindowsProcess();
 }
 
 #ifdef DEBUG
 bool WindowsPlatform::IsNativeDebuggerPresent() {
     bool result = false;
-    
+
     if (IsDebuggerPresent() == TRUE) {
         result = true;
     }
-    
+
     return result;
 }
 
@@ -374,7 +406,7 @@
             case '\\':
                 result += _T("//");
                 break;
-        
+
             case '/':
                 result += '\\';
                 break;
@@ -400,16 +432,16 @@
 // See WindowsPreferences.java toJavaName()
 TString ConvertJavaEcodedStringToString(TString Value) {
     TString result;
-    
+
     for (size_t index = 0; index < Value.length(); index++) {
         TCHAR c = Value[index];
-        
+
         switch (c) {
             case '/':
                 if ((index + 1) < Value.length()) {
                     index++;
                     TCHAR nextc = Value[index];
-                    
+
                     if (nextc >= 'A' && nextc <= 'Z') {
                         result += nextc;
                     }
@@ -426,7 +458,7 @@
                 break;
         }
     }
-    
+
     return result;
 }
 
@@ -439,8 +471,7 @@
 
     if (registry.Open(registryKey) == true) {
         std::list<TString> keys = registry.GetKeys();
-        TOrderedMap mapOfKeysAndValues;
-        int index = 1;
+        OrderedMap<TString, TString> mapOfKeysAndValues;
 
         for (std::list<TString>::const_iterator iterator = keys.begin(); iterator != keys.end(); iterator++) {
             TString key = *iterator;
@@ -449,13 +480,8 @@
             value = ConvertJavaEcodedStringToString(value);
 
             if (key.empty() == false) {
-                TValueIndex item;
-                item.value = value;
-                item.index = index;
-
-                mapOfKeysAndValues.insert(TOrderedMap::value_type(key, item));
+                mapOfKeysAndValues.Append(key, value);
                 result = true;
-                index++;
             }
         }
 
@@ -560,7 +586,7 @@
 
     for (unsigned index = 0; index < pNTHeader->FileHeader.NumberOfSections; index++, section++) {
         // Is the RVA is within this section?
-        if ((rva >= section->VirtualAddress) && 
+        if ((rva >= section->VirtualAddress) &&
             (rva < (section->VirtualAddress + section->Misc.VirtualSize))) {
             result = section;
         }
@@ -630,4 +656,140 @@
 
 //--------------------------------------------------------------------------------------------------
 
+#include <TlHelp32.h>
+
+WindowsJob::WindowsJob() {
+    FHandle = NULL;
+}
+
+WindowsJob::~WindowsJob() {
+    if (FHandle != NULL) {
+        CloseHandle(FHandle);
+    }
+}
+
+HANDLE WindowsJob::GetHandle() {
+    if (FHandle == NULL) {
+        FHandle = CreateJobObject(NULL, NULL); // GLOBAL
+
+        if (FHandle == NULL)
+        {
+            ::MessageBox( 0, _T("Could not create job object"), _T("TEST"), MB_OK);
+        }
+        else
+        {
+            JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
+
+            // Configure all child processes associated with the job to terminate when the
+            jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+            if (0 == SetInformationJobObject(FHandle, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
+            {
+                ::MessageBox( 0, _T("Could not SetInformationJobObject"), _T("TEST"), MB_OK);
+            }
+        }
+    }
+
+    return FHandle;
+}
+
+// Initialize static member of WindowsProcess
+WindowsJob WindowsProcess::FJob;
+
+WindowsProcess::WindowsProcess() : Process() {
+    FRunning = false;
+}
+
+WindowsProcess::~WindowsProcess() {
+    Terminate();
+}
+
+void WindowsProcess::Cleanup() {
+    CloseHandle(FProcessInfo.hProcess);
+    CloseHandle(FProcessInfo.hThread);
+}
+
+bool WindowsProcess::IsRunning() {
+    bool result = false;
+
+    HANDLE handle = ::CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
+    PROCESSENTRY32 process = { 0 };
+    process.dwSize = sizeof(process);
+
+    if (::Process32First(handle, &process)) {
+        do {
+            if (process.th32ProcessID == FProcessInfo.dwProcessId) {
+                result = true;
+                break;
+            }
+        }
+        while (::Process32Next(handle, &process));
+    }
+
+    CloseHandle(handle);
+
+    return result;
+}
+
+bool WindowsProcess::Terminate() {
+    bool result = false;
+
+    if (IsRunning() == true && FRunning == true) {
+        FRunning = false;
+    }
+
+    return result;
+}
+
+bool WindowsProcess::Execute(const TString Application, const std::vector<TString> Arguments, bool AWait) {
+    bool result = false;
+
+    if (FRunning == false) {
+        FRunning = true;
+
+        STARTUPINFO startupInfo;
+        ZeroMemory(&startupInfo, sizeof(startupInfo));
+        startupInfo.cb = sizeof(startupInfo);
+        ZeroMemory(&FProcessInfo, sizeof(FProcessInfo));
+
+        TString command = Application;
+
+        for (std::vector<TString>::const_iterator iterator = Arguments.begin(); iterator != Arguments.end(); iterator++) {
+            command += TString(_T(" ")) + *iterator;
+        }
+
+        if (::CreateProcess(Application.data(), (wchar_t*)command.data(), NULL,
+            NULL, FALSE, 0, NULL, NULL, &startupInfo, &FProcessInfo) == TRUE) {
+            TString message = PlatformString::Format(_T("Error: Unable to create process %s"), Application.data());
+            throw Exception(message);
+        }
+        else {
+            if (FJob.GetHandle() != NULL) {
+                if (::AssignProcessToJobObject(FJob.GetHandle(), FProcessInfo.hProcess) == 0) {
+                    // Failed to assign process to job. It doesn't prevent anything from continuing so continue.
+                }
+            }
+
+            // Wait until child process exits.
+            if (AWait == true) {
+                Wait();
+                // Close process and thread handles.
+                Cleanup();
+            }
+        }
+    }
+
+    return result;
+}
+
+bool WindowsProcess::Wait() {
+    bool result = false;
+
+    WaitForSingleObject(FProcessInfo.hProcess, INFINITE);
+    return result;
+}
+
+TProcessID WindowsProcess::GetProcessID() {
+    return FProcessInfo.dwProcessId;
+}
+
 #endif //WINDOWS
--- a/modules/fxpackager/src/main/native/library/common/WindowsPlatform.h	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/WindowsPlatform.h	Tue Mar 31 08:15:48 2015 -0700
@@ -53,12 +53,15 @@
 public:
     WindowsPlatform(void);
     virtual ~WindowsPlatform(void);
-    
+
     virtual TCHAR* ConvertStringToFileSystemString(TCHAR* Source, bool &release);
     virtual TCHAR* ConvertFileSystemStringToString(TCHAR* Source, bool &release);
 
     virtual void ShowMessage(TString title, TString description);
     virtual void ShowMessage(TString description);
+    virtual MessageResponse ShowResponseMessage(TString title, TString description);
+    //virtual MessageResponse ShowResponseMessage(TString description);
+
     virtual void SetCurrentDirectory(TString Value);
     virtual TString GetPackageRootDirectory();
     virtual TString GetAppDataDirectory();
@@ -66,7 +69,7 @@
     virtual TString GetSystemJVMLibraryFileName();
     virtual TString GetSystemJRE();
 
-    virtual PropertyContainer* GetConfigFile(TString FileName);
+    virtual ISectionalPropertyContainer* GetConfigFile(TString FileName);
 
     virtual TString GetModuleFileName();
     virtual Module LoadLibrary(TString FileName);
@@ -75,6 +78,8 @@
     virtual std::vector<TString> GetLibraryImports(const TString FileName);
     virtual std::vector<TString> FilterOutRuntimeDependenciesForPlatform(std::vector<TString> Imports);
 
+    virtual Process* CreateProcess();
+
     virtual bool IsMainThread();
     virtual TPlatformNumber GetMemorySize();
 
@@ -151,6 +156,43 @@
     std::vector<TString> GetImports();
 };
 
+
+class WindowsJob {
+private:
+    HANDLE FHandle;
+
+public:
+    WindowsJob();
+    ~WindowsJob();
+
+    HANDLE GetHandle();
+};
+
+
+class WindowsProcess : public Process {
+private:
+    bool FRunning;
+
+    PROCESS_INFORMATION FProcessInfo;
+    static WindowsJob FJob;
+
+    void Cleanup();
+
+public:
+    WindowsProcess();
+    virtual ~WindowsProcess();
+
+    virtual bool IsRunning();
+    virtual bool Terminate();
+    virtual bool Execute(const TString Application, const std::vector<TString> Arguments,
+        bool AWait = false);
+    virtual bool Wait();
+    virtual TProcessID GetProcessID();
+};
+
+
+
+
 #endif //WINDOWSPLATFORM_H
 
 #endif // WINDOWS
--- a/modules/fxpackager/src/main/native/library/common/main.cpp	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/library/common/main.cpp	Tue Mar 31 08:15:48 2015 -0700
@@ -39,16 +39,20 @@
 #include "Package.h"
 #include "PlatformThread.h"
 #include "Macros.h"
+#include "Messages.h"
 
-#include "jni.h"
 
 #ifdef WINDOWS
 #include <Shellapi.h>
 #endif
 
 
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+
 /*
-This is launcher program for application packaging on Windows, Mac and Linux.
+This is the launcher program for application packaging on Windows, Mac and Linux.
 
 Basic approach:
   - Launcher executable loads packager.dll/libpackager.dylib/libpackager.so and calls start_launcher below.
@@ -67,7 +71,6 @@
     See CR 6316197 for more information.
 */
 
-
 extern "C" {
 
 #ifdef WINDOWS
@@ -80,44 +83,121 @@
 
     bool start_launcher(int argc, TCHAR* argv[]) {
         bool result = false;
-        
-        // Platform and Package must be initialize first.
+        bool parentProcess = true;
+
+        // Platform must be initialize first.
         Platform& platform = Platform::GetInstance();
 
+        try {
+            platform.SetAppCDSState(cdsOn);
+
+            for (int index = 0; index < argc; index++) {
+                TString argument = argv[index];
+
+                if (argument == _T("-Xappcds:generatecache")) {
+                    platform.SetAppCDSState(cdsGenCache);
+                }
+                else if (argument == _T("-Xappcds:off")) {
+                    platform.SetAppCDSState(cdsNone);
+                }
+                else if (argument == _T("-Xapp:child")) {
+                    parentProcess = false;
+                }
 #ifdef DEBUG
-        if (argc > 1 && TString(argv[1]) == _T("-debug")) {
-#ifdef WINDOWS
-            if (::MessageBox(NULL, PlatformString(platform.GetProcessID()), _T("Would you like to debug?"), MB_OKCANCEL) != IDCANCEL) {
-#endif //WINDOWS
-#ifdef POSIX
-            printf("%s\n", PlatformString(platform.GetProcessID()).c_str());
-            fflush(stdout);
-#endif //POSIX
-                while (platform.IsNativeDebuggerPresent() == false) {
+//TODO There appears to be a compiler bug on Mac overloading ShowResponseMessage. Investigate.
+                else if (argument == _T("-nativedebug")) {
+                    if (platform.ShowResponseMessage(_T("Test"),
+                                                     TString(_T("Would you like to debug?\n\nProcessID: ")) +
+                                                     PlatformString(platform.GetProcessID()).toString()) == mrOK) {
+                        while (platform.IsNativeDebuggerPresent() == false) {
+                        }
+                    }
                 }
-#ifdef WINDOWS
+#endif //DEBUG
             }
-#endif //WINDOWS
+
+            // Package must be initialized after Platform is fully initialized.
+            Package& package = Package::GetInstance();
+            Macros::Initialize();
+            package.SetCommandLineArguments(argc, argv);
+            platform.SetCurrentDirectory(package.GetPackageAppDirectory());
+
+            switch (platform.GetAppCDSState()) {
+                case cdsGenCache: {
+                        TString cacheDirectory = package.GetAppCDSCacheDirectory();
+
+                        if (FilePath::DirectoryExists(cacheDirectory) == false) {
+                            FilePath::CreateDirectory(cacheDirectory, true);
+                        }
+                        else {
+                            TString cacheFileName = package.GetAppCDSCacheFileName();
+
+                            if (FilePath::FileExists(cacheFileName) == true) {
+                                FilePath::DeleteFile(cacheFileName);
+                            }
+                        }
+
+
+                        break;
+                    }
+
+                case cdsAuto: {
+                    TString cacheFileName = package.GetAppCDSCacheFileName();
+
+                    if (parentProcess == true && FilePath::FileExists(cacheFileName) == false) {
+                        AutoFreePtr<Process> process = platform.CreateProcess();
+                        std::vector<TString> args;
+                        args.push_back(_T("-Xappcds:generatecache"));
+                        args.push_back(_T("-Xapp:child"));
+                        process->Execute(platform.GetModuleFileName(), args, true);
+
+                        if (FilePath::FileExists(cacheFileName) == false) {
+                            // Cache does not exist after trying to generate it,
+                            // so run without cache.
+                            platform.SetAppCDSState(cdsNone);
+                            package.Clear();
+                            package.Initialize();
+                        }
+                    }
+
+                    break;
+                }
+
+                case cdsNone:
+                case cdsOn: {
+                    break;
+                }
+            }
+
+            // Validation
+            {
+                switch (platform.GetAppCDSState()) {
+                    case cdsOn:
+                    case cdsAuto: {
+                            TString cacheFileName = package.GetAppCDSCacheFileName();
+
+                            if (FilePath::FileExists(cacheFileName) == false) {
+                                Messages& messages = Messages::GetInstance();
+                                TString message = PlatformString::Format(messages.GetMessage(APPCDS_CACHE_FILE_NOT_FOUND), cacheFileName.data());
+                                throw FileNotFoundException(message);
+                            }
+                            break;
+                        }
+                }
+            }
+
+            TString logFileName = FilePath::IncludeTrailingSeparater(platform.GetAppDataDirectory().data()) + _T("log.txt");
+
+            // Run App
+            result = RunVM();
         }
-#endif //DEBUG
-
-        Package& package = Package::GetInstance();
-        Macros::Initialize();
-        package.SetCommandLineArguments(argc, argv);
-        platform.SetCurrentDirectory(package.GetPackageAppDirectory());
-        JavaVirtualMachine javavm;
-
-        if (javavm.StartJVM() == true) {
-            result = true;
-            javavm.ShutdownJVM();
-        }
-        else {
-            platform.ShowMessage(_T("Failed to launch JVM\n"));
+        catch (FileNotFoundException &e) {
+            platform.ShowMessage(e.GetMessage());
         }
 
         return result;
     }
-    
+
     void stop_launcher() {
     }
 }
--- a/modules/fxpackager/src/main/native/tests/linux/library/packager/nbproject/Makefile-Debug.mk	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/tests/linux/library/packager/nbproject/Makefile-Debug.mk	Tue Mar 31 08:15:48 2015 -0700
@@ -39,6 +39,7 @@
 	${OBJECTDIR}/_ext/839896833/FilePath.o \
 	${OBJECTDIR}/_ext/839896833/GenericPlatform.o \
 	${OBJECTDIR}/_ext/839896833/Helpers.o \
+	${OBJECTDIR}/_ext/839896833/IniFile.o \
 	${OBJECTDIR}/_ext/839896833/Java.o \
 	${OBJECTDIR}/_ext/839896833/JavaUserPreferences.o \
 	${OBJECTDIR}/_ext/839896833/JavaVirtualMachine.o \
@@ -100,6 +101,11 @@
 	${RM} "$@.d"
 	$(COMPILE.cc) -g -DDEBUG -DJAVAARCH=\"i386\" -I${HOME}/jdk/include -I${HOME}/jdk/include/linux -fPIC  -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/_ext/839896833/Helpers.o ../../../../library/common/Helpers.cpp
 
+${OBJECTDIR}/_ext/839896833/IniFile.o: ../../../../library/common/IniFile.cpp 
+	${MKDIR} -p ${OBJECTDIR}/_ext/839896833
+	${RM} "$@.d"
+	$(COMPILE.cc) -g -DDEBUG -DJAVAARCH=\"i386\" -I${HOME}/jdk/include -I${HOME}/jdk/include/linux -fPIC  -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/_ext/839896833/IniFile.o ../../../../library/common/IniFile.cpp
+
 ${OBJECTDIR}/_ext/839896833/Java.o: ../../../../library/common/Java.cpp 
 	${MKDIR} -p ${OBJECTDIR}/_ext/839896833
 	${RM} "$@.d"
--- a/modules/fxpackager/src/main/native/tests/linux/library/packager/nbproject/Makefile-Release.mk	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/tests/linux/library/packager/nbproject/Makefile-Release.mk	Tue Mar 31 08:15:48 2015 -0700
@@ -39,6 +39,7 @@
 	${OBJECTDIR}/_ext/839896833/FilePath.o \
 	${OBJECTDIR}/_ext/839896833/GenericPlatform.o \
 	${OBJECTDIR}/_ext/839896833/Helpers.o \
+	${OBJECTDIR}/_ext/839896833/IniFile.o \
 	${OBJECTDIR}/_ext/839896833/Java.o \
 	${OBJECTDIR}/_ext/839896833/JavaUserPreferences.o \
 	${OBJECTDIR}/_ext/839896833/JavaVirtualMachine.o \
@@ -100,6 +101,11 @@
 	${RM} "$@.d"
 	$(COMPILE.cc) -O2 -fPIC  -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/_ext/839896833/Helpers.o ../../../../library/common/Helpers.cpp
 
+${OBJECTDIR}/_ext/839896833/IniFile.o: ../../../../library/common/IniFile.cpp 
+	${MKDIR} -p ${OBJECTDIR}/_ext/839896833
+	${RM} "$@.d"
+	$(COMPILE.cc) -O2 -fPIC  -MMD -MP -MF "$@.d" -o ${OBJECTDIR}/_ext/839896833/IniFile.o ../../../../library/common/IniFile.cpp
+
 ${OBJECTDIR}/_ext/839896833/Java.o: ../../../../library/common/Java.cpp 
 	${MKDIR} -p ${OBJECTDIR}/_ext/839896833
 	${RM} "$@.d"
--- a/modules/fxpackager/src/main/native/tests/linux/library/packager/nbproject/configurations.xml	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/tests/linux/library/packager/nbproject/configurations.xml	Tue Mar 31 08:15:48 2015 -0700
@@ -43,6 +43,8 @@
     <itemPath>../../../../library/common/GenericPlatform.h</itemPath>
     <itemPath>../../../../library/common/Helpers.cpp</itemPath>
     <itemPath>../../../../library/common/Helpers.h</itemPath>
+    <itemPath>../../../../library/common/IniFile.cpp</itemPath>
+    <itemPath>../../../../library/common/IniFile.h</itemPath>
     <itemPath>../../../../library/common/Java.cpp</itemPath>
     <itemPath>../../../../library/common/Java.h</itemPath>
     <itemPath>../../../../library/common/JavaUserPreferences.cpp</itemPath>
@@ -58,6 +60,7 @@
     <itemPath>../../../../library/common/Macros.h</itemPath>
     <itemPath>../../../../library/common/Messages.cpp</itemPath>
     <itemPath>../../../../library/common/Messages.h</itemPath>
+    <itemPath>../../../../library/common/OrderedMap.h</itemPath>
     <itemPath>../../../../library/common/Package.cpp</itemPath>
     <itemPath>../../../../library/common/Package.h</itemPath>
     <itemPath>../../../../library/common/Platform.cpp</itemPath>
@@ -145,6 +148,16 @@
             tool="3"
             flavor2="0">
       </item>
+      <item path="../../../../library/common/IniFile.cpp"
+            ex="false"
+            tool="1"
+            flavor2="0">
+      </item>
+      <item path="../../../../library/common/IniFile.h"
+            ex="false"
+            tool="3"
+            flavor2="0">
+      </item>
       <item path="../../../../library/common/Java.cpp"
             ex="false"
             tool="1"
@@ -214,6 +227,11 @@
             tool="3"
             flavor2="0">
       </item>
+      <item path="../../../../library/common/OrderedMap.h"
+            ex="false"
+            tool="3"
+            flavor2="0">
+      </item>
       <item path="../../../../library/common/Package.cpp"
             ex="false"
             tool="1"
@@ -350,6 +368,16 @@
             tool="3"
             flavor2="0">
       </item>
+      <item path="../../../../library/common/IniFile.cpp"
+            ex="false"
+            tool="1"
+            flavor2="0">
+      </item>
+      <item path="../../../../library/common/IniFile.h"
+            ex="false"
+            tool="3"
+            flavor2="0">
+      </item>
       <item path="../../../../library/common/Java.cpp"
             ex="false"
             tool="1"
@@ -419,6 +447,11 @@
             tool="3"
             flavor2="0">
       </item>
+      <item path="../../../../library/common/OrderedMap.h"
+            ex="false"
+            tool="3"
+            flavor2="0">
+      </item>
       <item path="../../../../library/common/Package.cpp"
             ex="false"
             tool="1"
--- a/modules/fxpackager/src/main/native/tests/mac/library/packager/libpackager.xcodeproj/project.pbxproj	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/tests/mac/library/packager/libpackager.xcodeproj/project.pbxproj	Tue Mar 31 08:15:48 2015 -0700
@@ -7,6 +7,7 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		DE052CCE1A9F963700E05736 /* OrderedMap.h in Headers */ = {isa = PBXBuildFile; fileRef = DE052CCC1A9F963700E05736 /* OrderedMap.h */; };
 		DE0959CD19A51A02008845F2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE0959CC19A51A02008845F2 /* Cocoa.framework */; };
 		DE0959DE19A51A02008845F2 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE0959DD19A51A02008845F2 /* XCTest.framework */; };
 		DE0959DF19A51A02008845F2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE0959CC19A51A02008845F2 /* Cocoa.framework */; };
@@ -52,6 +53,8 @@
 		DE095A3F19A51A33008845F2 /* PropertyFile.h in Headers */ = {isa = PBXBuildFile; fileRef = DE095A1819A51A33008845F2 /* PropertyFile.h */; };
 		DE095A4019A51A33008845F2 /* WindowsPlatform.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE095A1919A51A33008845F2 /* WindowsPlatform.cpp */; };
 		DE095A4119A51A33008845F2 /* WindowsPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = DE095A1A19A51A33008845F2 /* WindowsPlatform.h */; };
+		DE4C1F2B1A8D31B10000D335 /* IniFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DE4C1F291A8D31B10000D335 /* IniFile.cpp */; };
+		DE4C1F2C1A8D31B10000D335 /* IniFile.h in Headers */ = {isa = PBXBuildFile; fileRef = DE4C1F2A1A8D31B10000D335 /* IniFile.h */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -65,6 +68,7 @@
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
+		DE052CCC1A9F963700E05736 /* OrderedMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OrderedMap.h; path = ../../../../../library/common/OrderedMap.h; sourceTree = "<group>"; };
 		DE0959C919A51A02008845F2 /* libpackager.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libpackager.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
 		DE0959CC19A51A02008845F2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
 		DE0959CF19A51A02008845F2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@@ -76,17 +80,17 @@
 		DE0959E519A51A02008845F2 /* libpackagerTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "libpackagerTests-Info.plist"; sourceTree = "<group>"; };
 		DE0959E719A51A02008845F2 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		DE0959E919A51A02008845F2 /* packagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = packagerTests.m; sourceTree = "<group>"; };
-		DE0959F419A51A33008845F2 /* Exports.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Exports.cpp; path = ../../../../../library/common/Exports.cpp; sourceTree = "<group>"; };
+		DE0959F419A51A33008845F2 /* Exports.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = Exports.cpp; path = ../../../../../library/common/Exports.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		DE0959F519A51A33008845F2 /* Exports.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exports.h; path = ../../../../../library/common/Exports.h; sourceTree = "<group>"; };
 		DE0959F619A51A33008845F2 /* FilePath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FilePath.cpp; path = ../../../../../library/common/FilePath.cpp; sourceTree = "<group>"; };
 		DE0959F719A51A33008845F2 /* FilePath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FilePath.h; path = ../../../../../library/common/FilePath.h; sourceTree = "<group>"; };
 		DE0959F819A51A33008845F2 /* GenericPlatform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = GenericPlatform.cpp; path = ../../../../../library/common/GenericPlatform.cpp; sourceTree = "<group>"; };
 		DE0959F919A51A33008845F2 /* GenericPlatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GenericPlatform.h; path = ../../../../../library/common/GenericPlatform.h; sourceTree = "<group>"; };
-		DE0959FA19A51A33008845F2 /* Helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Helpers.cpp; path = ../../../../../library/common/Helpers.cpp; sourceTree = "<group>"; };
-		DE0959FB19A51A33008845F2 /* Helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Helpers.h; path = ../../../../../library/common/Helpers.h; sourceTree = "<group>"; };
+		DE0959FA19A51A33008845F2 /* Helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = Helpers.cpp; path = ../../../../../library/common/Helpers.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+		DE0959FB19A51A33008845F2 /* Helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = Helpers.h; path = ../../../../../library/common/Helpers.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
 		DE0959FC19A51A33008845F2 /* Java.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Java.cpp; path = ../../../../../library/common/Java.cpp; sourceTree = "<group>"; };
 		DE0959FD19A51A33008845F2 /* Java.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Java.h; path = ../../../../../library/common/Java.h; sourceTree = "<group>"; };
-		DE0959FE19A51A33008845F2 /* JavaUserPreferences.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JavaUserPreferences.cpp; path = ../../../../../library/common/JavaUserPreferences.cpp; sourceTree = "<group>"; };
+		DE0959FE19A51A33008845F2 /* JavaUserPreferences.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = JavaUserPreferences.cpp; path = ../../../../../library/common/JavaUserPreferences.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
 		DE0959FF19A51A33008845F2 /* JavaUserPreferences.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JavaUserPreferences.h; path = ../../../../../library/common/JavaUserPreferences.h; sourceTree = "<group>"; };
 		DE095A0019A51A33008845F2 /* JavaVirtualMachine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JavaVirtualMachine.cpp; path = ../../../../../library/common/JavaVirtualMachine.cpp; sourceTree = "<group>"; };
 		DE095A0119A51A33008845F2 /* JavaVirtualMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JavaVirtualMachine.h; path = ../../../../../library/common/JavaVirtualMachine.h; sourceTree = "<group>"; };
@@ -115,6 +119,8 @@
 		DE095A1819A51A33008845F2 /* PropertyFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PropertyFile.h; path = ../../../../../library/common/PropertyFile.h; sourceTree = "<group>"; };
 		DE095A1919A51A33008845F2 /* WindowsPlatform.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WindowsPlatform.cpp; path = ../../../../../library/common/WindowsPlatform.cpp; sourceTree = "<group>"; };
 		DE095A1A19A51A33008845F2 /* WindowsPlatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WindowsPlatform.h; path = ../../../../../library/common/WindowsPlatform.h; sourceTree = "<group>"; };
+		DE4C1F291A8D31B10000D335 /* IniFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = IniFile.cpp; path = ../../../../../library/common/IniFile.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
+		DE4C1F2A1A8D31B10000D335 /* IniFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = IniFile.h; path = ../../../../../library/common/IniFile.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -183,8 +189,11 @@
 			children = (
 				DE0959F419A51A33008845F2 /* Exports.cpp */,
 				DE0959F519A51A33008845F2 /* Exports.h */,
+				DE4C1F291A8D31B10000D335 /* IniFile.cpp */,
 				DE0959F619A51A33008845F2 /* FilePath.cpp */,
 				DE0959F719A51A33008845F2 /* FilePath.h */,
+				DE4C1F2A1A8D31B10000D335 /* IniFile.h */,
+				DE052CCC1A9F963700E05736 /* OrderedMap.h */,
 				DE0959F819A51A33008845F2 /* GenericPlatform.cpp */,
 				DE0959F919A51A33008845F2 /* GenericPlatform.h */,
 				DE0959FA19A51A33008845F2 /* Helpers.cpp */,
@@ -261,6 +270,7 @@
 				DE095A3319A51A33008845F2 /* Messages.h in Headers */,
 				DE095A3719A51A33008845F2 /* Platform.h in Headers */,
 				DE095A3519A51A33008845F2 /* Package.h in Headers */,
+				DE4C1F2C1A8D31B10000D335 /* IniFile.h in Headers */,
 				DE095A3B19A51A33008845F2 /* PlatformThread.h in Headers */,
 				DE095A4119A51A33008845F2 /* WindowsPlatform.h in Headers */,
 				DE095A2419A51A33008845F2 /* Java.h in Headers */,
@@ -275,6 +285,7 @@
 				DE095A1E19A51A33008845F2 /* FilePath.h in Headers */,
 				DE095A3019A51A33008845F2 /* Macros.h in Headers */,
 				DE095A2819A51A33008845F2 /* JavaVirtualMachine.h in Headers */,
+				DE052CCE1A9F963700E05736 /* OrderedMap.h in Headers */,
 				DE095A2D19A51A33008845F2 /* MacPlatform.h in Headers */,
 				DE095A3919A51A33008845F2 /* PlatformString.h in Headers */,
 			);
@@ -378,6 +389,7 @@
 				DE095A3C19A51A33008845F2 /* PosixPlatform.cpp in Sources */,
 				DE095A2B19A51A33008845F2 /* Lock.cpp in Sources */,
 				DE095A2919A51A33008845F2 /* LinuxPlatform.cpp in Sources */,
+				DE4C1F2B1A8D31B10000D335 /* IniFile.cpp in Sources */,
 				DE095A3219A51A33008845F2 /* Messages.cpp in Sources */,
 				DE095A2E19A51A33008845F2 /* MacPlatform.mm in Sources */,
 				DE095A2319A51A33008845F2 /* Java.cpp in Sources */,
--- a/modules/fxpackager/src/main/native/tests/win/library/library.vcxproj	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/native/tests/win/library/library.vcxproj	Tue Mar 31 08:15:48 2015 -0700
@@ -109,6 +109,7 @@
     <ClCompile Include="..\..\..\library\common\FilePath.cpp" />
     <ClCompile Include="..\..\..\library\common\GenericPlatform.cpp" />
     <ClCompile Include="..\..\..\library\common\Helpers.cpp" />
+    <ClCompile Include="..\..\..\library\common\IniFile.cpp" />
     <ClCompile Include="..\..\..\library\common\Java.cpp" />
     <ClCompile Include="..\..\..\library\common\JavaUserPreferences.cpp" />
     <ClCompile Include="..\..\..\library\common\JavaVirtualMachine.cpp" />
@@ -130,6 +131,7 @@
     <ClInclude Include="..\..\..\library\common\FilePath.h" />
     <ClInclude Include="..\..\..\library\common\GenericPlatform.h" />
     <ClInclude Include="..\..\..\library\common\Helpers.h" />
+    <ClInclude Include="..\..\..\library\common\IniFile.h" />
     <ClInclude Include="..\..\..\library\common\Java.h" />
     <ClInclude Include="..\..\..\library\common\JavaUserPreferences.h" />
     <ClInclude Include="..\..\..\library\common\JavaVirtualMachine.h" />
@@ -138,6 +140,7 @@
     <ClInclude Include="..\..\..\library\common\MacPlatform.h" />
     <ClInclude Include="..\..\..\library\common\Macros.h" />
     <ClInclude Include="..\..\..\library\common\Messages.h" />
+    <ClInclude Include="..\..\..\library\common\OrderedMap.h" />
     <ClInclude Include="..\..\..\library\common\Package.h" />
     <ClInclude Include="..\..\..\library\common\Platform.h" />
     <ClInclude Include="..\..\..\library\common\PlatformString.h" />
@@ -149,4 +152,4 @@
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>
-</Project>
+</Project>
\ No newline at end of file
--- a/modules/fxpackager/src/main/resources/com/oracle/tools/packager/AbstractBundler.properties	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/AbstractBundler.properties	Tue Mar 31 08:15:48 2015 -0700
@@ -1,9 +1,6 @@
 param.images-root.name=
 param.images-root.description=
 
-error.jre-missing-file=Java Runtime does not include {0}
-error.jre-missing-file.advice=Make sure ant is using Oracle JDK 8 or later.
-
 message.using-default-resource=Using default package resource {0} (add {1} to the class path to customize)
 message.using-custom-resource-from-file=\   Using custom package resource {0} (loaded from file {1})
 message.using-custom-resource-from-classpath=\  Using custom package resource {0} (loaded from {1})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/AbstractImageBundler.properties	Tue Mar 31 08:15:48 2015 -0700
@@ -0,0 +1,7 @@
+param.launcher-cfg-format.name=Launcher .cfg File Format
+param.launcher-cfg-format.description=The file format of the .cfg file used by the launcher executable.  Current values are 'ini' and 'prop'.
+
+error.jre-missing-file=Java Runtime does not include {0}
+error.jre-missing-file.advice=Make sure ant is using Oracle JDK 8 or later.
+
+message.jvm-user-arg-is-null=WARNING\: a jvmuserarg has a null name or value.
--- a/modules/fxpackager/src/main/resources/com/oracle/tools/packager/StandardBundlerParam.properties	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/StandardBundlerParam.properties	Tue Mar 31 08:15:48 2015 -0700
@@ -133,6 +133,15 @@
 param.fa-description.name=File Association Description
 param.fa-description.description=The description to be used for associated files.  The default is "<appName> File".
 
+param.commercial-features.name=Unlock Commercial Features
+param.commercial-features.description=Some options require commercial features to be unlocked.  This must be passed in as true to unlock those features.  Otherwise they will be ignored.
+
+param.com-app-cds.name=Enable AppCDS
+param.com-app-cds.description=Enabled and package with Application Class Data Sharing, including generation of .jsa file.
+
+param.com-app-cds-root.name=AppCDS Root Classes
+param.com-app-cds-root.description=List of "root classes" for AppCDS to generate class sharing data from.  Default is the main class.
+
 error.required-parameter={0} is a required parameter.
 error.no-main-class-with-main-jar=An application class was not specified nor was one found in the jar {0}
 error.no-main-class-with-main-jar.advice=Please specify a applicationClass or ensure that the jar {0} specifies one in the manifest.
--- a/modules/fxpackager/src/main/resources/com/oracle/tools/packager/linux/LinuxAppBundler.properties	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/linux/LinuxAppBundler.properties	Tue Mar 31 08:15:48 2015 -0700
@@ -13,7 +13,7 @@
 error.parameters-null=Parameters map is null.
 error.parameters-null.advice=Pass in a non-null parameters map.
 error.empty-user-jvm-option-value=UserJvmOption key ''{0}'' has a null or empty value.
-error.empty-user-jvm-option-value.advice=Provide a value for the key or split the key into a key/value pair.  Such as '-Xmx1G' into '-Xmx' and '1G'. 
+error.empty-user-jvm-option-value.advice=Provide a value for the key or split the key into a key/value pair.  Such as '-Xmx1G' into '-Xmx' and '1G'.
 error.no-linux-resources=This copy of ant-javafx.jar does not support Linux.
 error.no-linux-resources.advice=Please use ant-javafx.jar coming with Oracle JDK for Linux.
 error.no-application-jar=Main application jar is missing.
--- a/modules/fxpackager/src/main/resources/com/oracle/tools/packager/linux/template.postinst	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/linux/template.postinst	Tue Mar 31 08:15:48 2015 -0700
@@ -21,6 +21,7 @@
     configure)
         echo Adding shortcut to the menu
 SECONDARY_LAUNCHERS_INSTALL
+APP_CDS_CACHE
         xdg-desktop-menu install --novendor /opt/APPLICATION_FS_NAME/APPLICATION_LAUNCHER_FILENAME.desktop
 FILE_ASSOCIATION_INSTALL
 
--- a/modules/fxpackager/src/main/resources/com/oracle/tools/packager/linux/template.spec	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/linux/template.spec	Tue Mar 31 08:15:48 2015 -0700
@@ -36,6 +36,7 @@
 
 %post
 SECONDARY_LAUNCHERS_INSTALL
+APP_CDS_CACHE
 xdg-desktop-menu install --novendor /opt/APPLICATION_FS_NAME/APPLICATION_LAUNCHER_FILENAME.desktop
 FILE_ASSOCIATION_INSTALL
 if [ "SERVICE_HINT" = "true" ]; then
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/mac/Info-lite.plist.template	Tue Mar 31 08:15:48 2015 -0700
@@ -0,0 +1,38 @@
+<?xml version="1.0" ?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+ <dict>
+  <key>LSMinimumSystemVersion</key>
+  <string>10.7.4</string>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>English</string>
+  <key>CFBundleAllowMixedLocalizations</key>
+  <true/>
+  <key>CFBundleExecutable</key>
+  <string>DEPLOY_LAUNCHER_NAME</string>
+  <key>CFBundleIconFile</key>
+  <string>DEPLOY_ICON_FILE</string>
+  <key>CFBundleIdentifier</key>
+  <string>DEPLOY_BUNDLE_IDENTIFIER</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>DEPLOY_BUNDLE_NAME</string>
+  <key>CFBundlePackageType</key>
+  <string>APPL</string>
+  <key>CFBundleShortVersionString</key>
+  <string>DEPLOY_BUNDLE_SHORT_VERSION</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <!-- See http://developer.apple.com/library/mac/#releasenotes/General/SubmittingToMacAppStore/_index.html
+       for list of AppStore categories -->
+  <key>LSApplicationCategoryType</key>
+  <string>DEPLOY_BUNDLE_CATEGORY</string>
+  <key>CFBundleVersion</key>
+  <string>DEPLOY_BUNDLE_CFBUNDLE_VERSION</string>
+  <key>NSHumanReadableCopyright</key>
+  <string>DEPLOY_BUNDLE_COPYRIGHT</string>DEPLOY_FILE_ASSOCIATIONS
+  <key>NSHighResolutionCapable</key>
+  <string>true</string>
+ </dict>
+</plist>
--- a/modules/fxpackager/src/main/resources/com/oracle/tools/packager/mac/MacAppBundler.properties	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/mac/MacAppBundler.properties	Tue Mar 31 08:15:48 2015 -0700
@@ -10,8 +10,11 @@
 param.config-root.name=
 param.config-root.description=
 
+param.configure-launcher-in-plist=Configure Launcher in Info.plist
+param.configure-launcher-in-plist.description=Should the legacy method of configuring hte launcher in the Info.plist be used.
+
 param.category-name=Category
-param.category-name.description=Mac App Store Categories. Note that the key is the string to display to the user and the value is the id of the category
+param.category-name.description=Mac App Store Categories. Note that the key is the string to display to the user and the value is the id of the category.
 
 param.cfbundle-name.name=CFBundleName
 param.cfbundle-name.description=The name of the app as it appears in the Menu Bar.  This can be different from the application name.  This name should be less than 16 characters long and be suitable for displaying in the menu bar and the app’s Info window.
@@ -37,7 +40,7 @@
 error.no-application-jar=Main application jar is missing.
 error.no-application-jar.advice=Make sure to use fx\:jar task to create main application jar.
 error.empty-user-jvm-option-value=UserJvmOption key ''{0}'' has a null or empty value.
-error.empty-user-jvm-option-value.advice=Provide a value for the key or split the key into a key/value pair.  Such as '-Xmx1G' into '-Xmx' and '1G'. 
+error.empty-user-jvm-option-value.advice=Provide a value for the key or split the key into a key/value pair.  Such as '-Xmx1G' into '-Xmx' and '1G'.
 error.cannot-create-output-dir=Output directory {0} cannot be created.
 error.cannot-write-to-output-dir=Output directory {0} is not writable.
 error.invalid-cfbundle-version=Invalid CFBundleVersion - ''{0}''
--- a/modules/fxpackager/src/main/resources/com/oracle/tools/packager/windows/WinAppBundler.properties	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/windows/WinAppBundler.properties	Tue Mar 31 08:15:48 2015 -0700
@@ -18,7 +18,7 @@
 error.parameters-null=Parameters map is null.
 error.parameters-null.advice=Pass in a non-null parameters map.
 error.empty-user-jvm-option-value=UserJvmOption key ''{0}'' has a null or empty value.
-error.empty-user-jvm-option-value.advice=Provide a value for the key or split the key into a key/value pair.  Such as '-Xmx1G' into '-Xmx' and '1G'. 
+error.empty-user-jvm-option-value.advice=Provide a value for the key or split the key into a key/value pair.  Such as '-Xmx1G' into '-Xmx' and '1G'.
 error.no-windows-resources=This copy of ant-javafx.jar does not support Windows.
 error.no-windows-resources.advice=Please use ant-javafx.jar coming with Oracle JDK for Windows.
 error.no-application-jar=Main application jar is missing.
--- a/modules/fxpackager/src/main/resources/com/oracle/tools/packager/windows/template.iss	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/windows/template.iss	Tue Mar 31 08:15:48 2015 -0700
@@ -48,6 +48,7 @@
 SECONDARY_LAUNCHERS
 
 [Run]
+Filename: "{app}\RUN_FILENAME.exe"; Parameters: "-Xappcds:generatecache"; Check: APPLICATION_APP_CDS()
 Filename: "{app}\RUN_FILENAME.exe"; Description: "{cm:LaunchProgram,APPLICATION_NAME}"; Flags: nowait postinstall skipifsilent; Check: APPLICATION_NOT_SERVICE()
 Filename: "{app}\RUN_FILENAME.exe"; Parameters: "-install -svcName ""APPLICATION_NAME"" -svcDesc ""APPLICATION_DESCRIPTION"" -mainExe ""APPLICATION_LAUNCHER_FILENAME"" START_ON_INSTALL RUN_AT_STARTUP"; Check: APPLICATION_SERVICE()
 
--- a/modules/fxpackager/src/main/resources/com/oracle/tools/packager/windows/template.wxs	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/main/resources/com/oracle/tools/packager/windows/template.wxs	Tue Mar 31 08:15:48 2015 -0700
@@ -40,6 +40,7 @@
         </DirectoryRef>        
         <?include bundle.wxi ?>
 UI_BLOCK
+APP_CDS_BLOCK
         <Icon Id="DesktopIcon.exe" SourceFile="APPLICATION_ICON" />
         <Icon Id="StartMenuIcon.exe" SourceFile="APPLICATION_ICON" />
 SECONDARY_LAUNCHER_ICONS
--- a/modules/fxpackager/src/test/java/com/oracle/tools/packager/CLITest.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/test/java/com/oracle/tools/packager/CLITest.java	Tue Mar 31 08:15:48 2015 -0700
@@ -103,6 +103,7 @@
                     "-paramFile", f.getPath(),
                     "-native", "image",
                     "-name", "SmokeParams",
+                    "-Blauncher-cfg-format=prop",
                     "-BOptionThatWillNeverExist=true",
                     "-BuserJvmOptions=-Xmx=1g",
                     "-BuserJvmOptions=-Xms=512m",
--- a/modules/fxpackager/src/test/java/com/oracle/tools/packager/linux/LinuxAppBundlerTest.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/test/java/com/oracle/tools/packager/linux/LinuxAppBundlerTest.java	Tue Mar 31 08:15:48 2015 -0700
@@ -219,6 +219,7 @@
             assertNotNull(p.getProperty("app.preferences.id"));
             assertNotNull(p.getProperty("app.mainclass"));
             assertNotNull(p.getProperty("app.classpath"));
+            assertNotNull(p.getProperty("app.identifier"));
 
             // - make sure 'app.classpath=null' doesn't show up, prefer 'app.classpath='
             assertFalse(p.getProperty("app.classpath").equals("null"));
--- a/modules/fxpackager/src/test/java/com/oracle/tools/packager/linux/LinuxDebBundlerTest.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/test/java/com/oracle/tools/packager/linux/LinuxDebBundlerTest.java	Tue Mar 31 08:15:48 2015 -0700
@@ -53,6 +53,7 @@
 import java.util.TreeMap;
 
 import static com.oracle.tools.packager.StandardBundlerParam.*;
+import static com.oracle.tools.packager.linux.LinuxAppBundler.LINUX_RUNTIME;
 import static com.oracle.tools.packager.linux.LinuxDebBundler.BUNDLE_NAME;
 import static com.oracle.tools.packager.linux.LinuxDebBundler.EMAIL;
 import static org.junit.Assert.*;
@@ -63,6 +64,8 @@
     static File workDir;
     static File appResourcesDir;
     static File fakeMainJar;
+    static String runtimeJdk;
+    static String runtimeJre;
     static Set<File> appResources;
     static boolean retain = false;
 
@@ -71,6 +74,9 @@
         // only run on linux
         Assume.assumeTrue(System.getProperty("os.name").toLowerCase().startsWith("linux"));
 
+        runtimeJdk = System.getenv("PACKAGER_JDK_ROOT");
+        runtimeJre = System.getenv("PACKAGER_JRE_ROOT");
+
         Assume.assumeTrue(LinuxDebBundler.testTool(LinuxDebBundler.TOOL_DPKG, "1"));
 
         Log.setLogger(new Log.Logger(true));
@@ -586,4 +592,36 @@
 
         bundler.validate(bundleParams);
     }
+
+
+    /**
+     * Turn on AppCDS
+     */
+    @Test
+    public void testAppCDS() throws IOException, ConfigException, UnsupportedPlatformException {
+        Bundler bundler = new LinuxDebBundler();
+
+        Map<String, Object> bundleParams = new HashMap<>();
+
+        // not part of the typical setup, for testing
+        bundleParams.put(BUILD_ROOT.getID(), tmpBase);
+        bundleParams.put(VERBOSE.getID(), true);
+        if (runtimeJdk != null) {
+            bundleParams.put(LINUX_RUNTIME.getID(), runtimeJdk);
+        }
+
+        bundleParams.put(APP_NAME.getID(), "AppCDS");
+        bundleParams.put(IDENTIFIER.getID(), "com.example.appcds.deb.Test");
+        bundleParams.put(APP_RESOURCES.getID(), new RelativeFileSet(appResourcesDir, appResources));
+        bundleParams.put(UNLOCK_COMMERCIAL_FEATURES.getID(), true);
+        bundleParams.put(ENABLE_APP_CDS.getID(), true);
+
+        boolean valid = bundler.validate(bundleParams);
+        assertTrue(valid);
+
+        File output = bundler.execute(bundleParams, new File(workDir, "CDSTest"));
+        System.err.println("Bundle at - " + output);
+        assertNotNull(output);
+        assertTrue(output.exists());
+    }
 }
--- a/modules/fxpackager/src/test/java/com/oracle/tools/packager/linux/LinuxRpmBundlerTest.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/test/java/com/oracle/tools/packager/linux/LinuxRpmBundlerTest.java	Tue Mar 31 08:15:48 2015 -0700
@@ -52,6 +52,7 @@
 
 import static com.oracle.tools.packager.StandardBundlerParam.*;
 import static com.oracle.tools.packager.linux.LinuxAppBundler.ICON_PNG;
+import static com.oracle.tools.packager.linux.LinuxAppBundler.LINUX_RUNTIME;
 import static com.oracle.tools.packager.linux.LinuxRpmBundler.BUNDLE_NAME;
 import static org.junit.Assert.*;
 
@@ -61,6 +62,8 @@
     static File workDir;
     static File appResourcesDir;
     static File fakeMainJar;
+    static String runtimeJdk;
+    static String runtimeJre;
     static Set<File> appResources;
     static boolean retain = false;
 
@@ -69,6 +72,9 @@
         // only run on linux
         Assume.assumeTrue(System.getProperty("os.name").toLowerCase().startsWith("linux"));
 
+        runtimeJdk = System.getenv("PACKAGER_JDK_ROOT");
+        runtimeJre = System.getenv("PACKAGER_JRE_ROOT");
+
         Assume.assumeTrue(LinuxRpmBundler.testTool(LinuxRpmBundler.TOOL_RPMBUILD, LinuxRpmBundler.TOOL_RPMBUILD_MIN_VERSION));
 
         Log.setLogger(new Log.Logger(true));
@@ -521,4 +527,36 @@
         assertNotNull(result);
         assertTrue(result.exists());
     }
+
+    /**
+     * Turn on AppCDS
+     */
+    @Test
+    public void testAppCDS() throws IOException, ConfigException, UnsupportedPlatformException {
+        Bundler bundler = new LinuxRpmBundler();
+
+        Map<String, Object> bundleParams = new HashMap<>();
+
+        // not part of the typical setup, for testing
+        bundleParams.put(BUILD_ROOT.getID(), tmpBase);
+        bundleParams.put(VERBOSE.getID(), true);
+        if (runtimeJdk != null) {
+            bundleParams.put(LINUX_RUNTIME.getID(), runtimeJdk);
+        }
+
+        bundleParams.put(APP_NAME.getID(), "AppCDS");
+        bundleParams.put(IDENTIFIER.getID(), "com.example.appcds.rpm.Test");
+        bundleParams.put(APP_RESOURCES.getID(), new RelativeFileSet(appResourcesDir, appResources));
+        bundleParams.put(UNLOCK_COMMERCIAL_FEATURES.getID(), true);
+        bundleParams.put(ENABLE_APP_CDS.getID(), true);
+
+        boolean valid = bundler.validate(bundleParams);
+        assertTrue(valid);
+
+        File output = bundler.execute(bundleParams, new File(workDir, "CDSTest"));
+        System.err.println("Bundle at - " + output);
+        assertNotNull(output);
+        assertTrue(output.exists());
+    }
+    
 }
--- a/modules/fxpackager/src/test/java/com/oracle/tools/packager/mac/MacAppBundlerTest.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/test/java/com/oracle/tools/packager/mac/MacAppBundlerTest.java	Tue Mar 31 08:15:48 2015 -0700
@@ -760,6 +760,38 @@
     }
 
     /**
+     * Turn on AppCDS
+     */
+    @Test
+    public void testAppCDS() throws IOException, ConfigException, UnsupportedPlatformException {
+        Bundler bundler = new MacAppBundler();
+
+        Map<String, Object> bundleParams = new HashMap<>();
+
+        // not part of the typical setup, for testing
+        bundleParams.put(BUILD_ROOT.getID(), tmpBase);
+        bundleParams.put(VERBOSE.getID(), true);
+
+        bundleParams.put(APP_NAME.getID(), "AppCDSTest");
+        bundleParams.put(IDENTIFIER.getID(), "com.example.appcds.Test");
+        bundleParams.put(APP_RESOURCES.getID(), new RelativeFileSet(appResourcesDir, appResources));
+        bundleParams.put(UNLOCK_COMMERCIAL_FEATURES.getID(), true);
+        bundleParams.put(ENABLE_APP_CDS.getID(), true);
+
+        if (runtimeJdk != null) {
+            bundleParams.put(MAC_RUNTIME.getID(), runtimeJdk);
+        }
+
+        boolean valid = bundler.validate(bundleParams);
+        assertTrue(valid);
+
+        File output = bundler.execute(bundleParams, new File(workDir, "CDSTest"));
+        System.err.println("Bundle at - " + output);
+        assertNotNull(output);
+        assertTrue(output.exists());
+    }
+
+    /**
      * Verify a match on too many keys doesn't blow things up
      */
     @Test
--- a/modules/fxpackager/src/test/java/com/oracle/tools/packager/mac/MacAppStoreBundlerTest.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/test/java/com/oracle/tools/packager/mac/MacAppStoreBundlerTest.java	Tue Mar 31 08:15:48 2015 -0700
@@ -185,7 +185,7 @@
         );
         bundleParams.put(MAC_CF_BUNDLE_VERSION.getID(), "1.0." + new SimpleDateFormat("YYYYMMddHHmm").format(new Date()));
         bundleParams.put(CLASSPATH.getID(), "mainApp.jar");
-        bundleParams.put(IDENTIFIER.getID(), "com.example.javapacakger.hello.TestPackager");
+        bundleParams.put(IDENTIFIER.getID(), "com.example.javapackager.hello.TestPackager");
         bundleParams.put(MacAppBundler.MAC_CATEGORY.getID(), "public.app-category.developer-tools");
         bundleParams.put(APP_RESOURCES.getID(), new RelativeFileSet(appResourcesDir, appResources));
         bundleParams.put(VERBOSE.getID(), true);
@@ -320,7 +320,7 @@
                         new HashSet<>(Arrays.asList(fakeMainJar)))
         );
         bundleParams.put(CLASSPATH.getID(), "mainApp.jar");
-        bundleParams.put(IDENTIFIER.getID(), "com.example.javapacakger.hello.TestPackager");
+        bundleParams.put(IDENTIFIER.getID(), "com.example.javapackager.hello.TestPackager");
         bundleParams.put(MacAppBundler.MAC_CATEGORY.getID(), "public.app-category.developer-tools");
         bundleParams.put(APP_RESOURCES.getID(), new RelativeFileSet(appResourcesDir, appResources));
         bundleParams.put(VERBOSE.getID(), true);
@@ -355,7 +355,7 @@
                         new HashSet<>(Arrays.asList(fakeMainJar)))
         );
         bundleParams.put(CLASSPATH.getID(), "mainApp.jar");
-        bundleParams.put(IDENTIFIER.getID(), "com.example.javapacakger.hello.TestPackager");
+        bundleParams.put(IDENTIFIER.getID(), "com.example.javapackager.hello.TestPackager");
         bundleParams.put(MacAppBundler.MAC_CATEGORY.getID(), "public.app-category.developer-tools");
         bundleParams.put(APP_RESOURCES.getID(), new RelativeFileSet(appResourcesDir, appResources));
         bundleParams.put(VERBOSE.getID(), true);
--- a/modules/fxpackager/src/test/java/com/oracle/tools/packager/windows/WinAppBundlerTest.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/test/java/com/oracle/tools/packager/windows/WinAppBundlerTest.java	Tue Mar 31 08:15:48 2015 -0700
@@ -221,6 +221,7 @@
             assertNotNull(p.getProperty("app.preferences.id"));
             assertNotNull(p.getProperty("app.mainclass"));
             assertNotNull(p.getProperty("app.classpath"));
+            assertNotNull(p.getProperty("app.identifier"));
 
             // - make sure 'app.classpath=null' doesn't show up, prefer 'app.classpath='
             assertFalse(p.getProperty("app.classpath").equals("null"));
@@ -377,5 +378,36 @@
         System.err.println("Bundle at - " + output);
         assertNotNull(output);
         assertTrue(output.exists());
-    }    
+    }
+
+    /**
+     * Turn on AppCDS
+     */
+    @Test
+    public void testAppCDS() throws IOException, ConfigException, UnsupportedPlatformException {
+        Bundler bundler = new WinAppBundler();
+
+        Map<String, Object> bundleParams = new HashMap<>();
+
+        // not part of the typical setup, for testing
+        bundleParams.put(BUILD_ROOT.getID(), tmpBase);
+        bundleParams.put(VERBOSE.getID(), true);
+        if (runtimeJdk != null) {
+            bundleParams.put(WIN_RUNTIME.getID(), runtimeJdk);
+        }
+
+        bundleParams.put(APP_NAME.getID(), "AppCDS");
+        bundleParams.put(IDENTIFIER.getID(), "com.example.appcds.image.Test");
+        bundleParams.put(APP_RESOURCES.getID(), new RelativeFileSet(appResourcesDir, appResources));
+        bundleParams.put(UNLOCK_COMMERCIAL_FEATURES.getID(), true);
+        bundleParams.put(ENABLE_APP_CDS.getID(), true);
+
+        boolean valid = bundler.validate(bundleParams);
+        assertTrue(valid);
+
+        File output = bundler.execute(bundleParams, new File(workDir, "CDSTest"));
+        System.err.println("Bundle at - " + output);
+        assertNotNull(output);
+        assertTrue(output.exists());
+    }
 }
--- a/modules/fxpackager/src/test/java/com/oracle/tools/packager/windows/WinExeBundlerTest.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/test/java/com/oracle/tools/packager/windows/WinExeBundlerTest.java	Tue Mar 31 08:15:48 2015 -0700
@@ -63,6 +63,8 @@
     static File workDir;
     static File appResourcesDir;
     static File fakeMainJar;
+    static String runtimeJdk;
+    static String runtimeJre;
     static Set<File> appResources;
     static boolean retain = false;
 
@@ -71,6 +73,9 @@
         // only run on windows
         Assume.assumeTrue(System.getProperty("os.name").toLowerCase().startsWith("win"));
 
+        runtimeJdk = System.getenv("PACKAGER_JDK_ROOT");
+        runtimeJre = System.getenv("PACKAGER_JRE_ROOT");
+
         // only run if we have InnoSetup installed
         Assume.assumeNotNull(WinExeBundler.TOOL_INNO_SETUP_COMPILER_EXECUTABLE.fetchFrom(new HashMap<>()));
 
@@ -511,4 +516,36 @@
         assertNotNull(result);
         assertTrue(result.exists());
     }
+
+    /**
+     * Turn on AppCDS
+     */
+    @Test
+    public void testAppCDS() throws IOException, ConfigException, UnsupportedPlatformException {
+        Bundler bundler = new WinExeBundler();
+
+        Map<String, Object> bundleParams = new HashMap<>();
+
+        // not part of the typical setup, for testing
+        bundleParams.put(BUILD_ROOT.getID(), tmpBase);
+        bundleParams.put(VERBOSE.getID(), true);
+        if (runtimeJdk != null) {
+            bundleParams.put(WIN_RUNTIME.getID(), runtimeJdk);
+        }
+
+        bundleParams.put(APP_NAME.getID(), "AppCDS");
+        bundleParams.put(IDENTIFIER.getID(), "com.example.appcds.exe.Test");
+        bundleParams.put(APP_RESOURCES.getID(), new RelativeFileSet(appResourcesDir, appResources));
+        bundleParams.put(UNLOCK_COMMERCIAL_FEATURES.getID(), true);
+        bundleParams.put(ENABLE_APP_CDS.getID(), true);
+
+        boolean valid = bundler.validate(bundleParams);
+        assertTrue(valid);
+
+        File output = bundler.execute(bundleParams, new File(workDir, "CDSTest"));
+        System.err.println("Bundle at - " + output);
+        assertNotNull(output);
+        assertTrue(output.exists());
+    }
+    
 }
--- a/modules/fxpackager/src/test/java/com/oracle/tools/packager/windows/WinMsiBundlerTest.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/test/java/com/oracle/tools/packager/windows/WinMsiBundlerTest.java	Tue Mar 31 08:15:48 2015 -0700
@@ -64,6 +64,8 @@
     static File workDir;
     static File appResourcesDir;
     static File fakeMainJar;
+    static String runtimeJdk;
+    static String runtimeJre;
     static Set<File> appResources;
     static boolean retain = false;
 
@@ -72,6 +74,9 @@
         // only run on windows
         Assume.assumeTrue(System.getProperty("os.name").toLowerCase().startsWith("win"));
 
+        runtimeJdk = System.getenv("PACKAGER_JDK_ROOT");
+        runtimeJre = System.getenv("PACKAGER_JRE_ROOT");
+
         // only run if we have Wix tools installed
         Assume.assumeNotNull(WinMsiBundler.TOOL_LIGHT_EXECUTABLE.fetchFrom(new HashMap<>()));
         Assume.assumeNotNull(WinMsiBundler.TOOL_CANDLE_EXECUTABLE.fetchFrom(new HashMap<>()));
@@ -540,4 +545,36 @@
         assertNotNull(result);
         assertTrue(result.exists());    	
     }
+
+
+    /**
+     * Turn on AppCDS
+     */
+    @Test
+    public void testAppCDS() throws IOException, ConfigException, UnsupportedPlatformException {
+        Bundler bundler = new WinMsiBundler();
+
+        Map<String, Object> bundleParams = new HashMap<>();
+
+        // not part of the typical setup, for testing
+        bundleParams.put(BUILD_ROOT.getID(), tmpBase);
+        bundleParams.put(VERBOSE.getID(), true);
+        if (runtimeJdk != null) {
+            bundleParams.put(WIN_RUNTIME.getID(), runtimeJdk);
+        }
+
+        bundleParams.put(APP_NAME.getID(), "AppCDS");
+        bundleParams.put(IDENTIFIER.getID(), "com.example.appcds.msi.Test");
+        bundleParams.put(APP_RESOURCES.getID(), new RelativeFileSet(appResourcesDir, appResources));
+        bundleParams.put(UNLOCK_COMMERCIAL_FEATURES.getID(), true);
+        bundleParams.put(ENABLE_APP_CDS.getID(), true);
+
+        boolean valid = bundler.validate(bundleParams);
+        assertTrue(valid);
+
+        File output = bundler.execute(bundleParams, new File(workDir, "CDSTest"));
+        System.err.println("Bundle at - " + output);
+        assertNotNull(output);
+        assertTrue(output.exists());
+    }
 }
--- a/modules/fxpackager/src/test/java/hello/TestPackager.java	Mon Mar 30 20:30:05 2015 -0600
+++ b/modules/fxpackager/src/test/java/hello/TestPackager.java	Tue Mar 31 08:15:48 2015 -0700
@@ -172,6 +172,11 @@
         TestPackager.args = args;
         //Schedule a job for the event-dispatching thread:
         //creating and showing this application's GUI.
-        javax.swing.SwingUtilities.invokeLater(TestPackager::createAndShowGUI);
+		try {
+			javax.swing.SwingUtilities.invokeAndWait(TestPackager::createAndShowGUI);
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
     }
 }