changeset 9620:887ad2ef8dea jdk-9+111

8092093: Modularization support for JavaFX Summary: Initial JavaFX integration for JEP 200, JEP 260, and JEP 261 Reviewed-by: ddhill, vadim, cbensen Contributed-by: kevin.rushforth@oracle.com, chien.yang@oracle.com, danno.ferrin@oracle.com, chris.bensen@oracle.com, dmitry.cherepanov@oracle.com, david.hill@oracle.com, vadim.pakhnushev@oracle.com
author kcr
date Thu, 17 Mar 2016 14:01:55 -0700
parents 2209ba2006b3
children 8424bb5642b7 4bf08c297b46
files .idea/modules.xml apps/tests/Robot/nbproject/project.properties apps/toys/Hello/src/main/java/hello/HelloLaunchOnNewThread.java build.gradle build.properties buildSrc/src/main/java/jarjar/org/gradle/process/internal/child/BootstrapSecurityManager.java buildSrc/src/main/java/workaround/GradleJUnitWorker.java dependencies/java.base/module-info.java.extra dependencies/java.desktop/module-info.java.extra dependencies/jdk.jdeps/module-info.java.extra modules/base/make/build.properties modules/base/src/main/conf/security/java.policy modules/base/src/main/module-info/module-info.java modules/base/src/test/addExports modules/controls/make/build.properties modules/controls/src/main/conf/security/java.policy modules/controls/src/main/java/com/sun/javafx/scene/control/skin/Utils.java modules/controls/src/main/module-info/module-info.java modules/controls/src/test/addExports modules/fxml/make/build.properties modules/fxml/src/main/conf/security/java.policy modules/fxml/src/main/java/com/sun/javafx/fxml/BeanAdapter.java modules/fxml/src/main/java/com/sun/javafx/fxml/ModuleHelper.java modules/fxml/src/main/java/com/sun/javafx/fxml/builder/ProxyBuilder.java modules/fxml/src/main/java/com/sun/javafx/fxml/builder/URLBuilder.java modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java modules/fxml/src/main/java/javafx/fxml/JavaFXBuilderFactory.java modules/fxml/src/main/module-info/module-info.java modules/fxml/src/test/addExports modules/fxpackager/make/build.properties modules/fxpackager/src/main/java/com/oracle/tools/packager/AbstractBundler.java modules/fxpackager/src/main/java/com/oracle/tools/packager/AbstractImageBundler.java modules/fxpackager/src/main/java/com/oracle/tools/packager/BasicBundlers.java modules/fxpackager/src/main/java/com/oracle/tools/packager/BundlerParamInfo.java modules/fxpackager/src/main/java/com/oracle/tools/packager/Bundlers.java modules/fxpackager/src/main/java/com/oracle/tools/packager/JDepHelper.java modules/fxpackager/src/main/java/com/oracle/tools/packager/JLinkBundlerHelper.java modules/fxpackager/src/main/java/com/oracle/tools/packager/Module.java modules/fxpackager/src/main/java/com/oracle/tools/packager/ModuleManager.java modules/fxpackager/src/main/java/com/oracle/tools/packager/StandardBundlerParam.java modules/fxpackager/src/main/java/com/oracle/tools/packager/linux/LinuxAppBundler.java modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacAppBundler.java modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacAppStoreBundler.java modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacBaseInstallerBundler.java modules/fxpackager/src/main/java/com/oracle/tools/packager/windows/WinAppBundler.java modules/fxpackager/src/main/java/com/sun/javafx/tools/ant/Application.java modules/fxpackager/src/main/java/com/sun/javafx/tools/ant/DeployFXTask.java modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/DeployParams.java modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/Main.java modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/PackagerLib.java modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/bundlers/BundleParams.java modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/bundlers/Bundler.java modules/fxpackager/src/main/java/jdk/packager/builders/AbstractAppImageBuilder.java modules/fxpackager/src/main/java/jdk/packager/builders/linux/LinuxAppImageBuilder.java modules/fxpackager/src/main/java/jdk/packager/builders/mac/MacAppImageBuilder.java modules/fxpackager/src/main/java/jdk/packager/builders/windows/WindowsAppImageBuilder.java modules/fxpackager/src/main/java/jdk/packager/services/UserJvmOptionsService.java modules/fxpackager/src/main/java/jdk/packager/services/userjvmoptions/LauncherUserJvmOptions.java modules/fxpackager/src/main/java/jdk/packager/services/userjvmoptions/PreferencesUserJvmOptions.java modules/fxpackager/src/main/module-info/module-info.java modules/fxpackager/src/main/native/javapackager/shell/javapackager modules/fxpackager/src/main/native/library/common/GenericPlatform.cpp modules/fxpackager/src/main/native/library/common/Helpers.cpp modules/fxpackager/src/main/native/library/common/Helpers.h modules/fxpackager/src/main/native/library/common/JavaVirtualMachine.cpp modules/fxpackager/src/main/native/library/common/Package.cpp modules/fxpackager/src/main/native/library/common/Package.h modules/fxpackager/src/main/native/library/common/Platform.cpp modules/fxpackager/src/main/native/library/common/Platform.h modules/fxpackager/src/main/native/library/common/PosixPlatform.cpp modules/fxpackager/src/main/native/library/common/PosixPlatform.h modules/fxpackager/src/main/native/library/common/WindowsPlatform.cpp modules/fxpackager/src/main/native/library/common/WindowsPlatform.h modules/fxpackager/src/main/resources/com/oracle/tools/packager/JLinkBundlerHelper.properties modules/fxpackager/src/main/resources/com/oracle/tools/packager/mac/Runtime-Info.plist.template modules/fxpackager/src/main/resources/com/oracle/tools/packager/windows/WinAppBundler.properties modules/fxpackager/src/main/resources/jdk/packager/builders/AbstractAppImageBuilder.properties modules/fxpackager/src/main/resources/jdk/packager/builders/linux/LinuxAppImageBuilder.properties modules/fxpackager/src/main/resources/jdk/packager/builders/mac/MacAppImageBuilder.properties modules/fxpackager/src/main/resources/jdk/packager/builders/windows/WindowsAppImageBuilder.properties modules/fxpackager/src/test/java/com/oracle/tools/packager/mac/MacAppBundlerTest.java modules/fxpackager/src/test/java/com/oracle/tools/packager/mac/MacAppStoreBundlerTest.java modules/fxpackager/src/test/java/com/oracle/tools/packager/mac/MacDaemonBundlerTest.java modules/fxpackager/src/test/java/com/oracle/tools/packager/mac/MacDmgBundlerTest.java modules/fxpackager/src/test/java/com/oracle/tools/packager/mac/MacPkgBundlerTest.java modules/fxpackager/src/test/java/com/oracle/tools/packager/windows/RuntimeFlagsParserTest.java modules/fxpackager/src/test/java/hello/SimpleBundle.java modules/fxpackager/src/test/java/hello/TestPackager.java modules/fxpackagerservices/make/build.properties modules/fxpackagerservices/src/main/java/jdk/packager/services/UserJvmOptionsService.java modules/fxpackagerservices/src/main/java/jdk/packager/services/userjvmoptions/LauncherUserJvmOptions.java modules/fxpackagerservices/src/main/java/jdk/packager/services/userjvmoptions/PreferencesUserJvmOptions.java modules/fxpackagerservices/src/main/module-info/module-info.java modules/graphics/make/build.properties modules/graphics/src/main/conf/security/java.policy modules/graphics/src/main/java/com/sun/glass/utils/NativeLibLoader.java modules/graphics/src/main/java/com/sun/javafx/application/LauncherImpl.java modules/graphics/src/main/java/com/sun/javafx/css/StyleManager.java modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java modules/graphics/src/main/java/javafx/css/converter/URLConverter.java modules/graphics/src/main/java/javafx/scene/image/Image.java modules/graphics/src/main/java/netscape/javascript/JSException.java modules/graphics/src/main/java/netscape/javascript/JSObject.java modules/graphics/src/main/module-info/module-info.java modules/graphics/src/test/addExports modules/media/make/build.properties modules/media/src/main/conf/security/java.policy modules/media/src/main/java/com/sun/media/jfxmedia/locator/Locator.java modules/media/src/main/module-info/module-info.java modules/swing/make/build.properties modules/swing/src/main/conf/security/java.policy modules/swing/src/main/module-info/module-info.java modules/web/make/build.properties modules/web/src/main/conf/security/java.policy modules/web/src/main/java/com/sun/webkit/LocalizedStrings.java modules/web/src/main/module-info/module-info.java modules/web/src/test/addExports settings.gradle tests/system/src/test/addExports tests/system/src/test/java/test/com/sun/javafx/css/StylesheetWithSecurityManagerTest.java tests/system/src/test/java/test/sandbox/Constants.java tests/system/src/test/java/test/sandbox/SandboxAppTest.java tests/system/src/test/java/test/util/Util.java
diffstat 123 files changed, 6618 insertions(+), 3356 deletions(-) [+]
line wrap: on
line diff
--- a/.idea/modules.xml	Tue Mar 15 04:00:44 2016 -0700
+++ b/.idea/modules.xml	Thu Mar 17 14:01:55 2016 -0700
@@ -27,6 +27,7 @@
       <module fileurl="file://$PROJECT_DIR$/.idea/deploy.iml" filepath="$PROJECT_DIR$/.idea/deploy.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/fxml.iml" filepath="$PROJECT_DIR$/.idea/fxml.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/fxpackager.iml" filepath="$PROJECT_DIR$/.idea/fxpackager.iml" />
+      <module fileurl="file://$PROJECT_DIR$/.idea/fxpackagerServices.iml" filepath="$PROJECT_DIR$/.idea/fxpackagerServices.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/graphics.iml" filepath="$PROJECT_DIR$/.idea/graphics.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/media.iml" filepath="$PROJECT_DIR$/.idea/media.iml" />
       <module fileurl="file://$PROJECT_DIR$/.idea/rt.iml" filepath="$PROJECT_DIR$/.idea/rt.iml" />
--- a/apps/tests/Robot/nbproject/project.properties	Tue Mar 15 04:00:44 2016 -0700
+++ b/apps/tests/Robot/nbproject/project.properties	Thu Mar 17 14:01:55 2016 -0700
@@ -66,6 +66,7 @@
 run.classpath=\
     ${javac.classpath}:\
     ${build.classes.dir}
+run.jvmargs=-XaddExports:javafx.graphics/com.sun.glass.ui=ALL-UNNAMED
 run.test.classpath=\
     ${javac.test.classpath}:\
     ${build.test.classes.dir}
--- a/apps/toys/Hello/src/main/java/hello/HelloLaunchOnNewThread.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/apps/toys/Hello/src/main/java/hello/HelloLaunchOnNewThread.java	Thu Mar 17 14:01:55 2016 -0700
@@ -25,6 +25,7 @@
 
 package hello;
 
+import java.util.concurrent.atomic.AtomicBoolean;
 import javafx.application.Application;
 import javafx.scene.Group;
 import javafx.scene.Scene;
