--- old/./build.gradle 2018-07-13 12:28:16.000000000 +0200 +++ new/./build.gradle 2018-07-13 12:28:16.000000000 +0200 @@ -296,6 +296,8 @@ ext.IS_WINDOWS = OS_NAME.contains("windows") ext.IS_LINUX = OS_NAME.contains("linux") +ext.MAVEN_GROUP_ID = "org.openjfx" + // Verify that the architecture & OS are supported configurations. Note that // at present building on PI is not supported, but we would only need to make // some changes on assumptions on what should be built (like SWT / Swing) and @@ -549,6 +551,7 @@ defineProperty("RELEASE_SUFFIX", relSuffix) defineProperty("RELEASE_VERSION_SHORT", "${RELEASE_VERSION}${RELEASE_SUFFIX}") defineProperty("RELEASE_VERSION_LONG", "${RELEASE_VERSION_SHORT}+${PROMOTED_BUILD_NUMBER}${relOpt}") +defineProperty("MAVEN_VERSION", "$RELEASE_VERSION_LONG") // Check whether the COMPILE_TARGETS property has been specified (if so, it was done by // the user and not by this script). If it has not been defined then default @@ -1312,6 +1315,7 @@ logger.quiet("RELEASE_VERSION_SHORT: $RELEASE_VERSION_SHORT") logger.quiet("RELEASE_VERSION_LONG: $RELEASE_VERSION_LONG") logger.quiet("RELEASE_VERSION_PADDED: $RELEASE_VERSION_PADDED") +logger.quiet("MAVEN_VERSION: $MAVEN_VERSION") logger.quiet("UPDATE_STUB_CACHE: $UPDATE_STUB_CACHE") /****************************************************************************** @@ -1514,6 +1518,94 @@ } +void addMavenPublication(Project project, List projectDependencies) { + project.apply plugin: 'maven-publish' + + project.group = MAVEN_GROUP_ID + project.version = MAVEN_VERSION + + if (project.name == 'base') { + project.publishing { + publications { + javafx(MavenPublication) { + artifactId = 'javafx' + artifacts = [] + } + } + } + } + + gradle.taskGraph.whenReady { g -> + project.tasks.findAll { it.name == 'generatePomFileForJavafxPublication'}.each { it -> + it.doLast { + copy { + into project.file("${project.buildDir}/publications/javafx") + from file("${rootProject.projectDir}/javafx.pom") + rename "javafx.pom", "pom-default.xml" + filter { line -> + line.replaceAll("@VERSION@", MAVEN_VERSION) + } + } + } + } + } + + project.publishing { + repositories { + maven { + def repositoryUrl = project.hasProperty('repositoryUrl') ? project.getProperty('repositoryUrl') : "" + def repositoryUsername = project.hasProperty('repositoryUsername') ? project.getProperty('repositoryUsername') : "" + def repositoryPassword = project.hasProperty('repositoryPassword') ? project.getProperty('repositoryPassword') : "" + url repositoryUrl + credentials { + username repositoryUsername + password repositoryPassword + } + } + } + } + + compileTargets { t -> + project.publishing { + publications { + maven(MavenPublication) { + artifactId = "javafx-${project.name}" + + artifact project.tasks."moduleEmptyPublicationJar$t.capital" + artifact project.tasks."modularPublicationJar$t.capital" { + classifier "$t.name" + } + + pom.withXml { + Node parent = asNode().appendNode("parent") + parent.appendNode("groupId", MAVEN_GROUP_ID) + parent.appendNode("artifactId", "javafx") + parent.appendNode("version", MAVEN_VERSION) + + Node dependencies = asNode().appendNode("dependencies") + + Node projectDependencyPlatform = dependencies.appendNode("dependency") + projectDependencyPlatform.appendNode("groupId", MAVEN_GROUP_ID) + projectDependencyPlatform.appendNode("artifactId", "javafx-${project.name}") + projectDependencyPlatform.appendNode("version", MAVEN_VERSION) + projectDependencyPlatform.appendNode("classifier", "\${javafx.platform}") + + if (!projectDependencies.empty) { + projectDependencies.each { dep -> + Node projectDependency = dependencies.appendNode("dependency") + projectDependency.appendNode("groupId", MAVEN_GROUP_ID) + projectDependency.appendNode("artifactId", "javafx-$dep") + projectDependency.appendNode("version", MAVEN_VERSION) + } + } + } + } + } + + } + } +} + /** * Parses a JDK version string. The string must be in one of the following * two formats: @@ -1814,6 +1906,8 @@ sourceSets.main.java.srcDirs += "$buildDir/gensrc/java" compileJava.dependsOn processVersionInfo + addMavenPublication(project, []) + } // The graphics module is needed for any graphical JavaFX application. It requires @@ -1826,6 +1920,7 @@ project.ext.includeSources = true project.ext.moduleRuntime = true project.ext.moduleName = "javafx.graphics" + project.ext.mavenPublish = true getConfigurations().create("antlr"); @@ -2237,6 +2332,9 @@ } } } + + addMavenPublication(project, [ 'base' ]) + } project(":controls") { @@ -2295,6 +2393,9 @@ into project.moduleShimsDir include "**/*.bss" }) + + addMavenPublication(project, [ 'graphics' ]) + } project(":swing") { @@ -2331,6 +2432,8 @@ } compileJava.options.compilerArgs.addAll(qualExportsSwing) + + addMavenPublication(project, [ 'graphics' ]) } project(":swt") { @@ -2423,6 +2526,9 @@ // FIXME: change this to also allow JDK 9 boot jdk classpath += files("$JDK_HOME/jre/lib/ext/nashorn.jar") } + + addMavenPublication(project, [ 'controls' ]) + } project(":fxpackagerservices") { @@ -3623,6 +3729,9 @@ dependsOn buildNativeTargets } } + + addMavenPublication(project, [ 'graphics' ]) + } project(":web") { @@ -3855,6 +3964,9 @@ if (IS_COMPILE_WEBKIT) { assemble.dependsOn compileJavaDOMBinding, drtJar } + + addMavenPublication(project, [ 'controls', 'media' ]) + } // This project is for system tests that need to run with a full SDK. @@ -4194,7 +4306,6 @@ if (rootProject.hasProperty("EXTRA_COMPILE_ARGS") && project.hasProperty('compileTestJava')) { project.compileTestJava.options.compilerArgs.addAll(EXTRA_COMPILE_ARGS.split(' ')) } - } /****************************************************************************** @@ -4866,6 +4977,7 @@ // Create modular jars def srcClassesDir = "${buildDir}/${platformPrefix}module-classes" + def srcLibsDir = "${buildDir}/${platformPrefix}module-lib" def dstModularJarDir = "${standaloneLibDir}" def modularJarName = "${moduleName}.jar" def modularJarTask = project.task("modularJarStandalone$t.capital", type: Jar, dependsOn: project.assemble) { @@ -4885,7 +4997,6 @@ } // Copy other lib files - def srcLibsDir = "${buildDir}/${platformPrefix}module-lib" def dstLibsDir = "${standaloneLibDir}" def copyLibFilesTask = project.task("copyLibFilesStandalone$t.capital", type: Copy, dependsOn: copyNativeFilesTask) { from srcLibsDir @@ -4937,6 +5048,39 @@ // ============================================================ + // Maven Publications + def publicationDirName = "${platformPrefix}publications" + def publicationDir = "${rootProject.buildDir}/${publicationDirName}" + + moduleProjList.each { project -> + // Create publications to be uploaded + + def moduleName = project.ext.moduleName + def buildDir = project.buildDir + + def dstModularJarDir="${publicationDir}" + def srcClassesDir = "${buildDir}/${platformPrefix}module-classes" + def srcLibsDir = "${buildDir}/${platformPrefix}module-lib" + + def modularEmptyPublicationJarName = "${moduleName}.jar" + def modularEmptyPublicationJarTask = project.task("moduleEmptyPublicationJar${t.capital}", type: Jar) { + destinationDir = file("${dstModularJarDir}") + archiveName = modularEmptyPublicationJarName + } + + def modularPublicationJarName = "${moduleName}-${t.name}.jar" + def modularPublicationJarTask = project.task("modularPublicationJar${t.capital}", type: Jar, dependsOn: modularEmptyPublicationJarTask) { + destinationDir = file("${dstModularJarDir}") + archiveName = modularPublicationJarName + from srcLibsDir + from srcClassesDir + } + + buildModulesTask.dependsOn(modularPublicationJarTask) + + } + // ============================================================ + def buildRunArgsTask = task("buildRunArgs$t.capital", group: "Build", dependsOn: buildModulesTask) { outputs.file(runArgsFile); --- old/modules/javafx.graphics/src/main/java/com/sun/glass/utils/NativeLibLoader.java 2018-07-13 12:28:17.000000000 +0200 +++ new/modules/javafx.graphics/src/main/java/com/sun/glass/utils/NativeLibLoader.java 2018-07-13 12:28:16.000000000 +0200 @@ -25,10 +25,20 @@ package com.sun.glass.utils; import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.IOException; import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; import java.security.AccessController; +import java.security.DigestInputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.PrivilegedAction; +import java.util.Arrays; import java.util.HashSet; +import java.util.List; public class NativeLibLoader { @@ -36,7 +46,20 @@ public static synchronized void loadLibrary(String libname) { if (!loaded.contains(libname)) { - loadLibraryInternal(libname); + StackWalker walker = AccessController.doPrivileged((PrivilegedAction) () -> + StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)); + Class caller = walker.getCallerClass(); + loadLibraryInternal(libname, null, caller); + loaded.add(libname); + } + } + + public static synchronized void loadLibrary(String libname, List dependencies) { + if (!loaded.contains(libname)) { + StackWalker walker = AccessController.doPrivileged((PrivilegedAction) () -> + StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE)); + Class caller = walker.getCallerClass(); + loadLibraryInternal(libname, dependencies, caller); loaded.add(libname); } } @@ -87,7 +110,7 @@ return paths; } - private static void loadLibraryInternal(String libraryName) { + private static void loadLibraryInternal(String libraryName, List dependencies, Class caller) { // Look for the library in the same directory as the jar file // containing this class. // If that fails, then try System.loadLibrary. @@ -130,6 +153,10 @@ + libraryName + ") succeeded"); } } catch (UnsatisfiedLinkError ex2) { + // if the library is available in the jar, copy it to cache and load it from there + if (loadLibraryFromResource(libraryName, dependencies, caller)) { + return; + } //On iOS we link all libraries staticaly. Presence of library //is recognized by existence of JNI_OnLoad_libraryname() C function. //If libraryname contains hyphen, it needs to be translated @@ -150,6 +177,119 @@ } } + /** + * If there is a library with the platform-correct name at the + * root of the resources in this jar, use that. + */ + private static boolean loadLibraryFromResource(String libraryName, List dependencies, Class caller) { + return installLibraryFromResource(libraryName, dependencies, caller, true); + } + + /** + * If there is a library with the platform-correct name at the + * root of the resources in this jar, install it. If load is true, also load it. + */ + private static boolean installLibraryFromResource(String libraryName, List dependencies, Class caller, boolean load) { + try { + // first preload dependencies + if (dependencies != null) { + for (String dep: dependencies) { + boolean hasdep = installLibraryFromResource(dep, null, caller, false); + } + } + String reallib = "/"+libPrefix+libraryName+libSuffix; + InputStream is = caller.getResourceAsStream(reallib); + if (is != null) { + String fp = cacheLibrary(is, reallib, caller); + if (load) { + System.load(fp); + if (verbose) { + System.err.println("Loaded library " + reallib + " from resource"); + } + } else if (verbose) { + System.err.println("Unpacked library " + reallib + " from resource"); + } + return true; + } + } catch (Throwable t) { + // we should only be here if the resource exists in the module, but + // for some reasons it can't be loaded. + System.err.println("Loading library " + libraryName + " from resource failed: " + t); + t.printStackTrace(); + } + return false; + } + + private static String cacheLibrary(InputStream is, String name, Class caller) throws IOException { + String jfxVersion = System.getProperty("javafx.version", "versionless"); + String userCache = System.getProperty("user.home") + "/.openjfx/cache/" + jfxVersion; + File cacheDir = new File(userCache); + if (cacheDir.exists()) { + if (!cacheDir.isDirectory()) { + throw new IOException ("Cache exists but is not a directory: "+cacheDir); + } + } else { + if (!cacheDir.mkdirs()) { + throw new IOException ("Can not create cache at "+cacheDir); + } + } + // we have a cache directory. Add the file here + File f = new File(cacheDir, name); + // if it exists, calculate checksum and keep if same as inputstream. + boolean write = true; + if (f.exists()) { + byte[] isHash; + byte[] fileHash; + try { + DigestInputStream dis = new DigestInputStream(is, MessageDigest.getInstance("MD5")); + dis.getMessageDigest().reset(); + byte[] buffer = new byte[4096]; + while (dis.read(buffer) != -1) { /* empty loop body is intentional */ } + isHash = dis.getMessageDigest().digest(); + is.close(); + is = caller.getResourceAsStream(name); // mark/reset not supported, we have to reread + } + catch (NoSuchAlgorithmException nsa) { + isHash = new byte[1]; + } + fileHash = calculateCheckSum(f); + if (!Arrays.equals(isHash, fileHash)) { + Files.delete(f.toPath()); + } else { + // hashes are the same, we already have the file. + write = false; + } + } + if (write) { + Path path = f.toPath(); + Files.copy(is, path); + } + + String fp = f.getAbsolutePath(); + return fp; + } + + static byte[] calculateCheckSum(File file) { + try { + // not looking for security, just a checksum. MD5 should be faster than SHA + try (final InputStream stream = new FileInputStream(file); + final DigestInputStream dis = new DigestInputStream(stream, MessageDigest.getInstance("MD5")); ) { + dis.getMessageDigest().reset(); + byte[] buffer = new byte[4096]; + while (dis.read(buffer) != -1) { /* empty loop body is intentional */ } + return dis.getMessageDigest().digest(); + } + + } catch (IllegalArgumentException | NoSuchAlgorithmException | IOException | SecurityException e) { + // IOException also covers MalformedURLException + // SecurityException means some untrusted applet + + // Fall through... + } + return new byte[0]; + } + + /** * Load the native library from the same directory as the jar file * containing this class. @@ -223,4 +363,5 @@ throw (UnsatisfiedLinkError) new UnsatisfiedLinkError().initCause(e); } } + } --- old/modules/javafx.graphics/src/main/java/com/sun/javafx/tk/Toolkit.java 2018-07-13 12:28:17.000000000 +0200 +++ new/modules/javafx.graphics/src/main/java/com/sun/javafx/tk/Toolkit.java 2018-07-13 12:28:17.000000000 +0200 @@ -200,11 +200,6 @@ return TOOLKIT; } - // This loading of msvcp140.dll and vcruntime140.dll (VS2017) is required on Windows platforms - if (PlatformUtil.isWindows()) { - loadMSWindowsLibraries(); - } - AccessController.doPrivileged((PrivilegedAction) () -> { // Get the javafx.version and javafx.runtime.version from a preconstructed // java class, VersionInfo, created at build time. @@ -212,6 +207,11 @@ return null; }); + // This loading of msvcp140.dll and vcruntime140.dll (VS2017) is required on Windows platforms + if (PlatformUtil.isWindows()) { + loadMSWindowsLibraries(); + } + boolean userSpecifiedToolkit = true; // Check a system property to see if there is a specific toolkit to use. --- old/modules/javafx.media/src/main/java/com/sun/media/jfxmediaimpl/NativeMediaManager.java 2018-07-13 12:28:18.000000000 +0200 +++ new/modules/javafx.media/src/main/java/com/sun/media/jfxmediaimpl/NativeMediaManager.java 2018-07-13 12:28:18.000000000 +0200 @@ -36,6 +36,7 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.ListIterator; import java.util.Map; @@ -104,15 +105,35 @@ */ try { AccessController.doPrivileged((PrivilegedExceptionAction) () -> { + ArrayList dependencies = new ArrayList<>(); if (HostUtils.isWindows() || HostUtils.isMacOSX()) { NativeLibLoader.loadLibrary("glib-lite"); } if (!HostUtils.isLinux() && !HostUtils.isIOS()) { NativeLibLoader.loadLibrary("gstreamer-lite"); + } else { + dependencies.add("gstreamer-lite"); } - - NativeLibLoader.loadLibrary("jfxmedia"); + if (HostUtils.isLinux()) { + dependencies.add("fxplugins"); + dependencies.add("avplugin"); + dependencies.add("avplugin-54"); + dependencies.add("avplugin-56"); + dependencies.add("avplugin-57"); + dependencies.add("avplugin-ffmpeg-56"); + dependencies.add("avplugin-ffmpeg-57"); + } + if (HostUtils.isMacOSX()) { + dependencies.add("fxplugins"); + dependencies.add("glib-lite"); + dependencies.add("jfxmedia_avf"); + } + if (HostUtils.isWindows()) { + dependencies.add("fxplugins"); + dependencies.add("glib-lite"); + } + NativeLibLoader.loadLibrary("jfxmedia", dependencies); return null; }); } catch (PrivilegedActionException pae) {