@@ -35,6 +36,7 @@
 public class HelloLaunchOnNewThread extends Application {
 
     static long startTime;
+    static AtomicBoolean mainCalled = new AtomicBoolean(false);
 
     public HelloLaunchOnNewThread() {
         long endTime = System.nanoTime();
@@ -42,6 +44,11 @@
         System.err.println("DONE: elapsed time = " + elapsedMsec + " msec");
         System.err.println("Constructor: currentThread="
                 + Thread.currentThread().getName());
+        if (!mainCalled.get()) {
+            System.err.println("***************************************");
+            System.err.println("*** ERROR: main() method not called ***");
+            System.err.println("***************************************");
+        }
     }
 
     @Override public void init() {
@@ -81,6 +88,7 @@
      * @param args the command line arguments
      */
     public static void main(final String[] args) {
+        mainCalled.set(true);
         System.err.println("main: currentThread="
                 + Thread.currentThread().getName());
         new Thread(() -> {
--- a/build.gradle	Tue Mar 15 04:00:44 2016 -0700
+++ b/build.gradle	Thu Mar 17 14:01:55 2016 -0700
@@ -294,11 +294,27 @@
         new File(javaHomeFile.getParent(), "jdk1.${javaHomeFile.name.substring(3)}.0").toString() :
         javaHome) // we have to bail and set it to something and this is as good as any!
 ext.JAVA_HOME = JDK_HOME
+
+// Check whether JIGSAW_HOME is set. If it is, then it points to a JDK9
+// jigsaw build with modularization enabled and can be used for testing
+def envJigsawHome = cygpath(System.getenv("JIGSAW_HOME"))
+defineProperty("JIGSAW_HOME", envJigsawHome);
+
+if (JIGSAW_HOME == null || JIGSAW_HOME == "") {
+    logger.warn("JIGSAW_HOME is not set");
+    ext.USE_JIGSAW = false
+} else {
+    ext.USE_JIGSAW = true
+}
+
 defineProperty("JAVA", cygpath("$JDK_HOME/bin/java${IS_WINDOWS ? '.exe' : ''}"))
+defineProperty("JIGSAW_JAVA", cygpath("$JIGSAW_HOME/bin/java${IS_WINDOWS ? '.exe' : ''}"))
 defineProperty("JAVAC", cygpath("$JDK_HOME/bin/javac${IS_WINDOWS ? '.exe' : ''}"))
+defineProperty("JIGSAW_JAVAC", cygpath("$JIGSAW_HOME/bin/javac${IS_WINDOWS ? '.exe' : ''}"))
 defineProperty("JAVAH", cygpath("$JDK_HOME/bin/javah${IS_WINDOWS ? '.exe' : ''}"))
 defineProperty("JAVADOC", cygpath("$JDK_HOME/bin/javadoc${IS_WINDOWS ? '.exe' : ''}"))
 defineProperty("JDK_DOCS", "https://docs.oracle.com/javase/8/docs/api/")
+defineProperty("JIGSAW_MODULES", cygpath(System.getenv("JIGSAW_MODULES")) ?: "")
 
 defineProperty("javaRuntimeVersion", System.getProperty("java.runtime.version"))
 def javaVersionInfo = parseJavaVersion(javaRuntimeVersion)
@@ -356,11 +372,15 @@
 defineProperty("COMPILE_PARFAIT", "false")
 ext.IS_COMPILE_PARFAIT = Boolean.parseBoolean(COMPILE_PARFAIT)
 
+// FIXME: update the default when using 9 (pre-jigsaw) as boot jdk
 // COMPILE_JFR specifies whether to build code that logs to JRockit Flight Recorder
-// FIXME: change this to also allow JDK 9 boot jdk
 defineProperty("COMPILE_JFR", Boolean.toString(file("$JDK_HOME/jre/lib/jfr.jar").exists()))
 ext.IS_COMPILE_JFR = Boolean.parseBoolean(COMPILE_JFR)
 
+// BUILD_FXPACKAGER enables building the packager modules and native code
+defineProperty("BUILD_FXPACKAGER", "false")
+ext.IS_BUILD_FXPACKAGER = Boolean.parseBoolean(BUILD_FXPACKAGER)
+
 // RETAIN_PACKAGER_TESTS specifies whether the tests in fxpackager should
 // keep generated files instead of attempting to automatically delete them
 defineProperty("RETAIN_PACKAGER_TESTS", "false")
@@ -391,6 +411,12 @@
 defineProperty("FULL_TEST", "false")
 ext.IS_FULL_TEST = Boolean.parseBoolean(FULL_TEST);
 
+defineProperty("JIGSAW_TEST", "true")
+ext.IS_JIGSAW_TEST = Boolean.parseBoolean(JIGSAW_TEST) && USE_JIGSAW
+
+defineProperty("FORCE_TESTS", "false")
+ext.IS_FORCE_TESTS = Boolean.parseBoolean(FORCE_TESTS);
+
 // Specifies whether to run robot-based visual tests (only used when FULL_TEST is also enabled)
 defineProperty("USE_ROBOT", "false")
 ext.IS_USE_ROBOT = Boolean.parseBoolean(USE_ROBOT);
@@ -721,7 +747,7 @@
 
     if (targetProperties.compileSwing) COMPILE_SWING = true
     if (targetProperties.compileSWT) COMPILE_SWT = true
-    if (targetProperties.compileFXPackager) COMPILE_FXPACKAGER = true
+    if (IS_BUILD_FXPACKAGER && JIGSAW_HOME && targetProperties.compileFXPackager) COMPILE_FXPACKAGER = true
 
     if (!targetProperties.containsKey('compileWebnodeNative')) {
         // unless specified otherwise, we will compile native Webnode if IS_COMPILE_WEBKIT
@@ -742,19 +768,15 @@
 
     if (!targetProperties.containsKey('includeGTK')) targetProperties.includeGTK = IS_LINUX
 
-    // This value is used to under ./build/${sdkDirName} to allow for
-    // a common name for the hosted build (for use when building apps)
-    // and a unique name for cross builds.
+    // This value is used as a prefix for various directories under ./build,
+    // such as sdk, to allow for a common name for the hosted build
+    // (for use when building apps) and a unique name for cross builds.
     if (rootProject.defaultHostTarget.equals(t.name)) {
         // use a simple common default for the "host" build
-        targetProperties.sdkDirName="sdk"
-        targetProperties.exportDirName="export"
-        targetProperties.bundleDirName="bundles"
+        targetProperties.platformPrefix=""
     } else {
         // and a more complex one for cross builds
-        targetProperties.sdkDirName="${t.name}-sdk"
-        targetProperties.exportDirName="${t.name}-export"
-        targetProperties.bundleDirName="${t.name}-bundles"
+        targetProperties.platformPrefix="${t.name}-"
     }
 }
 
@@ -788,11 +810,12 @@
 
 // Make sure JDK_HOME/bin/java exists
 if (!file(JAVA).exists()) throw new Exception("Missing or incorrect path to 'java': '$JAVA'. Perhaps bad JDK_HOME? $JDK_HOME")
+if (!file(JIGSAW_JAVA).exists()) logger.warn("Missing or incorrect path to JIGSAW 'java': '$JIGSAW_JAVA'. Perhaps bad JIGSAW_HOME? $JIGSAW_HOME")
 if (!file(JAVAC).exists()) throw new Exception("Missing or incorrect path to 'javac': '$JAVAC'. Perhaps bad JDK_HOME? $JDK_HOME")
+if (!file(JIGSAW_JAVAC).exists()) logger.warn("Missing or incorrect path to JIGSAW 'javac': '$JIGSAW_JAVAC'. Perhaps bad JIGSAW_HOME? $JIGSAW_HOME")
 if (!file(JAVAH).exists()) throw new Exception("Missing or incorrect path to 'javah': '$JAVAH'. Perhaps bad JDK_HOME? $JDK_HOME")
 if (!file(JAVADOC).exists()) throw new Exception("Missing or incorrect path to 'javadoc': '$JAVADOC'. Perhaps bad JDK_HOME? $JDK_HOME")
 
-
 // Determine the verion of Java in JDK_HOME. It looks like this:
 //
 // $ java -version
@@ -835,8 +858,8 @@
     NUM_COMPILE_THREADS = 1
 }
 
-// Check that Gradle 2.9 is in use, error if < 1.8.
-if (gradle.gradleVersion != "2.9") {
+// Check that Gradle 2.11 is in use, error if < 2.9.
+if (gradle.gradleVersion != "2.11") {
     def ver = gradle.gradleVersion.split("[\\.]");
     def gradleMajor = Integer.parseInt(ver[0]);
     def gradleMinor = Integer.parseInt(ver[1]);
@@ -851,7 +874,7 @@
 
     logger.warn("*****************************************************************");
     logger.warn("Unsupported gradle version $gradle.gradleVersion in use.");
-    logger.warn("Only version 2.9 is supported. Use this version at your own risk");
+    logger.warn("Only version 2.11 is supported. Use this version at your own risk");
     if ( err != "") logger.warn(err);
     logger.warn("*****************************************************************");
 }
@@ -870,13 +893,14 @@
 logger.quiet("OS_ARCH: $OS_ARCH")
 logger.quiet("JAVA_HOME: $JAVA_HOME")
 logger.quiet("JDK_HOME: $JDK_HOME")
+logger.quiet("JIGSAW_HOME: $JIGSAW_HOME")
 logger.quiet("java.runtime.version: ${javaRuntimeVersion}")
 logger.quiet("java version: ${javaVersion}")
 logger.quiet("java build number: ${javaBuildNumber}")
 logger.quiet("jdk.runtime.version: ${jdkRuntimeVersion}")
 logger.quiet("jdk version: ${jdkVersion}")
 logger.quiet("jdk build number: ${jdkBuildNumber}")
-logger.quiet("minimum jdk version: ${jfxBuildJdkVersion}")
+logger.quiet("minimum jdk version: ${jfxBuildJdkVersionMin}")
 logger.quiet("minimum jdk build number: ${jfxBuildJdkBuildnumMin}")
 logger.quiet("STUB_RUNTIME: $STUB_RUNTIME")
 logger.quiet("CONF: $CONF")
@@ -1123,9 +1147,9 @@
 // Task to verify the minimum level of Java needed to build JavaFX
 task verifyJava() {
     doLast {
-        def status = compareJdkVersion(jdkVersion, jfxBuildJdkVersion);
+        def status = compareJdkVersion(jdkVersion, jfxBuildJdkVersionMin);
         if (status < 0) {
-            fail("java version mismatch: JDK version (${jdkVersion}) < minimum version (${jfxBuildJdkVersion})")
+            fail("java version mismatch: JDK version (${jdkVersion}) < minimum version (${jfxBuildJdkVersionMin})")
         } else if (status == 0) {
             def buildNum = Integer.parseInt(jdkBuildNumber)
             def minBuildNum = Integer.parseInt(jfxBuildJdkBuildnumMin)
@@ -1313,6 +1337,16 @@
 // The "base" project is our first module and the most basic one required for
 // all other modules. It is useful even for non-GUI applications.
 project(":base") {
+    project.ext.buildModule = true
+    project.ext.moduleRuntime = true
+    project.ext.moduleName = "javafx.base"
+
+    Set<String> testInclude = [ "test/**" ]
+    configureJigsawTests(project, null,
+        null, testInclude,
+        project.projectDir.path + "/src/test/addExports"
+        )
+
     dependencies {
         compile BUILD_SRC
     }
@@ -1374,6 +1408,23 @@
         stub
     }
 
+    project.ext.buildModule = true
+    project.ext.moduleRuntime = true
+    project.ext.moduleName = "javafx.graphics"
+
+    Set<String> testInclude = [ "test/**" ]
+    configureJigsawTests(project, [ "base" ],
+        null, testInclude,
+        project.projectDir.path + "/src/test/addExports"
+        )
+
+    project.ext.extraBuildDirs = [
+        "${buildDir}/classes/jsl-decora",
+        "${buildDir}/resources/jsl-decora",
+        "${buildDir}/classes/jsl-prism",
+        "${buildDir}/resources/jsl-prism"
+    ]
+
     dependencies {
         compile project(":base"), BUILD_SRC
         stubCompile group: "junit", name: "junit", version: "4.8.2",
@@ -1685,6 +1736,16 @@
 }
 
 project(":controls") {
+    project.ext.buildModule = true
+    project.ext.moduleRuntime = true
+    project.ext.moduleName = "javafx.controls"
+
+    Set<String> testInclude = [ "test/**" ]
+    configureJigsawTests(project, [ "base", "graphics" ],
+        null, testInclude,
+        project.projectDir.path + "/src/test/addExports"
+    )
+
     dependencies {
         compile BUILD_SRC, project(":base"), project(":graphics")
         // TODO not sure how to specify this? processResources project(":base"), project(":graphics")
@@ -1736,9 +1797,20 @@
         if (!COMPILE_SWING) it.enabled = false
     }
     */
+    project.ext.buildModule = COMPILE_SWING
+    project.ext.moduleRuntime = true
+    project.ext.moduleName = "javafx.swing"
+
     dependencies {
         compile BUILD_SRC, project(":base"), project(":graphics")
     }
+
+    Set<String> testInclude = [ "test/**" ]
+    configureJigsawTests(project, [ "base", "graphics", "controls" ],
+        null, testInclude,
+        null // no addExports
+    )
+
     test {
         enabled = IS_FULL_TEST && IS_AWT_TEST
     }
@@ -1777,6 +1849,16 @@
 }
 
 project(":fxml") {
+    project.ext.buildModule = true
+    project.ext.moduleRuntime = true
+    project.ext.moduleName = "javafx.fxml"
+
+    Set<String> testInclude = [ "test/**" ]
+    configureJigsawTests(project, [ "base", "graphics" ],
+        null, testInclude,
+        project.projectDir.path + "/src/test/addExports"
+    )
+
     dependencies {
         compile BUILD_SRC, project(":base"), project(":graphics"),
                 project(":controls"), project(":swt"), project(":swing")
@@ -1793,6 +1875,9 @@
 }
 
 project(":jmx") {
+    project.ext.buildModule = false // true
+    project.ext.moduleRuntime = false
+    project.ext.moduleName = "javafx.jmx"
     dependencies {
         compile project(":base")
         compile project(":graphics")
@@ -1811,10 +1896,30 @@
     }
 }
 
-project(":fxpackager") {
+project(":fxpackagerservices") {
+    project.ext.buildModule = COMPILE_FXPACKAGER
+    project.ext.moduleRuntime = false
+    project.ext.moduleName = "jdk.packager.services"
     tasks.all {
         if (!COMPILE_FXPACKAGER) it.enabled = false
     }
+
+    test {
+        if (IS_JIGSAW_TEST) {
+            enabled = false // FIXME: JIGSAW -- support this with modules
+            logger.info("JIGSAW Testing disabled for fxpackagerservices")
+        }
+    }
+}
+
+project(":fxpackager") {
+    project.ext.buildModule = COMPILE_FXPACKAGER
+    project.ext.moduleRuntime = false
+    project.ext.moduleName = "jdk.packager"
+    tasks.all {
+        if (!COMPILE_FXPACKAGER) it.enabled = false
+    }
+
     // fxpackager has a dependency on ant in order to build the ant jar,
     // and as such needs to point to the apache binary repository
     if (!BUILD_CLOSED) {
@@ -1827,6 +1932,8 @@
 
     dependencies {
         compile group: "org.apache.ant", name: "ant", version: "1.8.2"
+        compile project(":fxpackagerservices")
+        testCompile project(":controls")
     }
 
     // When producing the jar, we need to relocate a few class files
@@ -1835,6 +1942,7 @@
     jar {
         includeEmptyDirs = false
         archiveName = "ant-javafx.jar"
+        includes = ["com/sun/javafx/tools/ant/**", "com/javafx/main/**"]
         eachFile { FileCopyDetails details ->
             if (details.path.startsWith("com/javafx/main")) {
                 details.path = "resources/classes/$details.path"
@@ -1958,6 +2066,7 @@
             params.addAll(MAC.launcher.ccFlags)
             compiler = MAC.launcher.compiler
             output(file("$buildDir/classes/main/com/oracle/tools/packager/mac"))
+            outputs.file(file("$buildDir/classes/main/com/oracle/tools/packager/mac/JavaAppLauncher"))
             eachOutputFile = { f ->
                 return new File(f.getParent(), "JavaAppLauncher")
             }
@@ -2082,20 +2191,7 @@
         }
     }
 
-    task packagerJar(type: Jar) {
-        group = "Basic"
-        description = "Creates the packager.jar"
-        archiveName = "packager.jar";
-        includeEmptyDirs = false
-        from("$buildDir/classes/main");
-        from("$buildDir/resources/main");
-        include('jdk/packager/**')
-
-        dependsOn(buildJavaPackager);
-    }
-
     jar.dependsOn buildJavaPackager
-    jar.dependsOn packagerJar
 
     classes << {
         // Copy all of the download libraries to libs directory for the sake of the IDEs
@@ -2175,10 +2271,16 @@
     }
 
     test {
+        if (IS_JIGSAW_TEST) {
+            enabled = false // FIXME: JIGSAW -- support this with modules
+            logger.info("JIGSAW Testing disabled for fxpackager")
+        }
+
         dependsOn packagerFXPackagedJar
         systemProperty "RETAIN_PACKAGER_TESTS", RETAIN_PACKAGER_TESTS
         systemProperty "TEST_PACKAGER_DMG", TEST_PACKAGER_DMG
         systemProperty "FULL_TEST", FULL_TEST
+        executable = JIGSAW_JAVA;
     }
 
     def packagerDevOpts = []
@@ -2188,13 +2290,15 @@
         packagerDevOpts.addAll("image")
     }
 
-    task packagerDev(dependsOn: [jar, packagerFakeJar], type:JavaExec) {
+    task packagerDev(dependsOn: [jar, testClasses, packagerFakeJar], type:JavaExec) {
         workingDir = project.file("build/tmp/tests/appResources/")
+        executable = JIGSAW_JAVA
         classpath = project.files("build/libs/ant-javafx.jar", "build/classes/test", "build/resources/test")
         main = "hello.SimpleBundle"
         args = [
-                "-o", "$projectDir/build/dev",
-                "-all",
+                '-modulepath', JIGSAW_MODULES,
+                '-o', "$projectDir/build/dev",
+                '-all',
                 packagerDevOpts
         ].flatten()
     }
@@ -2205,6 +2309,10 @@
         media
     }
 
+    project.ext.buildModule = true
+    project.ext.moduleRuntime = true
+    project.ext.moduleName = "javafx.media"
+
     dependencies {
         compile BUILD_SRC, project(":base"), project(":graphics")
     }
@@ -2505,15 +2613,28 @@
     configurations {
         webkit
     }
+    project.ext.buildModule = true
+    project.ext.moduleRuntime = true
+    project.ext.moduleName = "javafx.web"
+
+    Set<String> testInclude = [ "test/**" ]
+    configureJigsawTests(project, [ "base", "graphics" ],
+        null, testInclude,
+        project.projectDir.path + "/src/test/addExports"
+        )
+
     dependencies {
         compile project(":base"), project(":graphics"), project(":controls"), project(":media")
     }
 
     test {
+        if (!IS_JIGSAW_TEST) {
+        //TODO: support this in Jake
         // Run web tests in headless mode
         systemProperty 'glass.platform', 'Monocle'
         systemProperty 'monocle.platform', 'Headless'
         systemProperty 'prism.order', 'sw'
+        }
     }
 
     if (!IS_COMPILE_WEBKIT) {
@@ -2707,8 +2828,7 @@
                     into "$gensrcDir/com/sun/webkit/dom"
                 }
             }
-            classpath = files(project.sourceSets.main.output.classesDir) +
-                        files(project(":graphics").sourceSets.main.output) // for JSObject
+            classpath = files(project.sourceSets.main.output.classesDir)
             source gensrcDir
             destinationDir = file("$buildDir/classes/main")
         }
@@ -2745,8 +2865,16 @@
     dependencies {
         testCompile project(":graphics").sourceSets.test.output
         testCompile project(":base").sourceSets.test.output
+        testCompile project(":controls").sourceSets.test.output
+        testCompile project(":swing").sourceSets.test.output
     }
 
+    Set<String> testInclude = [ "test/**" ]
+    configureJigsawTests(project, [ "base", "graphics", "controls", "swing", "fxml", "web" ],
+        null, testInclude,
+        project.projectDir.path + "/src/test/addExports"
+    )
+
     test {
         enabled = IS_FULL_TEST
         if (!IS_USE_ROBOT) {
@@ -2802,6 +2930,19 @@
     }
 }
 
+// fxpackager requires JDK 9 to compile
+project(":fxpackager") {
+    tasks.withType(JavaCompile) { compile ->
+        compile.options.forkOptions.executable = JIGSAW_JAVAC
+        compile.options.compilerArgs = [
+                "-XaddExports:java.base/sun.security.pkcs=ALL-UNNAMED,"
+                        + "java.base/sun.security.timestamp=ALL-UNNAMED,"
+                        + "java.base/sun.security.x509=ALL-UNNAMED,"
+                        + "jdk.jdeps/com.sun.tools.jdeps=ALL-UNNAMED",
+                "-encoding", "UTF-8"]
+    }
+}
+
 /******************************************************************************
  *                                                                            *
  *                             Top Level Tasks                                *
@@ -2996,15 +3137,32 @@
     dependsOn(sdk,publicExports,apps,perf,zips)
 }
 
+
+// Construct list of subprojects that are modules
+ext.moduleProjList = []
+subprojects {
+    if (project.hasProperty("buildModule") && project.ext.buildModule) {
+        rootProject.ext.moduleProjList += project
+        println "module: $project (buildModule=YES)"
+    } else {
+        println "module: $project (buildModule=NO)"
+    }
+}
+
+
+// Create the legacy sdk from the modular-sdk
+
 compileTargets { t ->
     def targetProperties = project.ext[t.upper]
-    def sdkDirName = targetProperties.sdkDirName
-    def library = targetProperties.library
-
-    def isWindows = IS_WINDOWS && t.name == "win";
-    def isMac = IS_MAC && t.name == "mac";
-
-    // The jfxrt task is responsible for creating the jfxrt.jar. A developer may
+    def platformPrefix = targetProperties.platformPrefix
+    def sdkDirName = "${platformPrefix}sdk"
+    def modularSdkDirName = "${platformPrefix}modular-sdk"
+    def modularSdkDir = "${rootProject.buildDir}/${modularSdkDirName}"
+    def modulesDir = "${modularSdkDir}/modules"
+    def modulesCmdsDir = "${modularSdkDir}/modules_cmds"
+    def modulesLibsDir = "${modularSdkDir}/modules_libs"
+
+    // The jfxrt task is responsible for creating the legacy jfxrt.jar. A developer may
     // have multiple SDK's on their system at any one time, depending on which
     // cross compiles they have done. For example, I might have:
     //      build/ios-sdk/lib/jfxrt.jar
@@ -3019,119 +3177,16 @@
         description = "Creates the jfxrt.jar for the $t.name target"
         archiveName = "build/${sdkDirName}/lib/jfxrt.jar";
         includeEmptyDirs = false
-        from("modules/base/build/classes/main",
-             "modules/base/build/resources/main",
-             "modules/graphics/build/classes/main",
-             "modules/graphics/build/resources/main",
-             "modules/controls/build/classes/main",
-             "modules/controls/build/resources/main",
-             "modules/fxml/build/classes/main",
-             "modules/fxml/build/resources/main",
-             "modules/graphics/build/classes/jsl-decora",
-             "modules/graphics/build/resources/jsl-decora",
-             "modules/graphics/build/classes/jsl-prism",
-             "modules/graphics/build/resources/jsl-prism",
-             "modules/media/build/classes/main",
-             "modules/media/build/resources/main")
-        if (COMPILE_SWING) from ("modules/swing/build/classes/main", "modules/swing/build/resources/main")
-
-        // Exclude obsolete, experimental, or non-shipping code
-        exclude("version.rc")
-        exclude("com/sun/glass/ui/swt")
-        exclude("com/sun/javafx/tools/ant")
-        exclude("com/javafx/main")
-        if (!IS_INCLUDE_NULL3D) {
-            exclude ("com/sun/prism/null3d")
+
+        moduleProjList.each { project ->
+            if (project.ext.moduleRuntime) {
+                from("${modulesDir}/${project.ext.moduleName}");
+            }
         }
-        if (!IS_INCLUDE_ES2) {
-               exclude("com/sun/prism/es2",
-                       "com/sun/scenario/effect/impl/es2")
-        }
-
-        // Exclude platform-specific classes for other platforms
-
-        if (!isMac) {
-            exclude ("com/sun/media/jfxmediaimpl/platform/osx",
-                     "com/sun/prism/es2/MacGL*",
-                     "com/sun/glass/events/mac",
-                     "com/sun/glass/ui/mac",
-                     )
-        }
-
-        if (!isWindows) {
-            exclude ("**/*.hlsl",
-                     "com/sun/glass/ui/win",
-                     "com/sun/prism/d3d",
-                     "com/sun/prism/es2/WinGL*",
-                     "com/sun/scenario/effect/impl/hw/d3d"
-                     )
-        }
-
-        if (!targetProperties.includeGTK) { //usually IS_LINUX
-            exclude (
-                     "com/sun/glass/ui/gtk",
-                     "com/sun/prism/es2/EGL*",
-                     "com/sun/prism/es2/X11GL*"
-                     )
-        }
-
-        if (!targetProperties.includeEGL) {
-            exclude ("com/sun/prism/es2/EGL*")
-        }
-
-        if (!targetProperties.includeLens) {
-            exclude ("com/sun/glass/ui/lens")
-        }
-
-        // FIXME: Figure out what to do with Monocle
-        /*
-        if (!targetProperties.includeMonocle) {
-            exclude ("com/sun/glass/ui/monocle")
-            exclude("com/sun/prism/es2/Monocle*")
-        }
-        */
-
-        if (t.name != 'ios') {
-            exclude ("com/sun/media/jfxmediaimpl/platform/ios",
-                     "com/sun/glass/ui/ios",
-                     "com/sun/prism/es2/IOS*"
-                     )
-        }
-
-        if (t.name != 'android' && t.name != 'dalvik') {
-            exclude ("com/sun/glass/ui/android")
-        }
-
-        // Filter out other platform-specific classes
-        if (targetProperties.containsKey('jfxrtJarExcludes')) {
-            exclude(targetProperties.jfxrtJarExcludes)
-        }
-
-        if (t.name == 'android') {
-            from ("modules/web/build/classes/android",
-                  "modules/web/build/resources/android",
-                  "modules/controls/build/classes/android",
-                  "modules/controls/build/resources/android")
-        } else if (t.name == 'ios') {
-            from ("modules/web/build/classes/ios",
-                  "modules/web/build/resources/ios",
-                  "modules/extensions/build/classes/ios")
-        } else {
-            from ("modules/web/build/classes/main", "modules/web/build/resources/main")
-        }
-
-        exclude("**/javafx/embed/swt/**")
-
-        if (!targetProperties.includeSwing) {
-            exclude("javafx/embed/swing")
-        }
-        exclude("js/**/*", // er...
-                "PrismLoaderBackend*", // More decora stuff
-                "**/*.stg",    // any glue files for decora must be excluded
-                "**/*.java");  // Builder java files are in build/classes and should be excluded
 
         dependsOn(subprojects.collect { project -> project.getTasksByName("assemble", true)});
     }
+
     def jfxrtIndexTask = task("jfxrtIndex$t.capital") {
         //the following is a workaround for the lack of indexing in gradle 1.4 through 1.7
         dependsOn(jfxrtTask)
@@ -3142,6 +3197,7 @@
     }
     jfxrt.dependsOn(jfxrtIndexTask)
 
+    // FIXME: JIGSAW -- update this for modules
     def jfxswtTask = task("jfxswt$t.capital", type: Jar) {
         enabled = COMPILE_SWT
         group = "Basic"
@@ -3154,6 +3210,7 @@
 
         dependsOn(subprojects.collect { project -> project.getTasksByName("assemble", true)});
     }
+
     def jfxswtIndexTask = task("jfxswtIndex$t.capital") {
         //the following is a workaround for the lack of indexing in gradle 1.4 through 1.7
         dependsOn(jfxswtTask)
@@ -3174,101 +3231,28 @@
         dependsOn project(":jmx").assemble
     }
 
-    // The 'sdk' task will build the rest of the SDK, and depends on the 'jfxrtTask' task. After
-    // executing this task the sdk bundle for the current COMPILE_TARGETS will be fully created.
+    // The 'sdk' task will build the rest of the legacy SDK, and depends
+    // on the 'jfxrtTask' task. After executing this task the sdk bundle for
+    // the current COMPILE_TARGETS will be fully created.
     def sdkTask = task("sdk$t.capital") {
         group = "Basic"
         description = "Creates the SDK for $t.name"
         doLast {
-            // TODO instead of using copy everywhere, I probably want to use "sync" instead?
-            // Copy all of the .dll / .so / .dylib native libraries into build/sdk/lib/
             copy {
-                def useLipo = targetProperties.containsKey('useLipo') ? targetProperties.useLipo : false
-                from("modules/graphics/build/libs/jsl-decora/${t.name}/${library(targetProperties.decora.lib)}")
-                def libs = ['font', 'prism', 'prismSW', 'glass', 'iio']
-                if (IS_INCLUDE_ES2) {
-                    libs += ['prismES2'];
+                moduleProjList.each { project ->
+                    from "${modulesLibsDir}/${project.ext.moduleName}"
                 }
-                if (IS_COMPILE_PANGO) {
-                    libs += ['fontFreetype', 'fontPango'];
+                into "build/${sdkDirName}/lib"
+            }
+
+            copy {
+                moduleProjList.each { project ->
+                    from "${modulesCmdsDir}/${project.ext.moduleName}"
                 }
-                libs.each { lib ->
-                    def variants = targetProperties[lib].containsKey('variants') && !useLipo ? targetProperties[lib].variants : [null]
-                    variants.each { variant ->
-                        def variantProperties = variant ? targetProperties[lib][variant] : targetProperties[lib]
-                        println "modules/graphics/build/libs/$lib/$t.name/${library(variantProperties.lib)}"
-                        from ("modules/graphics/build/libs/$lib/$t.name/${library(variantProperties.lib)}")
-                    }
-                }
-                if (IS_WINDOWS) {
-                    from ("modules/graphics/build/libs/prismD3D/${t.name}/${library(targetProperties.prismD3D.lib)}");
-                }
-                if (IS_COMPILE_WEBKIT) {
-                    from ("modules/web/build/libs/${t.name}/${library('jfxwebkit')}")
-                } else {
-                    if (t.name != "android" && t.name != "ios" && t.name != "dalvik") {
-                        from ("$LIBRARY_STUB/${library('jfxwebkit')}")
-                    }
-                }
-
-                def mediaBuildType = project(":media").ext.buildType
-                if (IS_COMPILE_MEDIA) {
-                    [ "fxplugins", "gstreamer-lite", "jfxmedia" ].each { name ->
-                        from ("modules/media/build/native/${t.name}/${mediaBuildType}/${library(name)}") }
-
-                    if (t.name == "mac") {
-                        // OSX media natives
-                        [ "jfxmedia_qtkit", "jfxmedia_avf", "glib-lite" ].each { name ->
-                            from ("modules/media/build/native/${t.name}/${mediaBuildType}/${library(name)}") }
-                    } else if (t.name == "linux") {
-                        from("modules/media/build/native/${t.name}/${mediaBuildType}") { include "libavplugin*.so" }
-                    } else from ("modules/media/build/native/${t.name}/${mediaBuildType}/${library("glib-lite")}")
-                } else {
-                    if (t.name != "android"  && t.name != "dalvik" ) {
-                        [ "fxplugins", "gstreamer-lite", "jfxmedia" ].each { name ->
-                            from ("$LIBRARY_STUB/${library(name)}") }
-                    }
-
-                    if (t.name == "mac") {
-                        // copy libjfxmedia_{avf,qtkit}.dylib if they exist
-                        [ "jfxmedia_qtkit", "jfxmedia_avf", "glib-lite" ].each { name ->
-                            from ("$LIBRARY_STUB/${library(name)}") }
-                    } else if (t.name == "linux") {
-                        from(LIBRARY_STUB) { include "libavplugin*.so" }
-                    }
-                    else if (t.name != "android"  && t.name != "dalvik" ) {
-                        from ("$LIBRARY_STUB/${library("glib-lite")}")
-                    }
-                }
-
-                def libDest = targetProperties.libDest
-                into ("build/${sdkDirName}/$libDest")
+                into "build/${sdkDirName}/bin"
             }
 
-            // Create the javafx.properties file
-            final File javafxProperties = file("build/${sdkDirName}/lib/javafx.properties")
-            javafxProperties.delete()
-            javafxProperties << "javafx.version=$RELEASE_VERSION_SHORT";
-            javafxProperties << "\n"
-            javafxProperties << "javafx.runtime.version=$RELEASE_VERSION_LONG";
-            javafxProperties << "\n"
-            javafxProperties << "javafx.runtime.build=$PROMOTED_BUILD_NUMBER";
-            javafxProperties << "\n"
-            // Include any properties that have been defined (most likely in
-            // one of the various platform gradle files)
-            if (targetProperties.containsKey("javafxProperties")) {
-                javafxProperties << targetProperties.javafxProperties
-                javafxProperties << "\n"
-            }
-
-            // Embedded builds define this file as well
-            if (targetProperties.containsKey("javafxPlatformProperties")) {
-                final File javafxPlatformProperties = file("build/${sdkDirName}/lib/javafx.platform.properties")
-                javafxPlatformProperties.delete()
-                javafxPlatformProperties << targetProperties.javafxPlatformProperties
-                javafxPlatformProperties << "\n"
-            }
-
+            // FIXME: JIGSAW -- update this for modules
             // Copy over the javadocs that were generated. This is done rather than just generating
             // the docs into the "right place" because for a cross-compile you only need one set of
             // docs but need to have a copy in each created sdk
@@ -3279,6 +3263,7 @@
                 }
             }
 
+            // FIXME: JIGSAW -- update this for modules
             // Copy over the javafx-src bundle
             if (IS_BUILD_SRC_ZIP) {
                 copy {
@@ -3287,25 +3272,12 @@
                 }
             }
 
-            // Copy over the fxpackager and rename as ant-javafx.jar
-            copy {
-                from "modules/fxpackager/build/libs"
-                into "build/${sdkDirName}/lib"
-            }
-
-            // Copy over the FXPackager man files
+            // FIXME: JIGSAW -- update this for modules
+            // Copy over the javapackager man files
             copy {
                 from "modules/fxpackager/build/man"
                 into "build/${sdkDirName}/man"
             }
-
-            // Copy over the javapackager executable
-            if (t.name == "win" || t.name == "linux" || t.name == "mac") {
-                copy {
-                    from "modules/fxpackager/build/javapackager"
-                    into "build/${sdkDirName}/bin"
-                }
-            }
         }
         dependsOn(jmxTask);
         dependsOn(jfxrtIndexTask)
@@ -3329,13 +3301,6 @@
     sdk.dependsOn(sdkTask)
 }
 
-    //task integrationCheck {
-    //    group = "Basic"
-    //    description = "Performs all the tasks necessary to ensure that the current build is ready for integration."
-    //    dependsOn sdk
-    //    dependsOn subprojects.collect { project -> project.getTasksByName("check", true)}
-    //}
-
 /*
  * This clause changes the way we handle a build.gradle within ./apps
  * It does a few things:
@@ -3367,7 +3332,8 @@
         // into our configuration.
 
         // override the apps build.xml with an explicit pointer to our jar.
-        def sdkDirName = rootProject.ext[t.upper].sdkDirName
+        def platformPrefix = rootProject.ext[t.upper].platformPrefix
+        def sdkDirName = "${platformPrefix}sdk"
         def jfxrtJar = "${rootProject.buildDir}/${sdkDirName}/lib/jfxrt.jar"
 
         def appsJar = project.task("appsJar${t.capital}") {
@@ -3403,140 +3369,594 @@
     }
 }
 
+
 /******************************************************************************
  *                                                                            *
- *                              OpenExport                                    *
+ *                               Modules                                      *
  *                                                                            *
  *****************************************************************************/
 
-task openExport() {
-    if (!BUILD_CLOSED) {
-        publicExports.dependsOn(openExport)
-    }
+ext.moduleDependencies = [file("dependencies")]
+
+task buildModules {
 }
 
-task openZip() {
-    if (!BUILD_CLOSED) {
-        zips.dependsOn(openZip)
-    }
-}
-
+// Combine the classes, lib, and bin for each module
 compileTargets { t ->
     def targetProperties = project.ext[t.upper]
 
-    def sdkDir = "${project.buildDir}/${targetProperties.sdkDirName}"
-    def exportDir = "${project.buildDir}/${targetProperties.exportDirName}"
-    def exportSDKDir = "${exportDir}/sdk"
-    def bundleDir = "${project.buildDir}/${targetProperties.bundleDirName}"
-    def jfxrtJar = "$sdkDir/lib/jfxrt.jar"
-
-    def isWindows = false
-    if (IS_WINDOWS && t.name == "win") {
-        isWindows = true
+    def platformPrefix = targetProperties.platformPrefix
+    def modularSdkDirName = "${platformPrefix}modular-sdk"
+    def modularSdkDir = "${rootProject.buildDir}/${modularSdkDirName}"
+    def modulesDir = "${modularSdkDir}/modules"
+    def modulesCmdsDir = "${modularSdkDir}/modules_cmds"
+    def modulesLibsDir = "${modularSdkDir}/modules_libs"
+    def modulesSrcDir = "${modularSdkDir}/modules_src"
+    def modulesConfDir = "${modularSdkDir}/modules_conf"
+    def modulesMakeDir = "${modularSdkDir}/make"
+
+    def zipTask = project.task("buildModuleZip$t.capital", type: Zip, group: "Build") {
+        // FIXME: JIGSAW -- this should be moved to a sub-directory so we can keep the same name
+        def jfxBundle = "${platformPrefix}javafx-exports.zip"
+
+        doFirst() {
+            file("${rootProject.buildDir}/${jfxBundle}").delete()
+        }
+
+        archiveName = jfxBundle
+        destinationDir = file("${rootProject.buildDir}")
+        includeEmptyDirs = false
+        from "${modularSdkDir}"
     }
-
-    def String compressJar = "false"
-    if (targetProperties.containsKey('deploy') &&
-        targetProperties.deploy.containsKey('compressBigJar')) {
-        compressJar = targetProperties.deploy.compressBigJar
-    }
-
-    def exportTask = project.task("openExport$t.capital", group: "Build") {
-        dependsOn("sdk$t.capital")
-
+    buildModules.dependsOn(zipTask)
+
+    def buildModulesTask = task("buildModules$t.capital", group: "Build") {
         doLast {
-            def exportTmp = "${exportDir}/tmp/classes"
-
-            // delete any old exports dir before rebuilding it
-            file("${exportDir}").deleteDir()
-
-            mkdir "${exportTmp}"
-
-            copy {
-                from "${sdkDir}"
-                into "${exportSDKDir}"
-                includeEmptyDirs = false
-                exclude '**/jfxrt.jar'
-
-                if (isWindows) {
-                    exclude '**/prism_es2.dll'
+            moduleProjList.each { project ->
+
+                // Copy classes, bin, and lib directories
+
+                def moduleName = project.ext.moduleName
+                def buildDir = project.buildDir
+
+                def srcClassesDir = "${buildDir}/${platformPrefix}module-classes"
+                def dstClassesDir = "${modulesDir}/${moduleName}"
+                copy {
+                    from srcClassesDir
+                    into dstClassesDir
+                }
+
+                def srcCmdsDir = "${buildDir}/${platformPrefix}module-bin"
+                def dstCmdsDir = "${modulesCmdsDir}/${moduleName}"
+                copy {
+                    from srcCmdsDir
+                    into dstCmdsDir
+                }
+
+                def srcLibsDir = "${buildDir}/${platformPrefix}module-lib"
+                def dstLibsDir = "${modulesLibsDir}/${moduleName}"
+                copy {
+                    from srcLibsDir
+                    into dstLibsDir
+                }
+
+                // Copy module-info.java
+                def srcModuleInfoDir = "${project.projectDir}/src/main/module-info"
+                def dstModuleInfoDir = "${modulesSrcDir}/${moduleName}"
+                copy {
+                    from srcModuleInfoDir
+                    into dstModuleInfoDir
+                    if (!IS_COMPILE_JFR && project.name.equals("base")) {
+                        filter { line-> line.contains("requires jdk.jfr;") ? "" : line }
+                    }
+                }
+
+                // Copy make/build.properties
+                def srcMakeDir = "${project.projectDir}/make"
+                def dstMakeDir = "${modulesMakeDir}/${moduleName}"
+                copy {
+                    from srcMakeDir
+                    into dstMakeDir
                 }
             }
 
+            // Copy dependencies/*/module-info.java.extra
+            def dependencyRoots = moduleDependencies
+            if (rootProject.hasProperty("closedModuleDepedencies")) {
+                dependencyRoots = [dependencyRoots, closedModuleDepedencies].flatten()
+            }
             copy {
-                from zipTree("${jfxrtJar}")
-                into "${exportTmp}"
+                dependencyRoots.each { root ->
+                    from root
+                }
+                into modulesSrcDir
             }
 
-            mkdir "${exportSDKDir}/lib"
-
-            ant.jar(
-                    destfile: "${exportSDKDir}/lib/jfxrt.jar",
-                    index: true,
-                    compress: compressJar
-                ) {
-                    delegate.manifest {
-                      attribute(name: 'Implementation-Title', value: 'OpenJavaFX')
-                    }
-
-                    fileset(dir: "${exportTmp}") {
-                       exclude(name:'META-INF/*')
-                       exclude(name:'com/sun/javafx/tools/ant/*')
-
-                       //-- Obsolete or experimental code --
-                       exclude(name:'com/sun/embeddedswing/**')
-                       exclude(name:'com/sun/javafx/tk/glass/**')
-                       exclude(name:'com/sun/javafx/tk/swing/**')
-                       exclude(name:'com/sun/prism/null3d/**')
-                       exclude(name:'com/sun/scenario/scenegraph/**')
-                       exclude(name:'com/sun/scenario/utils/**')
-                       exclude(name:'com/sun/webpane/sg/swing/**')
-                       exclude(name:'com/sun/webpane/swing/**')
-                       exclude(name:'com/sun/glass/ui/swt/**')
-
-                       if (isWindows) {
-                           //-- Strip ES2 pipeline on Windows platform only --
-                           exclude(name:'com/sun/prism/es2/**')
-                           exclude(name:'com/sun/scenario/effect/impl/es2/**')
-                           exclude(name:'com/sun/scenario/effect/impl/hw/ogl/**')
-                           exclude(name:'com/sun/scenario/effect/impl/j2d/jogl/**')
-                           exclude(name:'com/sun/scenario/effect/impl/j2d/rsl/**')
-                       }
-
-                       if(!targetProperties.includeLens) {
-                           exclude(name:'com/sun/glass/ui/lens/**')
-                       }
-
-                       if(!targetProperties.includeMonocle) {
-                           exclude(name:'com/sun/glass/ui/monocle/**')
-                           exclude(name:'com/sun/prism/es2/Monocle*')
-                       }
-                }
-            } // ant.jar
-
-            // remove {exportTmp}
-            file("${exportTmp}").deleteDir()
+            // concatecate java.policy files into a single file
+            //
+            def outputPolicyDir = "${modulesConfDir}/java.base/security"
+            def outputPolicyFile = file("${outputPolicyDir}/java.policy.extra")
+            mkdir outputPolicyDir
+            outputPolicyFile.delete()
+            moduleProjList.each { project ->
+                def policyDir = "${project.projectDir}/src/main/conf/security"
+                def policyFile = file("${policyDir}/java.policy")
+                if (policyFile.exists()) outputPolicyFile << policyFile.text
+            }
         }
     }
-
-    def jfxBundle = 'javafx-sdk-overlay.zip'
-
-    def zipTask = project.task("openZip$t.capital", type: Zip, group: "Build") {
-
-        doFirst() {
-            file("${bundleDir}/${jfxBundle}").delete()
+    zipTask.dependsOn(buildModulesTask);
+    buildModules.dependsOn(buildModulesTask)
+
+    def isWindows = IS_WINDOWS && t.name == "win";
+    def isMac = IS_MAC && t.name == "mac";
+
+    // Create layout for modular classes
+    moduleProjList.each { project ->
+        def buildModuleClassesTask = project.task("buildModule$t.capital", group: "Build") {
+            dependsOn(project.assemble)
+            def buildDir = project.buildDir
+            def sourceBuildDirs = [
+                "${buildDir}/classes/main",
+                "${buildDir}/resources/main"
+            ]
+            if (project.hasProperty("extraBuildDirs")) {
+                sourceBuildDirs += project.ext.extraBuildDirs
+            }
+            doLast {
+                def moduleClassesDir = "$buildDir/${platformPrefix}module-classes"
+                copy {
+                    includeEmptyDirs = false
+                    sourceBuildDirs.each { d ->
+                        from d
+                    }
+                    into moduleClassesDir
+
+                    // Exclude obsolete, experimental, or non-shipping code
+                    exclude("version.rc")
+                    exclude("com/sun/glass/ui/swt")
+                    exclude("com/sun/javafx/tools/ant")
+                    exclude("com/javafx/main")
+                    if (!IS_INCLUDE_NULL3D) {
+                        exclude ("com/sun/prism/null3d")
+                    }
+                    if (!IS_INCLUDE_ES2) {
+                           exclude("com/sun/prism/es2",
+                                   "com/sun/scenario/effect/impl/es2")
+                    }
+
+                    // Exclude platform-specific classes for other platforms
+
+                    if (!isMac) {
+                        exclude ("com/sun/media/jfxmediaimpl/platform/osx",
+                                 "com/sun/prism/es2/MacGL*",
+                                 "com/sun/glass/events/mac",
+                                 "com/sun/glass/ui/mac",
+                                 )
+                    }
+
+                    if (!isWindows) {
+                        exclude ("**/*.hlsl",
+                                 "com/sun/glass/ui/win",
+                                 "com/sun/prism/d3d",
+                                 "com/sun/prism/es2/WinGL*",
+                                 "com/sun/scenario/effect/impl/hw/d3d"
+                                 )
+                    }
+
+                    if (!targetProperties.includeGTK) { //usually IS_LINUX
+                        exclude (
+                                 "com/sun/glass/ui/gtk",
+                                 "com/sun/prism/es2/EGL*",
+                                 "com/sun/prism/es2/X11GL*"
+                                 )
+                    }
+
+                    if (!targetProperties.includeEGL) {
+                        exclude ("com/sun/prism/es2/EGL*")
+                    }
+
+                    if (!targetProperties.includeLens) {
+                        exclude ("com/sun/glass/ui/lens")
+                    }
+
+                    // FIXME: JIGSAW -- Figure out what to do with Monocle
+                    /*
+                    if (!targetProperties.includeMonocle) {
+                        exclude ("com/sun/glass/ui/monocle")
+                        exclude("com/sun/prism/es2/Monocle*")
+                    }
+                    */
+
+                    if (t.name != 'ios') {
+                        exclude ("com/sun/media/jfxmediaimpl/platform/ios",
+                                 "com/sun/glass/ui/ios",
+                                 "com/sun/prism/es2/IOS*"
+                                 )
+                    }
+
+                    if (t.name != 'android' && t.name != 'dalvik') {
+                        exclude ("com/sun/glass/ui/android")
+                    }
+
+                    // Filter out other platform-specific classes
+                    if (targetProperties.containsKey('jfxrtJarExcludes')) {
+                        exclude(targetProperties.jfxrtJarExcludes)
+                    }
+
+                    /* FIXME: JIGSAW -- handle this in the module itself
+                    if (t.name == 'android') {
+                        from ("modules/web/build/classes/android",
+                              "modules/web/build/resources/android",
+                              "modules/controls/build/classes/android",
+                              "modules/controls/build/resources/android")
+                    } else if (t.name == 'ios') {
+                        from ("modules/web/build/classes/ios",
+                              "modules/web/build/resources/ios",
+                              "modules/extensions/build/classes/ios")
+                    } else {
+                        from ("modules/web/build/classes/main", "modules/web/build/resources/main")
+                    }
+                    */
+                }
+            }
         }
-
-        archiveName = jfxBundle
-        destinationDir = file("$bundleDir")
-        includeEmptyDirs = false
-        from "${exportSDKDir}"
-
-        dependsOn(exportTask)
+        buildModulesTask.dependsOn(buildModuleClassesTask)
     }
 
-    openExport.dependsOn(exportTask)
-    openZip.dependsOn(zipTask)
+
+    def buildModuleLibsTask = task("buildModuleLibs$t.capital") {
+        group = "Basic"
+
+        def graphicsProject = project(":graphics");
+        dependsOn(graphicsProject.assemble)
+
+        def mediaProject = project(":media");
+        dependsOn(mediaProject.assemble)
+
+        def webProject = project(":web");
+        dependsOn(webProject.assemble)
+
+        def packagerProject = project(":fxpackager");
+        //dependsOn(packagerProject.assemble)
+        dependsOn(packagerProject.jar)
+        dependsOn(project(":fxpackagerservices").jar)
+
+        doLast {
+
+            def library = targetProperties.library
+
+            // javafx.base (lib/javafx.properties)
+
+            def baseProject = project(":base");
+            def moduleLibDir = "${baseProject.buildDir}/${platformPrefix}module-lib"
+            mkdir moduleLibDir
+            final File javafxProperties = file("${moduleLibDir}/javafx.properties")
+            javafxProperties.delete()
+            javafxProperties << "javafx.version=$RELEASE_VERSION_SHORT";
+            javafxProperties << "\n"
+            javafxProperties << "javafx.runtime.version=$RELEASE_VERSION_LONG";
+            javafxProperties << "\n"
+            javafxProperties << "javafx.runtime.build=$PROMOTED_BUILD_NUMBER";
+            javafxProperties << "\n"
+            // Include any properties that have been defined (most likely in
+            // one of the various platform gradle files)
+            if (targetProperties.containsKey("javafxProperties")) {
+                javafxProperties << targetProperties.javafxProperties
+                javafxProperties << "\n"
+            }
+
+            // Embedded builds define this file as well
+            if (targetProperties.containsKey("javafxPlatformProperties")) {
+                final File javafxPlatformProperties = file("${moduleLibDir}/javafx.platform.properties")
+                javafxPlatformProperties.delete()
+                javafxPlatformProperties << targetProperties.javafxPlatformProperties
+                javafxPlatformProperties << "\n"
+            }
+
+
+            def useLipo = targetProperties.containsKey('useLipo') ? targetProperties.useLipo : false
+            def libDest = targetProperties.libDest
+            def moduleNativeDirName = "${platformPrefix}module-$libDest"
+
+            // javafx.graphics native libraries
+
+            copy {
+                into "${graphicsProject.buildDir}/${moduleNativeDirName}"
+
+                from("modules/graphics/build/libs/jsl-decora/${t.name}/${library(targetProperties.decora.lib)}")
+                def libs = ['font', 'prism', 'prismSW', 'glass', 'iio']
+                if (IS_INCLUDE_ES2) {
+                    libs += ['prismES2'];
+                }
+                if (IS_COMPILE_PANGO) {
+                    libs += ['fontFreetype', 'fontPango'];
+                }
+                libs.each { lib ->
+                    def variants = targetProperties[lib].containsKey('variants') && !useLipo ? targetProperties[lib].variants : [null]
+                    variants.each { variant ->
+                        def variantProperties = variant ? targetProperties[lib][variant] : targetProperties[lib]
+                        from ("modules/graphics/build/libs/$lib/$t.name/${library(variantProperties.lib)}")
+                    }
+                }
+                if (IS_WINDOWS) {
+                    from ("modules/graphics/build/libs/prismD3D/${t.name}/${library(targetProperties.prismD3D.lib)}");
+                }
+            }
+
+
+            // javafx.media native libraries
+
+            copy {
+                into "${mediaProject.buildDir}/${moduleNativeDirName}"
+
+                def mediaBuildType = project(":media").ext.buildType
+                if (IS_COMPILE_MEDIA) {
+                    [ "fxplugins", "gstreamer-lite", "jfxmedia" ].each { name ->
+                        from ("modules/media/build/native/${t.name}/${mediaBuildType}/${library(name)}") }
+
+                    if (t.name == "mac") {
+                        // OSX media natives
+                        [ "jfxmedia_qtkit", "jfxmedia_avf", "glib-lite" ].each { name ->
+                            from ("modules/media/build/native/${t.name}/${mediaBuildType}/${library(name)}") }
+                    } else if (t.name == "linux") {
+                        from("modules/media/build/native/${t.name}/${mediaBuildType}") { include "libavplugin*.so" }
+                    } else from ("modules/media/build/native/${t.name}/${mediaBuildType}/${library("glib-lite")}")
+                } else {
+                    if (t.name != "android"  && t.name != "dalvik" ) {
+                        [ "fxplugins", "gstreamer-lite", "jfxmedia" ].each { name ->
+                            from ("$LIBRARY_STUB/${library(name)}") }
+                    }
+
+                    if (t.name == "mac") {
+                        // copy libjfxmedia_{avf,qtkit}.dylib if they exist
+                        [ "jfxmedia_qtkit", "jfxmedia_avf", "glib-lite" ].each { name ->
+                            from ("$LIBRARY_STUB/${library(name)}") }
+                    } else if (t.name == "linux") {
+                        from(LIBRARY_STUB) { include "libavplugin*.so" }
+                    }
+                    else if (t.name != "android"  && t.name != "dalvik" ) {
+                        from ("$LIBRARY_STUB/${library("glib-lite")}")
+                    }
+                }
+            }
+
+
+            // javafx.web native libraries
+
+            copy {
+                into "${webProject.buildDir}/${moduleNativeDirName}"
+
+                if (IS_COMPILE_WEBKIT) {
+                    from ("modules/web/build/libs/${t.name}/${library('jfxwebkit')}")
+                } else {
+                    if (t.name != "android" && t.name != "ios" && t.name != "dalvik") {
+                        from ("$LIBRARY_STUB/${library('jfxwebkit')}")
+                    }
+                }
+            }
+
+
+            // javafx.packager libraries and executable
+
+            // Copy over the javapackager libs
+            copy {
+                from "modules/fxpackager/build/libs"
+                into "${packagerProject.buildDir}/${platformPrefix}module-lib"
+            }
+
+            // Copy over the javapackager executable
+            if (t.name == "win" || t.name == "linux" || t.name == "mac") {
+                copy {
+                    from "modules/fxpackager/build/javapackager"
+                    into "${packagerProject.buildDir}/${platformPrefix}module-bin"
+                }
+            }
+
+        }
+    }
+    buildModulesTask.dependsOn(buildModuleLibsTask)
+
+    def sdkTask = tasks.getByName("sdk${t.capital}");
+    sdkTask.dependsOn(buildModulesTask)
+}
+sdk.dependsOn(buildModules)
+
+void configureJigsawTests(
+        Project p,
+        List<String> moduleDeps,
+        Set<String> patchInc,
+        Set<String> testsInc,
+        String addExportsFile
+        ) {
+
+    if(!IS_JIGSAW_TEST) {
+        return
+    }
+
+    p.configurations {
+        jigsawTest
+    }
+
+    p.dependencies {
+        jigsawTest group: "junit", name: "junit", version: "4.8.2"
+    }
+
+    compileTargets { t ->
+
+        def targetProperties = project.rootProject.ext[t.upper]
+
+        def modularSdkDirName = "${targetProperties.platformPrefix}modular-sdk"
+        def modularSdkDir = "${rootProject.buildDir}/${modularSdkDirName}"
+        def modulesDir = "${modularSdkDir}/modules"
+
+        boolean useModule = true
+        String moduleName
+        if(!p.hasProperty('moduleName')) {
+            useModule = false
+            moduleName = "systemTests"
+        } else {
+            moduleName = p.moduleName
+        }
+
+        logger.info("configuring $p.name for modular test copy");
+
+        def testingDir = "${rootProject.buildDir}/${targetProperties.platformPrefix}testing";
+        def patchesDir = new File("${testingDir}/modules");
+        File patchPolicyFile = new File("${testingDir}/java.patch.policy");
+
+        String javaLibraryPath = "${rootProject.buildDir}/sdk/$targetProperties.libDest"
+
+        def jigsawPatchesBaseDir = new File("${testingDir}/modules/$moduleName");
+        def jigsawPatchesTestDir = new File("${testingDir}/tests/$moduleName");
+
+        p.files(patchPolicyFile);
+
+        def srcClassesDir = "${p.buildDir}/${targetProperties.platformPrefix}module-classes"
+        Task classes =  p.task("jigsawCopyClasses${t.capital}", type: Copy, dependsOn: [p.classes]) {
+
+            enabled = useModule
+
+            from srcClassesDir
+            into jigsawPatchesBaseDir
+        }
+
+        Task shims =  p.task("jigsawCopyShims${t.capital}", type: Copy, dependsOn: [p.testClasses]) {
+            //from p.sourceSets.test.output.classesDir
+
+            enabled = useModule
+
+            from p.sourceSets.test.output
+            into jigsawPatchesBaseDir
+            if (patchInc != null) {
+                include patchInc
+            } else {
+                include "**/*"
+            }
+            if (testsInc != null) {
+                exclude testsInc
+            }
+            includeEmptyDirs = false
+            doLast() {
+                logger.info("project $p.name finished jigsawCopyShims to $jigsawPatchesBaseDir");
+            }
+        }
+
+        Task alltests =  p.task("jigsawCopyTests${t.capital}", type: Copy, dependsOn: [p.testClasses]) {
+            from p.sourceSets.test.output
+            into jigsawPatchesTestDir
+            if (patchInc != null) {
+                exclude patchInc
+            }
+            if (testsInc != null) {
+                include testsInc
+            } else {
+                include "**/*"
+            }
+            includeEmptyDirs = false
+            doLast() {
+                logger.info("project $p.name finished jigsawCopyTests to $jigsawPatchesTestDir");
+            }
+        }
+
+        // create & use just one of these per platform
+        String nameis = "moduleTestPatchPolicy${t.capital}"
+        Task patchPerms = null
+        if (rootProject.hasProperty(nameis)) {
+            patchPerms = rootProject.tasks[nameis]
+        } else {
+            patchPerms = rootProject.task(nameis) {
+                outputs.file(patchPolicyFile)
+                doLast() {
+                    logger.info("Creating test patch.policy file ${patchPolicyFile}")
+
+                    delete(patchPolicyFile)
+                    mkdir(testingDir)
+
+                    [ "base", "graphics", "controls", "fxml", "swing", "web", ].each { mn ->
+                        String themod = file("${patchesDir}/javafx.${mn}").toURI()
+                        patchPolicyFile <<  "grant codeBase \"${themod}\" {\n" +
+                        "    permission java.security.AllPermission;\n" +
+                        "};\n"
+                    }
+                }
+            }
+        }
+
+        Task jigsawTestsTask =  p.task("jigsawTests${t.capital}", dependsOn: [classes, shims, alltests, patchPerms ]) {
+            doLast() {
+                logger.info("project $p.name finished jigsawTests${t.capital}");
+            }
+        }
+
+        FileCollection testclasspath = p.files(p.configurations.jigsawTest)
+
+        p.test.dependsOn jigsawTestsTask
+
+        if (moduleDeps != null) {
+            moduleDeps.each() {s->
+                logger.info("adding dep to project $p.name $s");
+                Project pdep = rootProject.project(s);
+                def jigsawTask = pdep.tasks.getByName("jigsawTests${t.capital}");
+                jigsawTestsTask.dependsOn jigsawTask;
+
+                testclasspath += p.files(pdep.ext.jigsawPatchesTestDir);
+            }
+        }
+
+        testclasspath += p.files(jigsawPatchesTestDir);
+
+        p.ext.jigsawTestClasspath = testclasspath
+        p.ext.jigsawPatchesTestDir = jigsawPatchesTestDir
+        p.ext.jigsawTestClasses = jigsawTestsTask
+
+        p.ext.argclasspathFile = "$testingDir/classpath_"+p.name+".txt"
+
+        p.test {
+            if (IS_FORCE_TESTS) {
+                dependsOn 'cleanTest'
+            }
+
+            scanForTestClasses = false
+            include("**/*Test.*")
+
+            if (IS_JIGSAW_TEST) {
+                dependsOn jigsawTestsTask
+
+                doFirst {
+                    classpath = testclasspath
+                    p.sourceSets.test.runtimeClasspath = testclasspath
+                }
+
+                String bcp = "-Xbootclasspath/a:" + rootProject.projectDir.path + "/buildSrc/build/libs/buildSrc.jar"
+
+                systemProperties 'worker.debug': false
+                systemProperties 'worker.library.path': cygpath(javaLibraryPath)
+                systemProperties 'worker.xpatch.dir': cygpath(patchesDir.path)
+                if (addExportsFile != null) {
+                    systemProperties 'worker.exports.file': cygpath(addExportsFile)
+                }
+                systemProperties 'worker.classpath.file': cygpath(p.ext.argclasspathFile)
+                systemProperties 'worker.java.cmd': JIGSAW_JAVA
+
+                systemProperties 'worker.isJigsaw': true
+
+                systemProperties 'worker.patch.policy': cygpath(patchPolicyFile.path)
+
+                //systemProperties 'prism.order': 'sw'
+                //systemProperties 'glass.platform': 'Monocle'
+                //systemProperties
'glass.len': 'headless'
+
+                jvmArgs bcp, "workaround.GradleJUnitWorker"
+
+                environment("JDK_HOME", JIGSAW_HOME);
+                executable (JIGSAW_JAVA);
+
+              }
+        }
+
+    }
+
 }
 
 task checkrepo() {
@@ -3594,5 +4014,6 @@
             }
         }
     )
+
 }
 
--- a/build.properties	Tue Mar 15 04:00:44 2016 -0700
+++ b/build.properties	Thu Mar 17 14:01:55 2016 -0700
@@ -65,6 +65,7 @@
 #
 ##############################################################################
 
-jfx.build.jdk.version=1.8.0_40
-jfx.build.jdk.buildnum=27
-jfx.build.jdk.buildnum.min=26
+jfx.build.jdk.version.min=9
+jfx.build.jdk.buildnum.min=109
+jfx.build.jdk.version=9
+jfx.build.jdk.buildnum=109
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/buildSrc/src/main/java/jarjar/org/gradle/process/internal/child/BootstrapSecurityManager.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,68 @@
+/*
+ * 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 jarjar.org.gradle.process.internal.child;
+
+import java.security.Permission;
+
+/**
+ * override Gradle bootstrap loader hack for JDK 9
+ */
+public class BootstrapSecurityManager extends SecurityManager {
+
+    private boolean initialised;
+    private final ClassLoader target;
+
+    public BootstrapSecurityManager() {
+        this(null);
+    }
+
+    BootstrapSecurityManager(ClassLoader target) {
+        //System.err.println("STARTING OVERRIDE  BootstrapSecurityManager");
+        this.target = target;
+    }
+
+    @Override
+    public void checkPermission(Permission permission) {
+        synchronized (this) {
+            if (initialised) {
+                return;
+            }
+            if (System.in == null) {
+                // Still starting up
+                return;
+            }
+
+            initialised = true;
+        }
+
+        try {
+            System.clearProperty("java.security.manager");
+            System.setSecurityManager(null);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/buildSrc/src/main/java/workaround/GradleJUnitWorker.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 2015, 2016 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 workaround;
+
+import java.io.BufferedWriter;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Properties;
+
+/*
+ * This wrapper is designed to workaround a class loader issue
+ * when working with JDK9 and Gradle in the JFX builds
+ * NOTE: this worker assumes the @argfile support found in JDK9
+ *
+ * Due to the nature of the command line and where the this class is
+ * specified, certain command line properties may either be :
+ *  an argument - because it came after this file
+ *  a property - because it was before this file and was processed as a property
+ * Because of this, everything is checked as both.
+ *
+ * The worker specific properties are found below as worker.*. These
+ * properties also need to be forwarded as system properties just in case
+ * we have something like MainLauncherTest that needs some of these to
+ * construct a new java command.
+ *
+ */
+public class GradleJUnitWorker {
+
+    public static boolean debug = false;
+
+    private static final String ENCODERCLASS
+            = "jarjar.org.gradle.process.internal.child.EncodedStream$EncodedInput";
+
+    private static URL fileToURL(File file) throws IOException {
+        return file.getCanonicalFile().toURI().toURL();
+    }
+
+    // all of the "standard" System Properties that we will not forward
+    // to the worker.
+    private final static String[] defSysProps = {
+        "awt.toolkit",
+        "file.encoding.pkg",
+        "file.encoding",
+        "file.separator",
+        "ftp.nonProxyHosts",
+        "gopherProxySet",
+        "http.nonProxyHosts",
+        "java.awt.graphicsenv",
+        "java.awt.printerjob",
+        "java.class.path",
+        "java.class.version",
+        "java.endorsed.dirs",
+        "java.ext.dirs",
+        "java.home",
+        "java.io.tmpdir",
+        "java.library.path",
+        "java.runtime.name",
+        "java.runtime.version",
+        "java.specification.name",
+        "java.specification.vendor",
+        "java.specification.version",
+        "java.vendor.url.bug",
+        "java.vendor.url",
+        "java.vendor",
+        "java.version",
+        "java.vm.info",
+        "java.vm.name",
+        "java.vm.specification.name",
+        "java.vm.specification.vendor",
+        "java.vm.specification.version",
+        "java.vm.vendor",
+        "java.vm.version",
+        "line.separator",
+        "os.arch",
+        "os.name",
+        "os.version",
+        "path.separator",
+        "socksNonProxyHosts",
+        "sun.arch.data.model",
+        "sun.boot.class.path",
+        "sun.boot.library.path",
+        "sun.cpu.endian",
+        "sun.cpu.isalist",
+        "sun.io.unicode.encoding",
+        "sun.java.command",
+        "sun.java.launcher",
+        "sun.jnu.encoding",
+        "sun.management.compiler",
+        "sun.os.patch.level",
+        "user.country",
+        "user.dir",
+        "user.home",
+        "user.language",
+        "user.name",
+        "user.timezone",
+        // windows
+        "user.script",
+        "user.variant",
+        "sun.desktop",
+        // Jake
+        "java.vm.compressedOopsMode",
+        "jdk.boot.class.path.append",};
+
+    static HashSet<String> ignoreSysProps  =  new HashSet(defSysProps.length + 10);
+
+    public static void main(String args[]) {
+
+        try {
+            final ArrayList<String> cmd = new ArrayList<>(30);
+            String gradleWorkerJar = null;
+            String patchesDir = null;
+            String exportsFile = null;
+            String classpathFile = null;
+            String libraryPath = null;
+            String jigsawJavapath = null;
+
+            final String exportsFileProperty = "worker.exports.file";
+            final String workerDebugProperty = "worker.debug";
+            final String patchesDirProperty = "worker.xpatch.dir";
+            final String classpathFileProperty = "worker.classpath.file";
+            final String libraryPathProperty = "worker.library.path";
+            final String javaCmdProperty = "worker.java.cmd";
+
+            Collections.addAll(ignoreSysProps, defSysProps);
+            ignoreSysProps.add(exportsFileProperty);
+            ignoreSysProps.add(workerDebugProperty);
+            ignoreSysProps.add(patchesDirProperty);
+            ignoreSysProps.add(classpathFileProperty);
+            ignoreSysProps.add(libraryPathProperty);
+            ignoreSysProps.add(javaCmdProperty);
+
+            debug = Boolean.parseBoolean(System.getProperty(workerDebugProperty, "false"));
+
+            ArrayList<String> newArgs = new ArrayList<>(50);
+            for (int i = 0; i < args.length; i++) {
+                if (args[i].startsWith("-cp")) {
+                    gradleWorkerJar = args[i + 1];
+                    i++; // skip the path argument
+                    if (debug) System.err.println("XWORKER gradleWorkerJar="+exportsFile);
+                } else if (args[i].contains(exportsFileProperty)) {
+                    int equals = args[i].indexOf("=");
+                    exportsFile = args[i].substring(equals+1);
+                    if (debug) System.err.println("XWORKER "+exportsFileProperty+"="+exportsFile);
+                } else if (args[i].contains(patchesDirProperty)) {
+                    int equals = args[i].indexOf("=");
+                    patchesDir = args[i].substring(equals+1);
+                    if (debug) System.err.println("XWORKER "+patchesDirProperty+"="+patchesDir);
+                } else if (args[i].contains(javaCmdProperty)) {
+                    int equals = args[i].indexOf("=");
+                    jigsawJavapath = args[i].substring(equals+1);
+                    if (debug) System.err.println("XWORKER "+javaCmdProperty+"="+jigsawJavapath);
+                } else if (args[i].contains(classpathFileProperty)) {
+                    int equals = args[i].indexOf("=");
+                    classpathFile = args[i].substring(equals+1);
+                    if (debug) System.err.println("XWORKER "+classpathFileProperty+"="+classpathFile);
+                } else if (args[i].contains(libraryPathProperty)) {
+                    int equals = args[i].indexOf("=");
+                    libraryPath = args[i].substring(equals+1);
+                    if (debug) System.err.println("XWORKER "+libraryPathProperty+"="+libraryPath);
+                } else {
+                    if (debug) System.err.println("XWORKER forwarding cmd "+args[i]);
+                    newArgs.add(args[i]);
+                }
+            }
+
+            // Debug routine to capture a worker stream for replaying
+            if (false) {
+                File dumper = new File("datadump.txt");
+                FileOutputStream out
+                        = new FileOutputStream(dumper);
+
+                byte[] buf = new byte[1024];
+                int cnt;
+
+                while ((cnt = System.in.read(buf)) > 0) {
+                    out.write(buf, 0, cnt);
+                }
+                out.close();
+                System.exit(-1);
+            }
+
+            //Next we need to get the gradle encoder class from
+            // the gradle-worker.jar, which usually is on the classpath
+            // but as it is an arg in our case we need to load the jar
+            // into a classloader
+            ArrayList<URL> urlList = new ArrayList();
+            urlList.add(fileToURL(new File(gradleWorkerJar)));
+
+            URL[] urls = (URL[]) urlList.toArray(new URL[0]);
+            ClassLoader cloader = new URLClassLoader(urls);
+
+            if (debug) {
+                System.err.println("AND WE HAVE " + urls[0]);
+            }
+
+            // try to find the Gradle class that decodes the input
+            // stream. In newer versions (> 2. ?) they prefix with jarjar.
+            Class encoderClass = null;
+            if (encoderClass == null) {
+                try {
+                    encoderClass = Class.forName(ENCODERCLASS, true, cloader);
+                } catch (ClassNotFoundException e) {
+                    if (debug) {
+                        System.err.println("did not find " + ENCODERCLASS);
+                    }
+                }
+            }
+
+            if (encoderClass != null) {
+                if (debug) {
+                    System.err.println("Found EncoderClass " + encoderClass.getName());
+                }
+            } else {
+                throw new RuntimeException("Encoder not found");
+            }
+
+            Constructor constructor
+                    = encoderClass.getConstructor(new Class[]{InputStream.class});
+
+            InputStream encodedStream
+                    = (InputStream) constructor.newInstance(System.in);
+
+            DataInputStream inputStream
+                    = new DataInputStream(encodedStream);
+
+            int count = inputStream.readInt();
+
+            //And now lets build a command line.
+            ArrayList<String> cpelement = new ArrayList<>(50);
+
+            // start with the gradle-worker.jar
+            cpelement.add(gradleWorkerJar);
+
+            // read from the data stream sent by gradle to classpath setter
+            for (int dex = 0; dex < count; dex++) {
+                String entry = inputStream.readUTF();
+                // skipping any mention of jfxrt.jar....
+                if (!entry.contains("jfxrt.jar")) {
+                    File file = new File(entry);
+                    cpelement.add(file.toString());
+                }
+            }
+
+            if (debug) {
+                for (int i = 0; i < cpelement.size(); i++) {
+                    System.err.println("  " + i + " " + cpelement.get(i));
+                }
+            }
+
+            String securityManagerType = inputStream.readUTF();
+            if (debug) {
+                System.out.println("XWORKER security manager is " + securityManagerType);
+            }
+
+            /*
+             End read from the data stream send by gradle to classpath setter
+             Now we need to write this into our @argfile
+             */
+            File classPathArgFile;
+
+            if (classpathFile == null) {
+                classpathFile = System.getProperty(classpathFileProperty);
+            }
+
+            if (classpathFile != null) {
+                classPathArgFile = new File(classpathFile);
+            } else if (debug) {
+                classPathArgFile = new File("classpath.txt");
+            } else {
+                classPathArgFile = File.createTempFile("xworker-classpath", ".tmp");
+            }
+            try {
+                BufferedWriter br = new BufferedWriter(new OutputStreamWriter(
+                        new FileOutputStream(classPathArgFile)));
+
+                br.write("-classpath");
+                br.newLine();
+                for (int i = 0; i < cpelement.size(); i++) {
+                    if (i == 0) {
+                        br.write("  \"");
+                    } else {
+                        br.write("   ");
+                    }
+
+                    br.write(cpelement.get(i).replace('\\', '/'));
+                    if (i < cpelement.size() - 1) {
+                        br.write(File.pathSeparator);
+                        br.write("\\");
+                        br.newLine();
+                    }
+
+                }
+                br.write("\"");
+                br.newLine();
+                br.close();
+            } catch (IOException e) {
+                throw new RuntimeException("Could not write @classpath.txt");
+            }
+
+            String jdk_home_env = System.getenv("JIGSAW_HOME");
+            if (debug) System.err.println("XWORKER JIGSAW_HOME (env) is set to " + jdk_home_env);
+
+            if (jdk_home_env == null) {
+                jdk_home_env = System.getenv("JDK_HOME");
+                if (debug) System.err.println("XWORKER JDK_HOME (env) is set to " + jdk_home_env);
+            }
+
+            String jdk_home = System.getProperty("JDK_HOME");
+            if (debug) System.err.println("XWORKER JDK_HOME is set to " + jdk_home);
+
+            if (jigsawJavapath == null) {
+                jigsawJavapath = System.getProperty(javaCmdProperty);
+            }
+
+            String java_cmd = "java";
+            if (jigsawJavapath != null) {
+                // good we have it - probably the safest way on windows
+                java_cmd = jigsawJavapath;
+                if (debug) System.err.println("XWORKER JIGSAW_JAVA is set to " + java_cmd);
+            } else if (jdk_home_env != null) {
+                jigsawJavapath = jdk_home_env
+                        + File.separatorChar + "bin"
+                        + File.separatorChar + "java";
+            } else if (jdk_home != null) {
+                java_cmd = jdk_home
+                        + File.separatorChar + "bin"
+                        + File.separatorChar + "java";
+            }
+
+            if (debug) {
+                System.err.println("XWORKER using java  " + java_cmd);
+            }
+
+            cmd.add(java_cmd);
+
+            cmd.add("-D"+javaCmdProperty+"="+java_cmd);
+
+            if (patchesDir == null) {
+                patchesDir = System.getProperty(patchesDirProperty);
+            }
+
+            if (patchesDir != null) {
+                cmd.add("-Xpatch:" + patchesDir);
+                cmd.add("-D"+patchesDirProperty+"="+patchesDir);
+            }
+
+            if (exportsFile == null) {
+                exportsFile = System.getProperty(exportsFileProperty);
+            }
+
+            if (exportsFile != null) {
+                cmd.add("@" + exportsFile);
+                cmd.add("-D"+exportsFileProperty+"="+exportsFile);
+            }
+
+            final String cleanpath =
+                classPathArgFile.getAbsolutePath().replaceAll("\\\\", "/");
+            cmd.add("@" + cleanpath);
+            cmd.add("-D"+classpathFileProperty+"="+cleanpath);
+
+            if (libraryPath == null) {
+                libraryPath = System.getProperty(libraryPathProperty);
+            }
+
+            if (libraryPath != null) {
+                cmd.add("-Djava.library.path=" + libraryPath);
+                cmd.add("-D"+libraryPathProperty+"="+libraryPath);
+            }
+
+            if (debug) {
+                cmd.add("-D"+workerDebugProperty+"="+debug);
+            }
+
+            //forward any old system properties, other than the stock ones
+            Properties p = System.getProperties();
+            Enumeration keys = p.keys();
+            while (keys.hasMoreElements()) {
+                String key = (String) keys.nextElement();
+                if (!ignoreSysProps.contains(key)) {
+                    String value = (String) p.get(key);
+                    String newprop = "-D"+key+"="+value;
+                    cmd.add(newprop);
+                    if (debug) System.out.println("XWORKER adding "+newprop);
+
+                }
+            }
+
+            newArgs.forEach(s-> {
+                cmd.add(s);
+            });
+
+            if (debug) {
+                System.err.println("XWORKER: cmd is");
+                cmd.stream().forEach((s) -> {
+                    System.err.println(" " + s);
+                });
+                System.err.println("XWORKER: end cmd");
+            }
+
+            // Now we have a full command line, start the new worker process
+            ProcessBuilder pb = new ProcessBuilder(cmd);
+            Process proc = pb.start();
+
+            // And now setup and forward the input to the worker thread
+            // and the output from the worker thread.
+
+            new Thread(new Runnable() {
+
+                @Override
+                public void run() {
+                    try {
+                        OutputStream os = proc.getOutputStream();
+
+                        byte[] input = new byte[512];
+                        int cnt;
+
+                        while ((cnt = System.in.read(input)) > 0) {
+                            os.write(input, 0, cnt);
+                        }
+
+                        os.close();
+
+                    } catch (IOException io) {
+                        io.printStackTrace();
+                    }
+                }
+            }).start();
+
+            new Thread(new Runnable() {
+
+                @Override
+                public void run() {
+                    try {
+                        InputStream is = proc.getInputStream();
+
+                        byte[] input = new byte[1024];
+                        int cnt;
+
+                        while ((cnt = is.read(input)) > 0) {
+                            System.out.write(input, 0, cnt);
+                        }
+
+                        is.close();
+
+                    } catch (IOException io) {
+                        io.printStackTrace();
+                    }
+                }
+            }).start();
+
+            new Thread(new Runnable() {
+
+                @Override
+                public void run() {
+                    try {
+                        InputStream es = proc.getErrorStream();
+
+                        byte[] input = new byte[1024];
+                        int cnt;
+
+                        while ((cnt = es.read(input)) > 0) {
+                            System.err.write(input, 0, cnt);
+                        }
+
+                        es.close();
+
+                    } catch (IOException io) {
+                        io.printStackTrace();
+                    }
+                }
+            }).start();
+
+            // And lastly - forward the exit code from the worker
+            System.exit(proc.waitFor());
+
+        } catch (Exception e) {
+            throw new RuntimeException("Could not initialise system classpath.", e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dependencies/java.base/module-info.java.extra	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+exports jdk.internal.misc to javafx.graphics;
+exports sun.net.www to javafx.web;
+exports sun.nio.ch to javafx.media;
+exports sun.reflect.misc to javafx.base;
+exports sun.reflect.misc to javafx.fxml;
+exports sun.reflect.misc to javafx.web;
+exports sun.util.logging to javafx.base;
+exports sun.util.logging to javafx.controls;
+exports sun.util.logging to javafx.fxml;
+exports sun.util.logging to javafx.graphics;
+exports sun.util.logging to javafx.swing;
+exports sun.security.pkcs to jdk.packager;
+exports sun.security.timestamp to jdk.packager;
+exports sun.security.x509 to jdk.packager;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dependencies/java.desktop/module-info.java.extra	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+exports java.awt.dnd.peer to javafx.swing;
+exports sun.awt to javafx.swing;
+exports sun.awt.dnd to javafx.swing;
+exports sun.awt.image to javafx.swing;
+exports sun.java2d to javafx.swing;
+exports sun.swing to javafx.swing;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dependencies/jdk.jdeps/module-info.java.extra	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+exports com.sun.tools.jdeps to jdk.packager;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/base/make/build.properties	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+# Build properties for this module
+
+include_in_jre=true
+include_in_jdk=true
+include_in_jdk_server=false
+classloader=ext
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/base/src/main/conf/security/java.policy	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,4 @@
+grant codeBase "jrt:/javafx.base" {
+    permission java.security.AllPermission;
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/base/src/main/module-info/module-info.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ */
+
+module javafx.base {
+    requires java.desktop;
+    requires jdk.jfr;
+
+    exports javafx.beans;
+    exports javafx.beans.binding;
+    exports javafx.beans.property;
+    exports javafx.beans.property.adapter;
+    exports javafx.beans.value;
+    exports javafx.collections;
+    exports javafx.collections.transformation;
+    exports javafx.event;
+    exports javafx.util;
+    exports javafx.util.converter;
+
+    exports com.sun.javafx to
+        javafx.controls,
+        javafx.graphics,
+        javafx.swing;
+    exports com.sun.javafx.beans to
+        javafx.controls,
+        javafx.fxml,
+        javafx.graphics;
+    exports com.sun.javafx.binding to
+        javafx.controls,
+        javafx.graphics;
+    exports com.sun.javafx.collections to
+        javafx.controls,
+        javafx.graphics,
+        javafx.media,
+        javafx.swing;
+    exports com.sun.javafx.event to
+        javafx.controls,
+        javafx.graphics;
+    exports com.sun.javafx.logging to
+        javafx.graphics;
+    exports com.sun.javafx.property to
+        javafx.controls;
+    exports com.sun.javafx.runtime to
+        javafx.graphics;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/base/src/test/addExports	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,9 @@
+"-XaddExports:\
+    javafx.base/com.sun.javafx.binding=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx.collections=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx.event=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx.property.adapter=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx.property=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx.runtime=ALL-UNNAMED,\
+    \
+    java.base/sun.util.logging=ALL-UNNAMED"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/controls/make/build.properties	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+# Build properties for this module
+
+include_in_jre=true
+include_in_jdk=true
+include_in_jdk_server=false
+classloader=ext
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/controls/src/main/conf/security/java.policy	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,4 @@
+grant codeBase "jrt:/javafx.controls" {
+    permission java.security.AllPermission;
+};
+
--- a/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/Utils.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/controls/src/main/java/com/sun/javafx/scene/control/skin/Utils.java	Thu Mar 17 14:01:55 2016 -0700
@@ -48,6 +48,7 @@
 import javafx.scene.control.MenuItem;
 import javafx.scene.control.OverrunStyle;
 import com.sun.javafx.scene.control.ContextMenuContent;
+import java.net.URL;
 import javafx.scene.input.KeyCombination;
 import javafx.scene.input.Mnemonic;
 import javafx.scene.paint.Color;
@@ -808,4 +809,9 @@
             return null;
         }
     }
+
+    public static URL getResource(String str) {
+        return Utils.class.getResource(str);
+    }
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/controls/src/main/module-info/module-info.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+module javafx.controls {
+    requires public javafx.base;
+    requires public javafx.graphics;
+
+    exports javafx.scene.chart;
+    exports javafx.scene.control;
+    exports javafx.scene.control.cell;
+    exports javafx.scene.control.skin;
+
+    exports com.sun.javafx.scene.control.behavior to
+        javafx.web;
+    exports com.sun.javafx.scene.control.inputmap to
+        javafx.web;
+    exports com.sun.javafx.scene.control.skin to
+        javafx.graphics,
+        javafx.web;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/controls/src/test/addExports	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,37 @@
+"-XaddExports:\
+    javafx.base/com.sun.javafx.collections=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx.event=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx.property=ALL-UNNAMED,\
+    \
+    javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.perf=ALL-UNNAMED,\
+    javafx.graphics/com.sun.scenario.animation=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.geom=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.application=ALL-UNNAMED,\
+    javafx.graphics/com.sun.prism=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.font=ALL-UNNAMED,\
+    \
+    javafx.controls/javafx.scene.chart=ALL-UNNAMED,\
+    javafx.controls/com.sun.javafx.scene.control.behavior=ALL-UNNAMED,\
+    javafx.controls/com.sun.javafx.scene.control=ALL-UNNAMED,\
+    javafx.controls/com.sun.javafx.scene.control.inputmap=ALL-UNNAMED,\
+    javafx.controls/com.sun.javafx.scene.control.skin=ALL-UNNAMED,\
+    javafx.controls/com.sun.javafx.charts=ALL-UNNAMED,\
+    \
+    javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.application=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.util=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.scene.input=ALL-UNNAMED,\
+    \
+    javafx.base/javafx.beans.property=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx.event=ALL-UNNAMED,\
+    javafx.base/com.sun.javafx.binding=ALL-UNNAMED,\
+    \
+    javafx.graphics/com.sun.javafx.scene.text=ALL-UNNAMED,\
+    javafx.graphics/com.sun.prism.paint=ALL-UNNAMED,\
+    javafx.graphics/com.sun.scenario=ALL-UNNAMED,\
+    \
+    java.base/sun.util.logging=ALL-UNNAMED"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxml/make/build.properties	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+# Build properties for this module
+
+include_in_jre=true
+include_in_jdk=true
+include_in_jdk_server=false
+classloader=ext
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxml/src/main/conf/security/java.policy	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,4 @@
+grant codeBase "jrt:/javafx.fxml" {
+    permission java.security.AllPermission;
+};
+
--- a/modules/fxml/src/main/java/com/sun/javafx/fxml/BeanAdapter.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxml/src/main/java/com/sun/javafx/fxml/BeanAdapter.java	Thu Mar 17 14:01:55 2016 -0700
@@ -209,7 +209,7 @@
         Object value;
         if (getterMethod != null) {
             try {
-                value = MethodUtil.invoke(getterMethod, bean, (Object[]) null);
+                value = ModuleHelper.invoke(getterMethod, bean, (Object[]) null);
             } catch (IllegalAccessException exception) {
                 throw new RuntimeException(exception);
             } catch (InvocationTargetException exception) {
@@ -255,7 +255,7 @@
         }
 
         try {
-            MethodUtil.invoke(setterMethod, bean, new Object[] { coerce(value, getType(key)) });
+            ModuleHelper.invoke(setterMethod, bean, new Object[] { coerce(value, getType(key)) });
         } catch (IllegalAccessException exception) {
             throw new RuntimeException(exception);
         } catch (InvocationTargetException exception) {
@@ -503,7 +503,7 @@
             }
 
             try {
-                coercedValue = MethodUtil.invoke(valueOfMethod, null, new Object[] { value });
+                coercedValue = ModuleHelper.invoke(valueOfMethod, null, new Object[] { value });
             } catch (IllegalAccessException exception) {
                 throw new RuntimeException(exception);
             } catch (InvocationTargetException exception) {
@@ -541,7 +541,7 @@
 
         if (getterMethod != null) {
             try {
-                value = (T) MethodUtil.invoke(getterMethod, null, new Object[] { target } );
+                value = (T) ModuleHelper.invoke(getterMethod, null, new Object[] { target } );
             } catch (InvocationTargetException exception) {
                 throw new RuntimeException(exception);
             } catch (IllegalAccessException exception) {
@@ -599,7 +599,7 @@
 
         // Invoke the setter
         try {
-            MethodUtil.invoke(setterMethod, null, new Object[] { target, value });
+            ModuleHelper.invoke(setterMethod, null, new Object[] { target, value });
         } catch (InvocationTargetException exception) {
             throw new RuntimeException(exception);
         } catch (IllegalAccessException exception) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxml/src/main/java/com/sun/javafx/fxml/ModuleHelper.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,104 @@
+/*
+ * 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.sun.javafx.fxml;
+
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.reflect.misc.MethodUtil;
+
+public class ModuleHelper {
+    private static final Method getModuleMethod;
+    private static final Method getResourceAsStreamMethod;
+
+    private static final boolean verbose;
+
+    static {
+        verbose = AccessController.doPrivileged((PrivilegedAction<Boolean>) () ->
+                Boolean.getBoolean("javafx.verbose"));
+
+        if (verbose) {
+            System.err.println("" + ModuleHelper.class.getName() + " : <clinit>");
+        }
+        Method mGetModule = null;
+        Method mGetResourceAsStream = null;
+        try {
+            mGetModule = Class.class.getMethod("getModule");
+            Class<?> moduleClass = mGetModule.getReturnType();
+            mGetResourceAsStream = moduleClass.getMethod("getResourceAsStream", String.class);
+        } catch (NoSuchMethodException e) {
+            // ignore
+        }
+        getModuleMethod = mGetModule;
+        getResourceAsStreamMethod = mGetResourceAsStream;
+        if (verbose) {
+            System.err.println("getModuleMethod = " + getModuleMethod);
+            System.err.println("getResourceAsStreamMethod = " + getResourceAsStreamMethod);
+        }
+    }
+
+    public static Object getModule(Class clazz) {
+        if (getModuleMethod != null) {
+            try {
+                return getModuleMethod.invoke(clazz);
+            } catch (IllegalAccessException | InvocationTargetException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        return null;
+    }
+
+    // FIXME: JIGSAW -- remove this method if not needed
+    public static InputStream getResourceAsStream(Object thisModule, String name) {
+        if (getResourceAsStreamMethod != null) {
+            try {
+                return (InputStream)getResourceAsStreamMethod.invoke(thisModule, name);
+            } catch (IllegalAccessException | InvocationTargetException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+        return null;
+    }
+
+    public static Object invoke(Method m, Object obj, Object[] params)
+            throws InvocationTargetException, IllegalAccessException
+    {
+        Object thisModule = getModule(ModuleHelper.class);
+        Object methodModule = getModule(m.getDeclaringClass());
+        if (verbose) {
+            System.out.println("thisModule = " + thisModule);
+            System.out.println("methodModule = " + methodModule);
+            System.out.println("m = " + m);
+        }
+        if (methodModule != thisModule) {
+            return MethodUtil.invoke(m, obj, params);
+        } else {
+            return m.invoke(obj, params);
+        }
+    }
+}
--- a/modules/fxml/src/main/java/com/sun/javafx/fxml/builder/ProxyBuilder.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxml/src/main/java/com/sun/javafx/fxml/builder/ProxyBuilder.java	Thu Mar 17 14:01:55 2016 -0700
@@ -25,6 +25,7 @@
 package com.sun.javafx.fxml.builder;
 
 import com.sun.javafx.fxml.BeanAdapter;
+import com.sun.javafx.fxml.ModuleHelper;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
@@ -45,7 +46,6 @@
 import javafx.beans.NamedArg;
 import javafx.util.Builder;
 import sun.reflect.misc.ConstructorUtil;
-import sun.reflect.misc.MethodUtil;
 import sun.reflect.misc.ReflectUtil;
 
 /**
@@ -556,7 +556,7 @@
 
         public void invoke(Object obj, Object argStr) throws Exception {
             Object arg[] = new Object[]{BeanAdapter.coerce(argStr, type)};
-            MethodUtil.invoke(method, obj, arg);
+            ModuleHelper.invoke(method, obj, arg);
         }
     }
 
@@ -569,7 +569,7 @@
         @Override
         public void invoke(Object obj, Object argStr) throws Exception {
             // we know that this.method returns collection otherwise it wouldn't be here
-            Collection to = (Collection) MethodUtil.invoke(method, obj, new Object[]{});
+            Collection to = (Collection) ModuleHelper.invoke(method, obj, new Object[]{});
             if (argStr instanceof Collection) {
                 Collection from = (Collection) argStr;
                 to.addAll(from);
--- a/modules/fxml/src/main/java/com/sun/javafx/fxml/builder/URLBuilder.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxml/src/main/java/com/sun/javafx/fxml/builder/URLBuilder.java	Thu Mar 17 14:01:55 2016 -0700
@@ -74,6 +74,7 @@
             String spec = value.toString();
 
             if (spec.startsWith("/")) {
+                // FIXME: JIGSAW -- use Class.getResourceAsStream if resource is in a module
                 url = classLoader.getResource(spec);
             } else {
                 try {
--- a/modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxml/src/main/java/javafx/fxml/FXMLLoader.java	Thu Mar 17 14:01:55 2016 -0700
@@ -391,6 +391,7 @@
                     return aValue;
                 } else {
                         if (aValue.charAt(0) == '/') {
+                            // FIXME: JIGSAW -- use Class.getResourceAsStream if resource is in a module
                             final URL res = getClassLoader().getResource(aValue.substring(1));
                             if (res == null) {
                                 throw constructLoadException("Invalid resource: " + aValue + " not found on the classpath");
@@ -1113,6 +1114,7 @@
             URL location;
             final ClassLoader cl = getClassLoader();
             if (source.charAt(0) == '/') {
+            // FIXME: JIGSAW -- use Class.getResourceAsStream if resource is in a module
                 location = cl.getResource(source.substring(1));
                 if (location == null) {
                     throw constructLoadException("Cannot resolve path: " + source);
@@ -1537,6 +1539,7 @@
                 try {
                     URL location;
                     if (source.charAt(0) == '/') {
+                        // FIXME: JIGSAW -- use Class.getResourceAsStream if resource is in a module
                         location = cl.getResource(source.substring(1));
                     } else {
                         if (FXMLLoader.this.location == null) {
--- a/modules/fxml/src/main/java/javafx/fxml/JavaFXBuilderFactory.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxml/src/main/java/javafx/fxml/JavaFXBuilderFactory.java	Thu Mar 17 14:01:55 2016 -0700
@@ -210,7 +210,7 @@
 
             private ObjectBuilder() {
                 try {
-                    builder = MethodUtil.invoke(createMethod, null, NO_ARGS);
+                    builder = createMethod.invoke(null, NO_ARGS);
                 } catch (Exception e) {
                     //TODO
                     throw new RuntimeException("Creation of the builder " + builderClass.getName() + " failed.", e);
@@ -227,7 +227,7 @@
 
                 Object res;
                 try {
-                    res = MethodUtil.invoke(buildMethod, builder, NO_ARGS);
+                    res = buildMethod.invoke(builder, NO_ARGS);
                     // TODO:
                     // temporary special case for Node properties until
                     // platform builders are fixed
@@ -308,7 +308,7 @@
                             value = array;
                         }
 
-                        MethodUtil.invoke(m, builder, new Object[] { BeanAdapter.coerce(value, type) });
+                        m.invoke(builder, new Object[] { BeanAdapter.coerce(value, type) });
                     } catch (Exception e) {
                         Logger.getLogger(ObjectBuilderWrapper.class.getName()).log(Level.WARNING,
                                 "Method " + m.getName() + " failed", e);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxml/src/main/module-info/module-info.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+module javafx.fxml {
+    requires public javafx.base;
+
+    requires java.logging;
+    requires java.scripting;
+    requires java.xml;
+    requires javafx.graphics;
+
+    exports javafx.fxml;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxml/src/test/addExports	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,14 @@
+"-XaddExports:\
+    javafx.base/com.sun.javafx.collections=ALL-UNNAMED,\
+    \
+    javafx.graphics/com.sun.javafx.application=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.font=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.geom=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.perf=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.scene.text=ALL-UNNAMED,\
+    javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED,\
+    javafx.graphics/com.sun.prism=ALL-UNNAMED,\
+    javafx.graphics/com.sun.scenario.animation=ALL-UNNAMED,\
+    \
+    javafx.fxml/com.sun.javafx.fxml.builder=ALL-UNNAMED,\
+    javafx.fxml/com.sun.javafx.fxml.expression=ALL-UNNAMED"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/make/build.properties	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+# Build properties for this module
+
+include_in_jre=false
+include_in_jdk=true
+include_in_jdk_server=false
+classloader=app
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/AbstractBundler.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/AbstractBundler.java	Thu Mar 17 14:01:55 2016 -0700
@@ -29,9 +29,10 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URL;
+import java.nio.file.Files;
 import java.text.MessageFormat;
 import java.util.*;
 
@@ -58,9 +59,9 @@
             String publicName, String category,
             String defaultName, File result, boolean verbose, File publicRoot)
             throws IOException {
-        URL u = locateResource(publicName, category, defaultName, verbose, publicRoot);
-        if (u != null) {
-            IOUtils.copyFromURL(u, result);
+        InputStream is = streamResource(publicName, category, defaultName, verbose, publicRoot);
+        if (is != null) {
+            Files.copy(is, result.toPath());
         } else {
             if (verbose) {
                 Log.info(MessageFormat.format(I18N.getString("message.using-default-resource"), category == null ? "" : "[" + category + "] ", publicName));
@@ -72,9 +73,9 @@
             String publicName, String category,
             File defaultFile, File result, boolean verbose, File publicRoot)
             throws IOException {
-        URL u = locateResource(publicName, category, null, verbose, publicRoot);
-        if (u != null) {
-            IOUtils.copyFromURL(u, result);
+        InputStream is = streamResource(publicName, category, null, verbose, publicRoot);
+        if (is != null) {
+            Files.copy(is, result.toPath());
         } else {
             IOUtils.copyFile(defaultFile, result);
             if (verbose) {
@@ -83,41 +84,40 @@
         }
     }
 
-    private URL locateResource(String publicName, String category,
+    private InputStream streamResource(String publicName, String category,
                                String defaultName, boolean verbose, File publicRoot) throws IOException {
-        URL u = null;
         boolean custom = false;
+        InputStream is = null;
         if (publicName != null) {
             if (publicRoot != null) {
                 File publicResource = new File(publicRoot, publicName);
                 if (publicResource.exists() && publicResource.isFile()) {
-                    u = publicResource.toURI().toURL();
+                    is = new FileInputStream(publicResource);
                 }
             } else {
-                u = baseResourceLoader.getClassLoader().getResource(publicName);
+                is = baseResourceLoader.getClassLoader().getResourceAsStream(publicName);
             }
-            custom = (u != null);
+            custom = (is != null);
         }
-        if (u == null && defaultName != null) {
-            u = baseResourceLoader.getResource(defaultName);
+        if (is == null && defaultName != null) {
+            is = baseResourceLoader.getResourceAsStream(defaultName);
         }
         String msg = null;
         if (custom) {
             msg = MessageFormat.format(I18N.getString("message.using-custom-resource-from-classpath"), category == null ? "" : "[" + category + "] ", publicName);
-        } else if (u != null) {
+        } else if (is != null) {
             msg = MessageFormat.format(I18N.getString("message.using-default-resource-from-classpath"), category == null ? "" : "[" + category + "] ", publicName);
         }
-        if (verbose && u != null) {
+        if (verbose && is != null) {
             Log.info(msg);
         }
-        return u;
+        return is;
     }
 
     protected String preprocessTextResource(String publicName, String category,
                                             String defaultName, Map<String, String> pairs,
                                             boolean verbose, File publicRoot) throws IOException {
-        URL u = locateResource(publicName, category, defaultName, verbose, publicRoot);
-        InputStream inp = u.openStream();
+        InputStream inp = streamResource(publicName, category, defaultName, verbose, publicRoot);
         if (inp == null) {
             throw new RuntimeException("Jar corrupt? No "+defaultName+" resource!");
         }
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/AbstractImageBundler.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/AbstractImageBundler.java	Thu Mar 17 14:01:55 2016 -0700
@@ -24,15 +24,13 @@
  */
 package com.oracle.tools.packager;
 
-import com.sun.javafx.tools.packager.bundlers.BundleParams;
-
 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.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.ResourceBundle;
@@ -40,7 +38,6 @@
 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.
@@ -50,35 +47,6 @@
     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 imageBundleValidation(Map<String, ? super Object> p) throws ConfigException {
         StandardBundlerParam.validateMainClassInfoFromAppResources(p);
 
@@ -99,162 +67,15 @@
                     I18N.getString("error.no-application-jar.advice"));
         }
 
-        extractRuntimeFlags(p);
-
         if (ENABLE_APP_CDS.fetchFrom(p)) {
-            if (UNLOCK_COMMERCIAL_FEATURES.fetchFrom(p)) {
-                if (p.containsKey(BundleParams.PARAM_RUNTIME)
-                        && (p.get(BundleParams.PARAM_RUNTIME) == null))
-                {
-                    throw new ConfigException(
-                            I18N.getString("error.app-cds-requires-runtime"),
-                            I18N.getString("error.app-cds-requires-runtime.advice"));
-                }
-                Object majorV = p.get(".runtime.version.major");
-                Object minorV = p.get(".runtime.version.minor");
-                if (majorV != null && minorV != null) {
-                    try {
-                        int major = Integer.parseInt(majorV.toString());
-                        int minor = Integer.parseInt(minorV.toString());
-                        if ((major < 8) || (major == 8 && minor < 40)) {
-                            throw new ConfigException(
-                                    I18N.getString("error.app-cds-bad-version"),
-                                    I18N.getString("error.app-cds-bad-version.advice"));
-                        }
-                    } catch (NumberFormatException nfe) {
-                        //maybe log a failure to check versions?
-                    }
-                }
-            } else {
+            if (!UNLOCK_COMMERCIAL_FEATURES.fetchFrom(p)) {
                 throw new ConfigException(
                         I18N.getString("error.app-cds-no-commercial-unlock"),
                         I18N.getString("error.app-cds-no-commercial-unlock.advice"));
             }
         }
-
     }
 
-    public void writeCfgFile(Map<String, ? super Object> params, File cfgFileName, String runtimeLocation) throws IOException {
-        cfgFileName.delete();
-
-        boolean appCDEnabled = UNLOCK_COMMERCIAL_FEATURES.fetchFrom(params) && ENABLE_APP_CDS.fetchFrom(params);
-        String appCDSCacheMode = APP_CDS_CACHE_MODE.fetchFrom(params);
-
-        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));
-        if (appCDEnabled) {
-            out.println("app.appcds.cache=" + appCDSCacheMode.split("\\+")[0]);
-        }
-
-
-        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 (appCDEnabled) {
-            prepareAppCDS(params, out);
-        }
-
-        out.println();
-        out.println("[ArgOptions]");
-        List<String> args = ARGUMENTS.fetchFrom(params);
-        for (String arg : args) {
-            if (arg.endsWith("=") && (arg.indexOf("=") == arg.lastIndexOf("="))) {
-                out.print(arg.substring(0, arg.length() - 1));
-                out.println("\\=");
-            } else {
-                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:auto");
-        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");
-        }
-    }
-
-    abstract public void extractRuntimeFlags(Map<String, ? super Object> params);
-
     public static void extractFlagsFromVersion(Map<String, ? super Object> params, String versionOutput) {
         Pattern bitArchPattern = Pattern.compile("(\\d*)[- ]?[bB]it");
         Matcher matcher = bitArchPattern.matcher(versionOutput);
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/BasicBundlers.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/BasicBundlers.java	Thu Mar 17 14:01:55 2016 -0700
@@ -93,40 +93,8 @@
         return null;
     }
 
-    /**
-     * Loads the bundlers common to OpenJFX.
-     * <UL>
-     *     <LI>Windows file image</LI>
-     *     <LI>Mac .app</LI>
-     *     <LI>Linux file image</LI>
-     *     <LI>Windows MSI</LI>
-     *     <LI>Windows EXE</LI>
-     *     <LI>Mac DMG</LI>
-     *     <LI>Mac PKG</LI>
-     *     <LI>Linux DEB</LI>
-     *     <LI>Linux RPM</LI>
-     *
-     * </UL>
-     */
     public void loadDefaultBundlers() {
-        if (defaultsLoaded) return;
-
-        bundlers.add(new WinAppBundler());
-        bundlers.add(new WinExeBundler());
-        bundlers.add(new WinMsiBundler());
-
-        bundlers.add(new LinuxAppBundler());
-        bundlers.add(new LinuxDebBundler());
-        bundlers.add(new LinuxRpmBundler());
-
-        bundlers.add(new MacAppBundler());
-        bundlers.add(new MacDmgBundler());
-        bundlers.add(new MacPkgBundler());
-        bundlers.add(new MacAppStoreBundler());
-
-        bundlers.add(new JNLPBundler());
-
-        defaultsLoaded = true;
+        // no-op.  We now load all bundlers from module system.
     }
 
     /**
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/BundlerParamInfo.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/BundlerParamInfo.java	Thu Mar 17 14:01:55 2016 -0700
@@ -25,6 +25,7 @@
 
 package com.oracle.tools.packager;
 
+import java.util.HashMap;
 import java.util.Map;
 import java.util.function.BiFunction;
 import java.util.function.Function;
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/Bundlers.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/Bundlers.java	Thu Mar 17 14:01:55 2016 -0700
@@ -111,6 +111,7 @@
      *     <LI>Windows MSI</LI>
      *     <LI>Windows EXE</LI>
      *     <LI>Mac DMG</LI>
+     *     <LI>Mac PKG</LI>
      *     <LI>Linux DEB</LI>
      *     <LI>Linux RPM</LI>
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/JDepHelper.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2016, 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 com.sun.tools.jdeps.Main;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+
+public final class JDepHelper {
+    private JDepHelper() {}
+
+    private static int invokeJdep(String[] args, PrintWriter out) {
+        return com.sun.tools.jdeps.Main.run(args, out);
+    }
+
+    public static List<String> getResourceFileJarList(Map<String, ? super Object> params) {
+        List<String> files = new ArrayList();
+
+        for (RelativeFileSet rfs : StandardBundlerParam.APP_RESOURCES_LIST.fetchFrom(params)) {
+            for (String s : rfs.files) {
+                if (s.endsWith(".jar")) {
+                    files.add(rfs.getBaseDirectory() + File.separator + s);
+                }
+            }
+        }
+
+        return files;
+    }
+
+    public static Set<String> calculateModules(List<String> Files, List<Path> modulePath) {
+        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+             PrintWriter writer = new PrintWriter(baos)) {
+
+            List<String> arguments = new ArrayList<>();
+            arguments.add("-s");
+
+            if (modulePath != null || !modulePath.isEmpty()) {
+                arguments.add("-modulepath");
+                arguments.add(ListOfPathToString(modulePath));
+            }
+
+            arguments.addAll(Files);
+
+            invokeJdep(arguments.toArray(new String[arguments.size()]), writer);
+
+            // output format is multiple lines of "this.jar -> that.module.name"
+            // we only care about what is to the right of the arrow
+            return Arrays.stream(baos.toString().split("\\s*\\S+\\s+->\\s+"))
+                    .map(String::trim)
+                    .filter(s -> !s.isEmpty() && !arguments.contains(s) && !"not found".equals(s))
+                    .collect(Collectors.toSet());
+        } catch (IOException ioe) {
+            Log.verbose(ioe);
+            return new LinkedHashSet();
+        }
+    }
+
+    private static String ListOfPathToString(List<Path> Value) {
+        String result = "";
+
+        for (Path path : Value) {
+            if (result.isEmpty()) {
+                result = path.toString();
+            }
+            else {
+                result = File.pathSeparator + path.toString();
+            }
+        }
+
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/JLinkBundlerHelper.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2015, 2016, 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 jdk.tools.jlink.Jlink;
+import jdk.tools.jlink.builder.ImageBuilder;
+import jdk.tools.jlink.plugin.Plugin;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+
+public class JLinkBundlerHelper {
+
+    private static final ResourceBundle I18N =
+            ResourceBundle.getBundle(JLinkBundlerHelper.class.getName());
+
+    //TODO Remove and replace with programmatic implementation JDK-8149975
+    private static final String[] JRE_MODULES = {"java.se",
+                                                "java.smartcardio",
+                                                "javafx.base",
+                                                "javafx.controls",
+                                                "javafx.deploy",
+                                                "javafx.fxml",
+                                                "javafx.graphics",
+                                                "javafx.media",
+                                                "javafx.swing",
+                                                "javafx.web",
+                                                "javafx.base",
+                                                "javafx.deploy",
+                                                "javafx.graphics",
+                                                "javafx.swing",
+                                                "javafx.controls",
+                                                "javafx.fxml",
+                                                "javafx.media",
+                                                "javafx.web",
+                                                "jdk.packager.services", //TODO rename to jdk.packager.runtime JDK-8148482
+                                                "jdk.accessibility",
+                                                "jdk.charsets",
+                                                "jdk.crypto.ec",
+                                                "jdk.crypto.pkcs11",
+                                                "jdk.dynalink",
+                                                "jdk.httpserver",
+                                                "jdk.internal.le",
+                                                "jdk.jfr",
+                                                "jdk.jvmstat",
+                                                "jdk.jvmstat.rmi",
+                                                "jdk.localedata",
+                                                "jdk.management",
+                                                "jdk.management.cmm",
+                                                "jdk.management.resource",
+                                                "jdk.naming.dns",
+                                                "jdk.naming.rmi",
+                                                "jdk.pack200",
+                                                "jdk.scripting.nashorn",
+                                                "jdk.scripting.nashorn.shell",
+                                                "jdk.sctp",
+                                                "jdk.security.auth",
+                                                "jdk.security.jgss",
+                                                "jdk.snmp",
+                                                "jdk.vm.cds",
+                                                "jdk.vm.ci",
+                                                "jdk.xml.dom",
+                                                "jdk.zipfs",
+                                                "jdk.crypto.mscapi",
+                                                "jdk.crypto.ucrypto",
+                                                "jdk.deploy.osx"}; // going away JDK-8148187
+
+    @SuppressWarnings("unchecked")
+    public static final BundlerParamInfo<List<Path>> MODULE_PATH =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.module-path.name"),
+                    I18N.getString("param.module-path.description"),
+                    "modulepath",
+                    (Class<List<Path>>) (Object)List.class,
+                    p -> new ArrayList(),
+                    (s, p) -> Arrays.asList(s.split("(\\s" + File.pathSeparator + ")+")).stream()
+                        .map(ss -> new File(ss).toPath())
+                        .collect(Collectors.toList()));
+
+    @SuppressWarnings("unchecked")
+    public static final BundlerParamInfo<String> JDK_MODULE_PATH =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.jdk-module-path.name"),
+                    I18N.getString("param.jdk-module-path.description"),
+                    "jdkmodulepath",
+                    String.class,
+                    p -> Paths.get(System.getProperty("java.home"), "jmods").toAbsolutePath().toString(),
+                    (s, p) -> String.valueOf(s));
+
+    @SuppressWarnings("unchecked")
+    public static final BundlerParamInfo<Set<String>> ADD_MODULES =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.add-modules.name"),
+                    I18N.getString("param.add-modules.description"),
+                    "addmods",
+                    (Class<Set<String>>) (Object) Set.class,
+                    p -> new LinkedHashSet(),
+                    (s, p) -> new LinkedHashSet<>(Arrays.asList(s.split("[,;: ]+"))));
+
+    @SuppressWarnings("unchecked")
+    public static final BundlerParamInfo<Set<String>> LIMIT_MODULES =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.limit-modules.name"),
+                    I18N.getString("param.limit-modules.description"),
+                    "limitmods",
+                    (Class<Set<String>>) (Object) Set.class,
+                    p -> new LinkedHashSet(),
+                    (s, p) -> new LinkedHashSet<>(Arrays.asList(s.split("[,;: ]+"))));
+
+    @SuppressWarnings("unchecked")
+    public static final BundlerParamInfo<Boolean> DETECT_MODULES =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.auto-modules.name"),
+                    I18N.getString("param.auto-modules.description"),
+                    "detectmods",
+                    Boolean.class,
+                    p -> Boolean.FALSE,
+                    (s, p) -> Boolean.valueOf(s));
+
+    @SuppressWarnings("unchecked")
+    public static final BundlerParamInfo<Boolean> STRIP_NATIVE_COMMANDS =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.strip-executables.name"),
+                    I18N.getString("param.strip-executables.description"),
+                    "stripexecutables",
+                    Boolean.class,
+                    p -> Boolean.TRUE,
+                    (s, p) -> Boolean.valueOf(s));
+
+    @SuppressWarnings("unchecked")
+    public static final BundlerParamInfo<Map<String, Object>> JLINK_OPTIONS =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.jlink-options.name"),
+                    I18N.getString("param.jlink-options.description"),
+                    "jlinkOptions",
+                    (Class<Map<String, Object>>) (Object) Map.class,
+                    p -> Collections.emptyMap(),
+                    (s, p) -> {
+                        try {
+                            Properties props = new Properties();
+                            props.load(new StringReader(s));
+                            return new LinkedHashMap<>((Map)props);
+                        } catch (IOException e) {
+                            return new LinkedHashMap<>();
+                        }
+                    });
+
+    @SuppressWarnings("unchecked")
+    public static final BundlerParamInfo<String> JLINK_BUILDER =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.jlink-builder.name"),
+                    I18N.getString("param.jlink-builder.description"),
+                    "jlink.builder",
+                    String.class,
+                    null,
+                    (s, p) -> s);
+
+
+    public static void execute(Map<String, ? super Object> params, File outputParentDir, ImageBuilder imageBuilder) {
+        String jdkmodulePath = JDK_MODULE_PATH.fetchFrom(params);
+        List<Path> modulePath = MODULE_PATH.fetchFrom(params);
+        Set<String> addModules = ADD_MODULES.fetchFrom(params);
+        Set<String> limitModules = LIMIT_MODULES.fetchFrom(params);
+        File jdkModulePathFile = new File(jdkmodulePath);
+
+        if (!jdkModulePathFile.exists() || !jdkModulePathFile.isDirectory()) {
+            Log.info("JDK Module path doesn't exist: " + jdkmodulePath);
+            //TODO fail?
+            jdkModulePathFile = null;
+        }
+
+        if (DETECT_MODULES.fetchFrom(params)) {
+            // Add JDK modules to the module path.
+            if (jdkModulePathFile != null) {
+                modulePath.add(jdkModulePathFile.toPath());
+            }
+
+            // Get App Jars.
+            List<String> appJars = JDepHelper.getResourceFileJarList(params);
+
+            // Ask Jdeps for the list of dependent modules.
+            Collection<String> detectedModules = JDepHelper.calculateModules(appJars, modulePath);
+            addModules.addAll(detectedModules);
+            Log.info("Automatically adding detected modules " + detectedModules);
+        } else if (addModules.isEmpty()) {
+            // Add all modules on user specified path (-modulepath).
+            addModules.addAll(getModuleNamesFromPath(modulePath));
+
+            // Only retain Java SE Modules.
+            if (jdkModulePathFile != null) {
+                Set<String> jdkModuleNames = getModuleNamesFromPath(jdkModulePathFile.toPath());
+                Set<String> javaseModules = new HashSet<>(Arrays.asList(JRE_MODULES));
+
+                //TODO JDK-8149975 programmatically determine JRE vs JDK modules
+                jdkModuleNames.retainAll(javaseModules); // strip out JDK modules
+                addModules.addAll(jdkModuleNames);
+
+                // Add JDK modules to the module path.
+                modulePath.add(jdkModulePathFile.toPath());
+            }
+        }
+
+        Path output = outputParentDir.toPath();
+
+        // jlink main arguments
+        Jlink.JlinkConfiguration jlinkConfig = new Jlink.JlinkConfiguration(output,
+                                                                            modulePath,
+                                                                            addModules,
+                                                                            limitModules);
+
+        // plugin configuration
+        List<Plugin> plugins = new ArrayList<>();
+
+        if (STRIP_NATIVE_COMMANDS.fetchFrom(params)) {
+            plugins.add(Jlink.newPlugin(
+                    "strip-native-commands",
+                    Collections.singletonMap("strip-native-commands", "on"),
+                    null));
+        }
+
+        plugins.add(Jlink.newPlugin(
+                "exclude-files",
+                Collections.singletonMap("exclude-files", getExcludeFileList()),
+                null));
+
+        // add user supplied jlink arguments
+        for (Map.Entry<String, Object> entry : JLINK_OPTIONS.fetchFrom(params).entrySet()) {
+            Object o = entry.getValue();
+            if (o instanceof String) {
+                String key = entry.getKey();
+                String value = (String)entry.getValue();
+                plugins.add(Jlink.newPlugin(key,
+                            Collections.singletonMap(key, value),
+                            null));
+            }
+        }
+
+        plugins.add(Jlink.newPlugin("installed-modules", Collections.emptyMap(), null));
+
+        //TODO --compress-resources
+
+        Jlink.PluginsConfiguration pluginConfig = new Jlink.PluginsConfiguration(plugins, imageBuilder, null);
+
+        // Build the image
+        Jlink jlink = new Jlink();
+
+        try {
+            jlink.build(jlinkConfig, pluginConfig);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static Set<String> getModuleNamesFromPath(List<Path> Value) {
+            Set<String> result = new LinkedHashSet();
+            ModuleManager mm = new ModuleManager(Value);
+            List<Module> modules = mm.getModules(EnumSet.of(ModuleManager.SearchType.ModularJar,
+                                                 ModuleManager.SearchType.Jmod,
+                                                 ModuleManager.SearchType.ExplodedModule));
+
+            for (Module module : modules) {
+                result.add(module.getModuleName());
+            }
+
+            return result;
+    }
+
+    private static Set<String> getModuleNamesFromPath(Path Value) {
+        return getModuleNamesFromPath(new ArrayList<Path>(Arrays.asList(Value)));
+    }
+
+    //TODO
+    private static String getExcludeFileList() {
+        // strip debug symbols
+        String result = "*diz";
+
+        if (System.getProperty("os.name").toLowerCase().indexOf("mac") >= 0) {
+            // strip mac osx quicktime
+            result += ",*libjfxmedia_qtkit.dylib";
+        }
+
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/Module.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2016, 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.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+
+public final class Module {
+    private String FFileName;
+    private ModuleType FModuleType;
+
+    private enum JarType {Unknown, UnnamedJar, ModularJar}
+
+
+    public enum ModuleType {Unknown, UnnamedJar, ModularJar, Jmod, ExplodedModule}
+
+    public Module(File AFile) {
+        super();
+        FFileName = AFile.getPath();
+        FModuleType = getModuleType(AFile);
+    }
+
+    public String getFileName() {
+        return FFileName;
+    }
+
+    public String getModulePath() {
+        File file = new File(getFileName());
+        return file.getParent();
+    }
+
+    public String getModuleName() {
+        File file = new File(getFileName());
+        return getFileWithoutExtension(file.getName());
+    }
+
+    public ModuleType getModuleType() {
+        return FModuleType;
+    }
+
+    public List<Module> getRequiredModules() {
+        List<Module> result = new ArrayList();
+
+        List<String> files = new ArrayList();
+        files.add(getFileName());
+        Collection<String> detectedModules = JDepHelper.calculateModules(files, null);
+
+        for (String filename : detectedModules) {
+            Module module = new Module(new File(filename));
+            result.add(module);
+        }
+
+        return result;
+    }
+
+    private static ModuleType getModuleType(File AFile) {
+        ModuleType result = ModuleType.Unknown;
+        String filename = AFile.getAbsolutePath();
+
+        if (AFile.isFile()) {
+            if (filename.endsWith(".jmod")) {
+                result = ModuleType.Jmod;
+            }
+            else if (filename.endsWith(".jar")) {
+                JarType status = isModularJar(filename);
+
+                if (status == JarType.ModularJar) {
+                    result = ModuleType.ModularJar;
+                }
+                else if (status == JarType.UnnamedJar) {
+                    result = ModuleType.UnnamedJar;
+                }
+            }
+        }
+        else if (AFile.isDirectory()) {
+            File moduleInfo = new File(filename + File.separator + "module-info.class");
+
+            if (moduleInfo.exists()) {
+                result = ModuleType.ExplodedModule;
+            }
+        }
+
+        return result;
+    }
+
+    private static JarType isModularJar(String FileName) {
+        JarType result = JarType.Unknown;
+        List<String> classNames = new ArrayList<String>();
+
+        try {
+            ZipInputStream zip = new ZipInputStream(new FileInputStream(FileName));
+            result = JarType.UnnamedJar;
+
+            try {
+                for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
+                    if (entry.getName().matches("module-info.class")) {
+                        result = JarType.ModularJar;
+                        break;
+                    }
+                }
+
+                zip.close();
+            } catch (IOException ex) {
+            }
+        } catch (FileNotFoundException e) {
+        }
+
+        return result;
+    }
+
+    private static String getFileWithoutExtension(String FileName) {
+        return FileName.replaceFirst("[.][^.]+$", "");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/ModuleManager.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016, 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.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+
+public final class ModuleManager {
+    private List<String> FFolders = new ArrayList();
+
+    public enum SearchType {UnnamedJar, ModularJar, Jmod, ExplodedModule}
+
+    public ModuleManager(String Folders) {
+        super();
+        String lfolders = Folders.replaceAll("^\"|\"$", "");
+        List<Path> paths = new ArrayList();
+
+        for (String folder : Arrays.asList(lfolders.split(File.pathSeparator))) {
+            File file = new File(folder);
+            paths.add(file.toPath());
+        }
+
+        initialize(paths);
+    }
+
+    public ModuleManager(List<Path> Paths) {
+        super();
+        initialize(Paths);
+    }
+
+    private void initialize(List<Path> Paths) {
+        for (Path path : Paths) {
+            FFolders.add(path.toString().replaceAll("^\"|\"$", ""));
+        }
+    }
+
+    public List<Module> getModules() {
+        return getModules(EnumSet.of(SearchType.UnnamedJar,
+                SearchType.ModularJar, SearchType.Jmod, SearchType.ExplodedModule));
+    }
+
+    public List<Module> getModules(EnumSet<SearchType> Search) {
+        List<Module> result = new ArrayList();
+
+        for (String folder : FFolders) {
+            result.addAll(getAllModulesInDirectory(folder, Search));
+        }
+
+        return result;
+    }
+
+    private static List<Module> getAllModulesInDirectory(String Folder, EnumSet<SearchType> Search) {
+        List<Module> result = new ArrayList();
+        File lfolder = new File(Folder);
+        File[] files = lfolder.listFiles();
+
+        for (File file : files) {
+            Module module = new Module(file);
+
+            switch (module.getModuleType()) {
+                case Unknown:
+                    break;
+                case UnnamedJar:
+                    if (Search.contains(SearchType.UnnamedJar)) {
+                        result.add(module);
+                    }
+                    break;
+                case ModularJar:
+                    if (Search.contains(SearchType.ModularJar)) {
+                        result.add(module);
+                    }
+                    break;
+                case Jmod:
+                    if (Search.contains(SearchType.Jmod)) {
+                        result.add(module);
+                    }
+                    break;
+                case ExplodedModule:
+                    if (Search.contains(SearchType.ExplodedModule)) {
+                        result.add(module);
+                    }
+                    break;
+            }
+        }
+
+        return result;
+    }
+}
\ No newline at end of file
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/StandardBundlerParam.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/StandardBundlerParam.java	Thu Mar 17 14:01:55 2016 -0700
@@ -32,7 +32,19 @@
 import java.io.StringReader;
 import java.nio.file.Files;
 import java.text.MessageFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.ResourceBundle;
+import java.util.Set;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.jar.Attributes;
@@ -77,10 +89,34 @@
                     I18N.getString("param.app-resource-list.description"),
                     BundleParams.PARAM_APP_RESOURCES + "List",
                     (Class<List<RelativeFileSet>>) (Object) List.class,
-                    p -> new ArrayList<>(Arrays.asList(APP_RESOURCES.fetchFrom(p))), // Default is appResources, as a single item list
-                    null // no string translation, tool must provide complex type
+                    p -> new ArrayList<>(Collections.singletonList(APP_RESOURCES.fetchFrom(p))), // Default is appResources, as a single item list
+                    StandardBundlerParam::createAppResourcesListFromString
             );
 
+    private static List<RelativeFileSet> createAppResourcesListFromString(String s, Map<String, ? super Object> objectObjectMap) {
+        List<RelativeFileSet> result = new ArrayList<>();
+        for (String path : s.split("[:;]")) {
+            File f = new File(path);
+            if (f.getName().equals("*") || path.endsWith("/") || path.endsWith("\\")) {
+                if (f.getName().equals("*")) {
+                    f = f.getParentFile();
+                }
+                Set<File> theFiles = new HashSet<>();
+                try {
+                    Files.walk(f.toPath())
+                            .filter(Files::isRegularFile)
+                            .forEach(p -> theFiles.add(p.toFile()));
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+                result.add(new RelativeFileSet(f, theFiles));
+            } else {
+                result.add(new RelativeFileSet(f.getParentFile(), Collections.singleton(f)));
+            }
+        }
+        return result;
+    }
+
     public static final StandardBundlerParam<File> ICON =
             new StandardBundlerParam<>(
                     I18N.getString("param.icon-file.name"),
@@ -99,6 +135,7 @@
                     BundleParams.PARAM_APPLICATION_CLASS,
                     String.class,
                     params -> {
+                        //FIXME sniff modules
                         extractMainClassInfoFromAppResources(params);
                         return (String) params.get(BundleParams.PARAM_APPLICATION_CLASS);
                     },
@@ -195,7 +232,7 @@
                             File appResourcesRoot = rfs.getBaseDirectory();
                             File f = new File(appResourcesRoot, s);
                             if (f.exists()) {
-                                return new RelativeFileSet(appResourcesRoot, new LinkedHashSet<>(Arrays.asList(f)));
+                                return new RelativeFileSet(appResourcesRoot, new LinkedHashSet<>(Collections.singletonList(f)));
                             }
                         }
                         throw new IllegalArgumentException(
@@ -419,7 +456,7 @@
             );
 
     public static final BundlerParamInfo<String> LICENSE_TYPE =
-            new StandardBundlerParam<> (
+            new StandardBundlerParam<>(
                     I18N.getString("param.license-type.name"),
                     I18N.getString("param.license-type.description"),
                     BundleParams.PARAM_LICENSE_TYPE,
@@ -607,7 +644,7 @@
                     I18N.getString("param.com-app-cds-root.description"),
                     "commercial.AppCDS.classRoots",
                     (Class<List<String>>)((Object)List.class),
-                    p -> Arrays.asList(MAIN_CLASS.fetchFrom(p)),
+                    p -> Collections.singletonList(MAIN_CLASS.fetchFrom(p)),
                     (s, p) -> Arrays.asList(s.split("[ ,:]"))
             );
 
@@ -698,7 +735,7 @@
                             if (fnames[0] == null) {
                                 fnames[0] = file.getParentFile().toString();
                             }
-                            params.put(MAIN_JAR.getID(), new RelativeFileSet(new File(fnames[0]), new LinkedHashSet<>(Arrays.asList(file))));
+                            params.put(MAIN_JAR.getID(), new RelativeFileSet(new File(fnames[0]), new LinkedHashSet<>(Collections.singletonList(file))));
                         }
                         if (!hasMainJarClassPath) {
                             String cp = attrs.getValue(Attributes.Name.CLASS_PATH);
@@ -763,5 +800,4 @@
         l.add(current.toString());
         return l;
     }
-
 }
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/linux/LinuxAppBundler.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/linux/LinuxAppBundler.java	Thu Mar 17 14:01:55 2016 -0700
@@ -27,25 +27,28 @@
 
 import com.oracle.tools.packager.AbstractImageBundler;
 import com.oracle.tools.packager.BundlerParamInfo;
+import com.oracle.tools.packager.ConfigException;
+import com.oracle.tools.packager.IOUtils;
+import com.oracle.tools.packager.JLinkBundlerHelper;
 import com.oracle.tools.packager.JreUtils;
 import com.oracle.tools.packager.JreUtils.Rule;
+import com.oracle.tools.packager.Log;
+import com.oracle.tools.packager.RelativeFileSet;
 import com.oracle.tools.packager.StandardBundlerParam;
-import com.oracle.tools.packager.Log;
-import com.oracle.tools.packager.ConfigException;
-import com.oracle.tools.packager.IOUtils;
-import com.oracle.tools.packager.RelativeFileSet;
 import com.oracle.tools.packager.UnsupportedPlatformException;
 import com.sun.javafx.tools.packager.bundlers.BundleParams;
+import jdk.tools.jlink.builder.ImageBuilder;
+import jdk.packager.builders.linux.LinuxAppImageBuilder;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.io.PrintStream;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.text.MessageFormat;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.ResourceBundle;
 
 import static com.oracle.tools.packager.StandardBundlerParam.*;
 
@@ -57,7 +60,6 @@
     protected static final String LINUX_BUNDLER_PREFIX =
             BUNDLER_PREFIX + "linux" + File.separator;
     private static final String EXECUTABLE_NAME = "JavaAppLauncher";
-    private static final String LIBRARY_NAME    = "libpackager.so";
 
     public static final BundlerParamInfo<File> ICON_PNG = new StandardBundlerParam<>(
             I18N.getString("param.icon-png.name"),
@@ -151,15 +153,6 @@
                     I18N.getString("error.no-linux-resources.advice"));
         }
 
-        //validate required inputs
-        testRuntime(LINUX_RUNTIME.fetchFrom(p), new String[] {
-                "lib/[^/]+/[^/]+/libjvm.so", // most reliable
-                "lib/rt.jar", // fallback canary for JDK 8
-        });
-        if (USE_FX_PACKAGING.fetchFrom(p)) {
-            testRuntime(LINUX_RUNTIME.fetchFrom(p), new String[] {"lib/ext/jfxrt.jar", "lib/jfxrt.jar"});
-        }
-
         return true;
     }
 
@@ -169,16 +162,11 @@
         return new File(outDir, APP_FS_NAME.fetchFrom(p));
     }
 
-    public static String getLauncherName(Map<String, ? super Object> p) {
-        return APP_FS_NAME.fetchFrom(p);
-    }
-
     public static String getLauncherCfgName(Map<String, ? super Object> p) {
         return "app/" + APP_FS_NAME.fetchFrom(p) +".cfg";
     }
 
     File doBundle(Map<String, ? super Object> p, File outputDirectory, boolean dependentTask) {
-        Map<String, ? super Object> originalParams = new HashMap<>(p);
         try {
             if (!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) {
                 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), outputDirectory.getAbsolutePath()));
@@ -196,35 +184,12 @@
                 Log.info(MessageFormat.format(I18N.getString("message.creating-bundle-location"), rootDirectory.getAbsolutePath()));
             }
 
-            File runtimeDirectory = new File(rootDirectory, "runtime");
-
-            File appDirectory = new File(rootDirectory, "app");
-            appDirectory.mkdirs();
-
-            // create the primary launcher
-            createLauncherForEntryPoint(p, rootDirectory);
-
-            // Copy library to the launcher folder
-            IOUtils.copyFromURL(
-                    LinuxResources.class.getResource(LIBRARY_NAME),
-                    new File(rootDirectory, LIBRARY_NAME));
-
-            // 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);
+            if (!p.containsKey(JLinkBundlerHelper.JLINK_BUILDER.getID())) {
+                p.put(JLinkBundlerHelper.JLINK_BUILDER.getID(), "linuxapp-image-builder");
             }
 
-            // Copy runtime to PlugIns folder
-            copyRuntime(p, runtimeDirectory);
-
-            // Copy class path entries to Java folder
-            copyApplication(p, appDirectory);
-
-            // Copy icon to Resources folder
-//FIXME            copyIcon(resourcesDirectory);
+            ImageBuilder imageBuilder = new LinuxAppImageBuilder(p, outputDirectory.toPath());
+            JLinkBundlerHelper.execute(p, outputDirectory, imageBuilder);
 
             return rootDirectory;
         } catch (IOException ex) {
@@ -234,131 +199,6 @@
         }
     }
 
-    private void createLauncherForEntryPoint(Map<String, ? super Object> p, File rootDir) throws IOException {
-        // Copy executable to Linux folder
-        File executableFile = new File(rootDir, getLauncherName(p));
-        IOUtils.copyFromURL(
-                RAW_EXECUTABLE_URL.fetchFrom(p),
-                executableFile);
-
-        executableFile.setExecutable(true, false);
-        executableFile.setWritable(true, true); //for str
-
-        // 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)), getRuntimeLocation(p));
-        }
-    }
-
-    private void copyApplication(Map<String, ? super Object> params, File appDirectory) throws IOException {
-        List<RelativeFileSet> appResourcesList = APP_RESOURCES_LIST.fetchFrom(params);
-        if (appResourcesList == null) {
-            throw new RuntimeException("Null app resources?");
-        }
-        for (RelativeFileSet appResources : appResourcesList) {
-            if (appResources == null) {
-                throw new RuntimeException("Null app resources?");
-            }
-            File srcdir = appResources.getBaseDirectory();
-            for (String fname : appResources.getIncludedFiles()) {
-                IOUtils.copyFile(
-                        new File(srcdir, fname), new File(appDirectory, fname));
-            }
-        }
-    }
-
-    private String getRuntimeLocation(Map<String, ? super Object> params) {
-        if (LINUX_RUNTIME.fetchFrom(params) == null) {
-            return "";
-        } else {
-            return "$APPDIR/runtime";
-        }
-    }
-
-    private void writeCfgFile(Map<String, ? super Object> params, File rootDir) throws FileNotFoundException {
-        File cfgFile = new File(rootDir, getLauncherCfgName(params));
-
-        cfgFile.delete();
-        PrintStream out = new PrintStream(cfgFile);
-        out.println("app.runtime=" + getRuntimeLocation(params));
-        out.println("app.mainjar=" + MAIN_JAR.fetchFrom(params).getIncludedFiles().iterator().next());
-        out.println("app.version=" + VERSION.fetchFrom(params));
-
-        //use '/' in the class name (instead of '.' to simplify native code
-        out.println("app.mainclass=" +
-                MAIN_CLASS.fetchFrom(params).replaceAll("\\.", "/"));
-
-        StringBuilder macroedPath = new StringBuilder();
-        for (String s : CLASSPATH.fetchFrom(params).split("[ ;:]+")) {
-            macroedPath.append(s);
-            macroedPath.append(":");
-        }
-        macroedPath.deleteCharAt(macroedPath.length() - 1);
-        out.println("app.classpath=" + macroedPath.toString());
-
-        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);
-        }
-
-        //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;
-        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();
-    }
-
-    private void copyRuntime(Map<String, ? super Object> params, File runtimeDirectory) throws IOException {
-        RelativeFileSet runtime = LINUX_RUNTIME.fetchFrom(params);
-        if (runtime == null) {
-            //request to use system runtime
-            return;
-        }
-        runtimeDirectory.mkdirs();
-
-        File srcdir = runtime.getBaseDirectory();
-        Set<String> filesToCopy = runtime.getIncludedFiles();
-        for (String fname : filesToCopy) {
-            IOUtils.copyFile(
-                    new File(srcdir, fname), new File(runtimeDirectory, fname));
-        }
-    }
-
     @Override
     public String getName() {
         return I18N.getString("bundler.name");
@@ -407,40 +247,4 @@
     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 "$CACHEDIR/";
-    }
-
-    @Override
-    public void extractRuntimeFlags(Map<String, ? super Object> params) {
-        if (params.containsKey(".runtime.autodetect")) return;
-
-        params.put(".runtime.autodetect", "attempted");
-        RelativeFileSet runtime = LINUX_RUNTIME.fetchFrom(params);
-        String commandline;
-        if (runtime == null) {
-            //System JRE, report nothing useful
-            params.put(".runtime.autodetect", "systemjre");
-        } else {
-            File runtimePath = runtime.getBaseDirectory();
-            File launcherPath = new File(runtimePath, "bin/java");
-
-            ProcessBuilder pb = new ProcessBuilder(launcherPath.getAbsolutePath(), "-version");
-            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
-                try (PrintStream pout = new PrintStream(baos)) {
-                    IOUtils.exec(pb, Log.isDebug(), true, pout);
-                }
-
-                commandline = baos.toString();
-            } catch (IOException e) {
-                e.printStackTrace();
-                params.put(".runtime.autodetect", "failed");
-                return;
-            }
-            AbstractImageBundler.extractFlagsFromVersion(params, commandline);
-            params.put(".runtime.autodetect", "succeeded");
-        }
-    }
 }
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacAppBundler.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacAppBundler.java	Thu Mar 17 14:01:55 2016 -0700
@@ -26,32 +26,29 @@
 
 import com.oracle.tools.packager.AbstractImageBundler;
 import com.oracle.tools.packager.BundlerParamInfo;
+import com.oracle.tools.packager.ConfigException;
 import com.oracle.tools.packager.EnumeratedBundlerParam;
-import com.oracle.tools.packager.JreUtils;
-import com.oracle.tools.packager.JreUtils.Rule;
+import com.oracle.tools.packager.IOUtils;
+import com.oracle.tools.packager.JLinkBundlerHelper;
+import com.oracle.tools.packager.Log;
 import com.oracle.tools.packager.StandardBundlerParam;
-import com.oracle.tools.packager.Log;
-import com.sun.javafx.tools.packager.bundlers.BundleParams;
-import com.oracle.tools.packager.ConfigException;
-import com.oracle.tools.packager.IOUtils;
-import com.oracle.tools.packager.RelativeFileSet;
 import com.oracle.tools.packager.UnsupportedPlatformException;
+import jdk.tools.jlink.builder.ImageBuilder;
+import jdk.packager.builders.mac.MacAppImageBuilder;
 
-import java.io.*;
+import java.io.File;
+import java.io.IOException;
 import java.math.BigInteger;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.file.Files;
-import java.nio.file.Paths;
 import java.text.MessageFormat;
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.ResourceBundle;
 
 import static com.oracle.tools.packager.StandardBundlerParam.*;
-import static com.oracle.tools.packager.mac.MacBaseInstallerBundler.SIGNING_KEYCHAIN;
-import static com.oracle.tools.packager.mac.MacBaseInstallerBundler.SIGNING_KEY_USER;
-import static com.oracle.tools.packager.mac.MacBaseInstallerBundler.getPredefinedImage;
+import static com.oracle.tools.packager.mac.MacBaseInstallerBundler.*;
 
 public class MacAppBundler extends AbstractImageBundler {
 
@@ -61,12 +58,7 @@
     public final static String MAC_BUNDLER_PREFIX =
             BUNDLER_PREFIX + "macosx" + File.separator;
 
-    private static final String EXECUTABLE_NAME      = "JavaAppLauncher";
-    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_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<>();
@@ -115,15 +107,6 @@
         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"),
@@ -184,21 +167,6 @@
             },
             (s, p) -> new File(s));
 
-    public static final BundlerParamInfo<URL> RAW_EXECUTABLE_URL = new StandardBundlerParam<>(
-            I18N.getString("param.raw-executable-url.name"),
-            I18N.getString("param.raw-executable-url.description"),
-            "mac.launcher.url",
-            URL.class,
-            params -> MacResources.class.getResource(EXECUTABLE_NAME),
-            (s, p) -> {
-                try {
-                    return new URL(s);
-                } catch (MalformedURLException e) {
-                    Log.info(e.toString());
-                    return null;
-                }
-            });
-
     public static final BundlerParamInfo<String> DEFAULT_ICNS_ICON = new StandardBundlerParam<>(
             I18N.getString("param.default-icon-icns"),
             I18N.getString("param.default-icon-icns.description"),
@@ -207,24 +175,6 @@
             params -> TEMPLATE_BUNDLE_ICON,
             (s, p) -> s);
 
-    public static final BundlerParamInfo<Rule[]> MAC_RULES = new StandardBundlerParam<>(
-            "",
-            "",
-            ".mac.runtime.rules",
-            Rule[].class,
-            MacAppBundler::createMacRuntimeRules,
-            (s, p) -> null
-    );
-
-    public static final BundlerParamInfo<RelativeFileSet> MAC_RUNTIME = new StandardBundlerParam<>(
-            I18N.getString("param.runtime.name"),
-            I18N.getString("param.runtime.description"),
-            BundleParams.PARAM_RUNTIME,
-            RelativeFileSet.class,
-            params -> extractMacRuntime(System.getProperty("java.home"), params),
-            MacAppBundler::extractMacRuntime
-    );
-
     public static final BundlerParamInfo<String> DEVELOPER_ID_APP_SIGNING_KEY = new StandardBundlerParam<>(
             I18N.getString("param.signing-key-developer-id-app.name"),
             I18N.getString("param.signing-key-developer-id-app.description"),
@@ -256,43 +206,11 @@
             },
             (s, p) -> new File(s));
 
-    public static RelativeFileSet extractMacRuntime(String base, Map<String, ? super Object> params) {
-        if (base.isEmpty()) {
-            return null;
-        }
-
-        File workingBase = new File(base);
-        workingBase = workingBase.getAbsoluteFile();
-        try {
-            workingBase = workingBase.getCanonicalFile();
-        } catch (IOException ignore) {
-            // we tried, workingBase will remain absolute and not canonical.
-        }
-
-        if (workingBase.getName().equals("jre")) {
-            workingBase = workingBase.getParentFile();
-        }
-        if (workingBase.getName().equals("Home")) {
-            workingBase = workingBase.getParentFile();
-        }
-        if (workingBase.getName().equals("Contents")) {
-            workingBase = workingBase.getParentFile();
-        }
-        return JreUtils.extractJreAsRelativeFileSet(workingBase.toString(),
-                MAC_RULES.fetchFrom(params), true);
-    }
-
     public MacAppBundler() {
         super();
         baseResourceLoader = MacResources.class;
     }
 
-    @Override
-    protected String getCacheLocation(Map<String, ? super Object> params) {
-        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
@@ -368,29 +286,7 @@
             return true;
         }
 
-        // make sure we are pointing at the right JDK.
-        RelativeFileSet runtime = MAC_RUNTIME.fetchFrom(p);
-        if (runtime != null) {
-            runtime = new RelativeFileSet(runtime);
-            if ("jre".equals(runtime.getBaseDirectory().getName())) {
-                runtime.upshift();
-            }
-            if ("Home".equals(runtime.getBaseDirectory().getName())) {
-                runtime.upshift();
-            }
-            if ("Contents".equals(runtime.getBaseDirectory().getName())) {
-                runtime.upshift();
-            }
-        }
-
-        //validate required inputs
-        testRuntime(runtime, new String[] {
-                "Contents/Home/(jre/)?lib/[^/]+/libjvm.dylib", // most reliable
-                "Contents/Home/(jre/)?lib/rt.jar", // fallback canary for JDK 8
-        });
-        if (USE_FX_PACKAGING.fetchFrom(p)) {
-            testRuntime(runtime, new String[] {"Contents/Home/(jre/)?lib/ext/jfxrt.jar", "Contents/Home/(jre/)?lib/jfxrt.jar"});
-        }
+        //TODO warn if MAC_RUNTIME is set
 
         // validate short version
         if (!validCFBundleVersion(MAC_CF_BUNDLE_VERSION.fetchFrom(p))) {
@@ -420,41 +316,18 @@
         return new File(CONFIG_ROOT.fetchFrom(params), APP_NAME.fetchFrom(params) + ".icns");
     }
 
-    private void prepareConfigFiles(Map<String, ? super Object> params) throws IOException {
-        File infoPlistFile = getConfig_InfoPlist(params);
-        infoPlistFile.createNewFile();
-        writeInfoPlist(infoPlistFile, params);
 
-        // Copy icon to Resources folder
-        prepareIcon(params);
-    }
-
-    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()));
-        }
-        if (!outputDirectory.canWrite()) {
-            throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-write-to-output-dir"), outputDirectory.getAbsolutePath()));
-        }
-
+    File doBundle(Map<String, ? super Object> p, File outputDirectory, boolean dependentTask) {
         try {
-            final File predefinedImage = getPredefinedImage(p);
-            if (predefinedImage != null) {
-                return predefinedImage;
+            if (!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) {
+                throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), outputDirectory.getAbsolutePath()));
+            }
+            if (!outputDirectory.canWrite()) {
+                throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-write-to-output-dir"), outputDirectory.getAbsolutePath()));
             }
 
-            // side effect is temp dir is created if not specified
-            BUILD_ROOT.fetchFrom(p);
-
-            //prepare config resources (we will copy them to the bundle later)
-            // NB: explicitly saving them to simplify customization
-            prepareConfigFiles(p);
-
             // Create directory structure
-            rootDirectory = new File(outputDirectory, APP_NAME.fetchFrom(p) + ".app");
+            File rootDirectory = new File(outputDirectory, APP_NAME.fetchFrom(p) + ".app");
             IOUtils.deleteRecursive(rootDirectory);
             rootDirectory.mkdirs();
 
@@ -462,103 +335,18 @@
                 Log.info(MessageFormat.format(I18N.getString("message.creating-app-bundle"), rootDirectory.getAbsolutePath()));
             }
 
-            File contentsDirectory = new File(rootDirectory, "Contents");
-            contentsDirectory.mkdirs();
-
-            File macOSDirectory = new File(contentsDirectory, "MacOS");
-            macOSDirectory.mkdirs();
-
-            File javaDirectory = new File(contentsDirectory, "Java");
-            javaDirectory.mkdirs();
-
-            File plugInsDirectory = new File(contentsDirectory, "PlugIns");
-
-            File resourcesDirectory = new File(contentsDirectory, "Resources");
-            resourcesDirectory.mkdirs();
-
-            // Generate PkgInfo
-            File pkgInfoFile = new File(contentsDirectory, "PkgInfo");
-            pkgInfoFile.createNewFile();
-            writePkgInfo(pkgInfoFile);
-
-            // Copy executable to MacOS folder
-            File executableFile = new File(macOSDirectory, getLauncherName(p));
-            IOUtils.copyFromURL(
-                    RAW_EXECUTABLE_URL.fetchFrom(p),
-                    executableFile);
-
-            // Copy library to the MacOS folder
-            IOUtils.copyFromURL(
-                    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)), getRuntimeLocation(p));
-                }
+            if (!p.containsKey(JLinkBundlerHelper.JLINK_BUILDER.getID())) {
+                p.put(JLinkBundlerHelper.JLINK_BUILDER.getID(), "macapp-image-builder");
             }
 
-            executableFile.setExecutable(true, false);
-
-            // Copy runtime to PlugIns folder
-            copyRuntime(plugInsDirectory, p);
-
-            // Copy class path entries to Java folder
-            copyClassPathEntries(javaDirectory, p);
-
-            //TODO: Need to support adding native libraries.
-            // Copy library path entries to MacOS folder
-            //copyLibraryPathEntries(macOSDirectory);
-
-            /*********** Take care of "config" files *******/
-            // Copy icon to Resources folder
-            IOUtils.copyFile(getConfig_Icon(p),
-                    new File(resourcesDirectory, getConfig_Icon(p).getName()));
-
-            // copy file association icons
-            for (Map<String, ? super Object> fa : FILE_ASSOCIATIONS.fetchFrom(p)) {
-                File f = FA_ICON.fetchFrom(fa);
-                if (f != null && f.exists()) {
-                    IOUtils.copyFile(f,
-                            new File(resourcesDirectory, f.getName()));
-                }
-            }
-
-            // 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)) {
-                String signingIdentity = DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(p);
-                if (signingIdentity != null) {
-                    MacBaseInstallerBundler.signAppBundle(p, rootDirectory, signingIdentity, BUNDLE_ID_SIGNING_PREFIX.fetchFrom(p));
-                }
-            }
+            ImageBuilder imageBuilder = new MacAppImageBuilder(p, outputDirectory.toPath());
+            JLinkBundlerHelper.execute(p, outputDirectory, imageBuilder);
+            return rootDirectory;
         } catch (IOException ex) {
             Log.info(ex.toString());
             Log.verbose(ex);
             return null;
-        } finally {
-            if (!VERBOSE.fetchFrom(p)) {
-                //cleanup
-                cleanupConfigFiles(p);
-            } else {
-                Log.info(MessageFormat.format(I18N.getString("message.config-save-location"), CONFIG_ROOT.fetchFrom(p).getAbsolutePath()));
-            }
         }
-        return rootDirectory;
     }
 
     public void cleanupConfigFiles(Map<String, ? super Object> params) {
@@ -569,479 +357,6 @@
         }
     }
 
-    private void copyClassPathEntries(File javaDirectory, Map<String, ? super Object> params) throws IOException {
-        List<RelativeFileSet> resourcesList = APP_RESOURCES_LIST.fetchFrom(params);
-        if (resourcesList == null) {
-            throw new RuntimeException(I18N.getString("message.null-classpath"));
-        }
-
-        for (RelativeFileSet classPath : resourcesList) {
-            File srcdir = classPath.getBaseDirectory();
-            for (String fname : classPath.getIncludedFiles()) {
-                IOUtils.copyFile(
-                        new File(srcdir, fname), new File(javaDirectory, fname));
-            }
-        }
-    }
-
-    private void copyRuntime(File plugInsDirectory, Map<String, ? super Object> params) throws IOException {
-        RelativeFileSet runtime = MAC_RUNTIME.fetchFrom(params);
-        if (runtime == null) {
-            //request to use system runtime => do not bundle
-            return;
-        }
-        runtime = new RelativeFileSet(runtime);
-        if ("jre".equals(runtime.getBaseDirectory().getName())) {
-            runtime.upshift();
-        }
-        if ("Home".equals(runtime.getBaseDirectory().getName())) {
-            runtime.upshift();
-        }
-        if ("Contents".equals(runtime.getBaseDirectory().getName())) {
-            runtime.upshift();
-        }
-
-
-        plugInsDirectory.mkdirs();
-
-        File srcdir = runtime.getBaseDirectory();
-        // the name in .../Contents/PlugIns/ must have a dot to be verified
-        // properly by the Mac App Store.
-        File destDir = new File(plugInsDirectory, "Java.runtime");
-        Set<String> filesToCopy = runtime.getIncludedFiles();
-
-        for (String fname : filesToCopy) {
-            IOUtils.copyFile(
-                    new File(srcdir, fname), new File(destDir, fname));
-        }
-    }
-
-    private void prepareIcon(Map<String, ? super Object> params) throws IOException {
-        File icon = ICON_ICNS.fetchFrom(params);
-        if (icon == null || !icon.exists()) {
-            fetchResource(MAC_BUNDLER_PREFIX+ APP_NAME.fetchFrom(params) +".icns",
-                    "icon",
-                    DEFAULT_ICNS_ICON.fetchFrom(params),
-                    getConfig_Icon(params),
-                    VERBOSE.fetchFrom(params),
-                    DROP_IN_RESOURCES_ROOT.fetchFrom(params));
-        } else {
-            fetchResource(MAC_BUNDLER_PREFIX+ APP_NAME.fetchFrom(params) +".icns",
-                    "icon",
-                    icon,
-                    getConfig_Icon(params),
-                    VERBOSE.fetchFrom(params),
-                    DROP_IN_RESOURCES_ROOT.fetchFrom(params));
-        }
-    }
-
-    private String getLauncherName(Map<String, ? super Object> params) {
-        if (APP_NAME.fetchFrom(params) != null) {
-            return APP_NAME.fetchFrom(params);
-        } else {
-            return MAIN_CLASS.fetchFrom(params);
-        }
-    }
-
-    private String getBundleName(Map<String, ? super Object> params) {
-        //TODO: Check to see what rules/limits are in place for CFBundleName
-        if (MAC_CF_BUNDLE_NAME.fetchFrom(params) != null) {
-            String bn = MAC_CF_BUNDLE_NAME.fetchFrom(params);
-            if (bn.length() > 16) {
-                Log.info(MessageFormat.format(I18N.getString("message.bundle-name-too-long-warning"), MAC_CF_BUNDLE_NAME.getID(), bn));
-            }
-            return MAC_CF_BUNDLE_NAME.fetchFrom(params);
-        } else if (APP_NAME.fetchFrom(params) != null) {
-            return APP_NAME.fetchFrom(params);
-        } else {
-            String nm = MAIN_CLASS.fetchFrom(params);
-            if (nm.length() > 16) {
-                nm = nm.substring(0, 16);
-            }
-            return nm;
-        }
-    }
-
-    private String getRuntimeLocation(Map<String, ? super Object> params) {
-        if (MAC_RUNTIME.fetchFrom(params) == null) {
-            return "";
-        } else {
-            return "$APPDIR/PlugIns/Java.runtime";
-        }
-    }
-
-    private void writeInfoPlist(File file, Map<String, ? super Object> params) throws IOException {
-        Log.verbose(MessageFormat.format(I18N.getString("message.preparing-info-plist"), file.getAbsolutePath()));
-
-        //prepare config for exe
-        //Note: do not need CFBundleDisplayName if we do not support localization
-        Map<String, String> data = new HashMap<>();
-        data.put("DEPLOY_ICON_FILE", getConfig_Icon(params).getName());
-        data.put("DEPLOY_BUNDLE_IDENTIFIER",
-                MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params));
-        data.put("DEPLOY_BUNDLE_NAME",
-                getBundleName(params));
-        data.put("DEPLOY_BUNDLE_COPYRIGHT",
-                COPYRIGHT.fetchFrom(params) != null ? COPYRIGHT.fetchFrom(params) : "Unknown");
-        data.put("DEPLOY_LAUNCHER_NAME", getLauncherName(params));
-        if (MAC_RUNTIME.fetchFrom(params) != null) {
-            data.put("DEPLOY_JAVA_RUNTIME_NAME", "$APPDIR/PlugIns/Java.runtime");
-        } else {
-            data.put("DEPLOY_JAVA_RUNTIME_NAME", "");
-        }
-        data.put("DEPLOY_BUNDLE_SHORT_VERSION",
-                VERSION.fetchFrom(params) != null ? VERSION.fetchFrom(params) : "1.0.0");
-        data.put("DEPLOY_BUNDLE_CFBUNDLE_VERSION",
-                MAC_CF_BUNDLE_VERSION.fetchFrom(params) != null ? MAC_CF_BUNDLE_VERSION.fetchFrom(params) : "100");
-        data.put("DEPLOY_BUNDLE_CATEGORY",
-                //TODO parameters should provide set of values for IDEs
-                MAC_CATEGORY.validatedFetchFrom(params));
-
-        data.put("DEPLOY_MAIN_JAR_NAME", MAIN_JAR.fetchFrom(params).getIncludedFiles().iterator().next());
-
-        data.put("DEPLOY_PREFERENCES_ID", PREFERENCES_ID.fetchFrom(params).toLowerCase());
-
-        StringBuilder sb = new StringBuilder();
-        List<String> jvmOptions = JVM_OPTIONS.fetchFrom(params);
-
-        String newline = ""; //So we don't add unneccessary extra line after last append
-        for (String o : jvmOptions) {
-            sb.append(newline).append("    <string>").append(o).append("</string>");
-            newline = "\n";
-        }
-
-        Map<String, String> jvmProps = JVM_PROPERTIES.fetchFrom(params);
-        for (Map.Entry<String, String> entry : jvmProps.entrySet()) {
-            sb.append(newline)
-                    .append("    <string>-D")
-                    .append(entry.getKey())
-                    .append("=")
-                    .append(entry.getValue())
-                    .append("</string>");
-            newline = "\n";
-        }
-
-        String preloader = PRELOADER_CLASS.fetchFrom(params);
-        if (preloader != null) {
-            sb.append(newline)
-                    .append("    <string>-Djavafx.preloader=")
-                    .append(preloader)
-                    .append("</string>");
-            //newline = "\n";
-        }
-
-        data.put("DEPLOY_JVM_OPTIONS", sb.toString());
-
-        sb = new StringBuilder();
-        List<String> args = ARGUMENTS.fetchFrom(params);
-        newline = ""; //So we don't add unneccessary extra line after last append
-        for (String o : args) {
-            sb.append(newline).append("    <string>").append(o).append("</string>");
-            newline = "\n";
-        }
-        data.put("DEPLOY_ARGUMENTS", sb.toString());
-
-        newline = "";
-        sb = new StringBuilder();
-        Map<String, String> overridableJVMOptions = USER_JVM_OPTIONS.fetchFrom(params);
-        for (Map.Entry<String, String> arg: overridableJVMOptions.entrySet()) {
-            sb.append(newline)
-                .append("      <key>").append(arg.getKey()).append("</key>\n")
-                .append("      <string>").append(arg.getValue()).append("</string>");
-            newline = "\n";
-        }
-        data.put("DEPLOY_JVM_USER_OPTIONS", sb.toString());
-
-
-        data.put("DEPLOY_LAUNCHER_CLASS", MAIN_CLASS.fetchFrom(params));
-
-        StringBuilder macroedPath = new StringBuilder();
-        for (String s : CLASSPATH.fetchFrom(params).split("[ ;:]+")) {
-            macroedPath.append(s);
-            macroedPath.append(":");
-        }
-        macroedPath.deleteCharAt(macroedPath.length() - 1);
-
-        data.put("DEPLOY_APP_CLASSPATH", macroedPath.toString());
-
-        //TODO: Add remainder of the classpath
-
-        StringBuilder bundleDocumentTypes = new StringBuilder();
-        StringBuilder exportedTypes = new StringBuilder();
-        for (Map<String, ? super Object> fileAssociation : FILE_ASSOCIATIONS.fetchFrom(params)) {
-
-            List<String> extensions = FA_EXTENSIONS.fetchFrom(fileAssociation);
-
-            if (extensions == null) {
-                Log.info(I18N.getString("message.creating-association-with-null-extension"));
-            }
-
-            List<String> mimeTypes = FA_CONTENT_TYPE.fetchFrom(fileAssociation);
-            String itemContentType = MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params) + "." + ((extensions == null || extensions.isEmpty())
-                    ? "mime"
-                    : extensions.get(0));
-            String description = FA_DESCRIPTION.fetchFrom(fileAssociation);
-            File icon = FA_ICON.fetchFrom(fileAssociation); //TODO FA_ICON_ICNS
-
-            bundleDocumentTypes.append("    <dict>\n")
-                .append("      <key>LSItemContentTypes</key>\n")
-                .append("      <array>\n")
-                .append("        <string>")
-                .append(itemContentType)
-                .append("</string>\n")
-                .append("      </array>\n")
-                .append("\n")
-                .append("      <key>CFBundleTypeName</key>\n")
-                .append("      <string>")
-                .append(description)
-                .append("</string>\n")
-                .append("\n")
-                .append("      <key>LSHandlerRank</key>\n")
-                .append("      <string>Owner</string>\n") //TODO make a bundler arg
-                .append("\n")
-                .append("      <key>CFBundleTypeRole</key>\n")
-                .append("      <string>Editor</string>\n") // TODO make a bundler arg
-                .append("\n")
-                .append("      <key>LSIsAppleDefaultForType</key>\n")
-                .append("      <true/>\n") // TODO make a bundler arg
-                .append("\n");
-
-            if (icon != null && icon.exists()) {
-                //?
-                bundleDocumentTypes.append("      <key>CFBundleTypeIconFile</key>\n")
-                        .append("      <string>")
-                        .append(icon.getName())
-                        .append("</string>\n");
-            }
-            bundleDocumentTypes.append("    </dict>\n");
-
-            exportedTypes.append("    <dict>\n")
-                .append("      <key>UTTypeIdentifier</key>\n")
-                .append("      <string>")
-                .append(itemContentType)
-                .append("</string>\n")
-                .append("\n")
-                .append("      <key>UTTypeDescription</key>\n")
-                .append("      <string>")
-                .append(description)
-                .append("</string>\n")
-                .append("      <key>UTTypeConformsTo</key>\n")
-                .append("      <array>\n")
-                .append("          <string>public.data</string>\n") //TODO expose this?
-                .append("      </array>\n")
-                .append("\n");
-
-            if (icon != null && icon.exists()) {
-                exportedTypes.append("      <key>UTTypeIconFile</key>\n")
-                    .append("      <string>")
-                    .append(icon.getName())
-                    .append("</string>\n")
-                    .append("\n");
-            }
-
-            exportedTypes.append("\n")
-                .append("      <key>UTTypeTagSpecification</key>\n")
-                .append("      <dict>\n")
-            //TODO expose via param? .append("        <key>com.apple.ostype</key>\n");
-            //TODO expose via param? .append("        <string>ABCD</string>\n")
-                .append("\n");
-
-            if (extensions != null && !extensions.isEmpty()) {
-                exportedTypes.append("        <key>public.filename-extension</key>\n")
-                    .append("        <array>\n");
-
-                for (String ext : extensions) {
-                    exportedTypes.append("          <string>")
-                        .append(ext)
-                        .append("</string>\n");
-                }
-                exportedTypes.append("        </array>\n");
-            }
-            if (mimeTypes != null && !mimeTypes.isEmpty()) {
-                exportedTypes.append("        <key>public.mime-type</key>\n")
-                    .append("        <array>\n");
-
-                for (String mime : mimeTypes) {
-                    exportedTypes.append("          <string>")
-                        .append(mime)
-                        .append("</string>\n");
-                }
-                exportedTypes.append("        </array>\n");
-            }
-            exportedTypes.append("      </dict>\n")
-                    .append("    </dict>\n");
-        }
-        String associationData;
-        if (bundleDocumentTypes.length() > 0) {
-            associationData = "\n  <key>CFBundleDocumentTypes</key>\n  <array>\n"
-                    + bundleDocumentTypes.toString()
-                    + "  </array>\n\n  <key>UTExportedTypeDeclarations</key>\n  <array>\n"
-                    + exportedTypes.toString()
-                    + "  </array>\n";
-        } else {
-            associationData = "";
-        }
-        data.put("DEPLOY_FILE_ASSOCIATIONS", associationData);
-
-
-        Writer w = new BufferedWriter(new FileWriter(file));
-        w.write(preprocessTextResource(
-                MAC_BUNDLER_PREFIX + getConfig_InfoPlist(params).getName(),
-                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();
-
-    }
-
-    private void writePkgInfo(File file) throws IOException {
-
-        //hardcoded as it does not seem we need to change it ever
-        String signature = "????";
-
-        try (Writer out = new BufferedWriter(new FileWriter(file))) {
-            out.write(OS_TYPE_CODE + signature);
-            out.flush();
-        }
-    }
-
-    public static Rule[] createMacRuntimeRules(Map<String, ? super Object> params) {
-        if (!System.getProperty("os.name").toLowerCase().contains("os x")) {
-            // we will never get a sensible answer unless we are running on OSX,
-            // so quit now and return null indicating 'no sensible value'
-            return null;
-        }
-
-        //Subsetting of JRE is restricted.
-        //JRE README defines what is allowed to strip:
-        //   http://www.oracle.com/technetwork/java/javase/jre-8-readme-2095710.html
-        //
-
-        List<Rule> rules = new ArrayList<>();
-
-        File baseDir;
-
-        if (params.containsKey(MAC_RUNTIME.getID())) {
-            Object o = params.get(MAC_RUNTIME.getID());
-            if (o instanceof RelativeFileSet) {
-                baseDir = ((RelativeFileSet)o).getBaseDirectory();
-            } else {
-                baseDir = new File(o.toString());
-            }
-        } else {
-            baseDir = new File(System.getProperty("java.home"));
-        }
-
-        // we accept either pointing at the directories typically installed at:
-        // /Libraries/Java/JavaVirtualMachine/jdk1.8.0_40/
-        //   * .
-        //   * Contents/Home
-        //   * Contents/Home/jre
-        // /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin/
-        //   * .
-        //   * /Contents/Home
-        // version may change, and if we don't detect any Contents/Home or Contents/Home/jre we will
-        // presume we are at a root.
-
-        if (!baseDir.exists()) {
-            throw new RuntimeException(I18N.getString("error.non-existent-runtime"),
-                new ConfigException(I18N.getString("error.non-existent-runtime"),
-                    I18N.getString("error.non-existent-runtime.advice")));
-        }
-
-        boolean isJRE;
-        boolean isJDK;
-
-        try {
-            String path = baseDir.getCanonicalPath();
-            if (path.endsWith("/Contents/Home/jre")) {
-                baseDir = baseDir.getParentFile().getParentFile().getParentFile();
-            } else if (path.endsWith("/Contents/Home")) {
-                baseDir = baseDir.getParentFile().getParentFile();
-            }
-
-            isJRE = new File(baseDir, "Contents/Home/lib/jli/libjli.dylib").exists();
-            isJDK = new File(baseDir, "Contents/Home/jre/lib/jli/libjli.dylib").exists();
-
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-
-        if (!(isJRE || isJDK)) {
-            throw new RuntimeException(I18N.getString("error.cannot-detect-runtime-in-directory"),
-                    new ConfigException(I18N.getString("error.cannot-detect-runtime-in-directory"),
-                            I18N.getString("error.cannot-detect-runtime-in-directory.advice")));
-        }
-
-        // we need the Info.plist for signing
-        rules.add(Rule.suffix("/contents/info.plist"));
-
-        // Strip some JRE specific stuff
-        if (isJRE) {
-            rules.add(Rule.suffixNeg("/contents/disabled.plist"));
-            rules.add(Rule.suffixNeg("/contents/enabled.plist"));
-            rules.add(Rule.substrNeg("/contents/frameworks/"));
-        }
-
-        // strip out command line tools
-        rules.add(Rule.suffixNeg("home/bin"));
-        if (isJDK) {
-            rules.add(Rule.suffixNeg("home/jre/bin"));
-        }
-
-        // strip out JRE stuff
-        if (isJRE) {
-            // update helper
-            rules.add(Rule.suffixNeg("resources"));
-            // interfacebuilder files
-            rules.add(Rule.suffixNeg("lib/nibs"));
-            // browser integration
-            rules.add(Rule.suffixNeg("lib/libnpjp2.dylib"));
-            // java webstart
-            rules.add(Rule.suffixNeg("lib/security/javaws.policy"));
-            rules.add(Rule.suffixNeg("lib/shortcuts"));
-
-            // general deploy libraries
-            rules.add(Rule.suffixNeg("lib/deploy"));
-            rules.add(Rule.suffixNeg("lib/deploy.jar"));
-            rules.add(Rule.suffixNeg("lib/javaws.jar"));
-            rules.add(Rule.suffixNeg("lib/libdeploy.dylib"));
-            rules.add(Rule.suffixNeg("lib/plugin.jar"));
-        }
-
-        // strip out man pages
-        rules.add(Rule.suffixNeg("home/man"));
-
-        // this is the build hashes, strip or keep?
-        //rules.add(Rule.suffixNeg("home/release"));
-
-        // strip out JDK stuff like JavaDB, JNI Headers, etc
-        if (isJDK) {
-            rules.add(Rule.suffixNeg("home/db"));
-            rules.add(Rule.suffixNeg("home/demo"));
-            rules.add(Rule.suffixNeg("home/include"));
-            rules.add(Rule.suffixNeg("home/lib"));
-            rules.add(Rule.suffixNeg("home/sample"));
-            rules.add(Rule.suffixNeg("home/src.zip"));
-            rules.add(Rule.suffixNeg("home/javafx-src.zip"));
-        }
-
-        //"home/rt" is not part of the official builds
-        // but we may be creating this symlink to make older NB projects
-        // happy. Make sure to not include it into final artifact
-        rules.add(Rule.suffixNeg("home/rt"));
-
-        //rules.add(Rule.suffixNeg("jre/lib/ext")); //need some of jars there for https to work
-
-        // strip out flight recorder
-        rules.add(Rule.suffixNeg("lib/jfr.jar"));
-
-        return rules.toArray(new Rule[rules.size()]);
-    }
-
     //////////////////////////////////////////////////////////////////////////////////
     // Implement Bundler
     //////////////////////////////////////////////////////////////////////////////////
@@ -1087,7 +402,7 @@
                 MAC_CF_BUNDLE_IDENTIFIER,
                 MAC_CF_BUNDLE_NAME,
                 MAC_CF_BUNDLE_VERSION,
-                MAC_RUNTIME,
+//                MAC_RUNTIME,
                 MAIN_CLASS,
                 MAIN_JAR,
                 PREFERENCES_ID,
@@ -1104,125 +419,23 @@
         return doBundle(params, outputParentDir, false);
     }
 
-    private void createLauncherForEntryPoint(Map<String, ? super Object> p, File rootDirectory) throws IOException {
-        prepareConfigFiles(p);
+//    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);
+//
+//    }
+//
 
-        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);
-        out.println("app.runtime=" + getRuntimeLocation(params));
-        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();
-    }
-    @Override
-    public void extractRuntimeFlags(Map<String, ? super Object> params) {
-        if (params.containsKey(".runtime.autodetect")) return;
-
-        params.put(".runtime.autodetect", "attempted");
-        RelativeFileSet runtime = MAC_RUNTIME.fetchFrom(params);
-        String commandline;
-        if (runtime == null) {
-            //System JRE, report nothing useful
-            params.put(".runtime.autodetect", "systemjre");
-        } else {
-            File workingBase = runtime.getBaseDirectory();
-            if (workingBase.getName().equals("jre")) {
-                workingBase = workingBase.getParentFile();
-            }
-            if (workingBase.getName().equals("Home")) {
-                workingBase = workingBase.getParentFile();
-            }
-            if (workingBase.getName().equals("Contents")) {
-                workingBase = workingBase.getParentFile();
-            }
-
-
-            try {
-                byte[] infoPlistBytes = Files.readAllBytes(workingBase.toPath().resolve(Paths.get("Contents", "Info.plist")));
-                String infoPlist = new String(infoPlistBytes);
-
-                Pattern cfBundleVersionMatcher = Pattern.compile("<key>CFBundleVersion</key>\\s*<string>([^<]+)</string>");
-                Matcher m = cfBundleVersionMatcher.matcher(infoPlist);
-                if (m.find()) {
-                    AbstractImageBundler.extractFlagsFromVersion(params, "java version \"" + m.group(1) + "\"\n");
-                    params.put(".runtime.autodetect", "succeeded");
-                } else {
-                    params.put(".runtime.autodetect", "failed");
-                }
-            } catch (IOException e) {
-                e.printStackTrace();
-                params.put(".runtime.autodetect", "failed");
-            }
-        }
-    }
 }
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacAppStoreBundler.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacAppStoreBundler.java	Thu Mar 17 14:01:55 2016 -0700
@@ -26,13 +26,12 @@
 package com.oracle.tools.packager.mac;
 
 import com.oracle.tools.packager.BundlerParamInfo;
-import com.oracle.tools.packager.JreUtils;
-import com.oracle.tools.packager.RelativeFileSet;
 import com.oracle.tools.packager.StandardBundlerParam;
 import com.oracle.tools.packager.Log;
 import com.oracle.tools.packager.ConfigException;
 import com.oracle.tools.packager.IOUtils;
 import com.oracle.tools.packager.UnsupportedPlatformException;
+import jdk.packager.builders.mac.MacAppImageBuilder;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -111,7 +110,7 @@
         p.put(DEFAULT_ICNS_ICON.getID(), TEMPLATE_BUNDLE_ICON_HIDPI);
 
         // next we need to change the jdk/jre stripping to strip gstreamer
-        p.put(MAC_RULES.getID(), createMacAppStoreRuntimeRules(p));
+//        p.put(MAC_RULES.getID(), createMacAppStoreRuntimeRules(p));
 
         // now we create the app
         File appImageDir = APP_IMAGE_BUILD_ROOT.fetchFrom(p);
@@ -129,7 +128,7 @@
             String entitlementsFile = getConfig_Entitlements(p).toString();
             String inheritEntitlements = getConfig_Inherit_Entitlements(p).toString();
 
-            signAppBundle(p, appLocation, signingIdentity, identifierPrefix, entitlementsFile, inheritEntitlements);
+            MacAppImageBuilder.signAppBundle(p, appLocation.toPath(), signingIdentity, identifierPrefix, entitlementsFile, inheritEntitlements);
             ProcessBuilder pb;
 
             // create the final pkg file
@@ -237,69 +236,6 @@
     }
 
 
-    public static JreUtils.Rule[] createMacAppStoreRuntimeRules(Map<String, ? super Object> params) {
-        //Subsetting of JRE is restricted.
-        //JRE README defines what is allowed to strip:
-        //   http://www.oracle.com/technetwork/java/javase/jre-8-readme-2095710.html
-        //
-
-        List<JreUtils.Rule> rules = new ArrayList<>();
-
-        rules.addAll(Arrays.asList(createMacRuntimeRules(params)));
-
-        File baseDir;
-
-        if (params.containsKey(MAC_RUNTIME.getID())) {
-            Object o = params.get(MAC_RUNTIME.getID());
-            if (o instanceof RelativeFileSet) {
-
-                baseDir = ((RelativeFileSet) o).getBaseDirectory();
-            } else {
-                baseDir = new File(o.toString());
-            }
-        } else {
-            baseDir = new File(System.getProperty("java.home"));
-        }
-
-        // we accept either pointing at the directories typically installed at:
-        // /Libraries/Java/JavaVirtualMachine/jdk1.8.0_40/
-        //   * .
-        //   * Contents/Home
-        //   * Contents/Home/jre
-        // /Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin/
-        //   * .
-        //   * /Contents/Home
-        // version may change, and if we don't detect any Contents/Home or Contents/Home/jre we will
-        // presume we are at a root.
-
-
-        try {
-            String path = baseDir.getCanonicalPath();
-            if (path.endsWith("/Contents/Home/jre")) {
-                baseDir = baseDir.getParentFile().getParentFile().getParentFile();
-            } else if (path.endsWith("/Contents/Home")) {
-                baseDir = baseDir.getParentFile().getParentFile();
-            }
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-
-        if (!baseDir.exists()) {
-            throw new RuntimeException(I18N.getString("error.non-existent-runtime"),
-                    new ConfigException(I18N.getString("error.non-existent-runtime"),
-                            I18N.getString("error.non-existent-runtime.advice")));
-        }
-
-        if (new File(baseDir, "Contents/Home/lib/libjfxmedia_qtkit.dylib").exists()
-            || new File(baseDir, "Contents/Home/jre/lib/libjfxmedia_qtkit.dylib").exists())
-        {
-            rules.add(JreUtils.Rule.suffixNeg("/lib/libjfxmedia_qtkit.dylib"));
-        } else {
-            rules.add(JreUtils.Rule.suffixNeg("/lib/libjfxmedia.dylib"));
-        }
-        return rules.toArray(new JreUtils.Rule[rules.size()]);
-    }
-
     //////////////////////////////////////////////////////////////////////////////////
     // Implement Bundler
     //////////////////////////////////////////////////////////////////////////////////
@@ -360,14 +296,7 @@
             //run basic validation to ensure requirements are met
 
             // Mac App Store apps cannot use the system runtime
-            if (params.containsKey(MAC_RUNTIME.getID()) && params.get(MAC_RUNTIME.getID()) == null) {
-                throw new ConfigException(
-                        I18N.getString("error.no-system-runtime"),
-                        I18N.getString("error.no-system-runtime.advice"));
-            }
-
-            //we need to change the jdk/jre stripping to strip qtkit code
-            params.put(MAC_RULES.getID(), createMacAppStoreRuntimeRules(params));
+            //TODO
 
             //we are not interested in return code, only possible exception
             validateAppImageAndBundeler(params);
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacBaseInstallerBundler.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/mac/MacBaseInstallerBundler.java	Thu Mar 17 14:01:55 2016 -0700
@@ -215,153 +215,11 @@
         return DAEMON_BUNDLER.fetchFrom(p).doBundle(p, daemonImageRoot, true);
     }
 
-    public static void signAppBundle(Map<String, ? super Object> params, File appLocation, String signingIdentity, String identifierPrefix) throws IOException {
-        signAppBundle(params, appLocation, signingIdentity, identifierPrefix, null, null);
-    }
+//    public static void signAppBundle(Map<String, ? super Object> params, File appLocation, String signingIdentity, String identifierPrefix) throws IOException {
+//        signAppBundle(params, appLocation, signingIdentity, identifierPrefix, null, null);
+//    }
+//
 
-    public static void signAppBundle(Map<String, ? super Object> params, File appLocation, String signingIdentity, String identifierPrefix, String entitlementsFile, String inheritedEntitlements) throws IOException {
-        AtomicReference<IOException> toThrow = new AtomicReference<>();
-        String appExecutable = "/Contents/MacOS/" + APP_NAME.fetchFrom(params);
-        String keyChain = SIGNING_KEYCHAIN.fetchFrom(params);
-
-        // sign all dylibs and jars
-        Files.walk(appLocation.toPath())
-                // while we are searching let's fix permissions
-                .peek(path -> {
-                    try {
-                        Set<PosixFilePermission> pfp = Files.getPosixFilePermissions(path);
-                        if (!pfp.contains(PosixFilePermission.OWNER_WRITE)) {
-                            pfp = EnumSet.copyOf(pfp);
-                            pfp.add(PosixFilePermission.OWNER_WRITE);
-                            Files.setPosixFilePermissions(path, pfp);
-                        }
-                    } catch (IOException e) {
-                        Log.debug(e);
-                    }
-                })
-                .filter(p -> Files.isRegularFile(p) &&
-                                !(p.toString().contains("/Contents/MacOS/libjli.dylib")
-                                  || p.toString().contains("/Contents/MacOS/JavaAppletPlugin")
-                                  || p.toString().endsWith(appExecutable))
-                ).forEach(p -> {
-            //noinspection ThrowableResultOfMethodCallIgnored
-            if (toThrow.get() != null) return;
-
-            List<String> args = new ArrayList<>();
-            args.addAll(Arrays.asList("codesign",
-                    "-s", signingIdentity, // sign with this key
-                    "--prefix", identifierPrefix, // use the identifier as a prefix
-                    "-vvvv"));
-            if (entitlementsFile != null &&
-                    (p.toString().endsWith(".jar")
-                      || p.toString().endsWith(".dylib")))
-            {
-                args.add("--entitlements");
-                args.add(entitlementsFile); // entitlements
-            } else if (inheritedEntitlements != null && Files.isExecutable(p)) {
-                args.add("--entitlements");
-                args.add(inheritedEntitlements); // inherited entitlements for executable processes
-            }
-            if (keyChain != null && !keyChain.isEmpty()) {
-                args.add("--keychain");
-                args.add(keyChain);
-            }
-            args.add(p.toString());
-
-            try {
-                Set<PosixFilePermission> oldPermissions = Files.getPosixFilePermissions(p);
-                File f = p.toFile();
-                f.setWritable(true, true);
-
-                ProcessBuilder pb = new ProcessBuilder(args);
-                IOUtils.exec(pb, VERBOSE.fetchFrom(params));
-
-                Files.setPosixFilePermissions(p, oldPermissions);
-            } catch (IOException ioe) {
-                toThrow.set(ioe);
-            }
-        });
-
-        IOException ioe = toThrow.get();
-        if (ioe != null) {
-            throw ioe;
-        }
-
-        // sign all plugins and frameworks
-        Consumer<? super Path> signIdentifiedByPList = path -> {
-            //noinspection ThrowableResultOfMethodCallIgnored
-            if (toThrow.get() != null) return;
-
-            try {
-                List<String> args = new ArrayList<>();
-                args.addAll(Arrays.asList("codesign",
-                        "-s", signingIdentity, // sign with this key
-                        "--prefix", identifierPrefix, // use the identifier as a prefix
-                        "-vvvv"));
-                if (keyChain != null && !keyChain.isEmpty()) {
-                    args.add("--keychain");
-                    args.add(keyChain);
-                }
-                args.add(path.toString());
-                ProcessBuilder pb = new ProcessBuilder(args);
-                IOUtils.exec(pb, VERBOSE.fetchFrom(params));
-
-                args = new ArrayList<>();
-                args.addAll(Arrays.asList("codesign",
-                        "-s", signingIdentity, // sign with this key
-                        "--prefix", identifierPrefix, // use the identifier as a prefix
-                        "-vvvv"));
-                if (keyChain != null && !keyChain.isEmpty()) {
-                    args.add("--keychain");
-                    args.add(keyChain);
-                }
-                args.add(path.toString() + "/Contents/_CodeSignature/CodeResources");
-                pb = new ProcessBuilder(args);
-                IOUtils.exec(pb, VERBOSE.fetchFrom(params));
-            } catch (IOException e) {
-                toThrow.set(e);
-            }
-        };
-
-        Path pluginsPath = appLocation.toPath().resolve("Contents/PlugIns");
-        if (Files.isDirectory(pluginsPath)) {
-            Files.list(pluginsPath)
-                    .forEach(signIdentifiedByPList);
-
-            ioe = toThrow.get();
-            if (ioe != null) {
-                throw ioe;
-            }
-        }
-        Path frameworkPath = appLocation.toPath().resolve("Contents/Frameworks");
-        if (Files.isDirectory(frameworkPath)) {
-            Files.list(frameworkPath)
-                    .forEach(signIdentifiedByPList);
-
-            ioe = toThrow.get();
-            if (ioe != null) {
-                throw ioe;
-            }
-        }
-
-        // sign the app itself
-        List<String> args = new ArrayList<>();
-        args.addAll(Arrays.asList("codesign",
-                "-s", signingIdentity, // sign with this key
-                "-vvvv")); // super verbose output
-        if (entitlementsFile != null) {
-            args.add("--entitlements");
-            args.add(entitlementsFile); // entitlements
-        }
-        if (keyChain != null && !keyChain.isEmpty()) {
-            args.add("--keychain");
-            args.add(keyChain);
-        }
-        args.add(appLocation.toString());
-
-        ProcessBuilder pb = new ProcessBuilder(args.toArray(new String[args.size()]));
-        IOUtils.exec(pb, VERBOSE.fetchFrom(params));
-    }
 
     @Override
     public Collection<BundlerParamInfo<?>> getBundleParameters() {
--- a/modules/fxpackager/src/main/java/com/oracle/tools/packager/windows/WinAppBundler.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/oracle/tools/packager/windows/WinAppBundler.java	Thu Mar 17 14:01:55 2016 -0700
@@ -27,78 +27,35 @@
 
 import com.oracle.tools.packager.AbstractImageBundler;
 import com.oracle.tools.packager.BundlerParamInfo;
-import com.oracle.tools.packager.StandardBundlerParam;
-import com.oracle.tools.packager.Log;
 import com.oracle.tools.packager.ConfigException;
 import com.oracle.tools.packager.IOUtils;
+import com.oracle.tools.packager.JLinkBundlerHelper;
+import com.oracle.tools.packager.Log;
 import com.oracle.tools.packager.RelativeFileSet;
+import com.oracle.tools.packager.StandardBundlerParam;
 import com.oracle.tools.packager.UnsupportedPlatformException;
+import jdk.packager.builders.windows.WindowsAppImageBuilder;
+import jdk.tools.jlink.builder.ImageBuilder;
 
-import java.io.*;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.nio.file.Files;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
 import java.text.MessageFormat;
-import java.util.*;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Pattern;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.ResourceBundle;
 
 import static com.oracle.tools.packager.StandardBundlerParam.*;
-import static com.oracle.tools.packager.windows.WindowsBundlerParam.BIT_ARCH_64;
-import static com.oracle.tools.packager.windows.WindowsBundlerParam.BIT_ARCH_64_RUNTIME;
-import static com.oracle.tools.packager.windows.WindowsBundlerParam.WIN_RUNTIME;
+import static com.oracle.tools.packager.windows.WindowsBundlerParam.*;
 
 public class WinAppBundler extends AbstractImageBundler {
 
     private static final ResourceBundle I18N =
             ResourceBundle.getBundle(WinAppBundler.class.getName());
 
-    public static final BundlerParamInfo<File> CONFIG_ROOT = new WindowsBundlerParam<>(
-            I18N.getString("param.config-root.name"),
-            I18N.getString("param.config-root.description"),
-            "configRoot",
-            File.class,
-            params -> {
-                File imagesRoot = new File(BUILD_ROOT.fetchFrom(params), "windows");
-                imagesRoot.mkdirs();
-                return imagesRoot;
-            },
-            (s, p) -> null);
-
-    private final static String EXECUTABLE_NAME = "WinLauncher.exe";
-    private final static String LIBRARY_NAME = "packager.dll";
-
-    private final static String[] VS_VERS = {"100", "110", "120"};
-    private final static String REDIST_MSVCR = "msvcrVS_VER.dll";
-    private final static String REDIST_MSVCP = "msvcpVS_VER.dll";
-
     private static final String TOOL_ICON_SWAP="IconSwap.exe";
-    private static final String TOOL_VERSION_INFO_SWAP="VersionInfoSwap.exe";
-
-    private static final String EXECUTABLE_PROPERTIES_TEMPLATE = "WinLauncher.properties";
-
-    public static final BundlerParamInfo<URL> RAW_EXECUTABLE_URL = new WindowsBundlerParam<>(
-            I18N.getString("param.raw-executable-url.name"),
-            I18N.getString("param.raw-executable-url.description"),
-            "win.launcher.url",
-            URL.class,
-            params -> WinResources.class.getResource(EXECUTABLE_NAME),
-            (s, p) -> {
-                try {
-                    return new URL(s);
-                } catch (MalformedURLException e) {
-                    Log.info(e.toString());
-                    return null;
-                }
-            });
-
-    public static final BundlerParamInfo<Boolean> REBRAND_EXECUTABLE = new WindowsBundlerParam<>(
-            I18N.getString("param.rebrand-executable.name"),
-            I18N.getString("param.rebrand-executable.description"),
-            "win.launcher.rebrand",
-            Boolean.class,
-            params -> Boolean.TRUE,
-            (s, p) -> Boolean.valueOf(s));
 
     public static final BundlerParamInfo<File> ICON_ICO = new StandardBundlerParam<>(
             I18N.getString("param.icon-ico.name"),
@@ -123,10 +80,6 @@
     public final static String WIN_BUNDLER_PREFIX =
             BUNDLER_PREFIX + "windows/";
 
-    File getConfigRoot(Map<String, ? super Object> params) {
-        return CONFIG_ROOT.fetchFrom(params);
-    }
-
     @Override
     public boolean validate(Map<String, ? super Object> params) throws UnsupportedPlatformException, ConfigException {
         try {
@@ -153,23 +106,12 @@
 
         imageBundleValidation(p);
 
-        if (WinResources.class.getResource(TOOL_ICON_SWAP) == null ||
-            WinResources.class.getResource(TOOL_VERSION_INFO_SWAP) == null)
-        {
+        if (WinResources.class.getResource(TOOL_ICON_SWAP) == null) {
             throw new ConfigException(
                     I18N.getString("error.no-windows-resources"),
                     I18N.getString("error.no-windows-resources.advice"));
         }
 
-        //validate required inputs
-        testRuntime(WIN_RUNTIME.fetchFrom(p), new String[] {
-                "bin\\\\[^\\\\]+\\\\jvm.dll", // most reliable
-                "lib\\\\rt.jar", // fallback canary for JDK 8
-        });
-        if (USE_FX_PACKAGING.fetchFrom(p)) {
-            testRuntime(WIN_RUNTIME.fetchFrom(p), new String[] {"lib\\\\ext\\\\jfxrt.jar", "lib\\\\jfxrt.jar"});
-        }
-
         //validate runtime bit-architectire
         testRuntimeBitArchitecture(p);
 
@@ -203,92 +145,11 @@
         return "app\\" + APP_NAME.fetchFrom(p) +".cfg";
     }
 
-    private File getConfig_AppIcon(Map<String, ? super Object> params) {
-        return new File(getConfigRoot(params), APP_NAME.fetchFrom(params) + ".ico");
-    }
-
-    private File getConfig_ExecutableProperties(Map<String, ? super Object> params) {
-        return new File(getConfigRoot(params), APP_NAME.fetchFrom(params) + ".properties");
-    }
-
-    private final static String TEMPLATE_APP_ICON ="javalogo_white_48.ico";
-
-    //remove
-    protected void cleanupConfigFiles(Map<String, ? super Object> params) {
-        getConfig_AppIcon(params).delete();
-        getConfig_ExecutableProperties(params).delete();
-    }
-
-    private void validateValueAndPut(Map<String, String> data, String key,
-                                     BundlerParamInfo<String> param, Map<String, ? super Object> params)
-    {
-        String value = param.fetchFrom(params);
-        if (value.contains("\r") || value.contains("\n")) {
-            Log.info("Configuration Parameter " + param.getID() + " contains multiple lines of text, ignore it");
-            data.put(key, "");
-            return;
-        }
-        data.put(key, value);
-    }
-
-    protected void prepareExecutableProperties(Map<String, ? super Object> params)
-        throws IOException
-    {
-        Map<String, String> data = new HashMap<>();
-
-        // mapping Java parameters in strings for version resource
-        data.put("COMMENTS", "");
-        validateValueAndPut(data, "COMPANY_NAME", VENDOR, params);
-        validateValueAndPut(data, "FILE_DESCRIPTION", DESCRIPTION, params);
-        validateValueAndPut(data, "FILE_VERSION", VERSION, params);
-        data.put("INTERNAL_NAME", getLauncherName(params));
-        validateValueAndPut(data, "LEGAL_COPYRIGHT", COPYRIGHT, params);
-        data.put("LEGAL_TRADEMARK", "");
-        data.put("ORIGINAL_FILENAME", getLauncherName(params));
-        data.put("PRIVATE_BUILD", "");
-        validateValueAndPut(data, "PRODUCT_NAME", APP_NAME, params);
-        validateValueAndPut(data, "PRODUCT_VERSION", VERSION, params);
-        data.put("SPECIAL_BUILD", "");
-
-        Writer w = new BufferedWriter(new FileWriter(getConfig_ExecutableProperties(params)));
-        String content = preprocessTextResource(
-                WinAppBundler.WIN_BUNDLER_PREFIX + getConfig_ExecutableProperties(params).getName(),
-                I18N.getString("resource.executable-properties-template"), EXECUTABLE_PROPERTIES_TEMPLATE, data,
-                VERBOSE.fetchFrom(params),
-                DROP_IN_RESOURCES_ROOT.fetchFrom(params));
-        w.write(content);
-        w.close();
-    }
-
-    private void prepareConfigFiles(Map<String, ? super Object> params) throws IOException {
-        File iconTarget = getConfig_AppIcon(params);
-
-        File icon = ICON_ICO.fetchFrom(params);
-        if (icon != null && icon.exists()) {
-            fetchResource(WIN_BUNDLER_PREFIX + iconTarget.getName(),
-                    I18N.getString("resource.application-icon"),
-                    icon,
-                    iconTarget,
-                    VERBOSE.fetchFrom(params),
-                    DROP_IN_RESOURCES_ROOT.fetchFrom(params));
-        } else {
-            fetchResource(WIN_BUNDLER_PREFIX + iconTarget.getName(),
-                    I18N.getString("resource.application-icon"),
-                    WinAppBundler.TEMPLATE_APP_ICON,
-                    iconTarget,
-                    VERBOSE.fetchFrom(params),
-                    DROP_IN_RESOURCES_ROOT.fetchFrom(params));
-        }
-
-        prepareExecutableProperties(params);
-    }
-
     public boolean bundle(Map<String, ? super Object> p, File outputDirectory) {
         return doBundle(p, outputDirectory, false) != null;
     }
 
     File doBundle(Map<String, ? super Object> p, File outputDirectory, boolean dependentTask) {
-        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()));
         }
@@ -305,33 +166,12 @@
             IOUtils.deleteRecursive(rootDirectory);
             rootDirectory.mkdirs();
 
-            File appDirectory = new File(rootDirectory, "app");
-            appDirectory.mkdirs();
+            if (!p.containsKey(JLinkBundlerHelper.JLINK_BUILDER.getID())) {
+                p.put(JLinkBundlerHelper.JLINK_BUILDER.getID(), "windowsapp-image-builder");
+            }
 
-            // create the .exe launchers
-            createLauncherForEntryPoint(p, rootDirectory);
-
-            // copy the jars
-            copyApplication(p, appDirectory);
-
-            // Copy runtime
-            File runtimeDirectory = new File(rootDirectory, "runtime");
-            copyRuntime(p, runtimeDirectory);
-
-            // copy in the needed libraries
-            IOUtils.copyFromURL(
-                    WinResources.class.getResource(LIBRARY_NAME),
-                    new File(rootDirectory, LIBRARY_NAME));
-
-            copyMSVCDLLs(rootDirectory, runtimeDirectory);
-
-            // 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);
-            }
+            ImageBuilder imageBuilder = new WindowsAppImageBuilder(p, outputDirectory.toPath());
+            JLinkBundlerHelper.execute(p, outputDirectory, imageBuilder);
 
             if (!dependentTask) {
                 Log.info(MessageFormat.format(I18N.getString("message.result-dir"), outputDirectory.getAbsolutePath()));
@@ -339,241 +179,12 @@
 
             return rootDirectory;
         } catch (IOException ex) {
-            Log.info("Exception: "+ex);
-            Log.debug(ex);
+            Log.info(ex.toString());
+            Log.verbose(ex);
             return null;
-        } finally {
-            if (VERBOSE.fetchFrom(p)) {
-                Log.info(MessageFormat.format(I18N.getString("message.config-save-location"), getConfigRoot(p).getAbsolutePath()));
-            } else {
-                cleanupConfigFiles(p);
-            }
-        }
-
-    }
-
-    private void copyMSVCDLLs(File rootDirectory, File jreDir) throws IOException {
-        String vsVer = null;
-        if (jreDir == null || !jreDir.isDirectory()) {
-            jreDir = new File(System.getProperty("java.home"));
-        }
-
-        // first copy the ones needed for the launcher
-        for (String thisVer : VS_VERS) {
-            if (copyMSVCDLLs(rootDirectory, thisVer)) {
-                vsVer = thisVer;
-                break;
-            }
-        }
-        if (vsVer == null) {
-            throw new RuntimeException("Not found MSVC dlls");
-        }
-
-        AtomicReference<IOException> ioe = new AtomicReference<>();
-        final String finalVsVer = vsVer;
-        Files.list(jreDir.toPath().resolve("bin"))
-                .filter(p -> Pattern.matches("msvc(r|p)\\d\\d\\d.dll", p.toFile().getName().toLowerCase()))
-                .filter(p -> !p.toString().toLowerCase().endsWith(finalVsVer + ".dll"))
-                .forEach(p -> {
-                    try {
-                        IOUtils.copyFile(p.toFile(), new File(rootDirectory, p.toFile().getName()));
-                    } catch (IOException e) {
-                        ioe.set(e);
-                    }
-                });
-
-        IOException e = ioe.get();
-        if (e != null) {
-            throw e;
         }
     }
 
-    private boolean copyMSVCDLLs(File rootDirectory, String VS_VER) throws IOException {
-        final URL REDIST_MSVCR_URL = WinResources.class.getResource(
-                                              REDIST_MSVCR.replaceAll("VS_VER", VS_VER));
-        final URL REDIST_MSVCP_URL = WinResources.class.getResource(
-                REDIST_MSVCP.replaceAll("VS_VER", VS_VER));
-
-        if (REDIST_MSVCR_URL != null && REDIST_MSVCP_URL != null) {
-            IOUtils.copyFromURL(
-                    REDIST_MSVCR_URL,
-                    new File(rootDirectory, REDIST_MSVCR.replaceAll("VS_VER", VS_VER)));
-            IOUtils.copyFromURL(
-                    REDIST_MSVCP_URL,
-                    new File(rootDirectory, REDIST_MSVCP.replaceAll("VS_VER", VS_VER)));
-            return true;
-        }
-
-        return false; // not found
-    }
-
-    private void createLauncherForEntryPoint(Map<String, ? super Object> p, File rootDirectory) throws IOException {
-        prepareConfigFiles(p);
-
-        // 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)), getRuntimeLocation(p));
-        }
-
-        // Copy executable root folder
-        File executableFile = new File(rootDirectory, getLauncherName(p));
-        IOUtils.copyFromURL(
-                RAW_EXECUTABLE_URL.fetchFrom(p),
-                executableFile);
-        executableFile.setExecutable(true, false);
-
-        //Update branding of exe file
-        if (REBRAND_EXECUTABLE.fetchFrom(p) && getConfig_AppIcon(p).exists()) {
-            //extract IconSwap helper tool
-            File iconSwapTool = File.createTempFile("iconswap", ".exe");
-            IOUtils.copyFromURL(
-                    WinResources.class.getResource(TOOL_ICON_SWAP),
-                    iconSwapTool,
-                    true);
-            iconSwapTool.setExecutable(true, false);
-            iconSwapTool.deleteOnExit();
-
-            //run it on launcher file
-            executableFile.setWritable(true);
-            ProcessBuilder pb = new ProcessBuilder(
-                    iconSwapTool.getAbsolutePath(),
-                    getConfig_AppIcon(p).getAbsolutePath(),
-                    executableFile.getAbsolutePath());
-            IOUtils.exec(pb, VERBOSE.fetchFrom(p));
-            executableFile.setReadOnly();
-            iconSwapTool.delete();
-        }
-
-        IOUtils.copyFile(getConfig_AppIcon(p),
-                new File(rootDirectory, APP_NAME.fetchFrom(p) + ".ico"));
-
-        if (REBRAND_EXECUTABLE.fetchFrom(p) && getConfig_ExecutableProperties(p).exists()) {
-            // extract VersionInfoHelper tool
-            File versionInfoTool = File.createTempFile("versioninfoswap", ".exe");
-            IOUtils.copyFromURL(
-                    WinResources.class.getResource(TOOL_VERSION_INFO_SWAP),
-                    versionInfoTool,
-                    true);
-            versionInfoTool.setExecutable(true, false);
-            versionInfoTool.deleteOnExit();
-
-            // run it on launcher file
-            executableFile.setWritable(true);
-            ProcessBuilder pb = new ProcessBuilder(
-                    versionInfoTool.getAbsolutePath(),
-                    getConfig_ExecutableProperties(p).getAbsolutePath(),
-                    executableFile.getAbsolutePath());
-            IOUtils.exec(pb, VERBOSE.fetchFrom(p));
-            executableFile.setReadOnly();
-            versionInfoTool.delete();
-        }
-    }
-
-    private void copyApplication(Map<String, ? super Object> params, File appDirectory) throws IOException {
-        List<RelativeFileSet> appResourcesList = APP_RESOURCES_LIST.fetchFrom(params);
-        if (appResourcesList == null) {
-            throw new RuntimeException("Null app resources?");
-        }
-        for (RelativeFileSet appResources : appResourcesList) {
-            if (appResources == null) {
-                throw new RuntimeException("Null app resources?");
-            }
-            File srcdir = appResources.getBaseDirectory();
-            for (String fname : appResources.getIncludedFiles()) {
-                IOUtils.copyFile(
-                        new File(srcdir, fname), new File(appDirectory, fname));
-            }
-        }
-    }
-
-    private String getRuntimeLocation(Map<String, ? super Object> params) {
-        if (WIN_RUNTIME.fetchFrom(params) == null) {
-            return "";
-        } else {
-            return "$APPDIR\\runtime";
-        }
-    }
-
-    private void writeCfgFile(Map<String, ? super Object> params, File rootDir) throws FileNotFoundException {
-        File cfgFile = new File(rootDir, getLauncherCfgName(params));
-
-        cfgFile.delete();
-
-        PrintStream out = new PrintStream(cfgFile);
-        out.println("app.runtime=" + getRuntimeLocation(params));
-        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();
-    }
-
-    private void copyRuntime(Map<String, ? super Object> params, File runtimeDirectory) throws IOException {
-        RelativeFileSet runtime = WIN_RUNTIME.fetchFrom(params);
-        if (runtime == null) {
-            //its ok, request to use system JRE
-            return;
-        }
-        runtimeDirectory.mkdirs();
-
-        File srcdir = runtime.getBaseDirectory();
-        Set<String> filesToCopy = runtime.getIncludedFiles();
-        for (String fname : filesToCopy) {
-            IOUtils.copyFile(
-                    new File(srcdir, fname), new File(runtimeDirectory, fname));
-        }
-    }
-
-    public void extractRuntimeFlags(Map<String, ? super Object> params) {
-        extractFlagsFromRuntime(params);
-    }
 
     public static void extractFlagsFromRuntime(Map<String, ? super Object> params) {
         if (params.containsKey(".runtime.autodetect")) return;
@@ -655,9 +266,4 @@
     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 "$CACHEDIR/";
-    }
 }
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/ant/Application.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/ant/Application.java	Thu Mar 17 14:01:55 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -61,6 +61,11 @@
     String version = null;
     Boolean daemon = null;
 
+    public List<Argument> addModule = new LinkedList<Argument>();
+    public List<Argument> limitModule = new LinkedList<Argument>();
+    String jdkModulePath;
+    boolean detectModules;
+
     public void setVersion(String v) {
         version = v;
     }
@@ -180,6 +185,94 @@
         daemon = b;
     }
 
+
+    /**
+     * "addModule" declaration for the application's runtime.
+     *
+     * Modules can be specified per-element, or comma/colon/semi-colon/space separated
+     *
+     * @ant.not-required Default is to bundle the whole platform
+     */
+    public Argument createAddModule() {
+        Argument a = new Argument();
+        addModule.add(a);
+        return a;
+    }
+
+    /**
+     * "addModule" declaration for the application's runtime
+     *
+     * @ant.not-required Default is to bundle the whole platform
+     */
+    List<String> getAddModule() {
+        List<String> lst = new LinkedList();
+        for(Argument a: arguments) {
+            for (String s : a.value.split("[:;,\\s]+")) {
+                lst.add(s);
+            }
+        }
+        return lst;
+    }
+
+    /**
+     * "limitModule" declaration for the application's runtime.
+     *
+     * Modules can be specified per-element, or comma/colon/semi-colon/space separated
+     *
+     * @ant.not-required Default is to bundle the whole platform
+     */
+    public Argument createLimitModule() {
+        Argument a = new Argument();
+        addModule.add(a);
+        return a;
+    }
+
+    /**
+     * "limitModule" declaration for the application's runtime
+     *
+     * @ant.not-required Default is to bundle the whole platform
+     */
+    List<String> getLimitModule() {
+        List<String> lst = new LinkedList();
+        for(Argument a: arguments) {
+            for (String s : a.value.split("[:;,\\s]+")) {
+                lst.add(s);
+            }
+        }
+        return lst;
+    }
+
+    /**
+     * Whether or not the bundler should attempt to detect and add used modules
+     */
+    public boolean getDetectModules() {
+        return detectModules;
+    }
+
+    /**
+     * Whether or not the bundler should attempt to detect and add used modules
+     * @ant.not-required default is false
+     */
+    public void setDetectModules(boolean Value) {
+        this.detectModules = Value;
+    }
+
+    /**
+     * Module path within the running applicaiton
+     */
+    public String getJdkModulePath() {
+        return jdkModulePath;
+    }
+
+    /**
+     * Module path within the running applicaiton
+     *
+     * @ant.not-required default is $PACKAGEPATH/modules
+     */
+    public void setJdkModulePath(String Value) {
+        this.jdkModulePath = Value;
+    }
+
     //return instance that actually has data. Could be referenced object ...
     public Application get() {
         return isReference() ?
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/ant/DeployFXTask.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/ant/DeployFXTask.java	Thu Mar 17 14:01:55 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -108,6 +108,7 @@
     private Resources resources = null;
     private Preferences prefs = null;
     private String codebase = null;
+    private String modulePath = null;
 
     //container to embed application into
     //could be either string id or js code. If it is string id then it needs to
@@ -135,6 +136,10 @@
         codebase = str;
     }
 
+    public void setLinkModulePath(String str) {
+        modulePath = str;
+    }
+
     public DeployFXTask() {
         packager = new PackagerLib();
         deployParams = new DeployParams();
@@ -147,6 +152,7 @@
         deployParams.setOfflineAllowed(offlineAllowed);
         deployParams.setVerbose(verbose);
         deployParams.setCodebase(codebase);
+        deployParams.setModulePath(modulePath);
         deployParams.setSignBundle(signBundle);
 
         if (width != null) {
@@ -180,6 +186,15 @@
             deployParams.setVersion(app.get().version);
             deployParams.setId(app.get().id);
             deployParams.setServiceHint(app.get().daemon);
+
+            for (String s : app.getAddModule()) {
+                deployParams.addAddModule(s);
+            }
+            for (String s : app.getLimitModule()) {
+                deployParams.addLimitModule(s);
+            }
+            deployParams.setDetectModules(app.getDetectModules());
+            deployParams.setJdkModulePath(app.getJdkModulePath());
         }
 
         if (appInfo != null) {
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/DeployParams.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/DeployParams.java	Thu Mar 17 14:01:55 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -74,6 +74,14 @@
     List<HtmlParam> htmlParams;
     List<String> arguments; //unnamed arguments
 
+    // Java 9 modules support
+    Set<String> addModules = new LinkedHashSet<>();
+    Set<String> limitModules = new LinkedHashSet<>();
+    boolean detectModules = false;
+    boolean stripExecutables = false;
+    String modulePath;
+    String jdkModulePath;
+
     int width;
     int height;
     String embeddedWidth = null;
@@ -241,6 +249,30 @@
         this.arguments = args;
     }
 
+    public void addAddModule(String module) {
+        addModules.add(module);
+    }
+
+    public void addLimitModule(String module) {
+        limitModules.add(module);
+    }
+
+    public void setModulePath(String value) {
+        this.modulePath = value;
+    }
+
+    public void setJdkModulePath(String value) {
+        this.jdkModulePath = value;
+    }
+
+    public void setDetectModules(boolean value) {
+        this.detectModules = value;
+    }
+
+    public void setStripExecutables(boolean value) {
+        this.stripExecutables = value;
+    }
+
     public void setDescription(String description) {
         this.description = description;
     }
@@ -523,7 +555,13 @@
             StandardBundlerParam.JVM_PROPERTIES.getID(),
             StandardBundlerParam.JVM_OPTIONS.getID(),
             StandardBundlerParam.USER_JVM_OPTIONS.getID(),
-            StandardBundlerParam.ARGUMENTS.getID()
+            StandardBundlerParam.ARGUMENTS.getID(),
+            //StandardBundlerParam.MODULE_NAME.getID(),
+            JLinkBundlerHelper.MODULE_PATH.getID(),
+            JLinkBundlerHelper.JDK_MODULE_PATH.getID(),
+            JLinkBundlerHelper.ADD_MODULES.getID(),
+            JLinkBundlerHelper.LIMIT_MODULES.getID(),
+            JLinkBundlerHelper.STRIP_NATIVE_COMMANDS.getID()
     ));
 
     @SuppressWarnings("unchecked")
@@ -604,6 +642,13 @@
         bundleParams.setJvmUserArgs(jvmUserArgs);
         bundleParams.setArguments(arguments);
 
+        bundleParams.setAddModules(addModules);
+        bundleParams.setLimitModules(limitModules);
+        bundleParams.setDetectModules(detectModules);
+        bundleParams.setStripExecutables(stripExecutables);
+        bundleParams.setAppModulePath(jdkModulePath);
+        bundleParams.setLinkModulePath(modulePath);
+
         File appIcon = null;
         List<Map<String, ? super Object>> bundlerIcons = new ArrayList<>();
         for (Icon ic: icons) {
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/Main.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/Main.java	Thu Mar 17 14:01:55 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2016, 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
@@ -229,6 +229,9 @@
                     boolean srcfilesSet = false;
                     File templateInFile = null;
                     File templateOutFile = null;
+                    deployParams.setBundleType(BundleType.JNLP);
+                    deployParams.setTargetFormat("jnlp");
+
 
                     //can only set it to true with command line, reset default
                     deployParams.setEmbedJNLP(false);
@@ -274,7 +277,6 @@
                                 } else {
                                     //assume it is request to build only specific format
                                     // (like exe or msi)
-                                    type = BundleType.INSTALLER;
                                     format = (v != null) ? v.toLowerCase() : null;
                                 }
                             }
@@ -338,6 +340,32 @@
                             addArgument(deployParams, nextArg(args, i++));
                         } else if (arg.equalsIgnoreCase("-nosign")) {
                             deployParams.setSignBundle(false);
+                        } else if (arg.equals("-addmods")) {
+                            deployParams.addModules.add(nextArg(args, i++));
+                        } else if (arg.equals("-limitmods")) {
+                            deployParams.limitModules.add(nextArg(args, i++));
+                        } else if (arg.equals("-detectmods")) {
+                            deployParams.detectModules = true;
+                        } else if (arg.equals("-stripexecutables")) {
+                            deployParams.stripExecutables = true;
+                        } else if (arg.equals("-modulepath")) {
+                            if (deployParams.modulePath == null) {
+                                deployParams.modulePath = nextArg(args, i++);
+                            } else {
+                                deployParams.modulePath =
+                                        deployParams.modulePath
+                                        + File.pathSeparator
+                                        + nextArg(args, i++);
+                            }
+                        } else if (arg.equals("-jdkmodulepath")) {
+                            if (deployParams.jdkModulePath == null) {
+                                deployParams.jdkModulePath = nextArg(args, i++);
+                            } else {
+                                deployParams.jdkModulePath =
+                                        deployParams.jdkModulePath
+                                        + File.pathSeparator
+                                        + nextArg(args, i++);
+                            }
                         } else {
                             throw new PackagerException("ERR_UnknownArgument", arg);
                         }
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/PackagerLib.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/PackagerLib.java	Thu Mar 17 14:01:55 2016 -0700
@@ -28,7 +28,6 @@
 import com.oracle.tools.packager.Bundlers;
 import com.oracle.tools.packager.ConfigException;
 import com.oracle.tools.packager.Log;
-import com.oracle.tools.packager.RelativeFileSet;
 import com.oracle.tools.packager.UnsupportedPlatformException;
 import com.sun.javafx.tools.packager.JarSignature.InputStreamSource;
 import com.sun.javafx.tools.packager.bundlers.BundleParams;
@@ -187,16 +186,16 @@
 
         //NOTE: This should be a save-to-temp file, then rename operation
         File applicationJar = new File(createJarParams.outdir,
-                        createJarParams.outfile.endsWith(".jar")
-                              ? createJarParams.outfile
-                              : createJarParams.outfile + ".jar");
+                createJarParams.outfile.endsWith(".jar")
+                        ? createJarParams.outfile
+                        : createJarParams.outfile + ".jar");
 
         if (jarToUpdate != null &&
                 applicationJar.getAbsoluteFile().equals(jarToUpdate.getAbsoluteFile())) {
             try {
                 File newInputJar = File.createTempFile("tempcopy", ".jar");
                 Files.move(jarToUpdate.toPath(), newInputJar.toPath(),
-                           StandardCopyOption.REPLACE_EXISTING);
+                        StandardCopyOption.REPLACE_EXISTING);
                 jarToUpdate = newInputJar;
             } catch (IOException ioe) {
                 throw new PackagerException(
@@ -315,8 +314,26 @@
         try {
             BundleParams bp = deployParams.getBundleParams();
             if (bp != null) {
-                generateNativeBundles(deployParams.outdir, bp.getBundleParamsAsMap(), "JNLP", "jnlp");
-                generateNativeBundles(new File(deployParams.outdir, "bundles"), bp.getBundleParamsAsMap(), deployParams.getBundleType().toString(), deployParams.getTargetFormat());
+                if (deployParams.getBundleType().equals(BundleType.ALL) && deployParams.getTargetFormat() == null) {
+                    // generate everything.
+
+                    // generate JNLP in the main directory
+                    generateNativeBundles(deployParams.outdir, bp.getBundleParamsAsMap(), BundleType.JNLP.toString(), "jnlp");
+                    // generate the rest in .../bundles
+
+                    // generate disk images
+                    generateNativeBundles(new File(deployParams.outdir, "bundles"), bp.getBundleParamsAsMap(), BundleType.IMAGE.toString(), deployParams.getTargetFormat());
+
+                    //TODO generate installers referencing disk image
+                    // for now just generate all images
+                    generateNativeBundles(new File(deployParams.outdir, "bundles"), bp.getBundleParamsAsMap(), BundleType.INSTALLER.toString(), deployParams.getTargetFormat());
+                } else if (deployParams.getBundleType().equals(BundleType.NONE) && deployParams.getTargetFormat() == null) {
+                    // old school default.  Just generate JNLP.
+                    generateNativeBundles(deployParams.outdir, bp.getBundleParamsAsMap(), BundleType.JNLP.toString(), "jnlp");
+                } else {
+                    // a specefic output format, just generate that.
+                    generateNativeBundles(deployParams.outdir, bp.getBundleParamsAsMap(), deployParams.getBundleType().toString(), deployParams.getTargetFormat());
+                }
             }
         } catch (PackagerException ex) {
             throw ex;
@@ -327,19 +344,7 @@
     }
 
     private void generateNativeBundles(File outdir, Map<String, ? super Object> params, String bundleType, String bundleFormat) throws PackagerException {
-        if (params.containsKey(BundleParams.PARAM_RUNTIME)) {
-            RelativeFileSet runtime = BundleParams.getRuntime(params);
-            if (runtime == null) {
-                com.oracle.tools.packager.Log.info(bundle.getString("MSG_NoJREPackaged"));
-            } else {
-                com.oracle.tools.packager.Log.info(MessageFormat.format(bundle.getString("MSG_UserProvidedJRE"), runtime.getBaseDirectory().getAbsolutePath()));
-                if (com.oracle.tools.packager.Log.isDebug()) {
-                    runtime.dump();
-                }
-            }
-        } else {
-            com.oracle.tools.packager.Log.info(bundle.getString("MSG_UseSystemJRE"));
-        }
+        //FIXME //TODO check for system JRE
 
         for (com.oracle.tools.packager.Bundler bundler : Bundlers.createBundlersInstance().getBundlers(bundleType)) {
 
@@ -432,7 +437,7 @@
 
     private void signFile(
             PackagerResource pr, JarSignature signature, File outdir, boolean verbose)
-               throws NoSuchAlgorithmException, IOException, SignatureException {
+            throws NoSuchAlgorithmException, IOException, SignatureException {
         if (pr.getFile().isDirectory()) {
             File[] children = pr.getFile().listFiles();
             if (children != null) {
@@ -463,7 +468,7 @@
             destJar.getParentFile().mkdirs();
             signedJar.renameTo(destJar);
             if (verbose) {
-               System.out.println("Signed as " + destJar.getPath());
+                System.out.println("Signed as " + destJar.getPath());
             }
         }
     }
@@ -523,7 +528,7 @@
             try (FileWriter sources = new FileWriter(tmpFile)) {
                 scanAndCopy(new PackagerResource(new File(srcDirName), "."), sources, compiledDir);
             }
-            String classpath = jfxHome + "/../rt/lib/ext/jfxrt.jar";
+            String classpath = jfxHome + "/../lib/jfxrt.jar";
             if (makeAllParams.classpath != null) {
                 classpath += File.pathSeparator + makeAllParams.classpath;
             }
@@ -635,8 +640,8 @@
                 } else {
                     copyFileToOutDir(new FileInputStream(f),
                             new File(outdir.getPath() + File.separator
-                            + dir.getRelativePath() + File.separator
-                            + f.getName()));
+                                    + dir.getRelativePath() + File.separator
+                                    + f.getName()));
                 }
             }
         } catch (IOException ex) {
@@ -669,7 +674,7 @@
     private void jar(
             Manifest manifest, List<PackagerResource> files,
             File importJarFile, JarOutputStream jar, Filter filter)
-                throws IOException, PackagerException {
+            throws IOException, PackagerException {
         try {
             jar.putNextEntry(new ZipEntry("META-INF/"));
             jar.closeEntry();
@@ -755,7 +760,7 @@
                 || (filter == Filter.RESOURCES && isResource(f.getAbsolutePath()))) {
             final String absPath = f.getAbsolutePath();
             if (absPath.endsWith("META-INF\\MANIFEST.MF")
-             || absPath.endsWith("META-INF/MANIFEST.MF")) {
+                    || absPath.endsWith("META-INF/MANIFEST.MF")) {
                 return;
             }
             createParentEntries(absPath.substring(cut).replace('\\', '/'), jar);
@@ -763,8 +768,8 @@
                 // generate bss file into temporary directory
                 int startOfExt = absPath.lastIndexOf(".") + 1;
                 String bssFileName = absPath
-                                      .substring(cut, startOfExt)
-                                      .concat("bss");
+                        .substring(cut, startOfExt)
+                        .concat("bss");
 
                 File bssFile = new File(bssTmpDir, bssFileName);
                 bssFile.getParentFile().mkdirs();
@@ -809,8 +814,8 @@
         } else if (f.getName().endsWith(".css")) {
             String cssFileName = f.getAbsolutePath();
             String bssFileName = new File(outdir.getAbsolutePath(),
-                                          replaceExtensionByBSS(relPath))
-                                          .getAbsolutePath();
+                    replaceExtensionByBSS(relPath))
+                    .getAbsolutePath();
             createBinaryCss(cssFileName, bssFileName);
         }
     }
@@ -831,7 +836,7 @@
         int lastIndexOfSlash = Math.max(classUrl.lastIndexOf("/"), classUrl.lastIndexOf("\\"));
 
         return classUrl.substring(0, lastIndexOfSlash)
-                    + "/../rt/lib/ext/jfxrt.jar!/";
+                + "/../lib/jfxrt.jar!/";
     }
 
     private Class loadClassFromRuntime(String className) throws PackagerException {
@@ -845,8 +850,8 @@
 
     private void createBinaryCss(String cssFile, String binCssFile) throws PackagerException {
         String ofname = (binCssFile != null)
-                            ? binCssFile
-                            : replaceExtensionByBSS(cssFile);
+                ? binCssFile
+                : replaceExtensionByBSS(cssFile);
 
         // create parent directories
         File of = new File(ofname);
@@ -872,7 +877,7 @@
         } catch (Exception ex) {
             Throwable causeEx = ex.getCause();
             String cause = (causeEx != null) ? causeEx.getMessage()
-                                             : bundle.getString("ERR_UnknownReason");
+                    : bundle.getString("ERR_UnknownReason");
 
             throw new PackagerException(ex, "ERR_BSSConversionFailed", cssFile, cause);
         }
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/bundlers/BundleParams.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/bundlers/BundleParams.java	Thu Mar 17 14:01:55 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, 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
@@ -26,9 +26,6 @@
 package com.sun.javafx.tools.packager.bundlers;
 
 import com.oracle.tools.packager.*;
-import com.oracle.tools.packager.linux.LinuxAppBundler;
-import com.oracle.tools.packager.mac.MacAppBundler;
-import com.oracle.tools.packager.windows.WindowsBundlerParam;
 import com.sun.javafx.tools.packager.bundlers.Bundler.BundleType;
 
 import java.io.File;
@@ -39,6 +36,7 @@
 import java.util.jar.Manifest;
 
 import static com.oracle.tools.packager.StandardBundlerParam.*;
+import static com.oracle.tools.packager.JLinkBundlerHelper.*;
 
 public class BundleParams {
 
@@ -170,6 +168,31 @@
         putUnlessNullOrEmpty(ARGUMENTS.getID(), arguments);
     }
 
+    public void setAddModules(Set<String> addModules) {
+        putUnlessNullOrEmpty(ADD_MODULES.getID(), addModules);
+    }
+
+    public void setLimitModules(Set<String> limitModules)  {
+        putUnlessNullOrEmpty(LIMIT_MODULES.getID(), limitModules);
+    }
+
+    public void setDetectModules(Boolean detectModules) {
+        putUnlessNull(DETECT_MODULES.getID(), detectModules);
+    }
+
+    public void setStripExecutables(Boolean value) {
+        putUnlessNull(STRIP_NATIVE_COMMANDS.getID(), value);
+    }
+
+    public void setAppModulePath(String appModulePath) {
+        putUnlessNull(JDK_MODULE_PATH.getID(), appModulePath);
+    }
+
+    public void setLinkModulePath(String linkModulePath) {
+        putUnlessNull(MODULE_PATH.getID(), linkModulePath);
+    }
+
+
     public String getApplicationID() {
         return fetchParam(IDENTIFIER);
     }
@@ -250,23 +273,6 @@
 
     public void setSignBundle(Boolean b) { putUnlessNull(SIGN_BUNDLE.getID(), b); }
 
-    public com.oracle.tools.packager.RelativeFileSet getRuntime() {
-        return getRuntime(params);
-    }
-
-    public static com.oracle.tools.packager.RelativeFileSet getRuntime(Map<String, ? super Object> params) {
-        String os = System.getProperty("os.name").toLowerCase();
-        if (os.startsWith("linux")) {
-            return LinuxAppBundler.LINUX_RUNTIME.fetchFrom(params);
-        } else if (os.contains("os x")) {
-            return MacAppBundler.MAC_RUNTIME.fetchFrom(params);
-        } else if (os.startsWith("win")) {
-            return WindowsBundlerParam.WIN_RUNTIME.fetchFrom(params);
-        } else {
-            return null;
-        }
-    }
-
     public boolean isShortcutHint() {
         return fetchParam(SHORTCUT_HINT);
     }
--- a/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/bundlers/Bundler.java	Tue Mar 15 04:00:44 2016 -0700
+++ b/modules/fxpackager/src/main/java/com/sun/javafx/tools/packager/bundlers/Bundler.java	Thu Mar 17 14:01:55 2016 -0700
@@ -33,7 +33,7 @@
      */
     @Deprecated
     public enum BundleType {
-        NONE, IMAGE, INSTALLER, ALL
+        NONE, IMAGE, INSTALLER, ALL, JNLP
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/java/jdk/packager/builders/AbstractAppImageBuilder.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2015, 2016, 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 jdk.packager.builders;
+
+import com.oracle.tools.packager.JLinkBundlerHelper;
+import com.oracle.tools.packager.RelativeFileSet;
+import jdk.tools.jlink.builder.*;
+import jdk.tools.jlink.plugin.Pool;
+
+import com.oracle.tools.packager.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import static com.oracle.tools.packager.StandardBundlerParam.*;
+import static com.oracle.tools.packager.StandardBundlerParam.ARGUMENTS;
+import static com.oracle.tools.packager.StandardBundlerParam.USER_JVM_OPTIONS;
+
+/**
+ *
+ * Created by dferrin on 9/1/15.
+ */
+public abstract class AbstractAppImageBuilder extends DefaultImageBuilder {
+
+    private static final ResourceBundle I18N =
+            ResourceBundle.getBundle(AbstractAppImageBuilder.class.getName());
+
+    //do not use file separator -
+    // we use it for classpath lookup and there / are not platform specific
+    public final static String BUNDLER_PREFIX = "package/";
+
+    public AbstractAppImageBuilder(Map<String, Object> properties, Path root) throws IOException {
+        super(true, root);
+    }
+
+    abstract protected void prepareApplicationFiles(Pool files, Set<String> modules) throws IOException;
+
+    abstract protected InputStream getResourceAsStream(String name);
+
+    protected InputStream locateResource(String publicName, String category,
+                                         String defaultName, File customFile,
+                                         boolean verbose, File publicRoot) throws IOException {
+        InputStream is = null;
+        boolean customFromClasspath = false;
+        boolean customFromFile = false;
+        if (publicName != null) {
+            if (publicRoot != null) {
+                File publicResource = new File(publicRoot, publicName);
+                if (publicResource.exists() && publicResource.isFile()) {
+                    is = new FileInputStream(publicResource);
+                }
+            } else {
+                is = getResourceAsStream(publicName);
+            }
+            customFromClasspath = (is != null);
+        }
+        if (is == null && customFile != null) {
+            is = new FileInputStream(customFile);
+            customFromFile = (is != null);
+        }
+        if (is == null && defaultName != null) {
+            is = getResourceAsStream(defaultName);
+        }
+        String msg = null;
+        if (customFromClasspath) {
+            msg = MessageFormat.format(I18N.getString("message.using-custom-resource-from-classpath"), category == null ? "" : "[" + category + "] ", publicName);
+        } else if (customFromFile) {
+            msg = MessageFormat.format(I18N.getString("message.using-custom-resource-from-file"), category == null ? "" : "[" + category + "] ", customFile.getAbsoluteFile());
+        } else if (is != null) {
+            msg = MessageFormat.format(I18N.getString("message.using-default-resource-from-classpath"), category == null ? "" : "[" + category + "] ", publicName);
+        } else {
+            msg = MessageFormat.format(I18N.getString("message.using-default-resource"), category == null ? "" : "[" + category + "] ", publicName);
+        }
+        if (verbose) {
+            Log.info(msg);
+        }
+        return is;
+    }
+
+
+    protected String preprocessTextResource(String publicName, String category,
+                                            String defaultName, Map<String, String> pairs,
+                                            boolean verbose, File publicRoot) throws IOException {
+        InputStream inp = locateResource(publicName, category, defaultName, null, verbose, publicRoot);
+        if (inp == null) {
+            throw new RuntimeException("Module corrupt? No "+defaultName+" resource!");
+        }
+
+        try (InputStream is = inp) {
+            //read fully into memory
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            byte[] buffer = new byte[1024];
+            int length;
+            while ((length = is.read(buffer)) != -1) {
+                baos.write(buffer, 0, length);
+            }
+
+            //substitute
+            String result = new String(baos.toByteArray());
+            for (Map.Entry<String, String> e : pairs.entrySet()) {
+                if (e.getValue() != null) {
+                    result = result.replace(e.getKey(), e.getValue());
+                }
+            }
+            return result;
+        }
+    }
+
+    public void writeCfgFile(Map<String, ? super Object> params, File cfgFileName, String runtimeLocation) throws IOException {
+        cfgFileName.delete();
+
+        boolean appCDEnabled = UNLOCK_COMMERCIAL_FEATURES.fetchFrom(params) && ENABLE_APP_CDS.fetchFrom(params);
+        String appCDSCacheMode = APP_CDS_CACHE_MODE.fetchFrom(params);
+
+        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.modulepath=" +
+                String.join(File.pathSeparator, JLinkBundlerHelper.JDK_MODULE_PATH.fetchFrom(params)));
+        out.println("app.runtime=" + runtimeLocation);
+        out.println("app.identifier=" + IDENTIFIER.fetchFrom(params));
+        if (appCDEnabled) {
+            out.println("app.appcds.cache=" + appCDSCacheMode.split("\\+")[0]);
+        }
+
+
+        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 (appCDEnabled) {
+            prepareAppCDS(params, out);
+        }
+
+        out.println();
+        out.println("[ArgOptions]");
+        List<String> args = ARGUMENTS.fetchFrom(params);
+        for (String arg : args) {
+            if (arg.endsWith("=") && (arg.indexOf("=") == arg.lastIndexOf("="))) {
+                out.print(arg.substring(0, arg.length() - 1));
+                out.println("\\=");
+            } else {
+                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:auto");
+        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");
+        }
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/java/jdk/packager/builders/linux/LinuxAppImageBuilder.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2015, 2016, 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 jdk.packager.builders.linux;
+
+import com.oracle.tools.packager.BundlerParamInfo;
+import com.oracle.tools.packager.Log;
+import com.oracle.tools.packager.RelativeFileSet;
+import com.oracle.tools.packager.StandardBundlerParam;
+import com.oracle.tools.packager.linux.LinuxResources;
+import jdk.packager.builders.AbstractAppImageBuilder;
+import jdk.tools.jlink.plugin.Pool;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermission;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import static com.oracle.tools.packager.StandardBundlerParam.*;
+
+/**
+ *
+ */
+public class LinuxAppImageBuilder extends AbstractAppImageBuilder {
+
+    private static final ResourceBundle I18N =
+            ResourceBundle.getBundle(LinuxAppImageBuilder.class.getName());
+
+    protected static final String LINUX_BUNDLER_PREFIX =
+            BUNDLER_PREFIX + "linux" + File.separator;
+    private static final String EXECUTABLE_NAME = "JavaAppLauncher";
+    private static final String LIBRARY_NAME = "libpackager.so";
+
+    private final Path root;
+    private final Path appDir;
+    private final Path runtimeRoot;
+    private final Path mdir;
+
+    private final Map<String, ? super Object> params;
+
+    public static final BundlerParamInfo<File> ICON_PNG = new StandardBundlerParam<>(
+            I18N.getString("param.icon-png.name"),
+            I18N.getString("param.icon-png.description"),
+            "icon.png",
+            File.class,
+            params -> {
+                File f = ICON.fetchFrom(params);
+                if (f != null && !f.getName().toLowerCase().endsWith(".png")) {
+                    Log.info(MessageFormat.format(I18N.getString("message.icon-not-png"), f));
+                    return null;
+                }
+                return f;
+            },
+            (s, p) -> new File(s));
+
+//    public static final BundlerParamInfo<URL> RAW_EXECUTABLE_URL = new StandardBundlerParam<>(
+//            I18N.getString("param.raw-executable-url.name"),
+//            I18N.getString("param.raw-executable-url.description"),
+//            "linux.launcher.url",
+//            URL.class,
+//            params -> LinuxResources.class.getResource(EXECUTABLE_NAME),
+//            (s, p) -> {
+//                try {
+//                    return new URL(s);
+//                } catch (MalformedURLException e) {
+//                    Log.info(e.toString());
+//                    return null;
+//                }
+//            });
+//
+
+    public LinuxAppImageBuilder(Map<String, Object> config, Path imageOutDir) throws IOException {
+        super(config, imageOutDir.resolve(APP_NAME.fetchFrom(config) + "/runtime"));
+
+        Objects.requireNonNull(imageOutDir);
+
+        //@SuppressWarnings("unchecked")
+        //String img = (String) config.get("jimage.name"); // FIXME constant
+
+        this.root = imageOutDir.resolve(APP_NAME.fetchFrom(config));
+        this.appDir = root.resolve("app");
+        this.runtimeRoot = root.resolve("runtime");
+        this.mdir = runtimeRoot.resolve("lib");
+        this.params = new HashMap<String, Object>();
+        config.entrySet().stream().forEach(e -> params.put(e.getKey().toString(), e.getValue()));
+        Files.createDirectories(appDir);
+    }
+
+    private Path destFile(String dir, String filename) {
+        return runtimeRoot.resolve(dir).resolve(filename);
+    }
+
+    private void writeEntry(InputStream in, Path dstFile) throws IOException {
+        Files.createDirectories(dstFile.getParent());
+        Files.copy(in, dstFile);
+    }
+
+    private void writeSymEntry(Path dstFile, Path target) throws IOException {
+        Files.createDirectories(dstFile.getParent());
+        Files.createLink(dstFile, target);
+    }
+
+    /**
+     * chmod ugo+x file
+     */
+    private void setExecutable(Path file) {
+        try {
+            Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);
+            perms.add(PosixFilePermission.OWNER_EXECUTE);
+            perms.add(PosixFilePermission.GROUP_EXECUTE);
+            perms.add(PosixFilePermission.OTHERS_EXECUTE);
+            Files.setPosixFilePermissions(file, perms);
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    private static void createUtf8File(File file, String content) throws IOException {
+        try (OutputStream fout = new FileOutputStream(file);
+             Writer output = new OutputStreamWriter(fout, "UTF-8")) {
+            output.write(content);
+        }
+    }
+
+
+    //it is static for the sake of sharing with "installer" bundlers
+    // that may skip calls to validate/bundle in this class!
+    public static File getRootDir(File outDir, Map<String, ? super Object> p) {
+        return new File(outDir, APP_FS_NAME.fetchFrom(p));
+    }
+
+    public static String getLauncherName(Map<String, ? super Object> p) {
+        return APP_FS_NAME.fetchFrom(p);
+    }
+
+    public static String getLauncherCfgName(Map<String, ? super Object> p) {
+        return "app/" + APP_FS_NAME.fetchFrom(p) + ".cfg";
+    }
+
+    @Override
+    protected InputStream getResourceAsStream(String name) {
+        return LinuxResources.class.getResourceAsStream(name);
+    }
+
+    @Override
+    protected void prepareApplicationFiles(Pool files, Set<String> modules) throws IOException {
+        Map<String, ? super Object> originalParams = new HashMap<>(params);
+        try {
+
+            // create the primary launcher
+            createLauncherForEntryPoint(params, root);
+
+            // Copy library to the launcher folder
+            writeEntry(LinuxResources.class.getResourceAsStream(LIBRARY_NAME), root.resolve(LIBRARY_NAME));
+
+            // create the secondary launchers, if any
+            List<Map<String, ? super Object>> entryPoints = StandardBundlerParam.SECONDARY_LAUNCHERS.fetchFrom(params);
+            for (Map<String, ? super Object> entryPoint : entryPoints) {
+                Map<String, ? super Object> tmp = new HashMap<>(originalParams);
+                tmp.putAll(entryPoint);
+                createLauncherForEntryPoint(tmp, root);
+            }
+
+            // Copy class path entries to Java folder
+            copyApplication();
+
+            // Copy icon to Resources folder
+//FIXME            copyIcon(resourcesDirectory);
+
+        } catch (IOException ex) {
+            Log.info("Exception: " + ex);
+            Log.debug(ex);
+        }
+    }
+
+    private void createLauncherForEntryPoint(Map<String, ? super Object> p, Path rootDir) throws IOException {
+        // Copy executable to Linux folder
+        Path executableFile = root.resolve(getLauncherName(p));
+
+        writeEntry(LinuxResources.class.getResourceAsStream(EXECUTABLE_NAME), executableFile);
+
+        executableFile.toFile().setExecutable(true, false);
+        executableFile.toFile().setWritable(true, true);
+
+        writeCfgFile(p, root.resolve(getLauncherCfgName(p)).toFile(), "$APPDIR/runtime");
+    }
+
+    private void copyApplication() throws IOException {
+        List<RelativeFileSet> appResourcesList = APP_RESOURCES_LIST.fetchFrom(params);
+        if (appResourcesList == null) {
+            throw new RuntimeException("Null app resources?");
+        }
+        for (RelativeFileSet appResources : appResourcesList) {
+            if (appResources == null) {
+                throw new RuntimeException("Null app resources?");
+            }
+            File srcdir = appResources.getBaseDirectory();
+            for (String fname : appResources.getIncludedFiles()) {
+                writeEntry(
+                        new FileInputStream(new File(srcdir, fname)),
+                        new File(appDir.toFile(), fname).toPath()
+                );
+            }
+        }
+    }
+
+    @Override
+    protected String getCacheLocation(Map<String, ? super Object> params) {
+        return "$CACHEDIR/";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/java/jdk/packager/builders/mac/MacAppImageBuilder.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,873 @@
+/*
+ * Copyright (c) 2015, 2016, 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 jdk.packager.builders.mac;
+
+import com.oracle.tools.packager.BundlerParamInfo;
+import com.oracle.tools.packager.IOUtils;
+import com.oracle.tools.packager.Log;
+import com.oracle.tools.packager.RelativeFileSet;
+import com.oracle.tools.packager.StandardBundlerParam;
+import com.oracle.tools.packager.mac.MacResources;
+import jdk.packager.builders.AbstractAppImageBuilder;
+import jdk.tools.jlink.plugin.Pool;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
+import java.io.Writer;
+import java.math.BigInteger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermission;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+
+import static com.oracle.tools.packager.StandardBundlerParam.*;
+import static com.oracle.tools.packager.mac.MacBaseInstallerBundler.*;
+import static com.oracle.tools.packager.mac.MacAppBundler.*;
+/**
+ *
+ */
+public class MacAppImageBuilder extends AbstractAppImageBuilder {
+
+    private static final ResourceBundle I18N =
+            ResourceBundle.getBundle(MacAppImageBuilder.class.getName());
+
+    private static final String EXECUTABLE_NAME = "JavaAppLauncher";
+    private static final 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_LITE = "Info-lite.plist.template";
+    private static final String TEMPLATE_RUNTIME_INFO_PLIST = "Runtime-Info.plist.template";
+
+    private final Path root;
+    private final Path contentsDir;
+    private final Path javaDir;
+    private final Path resourcesDir;
+    private final Path macOSDir;
+    private final Path runtimeDir;
+    private final Path runtimeRoot;
+    private final Path mdir;
+
+    private final Map<String, ? super Object> params;
+
+    private static Map<String, String> getMacCategories() {
+        Map<String, String> map = new HashMap<>();
+        map.put("Business", "public.app-category.business");
+        map.put("Developer Tools", "public.app-category.developer-tools");
+        map.put("Education", "public.app-category.education");
+        map.put("Entertainment", "public.app-category.entertainment");
+        map.put("Finance", "public.app-category.finance");
+        map.put("Games", "public.app-category.games");
+        map.put("Graphics & Design", "public.app-category.graphics-design");
+        map.put("Healthcare & Fitness", "public.app-category.healthcare-fitness");
+        map.put("Lifestyle", "public.app-category.lifestyle");
+        map.put("Medical", "public.app-category.medical");
+        map.put("Music", "public.app-category.music");
+        map.put("News", "public.app-category.news");
+        map.put("Photography", "public.app-category.photography");
+        map.put("Productivity", "public.app-category.productivity");
+        map.put("Reference", "public.app-category.reference");
+        map.put("Social Networking", "public.app-category.social-networking");
+        map.put("Sports", "public.app-category.sports");
+        map.put("Travel", "public.app-category.travel");
+        map.put("Utilities", "public.app-category.utilities");
+        map.put("Video", "public.app-category.video");
+        map.put("Weather", "public.app-category.weather");
+
+        map.put("Action Games", "public.app-category.action-games");
+        map.put("Adventure Games", "public.app-category.adventure-games");
+        map.put("Arcade Games", "public.app-category.arcade-games");
+        map.put("Board Games", "public.app-category.board-games");
+        map.put("Card Games", "public.app-category.card-games");
+        map.put("Casino Games", "public.app-category.casino-games");
+        map.put("Dice Games", "public.app-category.dice-games");
+        map.put("Educational Games", "public.app-category.educational-games");
+        map.put("Family Games", "public.app-category.family-games");
+        map.put("Kids Games", "public.app-category.kids-games");
+        map.put("Music Games", "public.app-category.music-games");
+        map.put("Puzzle Games", "public.app-category.puzzle-games");
+        map.put("Racing Games", "public.app-category.racing-games");
+        map.put("Role Playing Games", "public.app-category.role-playing-games");
+        map.put("Simulation Games", "public.app-category.simulation-games");
+        map.put("Sports Games", "public.app-category.sports-games");
+        map.put("Strategy Games", "public.app-category.strategy-games");
+        map.put("Trivia Games", "public.app-category.trivia-games");
+        map.put("Word Games", "public.app-category.word-games");
+
+        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 BundlerParamInfo<String> MAC_CATEGORY =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.category-name"),
+                    I18N.getString("param.category-name.description"),
+                    "mac.category",
+                    String.class,
+                    params -> "public.app-category.developer-tools", // this category is almost certianly wrong, encouraging the user to set a value
+                    (s, p) -> s
+            );
+
+    public static final BundlerParamInfo<String> MAC_CF_BUNDLE_NAME =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.cfbundle-name.name"),
+                    I18N.getString("param.cfbundle-name.description"),
+                    "mac.CFBundleName",
+                    String.class,
+                    params -> null,
+                    (s, p) -> s);
+
+    public static final BundlerParamInfo<String> MAC_CF_BUNDLE_IDENTIFIER =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.cfbundle-identifier.name"),
+                    I18N.getString("param.cfbundle-identifier.description"),
+                    "mac.CFBundleIdentifier",
+                    String.class,
+                    params -> "com.example.bad", //FIXME
+                    (s, p) -> s);
+
+    public static final BundlerParamInfo<String> MAC_CF_BUNDLE_VERSION =
+            new StandardBundlerParam<>(
+                    I18N.getString("param.cfbundle-version.name"),
+                    I18N.getString("param.cfbundle-version.description"),
+                    "mac.CFBundleVersion",
+                    String.class,
+                    p -> {
+                        String s = VERSION.fetchFrom(p);
+                        if (validCFBundleVersion(s)) {
+                            return s;
+                        } else {
+                            return "100";
+                        }
+                    },
+                    (s, p) -> s);
+
+    public static final BundlerParamInfo<File> CONFIG_ROOT = new StandardBundlerParam<>(
+            I18N.getString("param.config-root.name"),
+            I18N.getString("param.config-root.description"),
+            "configRoot",
+            File.class,
+            params -> {
+                File configRoot = new File(BUILD_ROOT.fetchFrom(params), "macosx");
+                configRoot.mkdirs();
+                return configRoot;
+            },
+            (s, p) -> new File(s));
+
+    public static final BundlerParamInfo<String> DEFAULT_ICNS_ICON = new StandardBundlerParam<>(
+            I18N.getString("param.default-icon-icns"),
+            I18N.getString("param.default-icon-icns.description"),
+            ".mac.default.icns",
+            String.class,
+            params -> TEMPLATE_BUNDLE_ICON,
+            (s, p) -> s);
+
+//    public static final BundlerParamInfo<String> DEVELOPER_ID_APP_SIGNING_KEY = new StandardBundlerParam<>(
+//            I18N.getString("param.signing-key-developer-id-app.name"),
+//            I18N.getString("param.signing-key-developer-id-app.description"),
+//            "mac.signing-key-developer-id-app",
+//            String.class,
+//            params -> MacBaseInstallerBundler.findKey("Developer ID Application: " + SIGNING_KEY_USER.fetchFrom(params), SIGNING_KEYCHAIN.fetchFrom(params), VERBOSE.fetchFrom(params)),
+//            (s, p) -> s);
+
+    //    public static final BundlerParamInfo<String> BUNDLE_ID_SIGNING_PREFIX = new StandardBundlerParam<>(
+//            I18N.getString("param.bundle-id-signing-prefix.name"),
+//            I18N.getString("param.bundle-id-signing-prefix.description"),
+//            "mac.bundle-id-signing-prefix",
+//            String.class,
+//            params -> IDENTIFIER.fetchFrom(params) + ".",
+//            (s, p) -> s);
+//
+    public static final BundlerParamInfo<File> ICON_ICNS = new StandardBundlerParam<>(
+            I18N.getString("param.icon-icns.name"),
+            I18N.getString("param.icon-icns.description"),
+            "icon.icns",
+            File.class,
+            params -> {
+                File f = ICON.fetchFrom(params);
+                if (f != null && !f.getName().toLowerCase().endsWith(".icns")) {
+                    Log.info(MessageFormat.format(I18N.getString("message.icon-not-icns"), f));
+                    return null;
+                }
+                return f;
+            },
+            (s, p) -> new File(s));
+
+    private static String extractAppName() {
+        return "";
+    }
+
+    public MacAppImageBuilder(Map<String, Object> config, Path imageOutDir) throws IOException {
+        super(config, imageOutDir.resolve(APP_NAME.fetchFrom(config) + ".app/Contents/PlugIns/Java.runtime/Contents/Home"));
+
+        Objects.requireNonNull(imageOutDir);
+
+        //@SuppressWarnings("unchecked")
+        //String img = (String) config.get("jimage.name"); // FIXME constant
+
+        this.params = config;
+
+        this.root = imageOutDir.resolve(APP_NAME.fetchFrom(params) + ".app");
+
+        this.contentsDir = root.resolve("Contents");
+        this.javaDir = contentsDir.resolve("Java");
+        this.resourcesDir = contentsDir.resolve("Resources");
+        this.macOSDir = contentsDir.resolve("MacOS");
+        this.runtimeDir = contentsDir.resolve("PlugIns/Java.runtime");
+        this.runtimeRoot = runtimeDir.resolve("Contents/Home");
+        this.mdir = runtimeRoot.resolve("lib");
+        Files.createDirectories(javaDir);
+        Files.createDirectories(resourcesDir);
+        Files.createDirectories(macOSDir);
+    }
+
+    private void writeEntry(InputStream in, Path dstFile) throws IOException {
+        Files.createDirectories(dstFile.getParent());
+        Files.copy(in, dstFile);
+    }
+
+    /**
+     * chmod ugo+x file
+     */
+    private void setExecutable(Path file) {
+        try {
+            Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);
+            perms.add(PosixFilePermission.OWNER_EXECUTE);
+            perms.add(PosixFilePermission.GROUP_EXECUTE);
+            perms.add(PosixFilePermission.OTHERS_EXECUTE);
+            Files.setPosixFilePermissions(file, perms);
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    private static void createUtf8File(File file, String content) throws IOException {
+        try (OutputStream fout = new FileOutputStream(file);
+             Writer output = new OutputStreamWriter(fout, "UTF-8")) {
+            output.write(content);
+        }
+    }
+
+    @Override
+    protected String getCacheLocation(Map<String, ? super Object> params) {
+        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
+        // unreleased) of the bundle. The build version number should be a
+        // string comprised of three non-negative, period-separated integers
+        // with the first integer being greater than zero. The string should
+        // only contain numeric (0-9) and period (.) characters. Leading zeros
+        // are truncated from each integer and will be ignored (that is,
+        // 1.02.3 is equivalent to 1.2.3). This key is not localizable.
+
+        if (v == null) {
+            return false;
+        }
+
+        String p[] = v.split("\\.");
+        if (p.length > 3 || p.length < 1) {
+            Log.verbose(I18N.getString("message.version-string-too-many-components"));
+            return false;
+        }
+
+        try {
+            BigInteger n = new BigInteger(p[0]);
+            if (BigInteger.ONE.compareTo(n) > 0) {
+                Log.verbose(I18N.getString("message.version-string-first-number-not-zero"));
+                return false;
+            }
+            if (p.length > 1) {
+                n = new BigInteger(p[1]);
+                if (BigInteger.ZERO.compareTo(n) > 0) {
+                    Log.verbose(I18N.getString("message.version-string-no-negative-numbers"));
+                    return false;
+                }
+            }
+            if (p.length > 2) {
+                n = new BigInteger(p[2]);
+                if (BigInteger.ZERO.compareTo(n) > 0) {
+                    Log.verbose(I18N.getString("message.version-string-no-negative-numbers"));
+                    return false;
+                }
+            }
+        } catch (NumberFormatException ne) {
+            Log.verbose(I18N.getString("message.version-string-numbers-only"));
+            Log.verbose(ne);
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    protected InputStream getResourceAsStream(String name) {
+        return MacResources.class.getResourceAsStream(name);
+    }
+
+
+    @Override
+    protected void prepareApplicationFiles(Pool files, Set<String> modules) throws IOException {
+        File f;
+
+        // Generate PkgInfo
+        File pkgInfoFile = new File(contentsDir.toFile(), "PkgInfo");
+        pkgInfoFile.createNewFile();
+        writePkgInfo(pkgInfoFile);
+
+
+        // Copy executable to MacOS folder
+        Path executable = macOSDir.resolve(getLauncherName(params));
+        writeEntry(MacResources.class.getResourceAsStream(EXECUTABLE_NAME), executable);
+        executable.toFile().setExecutable(true, false);
+
+        // Copy library to the MacOS folder
+        writeEntry(
+                MacResources.class.getResourceAsStream(LIBRARY_NAME),
+                macOSDir.resolve(LIBRARY_NAME)
+        );
+
+        // generate launcher config
+
+        writeCfgFile(params, new File(root.toFile(), getLauncherCfgName(params)), "$APPDIR/PlugIns/Java.runtime");
+
+        // Copy class path entries to Java folder
+        copyClassPathEntries(javaDir);
+
+        //TODO: Need to support adding native libraries.
+        // Copy library path entries to MacOS folder
+        //copyLibraryPathEntries(macOSDirectory);
+
+        /*********** Take care of "config" files *******/
+        // Copy icon to Resources folder
+        File icon = ICON_ICNS.fetchFrom(params);
+        InputStream in = locateResource("package/macosx/" + APP_NAME.fetchFrom(params) + ".icns",
+                "icon",
+                DEFAULT_ICNS_ICON.fetchFrom(params),
+                icon,
+                VERBOSE.fetchFrom(params),
+                DROP_IN_RESOURCES_ROOT.fetchFrom(params));
+        Files.copy(in, resourcesDir.resolve(APP_NAME.fetchFrom(params) + ".icns"));
+
+        // copy file association icons
+        for (Map<String, ? super Object> fa : FILE_ASSOCIATIONS.fetchFrom(params)) {
+            f = FA_ICON.fetchFrom(fa);
+            if (f != null && f.exists()) {
+                try (InputStream in2 = new FileInputStream(f)) {
+                    Files.copy(in2, resourcesDir.resolve(f.getName()));
+                }
+
+            }
+        }
+
+        // Generate Info.plist
+        writeInfoPlist(contentsDir.resolve("Info.plist").toFile());
+
+        // generate java runtime info.plist
+        writeRuntimeInfoPlist(runtimeDir.resolve("Contents/Info.plist").toFile());
+
+        // copy library
+        Path runtimeMacOSDir = Files.createDirectories(runtimeDir.resolve("Contents/MacOS"));
+        Files.copy(runtimeRoot.resolve("lib/jli/libjli.dylib"), runtimeMacOSDir.resolve("libjli.dylib"));
+
+        // maybe sign
+        if (Optional.ofNullable(SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.TRUE)) {
+            String signingIdentity = DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params);
+            if (signingIdentity != null) {
+                signAppBundle(params, root, signingIdentity, BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params), null, null);
+            }
+        }
+    }
+
+
+    private String getLauncherName(Map<String, ? super Object> params) {
+        if (APP_NAME.fetchFrom(params) != null) {
+            return APP_NAME.fetchFrom(params);
+        } else {
+            return MAIN_CLASS.fetchFrom(params);
+        }
+    }
+
+    public static String getLauncherCfgName(Map<String, ? super Object> p) {
+        return "Contents/Java/" + APP_NAME.fetchFrom(p) + ".cfg";
+    }
+
+    private void copyClassPathEntries(Path javaDirectory) throws IOException {
+        List<RelativeFileSet> resourcesList = APP_RESOURCES_LIST.fetchFrom(params);
+        if (resourcesList == null) {
+            throw new RuntimeException(I18N.getString("message.null-classpath"));
+        }
+
+        for (RelativeFileSet classPath : resourcesList) {
+            File srcdir = classPath.getBaseDirectory();
+            for (String fname : classPath.getIncludedFiles()) {
+                // use new File since fname can have file separators
+                Files.copy(new File(srcdir, fname).toPath(), new File(javaDirectory.toFile(), fname).toPath());
+            }
+        }
+    }
+
+    private String getBundleName(Map<String, ? super Object> params) {
+        //TODO: Check to see what rules/limits are in place for CFBundleName
+        if (MAC_CF_BUNDLE_NAME.fetchFrom(params) != null) {
+            String bn = MAC_CF_BUNDLE_NAME.fetchFrom(params);
+            if (bn.length() > 16) {
+                Log.info(MessageFormat.format(I18N.getString("message.bundle-name-too-long-warning"), MAC_CF_BUNDLE_NAME.getID(), bn));
+            }
+            return MAC_CF_BUNDLE_NAME.fetchFrom(params);
+        } else if (APP_NAME.fetchFrom(params) != null) {
+            return APP_NAME.fetchFrom(params);
+        } else {
+            String nm = MAIN_CLASS.fetchFrom(params);
+            if (nm.length() > 16) {
+                nm = nm.substring(0, 16);
+            }
+            return nm;
+        }
+    }
+
+    private void writeRuntimeInfoPlist(File file) throws IOException {
+        //FIXME //TODO these values are bogus.
+        Map<String, String> data = new HashMap<>();
+        data.put("CF_BUNDLE_INFO", "bundle info");
+        data.put("CF_BUNDLE_IDENTIFIER", "com.oracle.java.8u60.jdk");
+        data.put("CF_BUNDLE_NAME", "Java SE 9");
+        data.put("CF_BUNDLE_VERSION", "1.8.0_60");
+
+        Writer w = new BufferedWriter(new FileWriter(file));
+        w.write(preprocessTextResource(
+                "package/macosx/Runtime-Info.plist",
+                I18N.getString("resource.runtime-info-plist"),
+                TEMPLATE_RUNTIME_INFO_PLIST,
+                data,
+                VERBOSE.fetchFrom(params),
+                DROP_IN_RESOURCES_ROOT.fetchFrom(params)));
+        w.close();
+    }
+
+    private void writeInfoPlist(File file) throws IOException {
+        Log.verbose(MessageFormat.format(I18N.getString("message.preparing-info-plist"), file.getAbsolutePath()));
+
+        //prepare config for exe
+        //Note: do not need CFBundleDisplayName if we do not support localization
+        Map<String, String> data = new HashMap<>();
+        data.put("DEPLOY_ICON_FILE", APP_NAME.fetchFrom(params) + ".icns");
+        data.put("DEPLOY_BUNDLE_IDENTIFIER",
+                MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params));
+        data.put("DEPLOY_BUNDLE_NAME",
+                getBundleName(params));
+        data.put("DEPLOY_BUNDLE_COPYRIGHT",
+                COPYRIGHT.fetchFrom(params) != null ? COPYRIGHT.fetchFrom(params) : "Unknown");
+        data.put("DEPLOY_LAUNCHER_NAME", getLauncherName(params));
+        data.put("DEPLOY_JAVA_RUNTIME_NAME", "$APPDIR/PlugIns/Java.runtime");
+        data.put("DEPLOY_BUNDLE_SHORT_VERSION",
+                VERSION.fetchFrom(params) != null ? VERSION.fetchFrom(params) : "1.0.0");
+        data.put("DEPLOY_BUNDLE_CFBUNDLE_VERSION",
+                MAC_CF_BUNDLE_VERSION.fetchFrom(params) != null ? MAC_CF_BUNDLE_VERSION.fetchFrom(params) : "100");
+        data.put("DEPLOY_BUNDLE_CATEGORY",
+                //TODO parameters should provide set of values for IDEs
+                MAC_CATEGORY.fetchFrom(params));
+
+        data.put("DEPLOY_MAIN_JAR_NAME", MAIN_JAR.fetchFrom(params).getIncludedFiles().iterator().next());
+
+        data.put("DEPLOY_PREFERENCES_ID", PREFERENCES_ID.fetchFrom(params).toLowerCase());
+
+        StringBuilder sb = new StringBuilder();
+        List<String> jvmOptions = JVM_OPTIONS.fetchFrom(params);
+
+        String newline = ""; //So we don't add unneccessary extra line after last append
+        for (String o : jvmOptions) {
+            sb.append(newline).append("    <string>").append(o).append("</string>");
+            newline = "\n";
+        }
+
+        Map<String, String> jvmProps = JVM_PROPERTIES.fetchFrom(params);
+        for (Map.Entry<String, String> entry : jvmProps.entrySet()) {
+            sb.append(newline)
+                    .append("    <string>-D")
+                    .append(entry.getKey())
+                    .append("=")
+                    .append(entry.getValue())
+                    .append("</string>");
+            newline = "\n";
+        }
+
+        String preloader = PRELOADER_CLASS.fetchFrom(params);
+        if (preloader != null) {
+            sb.append(newline)
+                    .append("    <string>-Djavafx.preloader=")
+                    .append(preloader)
+                    .append("</string>");
+        }
+
+        data.put("DEPLOY_JVM_OPTIONS", sb.toString());
+
+        sb = new StringBuilder();
+        List<String> args = ARGUMENTS.fetchFrom(params);
+        newline = ""; //So we don't add unneccessary extra line after last append
+        for (String o : args) {
+            sb.append(newline).append("    <string>").append(o).append("</string>");
+            newline = "\n";
+        }
+        data.put("DEPLOY_ARGUMENTS", sb.toString());
+
+        newline = "";
+        sb = new StringBuilder();
+        Map<String, String> overridableJVMOptions = USER_JVM_OPTIONS.fetchFrom(params);
+        for (Map.Entry<String, String> arg : overridableJVMOptions.entrySet()) {
+            sb.append(newline)
+                    .append("      <key>").append(arg.getKey()).append("</key>\n")
+                    .append("      <string>").append(arg.getValue()).append("</string>");
+            newline = "\n";
+        }
+        data.put("DEPLOY_JVM_USER_OPTIONS", sb.toString());
+
+
+        data.put("DEPLOY_LAUNCHER_CLASS", MAIN_CLASS.fetchFrom(params));
+
+        StringBuilder macroedPath = new StringBuilder();
+        for (String s : CLASSPATH.fetchFrom(params).split("[ ;:]+")) {
+            macroedPath.append(s);
+            macroedPath.append(":");
+        }
+        macroedPath.deleteCharAt(macroedPath.length() - 1);
+
+        data.put("DEPLOY_APP_CLASSPATH", macroedPath.toString());
+
+        //TODO: Add remainder of the classpath
+
+        StringBuilder bundleDocumentTypes = new StringBuilder();
+        StringBuilder exportedTypes = new StringBuilder();
+        for (Map<String, ? super Object> fileAssociation : FILE_ASSOCIATIONS.fetchFrom(params)) {
+
+            List<String> extensions = FA_EXTENSIONS.fetchFrom(fileAssociation);
+
+            if (extensions == null) {
+                Log.info(I18N.getString("message.creating-association-with-null-extension"));
+            }
+
+            List<String> mimeTypes = FA_CONTENT_TYPE.fetchFrom(fileAssociation);
+            String itemContentType = MAC_CF_BUNDLE_IDENTIFIER.fetchFrom(params) + "." + ((extensions == null || extensions.isEmpty())
+                    ? "mime"
+                    : extensions.get(0));
+            String description = FA_DESCRIPTION.fetchFrom(fileAssociation);
+            File icon = FA_ICON.fetchFrom(fileAssociation); //TODO FA_ICON_ICNS
+
+            bundleDocumentTypes.append("    <dict>\n")
+                    .append("      <key>LSItemContentTypes</key>\n")
+                    .append("      <array>\n")
+                    .append("        <string>")
+                    .append(itemContentType)
+                    .append("</string>\n")
+                    .append("      </array>\n")
+                    .append("\n")
+                    .append("      <key>CFBundleTypeName</key>\n")
+                    .append("      <string>")
+                    .append(description)
+                    .append("</string>\n")
+                    .append("\n")
+                    .append("      <key>LSHandlerRank</key>\n")
+                    .append("      <string>Owner</string>\n") //TODO make a bundler arg
+                    .append("\n")
+                    .append("      <key>CFBundleTypeRole</key>\n")
+                    .append("      <string>Editor</string>\n") // TODO make a bundler arg
+                    .append("\n")
+                    .append("      <key>LSIsAppleDefaultForType</key>\n")
+                    .append("      <true/>\n") // TODO make a bundler arg
+                    .append("\n");
+
+            if (icon != null && icon.exists()) {
+                //?
+                bundleDocumentTypes.append("      <key>CFBundleTypeIconFile</key>\n")
+                        .append("      <string>")
+                        .append(icon.getName())
+                        .append("</string>\n");
+            }
+            bundleDocumentTypes.append("    </dict>\n");
+
+            exportedTypes.append("    <dict>\n")
+                    .append("      <key>UTTypeIdentifier</key>\n")
+                    .append("      <string>")
+                    .append(itemContentType)
+                    .append("</string>\n")
+                    .append("\n")
+                    .append("      <key>UTTypeDescription</key>\n")
+                    .append("      <string>")
+                    .append(description)
+                    .append("</string>\n")
+                    .append("      <key>UTTypeConformsTo</key>\n")
+                    .append("      <array>\n")
+                    .append("          <string>public.data</string>\n") //TODO expose this?
+                    .append("      </array>\n")
+                    .append("\n");
+
+            if (icon != null && icon.exists()) {
+                exportedTypes.append("      <key>UTTypeIconFile</key>\n")
+                        .append("      <string>")
+                        .append(icon.getName())
+                        .append("</string>\n")
+                        .append("\n");
+            }
+
+            exportedTypes.append("\n")
+                    .append("      <key>UTTypeTagSpecification</key>\n")
+                    .append("      <dict>\n")
+                            //TODO expose via param? .append("        <key>com.apple.ostype</key>\n");
+                            //TODO expose via param? .append("        <string>ABCD</string>\n")
+                    .append("\n");
+
+            if (extensions != null && !extensions.isEmpty()) {
+                exportedTypes.append("        <key>public.filename-extension</key>\n")
+                        .append("        <array>\n");
+
+                for (String ext : extensions) {
+                    exportedTypes.append("          <string>")
+                            .append(ext)
+                            .append("</string>\n");
+                }
+                exportedTypes.append("        </array>\n");
+            }
+            if (mimeTypes != null && !mimeTypes.isEmpty()) {
+                exportedTypes.append("        <key>public.mime-type</key>\n")
+                        .append("        <array>\n");
+
+                for (String mime : mimeTypes) {
+                    exportedTypes.append("          <string>")
+                            .append(mime)
+                            .append("</string>\n");
+                }
+                exportedTypes.append("        </array>\n");
+            }
+            exportedTypes.append("      </dict>\n")
+                    .append("    </dict>\n");
+        }
+        String associationData;
+        if (bundleDocumentTypes.length() > 0) {
+            associationData = "\n  <key>CFBundleDocumentTypes</key>\n  <array>\n"
+                    + bundleDocumentTypes.toString()
+                    + "  </array>\n\n  <key>UTExportedTypeDeclarations</key>\n  <array>\n"
+                    + exportedTypes.toString()
+                    + "  </array>\n";
+        } else {
+            associationData = "";
+        }
+        data.put("DEPLOY_FILE_ASSOCIATIONS", associationData);
+
+
+        Writer w = new BufferedWriter(new FileWriter(file));
+        w.write(preprocessTextResource(
+                //MAC_BUNDLER_PREFIX + getConfig_InfoPlist(params).getName(),
+                "package/macosx/Info.plist",
+                I18N.getString("resource.app-info-plist"),
+                TEMPLATE_INFO_PLIST_LITE,
+                data, VERBOSE.fetchFrom(params),
+                DROP_IN_RESOURCES_ROOT.fetchFrom(params)));
+        w.close();
+
+    }
+
+    private void writePkgInfo(File file) throws IOException {
+        //hardcoded as it does not seem we need to change it ever
+        String signature = "????";
+
+        try (Writer out = new BufferedWriter(new FileWriter(file))) {
+            out.write(OS_TYPE_CODE + signature);
+            out.flush();
+        }
+    }
+
+    public static void signAppBundle(Map<String, ? super Object> params, Path appLocation, String signingIdentity, String identifierPrefix, String entitlementsFile, String inheritedEntitlements) throws IOException {
+        AtomicReference<IOException> toThrow = new AtomicReference<>();
+        String appExecutable = "/Contents/MacOS/" + APP_NAME.fetchFrom(params);
+        String keyChain = SIGNING_KEYCHAIN.fetchFrom(params);
+
+        // sign all dylibs and jars
+        Files.walk(appLocation)
+                // while we are searching let's fix permissions
+                .peek(path -> {
+                    try {
+                        Set<PosixFilePermission> pfp = Files.getPosixFilePermissions(path);
+                        if (!pfp.contains(PosixFilePermission.OWNER_WRITE)) {
+                            pfp = EnumSet.copyOf(pfp);
+                            pfp.add(PosixFilePermission.OWNER_WRITE);
+                            Files.setPosixFilePermissions(path, pfp);
+                        }
+                    } catch (IOException e) {
+                        Log.debug(e);
+                    }
+                })
+                .filter(p -> Files.isRegularFile(p) &&
+                                !(p.toString().contains("/Contents/MacOS/libjli.dylib")
+                                        || p.toString().contains("/Contents/MacOS/JavaAppletPlugin")
+                                        || p.toString().endsWith(appExecutable))
+                ).forEach(p -> {
+            //noinspection ThrowableResultOfMethodCallIgnored
+            if (toThrow.get() != null) return;
+
+            List<String> args = new ArrayList<>();
+            args.addAll(Arrays.asList("codesign",
+                    "-s", signingIdentity, // sign with this key
+                    "--prefix", identifierPrefix, // use the identifier as a prefix
+                    "-vvvv"));
+            if (entitlementsFile != null &&
+                    (p.toString().endsWith(".jar")
+                            || p.toString().endsWith(".dylib"))) {
+                args.add("--entitlements");
+                args.add(entitlementsFile); // entitlements
+            } else if (inheritedEntitlements != null && Files.isExecutable(p)) {
+                args.add("--entitlements");
+                args.add(inheritedEntitlements); // inherited entitlements for executable processes
+            }
+            if (keyChain != null && !keyChain.isEmpty()) {
+                args.add("--keychain");
+                args.add(keyChain);
+            }
+            args.add(p.toString());
+
+            try {
+                Set<PosixFilePermission> oldPermissions = Files.getPosixFilePermissions(p);
+                File f = p.toFile();
+                f.setWritable(true, true);
+
+                ProcessBuilder pb = new ProcessBuilder(args);
+                IOUtils.exec(pb, VERBOSE.fetchFrom(params));
+
+                Files.setPosixFilePermissions(p, oldPermissions);
+            } catch (IOException ioe) {
+                toThrow.set(ioe);
+            }
+        });
+
+        IOException ioe = toThrow.get();
+        if (ioe != null) {
+            throw ioe;
+        }
+
+        // sign all plugins and frameworks
+        Consumer<? super Path> signIdentifiedByPList = path -> {
+            //noinspection ThrowableResultOfMethodCallIgnored
+            if (toThrow.get() != null) return;
+
+            try {
+                List<String> args = new ArrayList<>();
+                args.addAll(Arrays.asList("codesign",
+                        "-s", signingIdentity, // sign with this key
+                        "--prefix", identifierPrefix, // use the identifier as a prefix
+                        "-vvvv"));
+                if (keyChain != null && !keyChain.isEmpty()) {
+                    args.add("--keychain");
+                    args.add(keyChain);
+                }
+                args.add(path.toString());
+                ProcessBuilder pb = new ProcessBuilder(args);
+                IOUtils.exec(pb, VERBOSE.fetchFrom(params));
+
+                args = new ArrayList<>();
+                args.addAll(Arrays.asList("codesign",
+                        "-s", signingIdentity, // sign with this key
+                        "--prefix", identifierPrefix, // use the identifier as a prefix
+                        "-vvvv"));
+                if (keyChain != null && !keyChain.isEmpty()) {
+                    args.add("--keychain");
+                    args.add(keyChain);
+                }
+                args.add(path.toString() + "/Contents/_CodeSignature/CodeResources");
+                pb = new ProcessBuilder(args);
+                IOUtils.exec(pb, VERBOSE.fetchFrom(params));
+            } catch (IOException e) {
+                toThrow.set(e);
+            }
+        };
+
+        Path pluginsPath = appLocation.resolve("Contents/PlugIns");
+        if (Files.isDirectory(pluginsPath)) {
+            Files.list(pluginsPath)
+                    .forEach(signIdentifiedByPList);
+
+            ioe = toThrow.get();
+            if (ioe != null) {
+                throw ioe;
+            }
+        }
+        Path frameworkPath = appLocation.resolve("Contents/Frameworks");
+        if (Files.isDirectory(frameworkPath)) {
+            Files.list(frameworkPath)
+                    .forEach(signIdentifiedByPList);
+
+            ioe = toThrow.get();
+            if (ioe != null) {
+                throw ioe;
+            }
+        }
+
+        // sign the app itself
+        List<String> args = new ArrayList<>();
+        args.addAll(Arrays.asList("codesign",
+                "-s", signingIdentity, // sign with this key
+                "-vvvv")); // super verbose output
+        if (entitlementsFile != null) {
+            args.add("--entitlements");
+            args.add(entitlementsFile); // entitlements
+        }
+        if (keyChain != null && !keyChain.isEmpty()) {
+            args.add("--keychain");
+            args.add(keyChain);
+        }
+        args.add(appLocation.toString());
+
+        ProcessBuilder pb = new ProcessBuilder(args.toArray(new String[args.size()]));
+        IOUtils.exec(pb, VERBOSE.fetchFrom(params));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/fxpackager/src/main/java/jdk/packager/builders/windows/WindowsAppImageBuilder.java	Thu Mar 17 14:01:55 2016 -0700
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2015, 2016, 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 jdk.packager.builders.windows;
+
+import com.oracle.tools.packager.BundlerParamInfo;
+import com.oracle.tools.packager.Log;
+import com.oracle.tools.packager.RelativeFileSet;
+import com.oracle.tools.packager.IOUtils;
+import com.oracle.tools.packager.StandardBundlerParam;
+import com.oracle.tools.packager.windows.WinResources;
+import com.oracle.tools.packager.windows.WindowsBundlerParam;
+import jdk.packager.builders.AbstractAppImageBuilder;
+
+import jdk.tools.jlink.plugin.Pool;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UncheckedIOException;
+import java.io.Writer;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.PosixFilePermission;
+import java.text.MessageFormat;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Pattern;
+
+import static com.oracle.tools.packager.StandardBundlerParam.*;
+
+/**
+ *
+ */
+public class WindowsAppImageBuilder extends AbstractAppImageBuilder {
+
+    private static final ResourceBundle I18N =
+            ResourceBundle.getBundle(WindowsAppImageBuilder.class.getName());
+
+    protected static final String WINDOWS_BUNDLER_PREFIX =
+            BUNDLER_PREFIX + "windows" + File.separator;
+
+    private final static String EXECUTABLE_NAME = "WinLauncher.exe";
+    private final static String LIBRARY_NAME = "packager.dll";
+
+    private final static String[] VS_VERS = {"100", "110", "120"};
+    private final static String REDIST_MSVCR = "msvcrVS_VER.dll";
+    private final static String REDIST_MSVCP = "msvcpVS_VER.dll";
+
+    private final static String TEMPLATE_APP_ICON ="javalogo_white_48.ico";
+    private static final String TOOL_ICON_SWAP="IconSwap.exe";
+    private static final String TOOL_VERSION_INFO_SWAP="VersionInfoSwap.exe";
+
+    private static final String EXECUTABLE_PROPERTIES_TEMPLATE = "WinLauncher.properties";
+
+    private final Path root;
+    private final Path appDir;
+    private final Path runtimeRoot;
+    private final Path mdir;
+
+    private final Map<String, ? super Object> params;
+
+    public static final BundlerParamInfo<File> CONFIG_ROOT = new WindowsBundlerParam<>(
+            I18N.getString("param.config-root.name"),
+            I18N.getString("param.config-root.description"),
+            "configRoot",
+            File.class,
+            params -> {
+                File imagesRoot = new File(BUILD_ROOT.fetchFrom(params), "windows");
+                imagesRoot.mkdirs();
+                return imagesRoot;
+            },
+            (s, p) -> null);
+
+    public static final BundlerParamInfo<Boolean> REBRAND_EXECUTABLE = new WindowsBundlerParam<>(
+            I18N.getString("param.rebrand-executable.name"),
+            I18N.getString("param.rebrand-executable.description"),
+            "win.launcher.rebrand",
+            Boolean.class,
+            params -> Boolean.TRUE,
+            (s, p) -> Boolean.valueOf(s));
+
+    public static final BundlerParamInfo<File> ICON_ICO = new StandardBundlerParam<>(
+            I18N.getString("param.icon-ico.name"),
+            I18N.getString("param.icon-ico.description"),
+            "icon.ico",
+            File.class,
+            params -> {
+                File f = ICON.fetchFrom(params);
+                if (f != null && !f.getName().toLowerCase().endsWith(".ico")) {
+                    Log.info(MessageFormat.format(I18N.getString("message.icon-not-ico"), f));
+                    return null;
+                }
+                return f;
+            },
+            (s, p) -> new File(s));
+
+
+
+    public WindowsAppImageBuilder(Map<String, Object> config, Path imageOutDir) throws IOException {
+        super(config, imageOutDir.resolve(APP_NAME.fetchFrom(config) + "/runtime"));
+
+        Objects.requireNonNull(imageOutDir);
+
+        //@SuppressWarnings("unchecked")
+        //String img = (String) config.get("jimage.name"); // FIXME constant
+
+        this.params = config;
+
+        this.root = imageOutDir.resolve(APP_NAME.fetchFrom(params));
+        this.appDir = root.resolve("app");
+        this.runtimeRoot = root.resolve("runtime");
+        this.mdir = runtimeRoot.resolve("lib");
+        Files.createDirectories(appDir);
+    }
+
+    private Path destFile(String dir, String filename) {
+        return runtimeRoot.resolve(dir).resolve(filename);
+    }
+
+    private void writeEntry(InputStream in, Path dstFile) throws IOException {
+        Files.createDirectories(dstFile.getParent());
+        Files.copy(in, dstFile);
+    }
+
+    private void writeSymEntry(Path dstFile, Path target) throws IOException {
+        Files.createDirectories(dstFile.getParent());
+        Files.createLink(dstFile, target);
+    }
+
+    /**
+     * chmod ugo+x file
+     */
+    private void setExecutable(Path file) {
+        try {
+            Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);
+            perms.add(PosixFilePermission.OWNER_EXECUTE);
+            perms.add(PosixFilePermission.GROUP_EXECUTE);
+            perms.add(PosixFilePermission.OTHERS_EXECUTE);
+            Files.setPosixFilePermissions(file, perms);
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    private static void createUtf8File(File file, String content) throws IOException {
+        try (OutputStream fout = new FileOutputStream(file);
+             Writer output = new OutputStreamWriter(fout, "UTF-8")) {
+            output.write(content);
+        }
+    }
+
+
+
+    //it is static for the sake of sharing with "installer" bundlers
+    // that may skip calls to validate/bundle in this class!
+    public static File getRootDir(File outDir, Map<String, ? super Object> p) {
+        return new File(outDir, APP_FS_NAME.fetchFrom(p));
+    }
+
+    public static String getLauncherName(Map<String, ? super Object> p) {
+        return APP_FS_NAME.fetchFrom(p) + ".exe";
+    }
+
+    public static String getLauncherCfgName(Map<String, ? super Object> p) {
+        return "app/" + APP_FS_NAME.fetchFrom(p) +".cfg";
+    }
+
+    private File getConfig_AppIcon(Map<String, ? super Object> params) {
+        return new File(getConfigRoot(params), APP_FS_NAME.fetchFrom(params) + ".ico");
+    }
+
+    private File getConfig_ExecutableProperties(Map<String, ? super Object> params) {
+        return new File(getConfigRoot(params), APP_FS_NAME.fetchFrom(params) + ".properties");
+    }
+
+    File getConfigRoot(Map<String, ? super Object> params) {
+        return CONFIG_ROOT.fetchFrom(params);
+    }
+
+    protected void cleanupConfigFiles(Map<String, ? super Object> params) {
+        getConfig_AppIcon(params).delete();
+        getConfig_ExecutableProperties(params).delete();
+    }
+
+    @Override
+    protected InputStream getResourceAsStream(String name) {
+        return WinResources.class.getResourceAsStream(name);
+    }
+
+    @Override
+    protected void prepareApplicationFiles(Pool files, Set<String> modules) throws IOException {
+        Map<String, ? super Object> originalParams = new HashMap<>(params);
+        File rootFile = root.toFile();
+        if (!rootFile.isDirectory() && !rootFile.mkdirs()) {
+            throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), rootFile.getAbsolutePath()));
+        }
+        if (!rootFile.canWrite()) {
+            throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-write-to-output-dir"), rootFile.getAbsolutePath()));
+        }
+        try {
+//            if (!dependentTask) {
+//                Log.info(MessageFormat.format(I18N.getString("message.creating-app-bundle"), APP_NAME.fetchFrom(p), outputDirectory.getAbsolutePath()));
+//            }
+
+            // Create directory structure
+//            IOUtils.deleteRecursive(rootDirectory);
+//            rootDirectory.mkdirs();
+
+
+            // create the .exe launchers
+            createLauncherForEntryPoint(params);
+
+            // copy the jars
+            copyApplication(params);
+
+            // copy in the needed libraries
+            Files.copy(WinResources.class.getResourceAsStream(LIBRARY_NAME),
+                    root.resolve(LIBRARY_NAME));
+
+            copyMSVCDLLs();
+
+            // create the secondary launchers, if any
+            List<Map<String, ? super Object>> entryPoints = StandardBundlerParam.SECONDARY_LAUNCHERS.fetchFrom(params);
+            for (Map<String, ? super Object> entryPoint : entryPoints) {
+                Map<String, ? super Object> tmp = new HashMap<>(originalParams);
+                tmp.putAll(entryPoint);
+                createLauncherForEntryPoint(tmp);
+            }
+
+        } catch (IOException ex) {
+            Log.info("Exception: "+ex);
+            Log.debug(ex);
+        } finally {
+
+            if (VERBOSE.fetchFrom(params)) {
+                Log.info(MessageFormat.format(I18N.getString("message.config-save-location"), getConfigRoot(params).getAbsolutePath()));
+            } else {
+                cleanupConfigFiles(params);
+            }
+        }
+
+    }
+
+    private void copyMSVCDLLs() throws IOException {
+        String vsVer = null;
+
+        // first copy the ones needed for the launcher
+        for (String thisVer : VS_VERS) {
+            if (copyMSVCDLLs(thisVer)) {
+                vsVer = thisVer;
+                break;
+            }
+        }
+        if (vsVer == null) {
+            throw new RuntimeException("Not found MSVC dlls");
+        }
+
+        AtomicReference<IOException> ioe = new AtomicReference<>();
+        final String finalVsVer = vsVer;
+        Files.list(runtimeRoot.resolve("bin"))
+                .filter(p -> Pattern.matches("msvc(r|p)\\d\\d\\d.dll", p.toFile().getName().toLowerCase()))
+                .filter(p -> !p.toString().toLowerCase().endsWith(finalVsVer + ".dll"))
+                .forEach(p -> {
+                    try {
+                        Files.copy(p, root.resolve((p.toFile().getName())));
+                    } catch (IOException e) {
+                        ioe.set(e);
+                    }
+                });
+
+        IOException e = ioe.get();
+        if (e != null) {
+            throw e;
+        }
+    }
+
+    private boolean copyMSVCDLLs(String VS_VER) throws IOException {
+        final InputStream REDIST_MSVCR_URL = WinResources.class.getResourceAsStream(
+                REDIST_MSVCR.replaceAll("VS_VER", VS_VER));
+        final InputStream REDIST_MSVCP_URL = WinResources.class.getResourceAsStream(
+                REDIST_MSVCP.replaceAll("VS_VER", VS_VER));
+
+        if (REDIST_MSVCR_URL != null && REDIST_MSVCP_URL != null) {
+            Files.copy(
+                    REDIST_MSVCR_URL,
+                    root.resolve(REDIST_MSVCR.replaceAll("VS_VER", VS_VER)));
+            Files.copy(
+                    REDIST_MSVCP_URL,
+                    root.resolve(REDIST_MSVCP.replaceAll("VS_VER", VS_VER)));
+            return true;
+        }
+
+        return false; // not found
+    }
+
+    private void validateValueAndPut(Map<String, String> data, String key,
+                                     BundlerParamInfo<String> param, Map<String, ? super Object> params)
+    {
+        String value = param.fetchFrom(params);
+        if (value.contains("\r") || value.contains("\n")) {
+            Log.info("Configuration Parameter " + param.getID() + " contains multiple lines of text, ignore it");
+            data.put(key, "");
+            return;
+        }
+        data.put(key, value);
+    }
+
+    protected void prepareExecutableProperties(Map<String, ? super Object> params)
+            throws IOException
+    {
+        Map<String, String> data = new HashMap<>();
+
+        // mapping Java parameters in strings for version resource
+        data.put("COMMENTS", "");
+        validateValueAndPut(data, "COMPANY_NAME", VENDOR, params);
+        validateValueAndPut(data, "FILE_DESCRIPTION", DESCRIPTION, params);
+        validateValueAndPut(data, "FILE_VERSION", VERSION, params);
+        data.put("INTERNAL_NAME", getLauncherName(params));
+        validateValueAndPut(data, "LEGAL_COPYRIGHT", COPYRIGHT, params);
+        data.put("LEGAL_TRADEMARK", "");
+        data.put("ORIGINAL_FILENAME", getLauncherName(params));
+        data.put("PRIVATE_BUILD", "");
+        validateValueAndPut(data, "PRODUCT_NAME", APP_NAME, params);
+        validateValueAndPut(data, "PRODUCT_VERSION", VERSION, params);
+        data.put("SPECIAL_BUILD", "");
+
+        Writer w = new BufferedWriter(new FileWriter(getConfig_ExecutableProperties(params)));
+        String content = preprocessTextResource(
+                WINDOWS_BUNDLER_PREFIX + getConfig_ExecutableProperties(params).getName(),
+                I18N.getString("resource.executable-properties-template"), EXECUTABLE_PROPERTIES_TEMPLATE, data,
+                VERBOSE.fetchFrom(params),
+                DROP_IN_RESOURCES_ROOT.fetchFrom(params));
+        w.write(content);
+        w.close();
+    }
+
+    private void createLauncherForEntryPoint(Map<String, ? super Object> p) throws IOException {
+
+        File icon = ICON_ICO.fetchFrom(params);
+        File iconTarget = getConfig_AppIcon(params);
+
+        InputStream in = locateResource("package/windows/" + APP_NAME.fetchFrom(params) + ".ico",
+                "icon",
+                TEMPLATE_APP_ICON,
+                icon,
+                VERBOSE.fetchFrom(params),
+                DROP_IN_RESOURCES_ROOT.fetchFrom(params));
+        Files.copy(in, iconTarget.toPath());
+
+        writeCfgFile(p, root.resolve(getLauncherCfgName(p)).toFile(), "$APPDIR\\runtime");
+
+        prepareExecutableProperties(p);
+
+        // Copy executable root folder
+        Path executableFile = root.resolve(getLauncherName(p));
+        writeEntry(WinResources.class.getResourceAsStream(EXECUTABLE_NAME), executableFile);
+        executableFile.toFile().setWritable(true, true);
+
+        //Update branding of exe file
+        if (REBRAND_EXECUTABLE.fetchFrom(p) && iconTarget.exists()) {
+            //extract IconSwap helper tool
+            File iconSwapTool = File.createTempFile("iconswap", ".exe");
+            IOUtils.copyFromURL(
+                    WinResources.class.getResource(TOOL_ICON_SWAP),
+                    iconSwapTool,
+                    true);
+            iconSwapTool.setExecutable(true, false);
+            iconSwapTool.deleteOnExit();
+
+            //run it on launcher file
+            executableFile.toFile().setWritable(true);
+            ProcessBuilder pb = new ProcessBuilder(
+                    iconSwapTool.getAbsolutePath(),
+                    getConfig_AppIcon(p).getAbsolutePath(),
+                    executableFile.toFile().getAbsolutePath());
+            IOUtils.exec(pb, VERBOSE.fetchFrom(p));
+            executableFile.toFile().setReadOnly();
+            iconSwapTool.delete();
+        }
+
+        Files.copy(iconTarget.toPath(), root.resolve(APP_NAME.fetchFrom(p) + ".ico"));
+
+        if (REBRAND_EXECUTABLE.fetchFrom(p) && getConfig_ExecutableProperties(p).exists()) {
+            // extract VersionInfoHelper tool
+            File versionInfoTool = File.createTempFile("versioninfoswap", ".exe");
+            IOUtils.copyFromURL(
+                    WinResources.class.getResource(TOOL_VERSION_INFO_SWAP),
+                    versionInfoTool,
+                    true);
+            versionInfoTool.setExecutable(true, false);
+            versionInfoTool.deleteOnExit();
+
+            // run it on launcher file
+            executableFile.toFile().setWritable(true);
+            ProcessBuilder pb = new ProcessBuilder(
+                    versionInfoTool.getAbsolutePath(),
+                    getConfig_ExecutableProperties(p).getAbsolutePath(),
+                    executableFile.toFile().getAbsolutePath());
+            IOUtils.exec(pb, VERBOSE.fetchFrom(p));
+            executableFile.toFile().setReadOnly();
+            versionInfoTool.delete();
+        }
+    }
+
+    private void copyApplication(Map<String, ? super Object> params) throws IOException {
+        List<RelativeFileSet> appResourcesList = APP_RESOURCES_LIST.fetchFrom(params);
+        if (appResourcesList == null) {
+            throw new RuntimeException("Null app resources?");
+        }
+        for (RelativeFileSet appResources : appResourcesList) {
+            if (appResources == null) {
+                throw new RuntimeException("Null app resources?");
+            }
+            File srcdir = appResources.getBaseDirectory();
+            for (String fname : appResources.getIncludedFiles()) {
+                Files.copy(new File(srcdir, fname).toPath(), new File(appDir.toFile(), fname).toPath());
+            }
+        }
+    }
+
+    @Override
+    protected String getCacheLocation(Map<String, ? super Object> params) {
+        return "$CACHEDIR/";
+    }
+
+}
--- a/modules/fxpackager/src/main/java/jdk/packager/services/UserJvmOptionsService.java	Tue Mar 15 04:00:44 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2014, 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 jdk.packager.services;
-
-import jdk.packager.services.userjvmoptions.LauncherUserJvmOptions;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.ServiceLoader;
-
-/**
- * Runtime access to the UserJVMOptions.
- *
- * This class is not typically available in the Java Runtime, you must
- * explicitly include the 'packager.jar' file from the lib directory
- * of the JDK as part of your application bundle.
- *
- * @since 8u40
- */
-public interface UserJvmOptionsService {
-
-    /**
-     * Get the instance of UserJvmOptionService to use.  Which one to use is
-     * configured by the packager and the launcher.  Do not directly
-     * instantiate any instance of this interface, use this method to get
-     * an appropriate instance.
-     *
-     * @return the instance of UserJvmOptionsService for your application.
-     */
-    static UserJvmOptionsService getUserJVMDefaults() {
-        ServiceLoader<UserJvmOptionsService> loader = ServiceLoader.load(UserJvmOptionsService.class);
-        Iterator<UserJvmOptionsService> iter = loader.iterator();
-        if (iter.hasNext()) {
-            return iter.next();
-        } else {
-            return new LauncherUserJvmOptions();
-            //return new PreferencesUserJvmOptions();
-        }
-    }
-
-    /**
-     * The "current" set of UserJVMOptions.
-     *
-     * This will take effect on the next application start, and this may not
-     * reflect the current set of UserJVMOptions used to start this application.
-     *
-     * @return A map of the keys and values.  Alterations to this map will not
-     *         change the stored UserJVMOptions
-     */
-    Map<String, String> getUserJVMOptions();
-
-    /**
-     * Sets the passed in options as the UserJVMOptions.
-     *
-     * If the application has specified default values and those keys are not
-     * in this map, they will be replaced by the default values.
-     *
-     * No validation or error checking is performed on these values.  It is
-     * entirely possible that you may provide a set of UserJVMOptions that
-     * may prevent the normal startup of your application and may require
-     * manual intervention to resolve.
-     *
-     * @param options The UserJVMOptions to set.
-     */
-    void setUserJVMOptions(Map<String, String> options);
-
-    /**
-     * The "default" set of UserJVMOptions.
-     *
-     * This returns the default set of keys and values that the application has
-     * been configured to use.
-     *
-     * @return the keys and values of the default UserJVMOptions.
-     * @throws UnsupportedOperationException if the defaults cannot be calculated.
-     */
-    Map<String, String> getUserJVMOptionDefaults();
-
-}
--- a/modules/fxpackager/src/main/java/jdk/packager/services/userjvmoptions/LauncherUserJvmOptions.java	Tue Mar 15 04:00:44 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-/*
- * Copyright (c) 2014, 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 jdk.packager.services.userjvmoptions;
-
-import jdk.packager.services.UserJvmOptionsService;
-
-import java.security.AllPermission;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-/**
- *
- * Access the UserJVMOptions via a native library provided by the launcher.
- *
- * Do not instantiate this class directly, instead use
- * {@see jdk.packager.services.UserJvmOptionsService#getUserJVMDefaults()}
- * to get an instance.
- *
- * @since 8u40
- */
-final public class LauncherUserJvmOptions implements UserJvmOptionsService {
-
-    private static final Object semaphore = new Object();
-
-    static {
-        try {
-            checkAllPermissions();
-            System.loadLibrary("packager");
-        } catch (SecurityException se) {
-            // fail to load, we will also throw on all public methods
-        }
-    }
-
-    private static void checkAllPermissions() {
-        final SecurityManager securityManager = System.getSecurityManager();
-        if (securityManager != null) {
-            securityManager.checkPermission(new AllPermission());
-        }
-    }
-
-    /**
-     * Access the default User JVM Option for a specific key
-     *
-     * @param option the key for the User JVM Option
-     *
-     * @return the default value of the user JVM Option.  Currently set user
-     * values are not considered, and only the default is returned.  If there
-     * is no default value then null is returned.
-     */
-    private static native String _getUserJvmOptionDefaultValue(String option);
-
-    /**
-     * This lists the keys for User JVM Options that will have a default
-     * provided by the launcher.
-     *
-     * This list will be a subset of the keys used by the launcher and only
-     * lists those values that will have a default value provided if the user
-     * does not set a value of their own.
-     *
-     * @return an array of keys in no particular order.
-     */
-    private static native String[] _getUserJvmOptionDefaultKeys();
-    /**
-     * Access the current User JVM Option for a specific key
-     *
-     * @param option the key for the User JVM Option
-     *
-     * @return the current value of the user JVM Option.  If the user has not
-     * set a value then the default value is returned, except in the case where
-     * there is no default value, where null is returned.
-     */
-    private static native String _getUserJvmOptionValue(String option);
-
-    /**
-     * Update the all User JVM Options
-     *
-     * All option/value pairs will be replaced with the values provided. The
-     * parameters options and values are paired at the same index.
-     * Example: options[3] = -Xmx and values[3] = 999m
-     * This cannot be used to adjust default values.
-     *
-     * @param options the keys for the User JVM Options
-     * @param values the values for the User JVM Options
-     */
-    private static native void _setUserJvmKeysAndValues(String[] options, String[] values);
-
-    /**
-     * This lists the keys for all User JVM Options that will be used by the
-     * launcher.
-     *
-     * This list will be a superset of the defaults as may also include user
-     * values that do not have a default.
-     *
-     * @return an array of keys in no particular order.
-     */
-    private static native String[] _getUserJvmOptionKeys();
-
-    @Override
-    public Map<String, String> getUserJVMOptions() {
-        checkAllPermissions();
-        synchronized (semaphore) {
-            Map<String, String> results = new LinkedHashMap<>();
-            for (String s : _getUserJvmOptionKeys()) {
-                results.put(s, _getUserJvmOptionValue(s));
-            }
-            return results;
-        }
-    }
-
-    @Override
-    public void setUserJVMOptions(Map<String, String> options) {
-        checkAllPermissions();
-        synchronized (semaphore) {
-            List<String> keys = new LinkedList<>();
-            List<String> values = new LinkedList<>();
-
-            for (Map.Entry<String, String> option : options.entrySet()) {
-                if (option.getKey() == null) {
-                    throw new IllegalArgumentException("For Launcher Backed UserJVMOptions keys in the UserJVMOptions map cannot be null.");
-                }
-                if (option.getValue() == null) {
-                    throw new IllegalArgumentException("For Launcher Backed UserJVMOptions values in the UserJVMOptions map cannot be null.  Keys are removed by absence, not by setting keys to null.");
-                }
-                keys.add(option.getKey());
-                values.add(option.getValue());
-            }
-
-            _setUserJvmKeysAndValues(keys.toArray(new String[keys.size()]),
-                    values.toArray(new String[values.size()]));
-        }
-    }
-
-    @Override
-    public Map<String, String> getUserJVMOptionDefaults() {
-        checkAllPermissions();
-        synchronized (semaphore) {
-            Map<String, String> results = new LinkedHashMap<>();
-            for (String s : _getUserJvmOptionDefaultKeys()) {
-                results.put(s, _getUserJvmOptionDefaultValue(s));
-            }
-            return results;
-        }
-    }
-}
--- a/modules/fxpackager/src/main/java/jdk/packager/services/userjvmoptions/PreferencesUserJvmOptions.java	Tue Mar 15 04:00:44 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2014, 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 jdk.packager.services.userjvmoptions;
-
-import jdk.packager.services.UserJvmOptionsService;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.prefs.BackingStoreException;
-import java.util.prefs.Preferences;
-
-/**
- * Access to old preferences based UserJvmOptions
- *
- * Do not instantiate this class directly, instead use
- * {@see jdk.packager.services.UserJvmOptionsService#getUserJVMDefaults()}
- * to get an instance.
- *
- * @since 8u40
- */
-final public class PreferencesUserJvmOptions implements UserJvmOptionsService {
-
-    Preferences node = Preferences.userRoot().node(System.getProperty("app.preferences.id").replace(".", "/")).node("JVMUserOptions");
-
-    @Override
-    public Map<String, String> getUserJVMOptions() {
-        Map<String, String> result = new LinkedHashMap<>();
-        try {
-            for (String s : node.childrenNames()) {
-                String o = node.get(s, null);
-                if (o != null) {
-                    result.put(s, o);
-                }
-            }
-        } catch (BackingStoreException ignore) {
-        }
-
-        return result;
-    }
-
-    @Override
-    public void setUserJVMOptions(Map<String, String> options) {
-        try {
-            node.clear();
-            for (Map.Entry<String, String> entry : options.entrySet()) {
-                node.put(entry.getKey(), entry.getValue());
-            }
-            node.flush