< prev index next >

modules/fxpackager/src/main/java/com/oracle/tools/packager/linux/LinuxAppBundler.java

Print this page
rev 9619 : imported patch 9-jake-fxpackager.patch


  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.oracle.tools.packager.linux;
  27 
  28 import com.oracle.tools.packager.AbstractImageBundler;
  29 import com.oracle.tools.packager.BundlerParamInfo;



  30 import com.oracle.tools.packager.JreUtils;
  31 import com.oracle.tools.packager.JreUtils.Rule;
  32 import com.oracle.tools.packager.StandardBundlerParam;
  33 import com.oracle.tools.packager.Log;
  34 import com.oracle.tools.packager.ConfigException;
  35 import com.oracle.tools.packager.IOUtils;
  36 import com.oracle.tools.packager.RelativeFileSet;

  37 import com.oracle.tools.packager.UnsupportedPlatformException;
  38 import com.sun.javafx.tools.packager.bundlers.BundleParams;


  39 
  40 import java.io.ByteArrayOutputStream;
  41 import java.io.File;
  42 import java.io.FileNotFoundException;
  43 import java.io.IOException;
  44 import java.io.PrintStream;
  45 import java.net.MalformedURLException;
  46 import java.net.URL;
  47 import java.text.MessageFormat;
  48 import java.util.*;



  49 
  50 import static com.oracle.tools.packager.StandardBundlerParam.*;
  51 
  52 public class LinuxAppBundler extends AbstractImageBundler {
  53 
  54     private static final ResourceBundle I18N =
  55             ResourceBundle.getBundle(LinuxAppBundler.class.getName());
  56 
  57     protected static final String LINUX_BUNDLER_PREFIX =
  58             BUNDLER_PREFIX + "linux" + File.separator;
  59     private static final String EXECUTABLE_NAME = "JavaAppLauncher";
  60     private static final String LIBRARY_NAME    = "libpackager.so";
  61 
  62     public static final BundlerParamInfo<File> ICON_PNG = new StandardBundlerParam<>(
  63             I18N.getString("param.icon-png.name"),
  64             I18N.getString("param.icon-png.description"),
  65             "icon.png",
  66             File.class,
  67             params -> {
  68                 File f = ICON.fetchFrom(params);
  69                 if (f != null && !f.getName().toLowerCase().endsWith(".png")) {
  70                     Log.info(MessageFormat.format(I18N.getString("message.icon-not-png"), f));
  71                     return null;
  72                 }
  73                 return f;
  74             },
  75             (s, p) -> new File(s));
  76 
  77     public static final BundlerParamInfo<URL> RAW_EXECUTABLE_URL = new StandardBundlerParam<>(
  78             I18N.getString("param.raw-executable-url.name"),
  79             I18N.getString("param.raw-executable-url.description"),
  80             "linux.launcher.url",


 134             } else {
 135                 throw new ConfigException(re);
 136             }
 137         }
 138     }
 139 
 140     //used by chained bundlers to reuse validation logic
 141     boolean doValidate(Map<String, ? super Object> p) throws UnsupportedPlatformException, ConfigException {
 142         if (!System.getProperty("os.name").toLowerCase().startsWith("linux")) {
 143             throw new UnsupportedPlatformException();
 144         }
 145 
 146         imageBundleValidation(p);
 147 
 148         if (RAW_EXECUTABLE_URL.fetchFrom(p) == null) {
 149             throw new ConfigException(
 150                     I18N.getString("error.no-linux-resources"),
 151                     I18N.getString("error.no-linux-resources.advice"));
 152         }
 153 
 154         //validate required inputs
 155         testRuntime(LINUX_RUNTIME.fetchFrom(p), new String[] {
 156                 "lib/[^/]+/[^/]+/libjvm.so", // most reliable
 157                 "lib/rt.jar", // fallback canary for JDK 8
 158         });
 159         if (USE_FX_PACKAGING.fetchFrom(p)) {
 160             testRuntime(LINUX_RUNTIME.fetchFrom(p), new String[] {"lib/ext/jfxrt.jar", "lib/jfxrt.jar"});
 161         }
 162 
 163         return true;
 164     }
 165 
 166     //it is static for the sake of sharing with "installer" bundlers
 167     // that may skip calls to validate/bundle in this class!
 168     public static File getRootDir(File outDir, Map<String, ? super Object> p) {
 169         return new File(outDir, APP_FS_NAME.fetchFrom(p));
 170     }
 171 
 172     public static String getLauncherName(Map<String, ? super Object> p) {
 173         return APP_FS_NAME.fetchFrom(p);
 174     }
 175 
 176     public static String getLauncherCfgName(Map<String, ? super Object> p) {
 177         return "app/" + APP_FS_NAME.fetchFrom(p) +".cfg";
 178     }
 179 
 180     File doBundle(Map<String, ? super Object> p, File outputDirectory, boolean dependentTask) {
 181         Map<String, ? super Object> originalParams = new HashMap<>(p);
 182         try {
 183             if (!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) {
 184                 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), outputDirectory.getAbsolutePath()));
 185             }
 186             if (!outputDirectory.canWrite()) {
 187                 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-write-to-output-dir"), outputDirectory.getAbsolutePath()));
 188             }
 189 
 190             // Create directory structure
 191             File rootDirectory = getRootDir(outputDirectory, p);
 192             IOUtils.deleteRecursive(rootDirectory);
 193             rootDirectory.mkdirs();
 194 
 195             if (!dependentTask) {
 196                 Log.info(MessageFormat.format(I18N.getString("message.creating-bundle-location"), rootDirectory.getAbsolutePath()));
 197             }
 198 
 199             File runtimeDirectory = new File(rootDirectory, "runtime");
 200 
 201             File appDirectory = new File(rootDirectory, "app");
 202             appDirectory.mkdirs();
 203 
 204             // create the primary launcher
 205             createLauncherForEntryPoint(p, rootDirectory);
 206 
 207             // Copy library to the launcher folder
 208             IOUtils.copyFromURL(
 209                     LinuxResources.class.getResource(LIBRARY_NAME),
 210                     new File(rootDirectory, LIBRARY_NAME));
 211 
 212             // create the secondary launchers, if any
 213             List<Map<String, ? super Object>> entryPoints = StandardBundlerParam.SECONDARY_LAUNCHERS.fetchFrom(p);
 214             for (Map<String, ? super Object> entryPoint : entryPoints) {
 215                 Map<String, ? super Object> tmp = new HashMap<>(originalParams);
 216                 tmp.putAll(entryPoint);
 217                 createLauncherForEntryPoint(tmp, rootDirectory);
 218             }
 219 
 220             // Copy runtime to PlugIns folder
 221             copyRuntime(p, runtimeDirectory);
 222 
 223             // Copy class path entries to Java folder
 224             copyApplication(p, appDirectory);
 225 
 226             // Copy icon to Resources folder
 227 //FIXME            copyIcon(resourcesDirectory);
 228 
 229             return rootDirectory;
 230         } catch (IOException ex) {
 231             Log.info("Exception: "+ex);
 232             Log.debug(ex);
 233             return null;
 234         }
 235     }
 236 
 237     private void createLauncherForEntryPoint(Map<String, ? super Object> p, File rootDir) throws IOException {
 238         // Copy executable to Linux folder
 239         File executableFile = new File(rootDir, getLauncherName(p));
 240         IOUtils.copyFromURL(
 241                 RAW_EXECUTABLE_URL.fetchFrom(p),
 242                 executableFile);
 243 
 244         executableFile.setExecutable(true, false);
 245         executableFile.setWritable(true, true); //for str
 246 
 247         // Generate launcher .cfg file
 248         if (LAUNCHER_CFG_FORMAT.fetchFrom(p).equals(CFG_FORMAT_PROPERTIES)) {
 249             writeCfgFile(p, rootDir);
 250         } else {
 251             writeCfgFile(p, new File(rootDir, getLauncherCfgName(p)), getRuntimeLocation(p));
 252         }
 253     }
 254 
 255     private void copyApplication(Map<String, ? super Object> params, File appDirectory) throws IOException {
 256         List<RelativeFileSet> appResourcesList = APP_RESOURCES_LIST.fetchFrom(params);
 257         if (appResourcesList == null) {
 258             throw new RuntimeException("Null app resources?");
 259         }
 260         for (RelativeFileSet appResources : appResourcesList) {
 261             if (appResources == null) {
 262                 throw new RuntimeException("Null app resources?");
 263             }
 264             File srcdir = appResources.getBaseDirectory();
 265             for (String fname : appResources.getIncludedFiles()) {
 266                 IOUtils.copyFile(
 267                         new File(srcdir, fname), new File(appDirectory, fname));
 268             }
 269         }
 270     }
 271 
 272     private String getRuntimeLocation(Map<String, ? super Object> params) {
 273         if (LINUX_RUNTIME.fetchFrom(params) == null) {
 274             return "";
 275         } else {
 276             return "$APPDIR/runtime";
 277         }
 278     }
 279 
 280     private void writeCfgFile(Map<String, ? super Object> params, File rootDir) throws FileNotFoundException {
 281         File cfgFile = new File(rootDir, getLauncherCfgName(params));
 282 
 283         cfgFile.delete();
 284         PrintStream out = new PrintStream(cfgFile);
 285         out.println("app.runtime=" + getRuntimeLocation(params));
 286         out.println("app.mainjar=" + MAIN_JAR.fetchFrom(params).getIncludedFiles().iterator().next());
 287         out.println("app.version=" + VERSION.fetchFrom(params));
 288 
 289         //use '/' in the class name (instead of '.' to simplify native code
 290         out.println("app.mainclass=" +
 291                 MAIN_CLASS.fetchFrom(params).replaceAll("\\.", "/"));
 292 
 293         StringBuilder macroedPath = new StringBuilder();
 294         for (String s : CLASSPATH.fetchFrom(params).split("[ ;:]+")) {
 295             macroedPath.append(s);
 296             macroedPath.append(":");
 297         }
 298         macroedPath.deleteCharAt(macroedPath.length() - 1);
 299         out.println("app.classpath=" + macroedPath.toString());
 300 
 301         List<String> jvmargs = JVM_OPTIONS.fetchFrom(params);
 302         int idx = 1;
 303         for (String a : jvmargs) {
 304             out.println("jvmarg."+idx+"="+a);
 305             idx++;
 306         }
 307         Map<String, String> jvmProps = JVM_PROPERTIES.fetchFrom(params);
 308         for (Map.Entry<String, String> entry : jvmProps.entrySet()) {
 309             out.println("jvmarg."+idx+"=-D"+entry.getKey()+"="+entry.getValue());
 310             idx++;
 311         }
 312 
 313         String preloader = PRELOADER_CLASS.fetchFrom(params);
 314         if (preloader != null) {
 315             out.println("jvmarg."+idx+"=-Djavafx.preloader="+preloader);
 316         }
 317 
 318         //app.id required for setting user preferences (Java Preferences API)
 319         out.println("app.preferences.id=" + PREFERENCES_ID.fetchFrom(params));
 320         out.println("app.identifier=" + IDENTIFIER.fetchFrom(params));
 321 
 322         Map<String, String> overridableJVMOptions = USER_JVM_OPTIONS.fetchFrom(params);
 323         idx = 1;
 324         for (Map.Entry<String, String> arg: overridableJVMOptions.entrySet()) {
 325             if (arg.getKey() == null || arg.getValue() == null) {
 326                 Log.info(I18N.getString("message.jvm-user-arg-is-null"));
 327             }
 328             else {
 329                 out.println("jvmuserarg."+idx+".name="+arg.getKey());
 330                 out.println("jvmuserarg."+idx+".value="+arg.getValue());
 331             }
 332             idx++;
 333         }
 334 
 335         // add command line args
 336         List<String> args = ARGUMENTS.fetchFrom(params);
 337         idx = 1;
 338         for (String a : args) {
 339             out.println("arg."+idx+"="+a);
 340             idx++;
 341         }
 342 
 343         out.close();
 344     }
 345 
 346     private void copyRuntime(Map<String, ? super Object> params, File runtimeDirectory) throws IOException {
 347         RelativeFileSet runtime = LINUX_RUNTIME.fetchFrom(params);
 348         if (runtime == null) {
 349             //request to use system runtime
 350             return;
 351         }
 352         runtimeDirectory.mkdirs();
 353 
 354         File srcdir = runtime.getBaseDirectory();
 355         Set<String> filesToCopy = runtime.getIncludedFiles();
 356         for (String fname : filesToCopy) {
 357             IOUtils.copyFile(
 358                     new File(srcdir, fname), new File(runtimeDirectory, fname));
 359         }
 360     }
 361 
 362     @Override
 363     public String getName() {
 364         return I18N.getString("bundler.name");
 365     }
 366 
 367     @Override
 368     public String getDescription() {
 369         return I18N.getString("bundler.description");
 370     }
 371 
 372     @Override
 373     public String getID() {
 374         return "linux.app";
 375     }
 376 
 377     @Override
 378     public String getBundleType() {
 379         return "IMAGE";
 380     }
 381 


 389                 APP_NAME,
 390                 APP_RESOURCES,
 391                 // APP_RESOURCES_LIST, // ??
 392                 ARGUMENTS,
 393                 CLASSPATH,
 394                 JVM_OPTIONS,
 395                 JVM_PROPERTIES,
 396                 LINUX_RUNTIME,
 397                 MAIN_CLASS,
 398                 MAIN_JAR,
 399                 PREFERENCES_ID,
 400                 PRELOADER_CLASS,
 401                 USER_JVM_OPTIONS,
 402                 VERSION
 403         );
 404     }
 405 
 406     @Override
 407     public File execute(Map<String, ? super Object> params, File outputParentDir) {
 408         return doBundle(params, outputParentDir, false);
 409     }
 410 
 411     @Override
 412     protected String getCacheLocation(Map<String, ? super Object> params) {
 413         return "$CACHEDIR/";
 414     }
 415 
 416     @Override
 417     public void extractRuntimeFlags(Map<String, ? super Object> params) {
 418         if (params.containsKey(".runtime.autodetect")) return;
 419 
 420         params.put(".runtime.autodetect", "attempted");
 421         RelativeFileSet runtime = LINUX_RUNTIME.fetchFrom(params);
 422         String commandline;
 423         if (runtime == null) {
 424             //System JRE, report nothing useful
 425             params.put(".runtime.autodetect", "systemjre");
 426         } else {
 427             File runtimePath = runtime.getBaseDirectory();
 428             File launcherPath = new File(runtimePath, "bin/java");
 429 
 430             ProcessBuilder pb = new ProcessBuilder(launcherPath.getAbsolutePath(), "-version");
 431             try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
 432                 try (PrintStream pout = new PrintStream(baos)) {
 433                     IOUtils.exec(pb, Log.isDebug(), true, pout);
 434                 }
 435 
 436                 commandline = baos.toString();
 437             } catch (IOException e) {
 438                 e.printStackTrace();
 439                 params.put(".runtime.autodetect", "failed");
 440                 return;
 441             }
 442             AbstractImageBundler.extractFlagsFromVersion(params, commandline);
 443             params.put(".runtime.autodetect", "succeeded");
 444         }
 445     }
 446 }


  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.oracle.tools.packager.linux;
  27 
  28 import com.oracle.tools.packager.AbstractImageBundler;
  29 import com.oracle.tools.packager.BundlerParamInfo;
  30 import com.oracle.tools.packager.ConfigException;
  31 import com.oracle.tools.packager.IOUtils;
  32 import com.oracle.tools.packager.JLinkBundlerHelper;
  33 import com.oracle.tools.packager.JreUtils;
  34 import com.oracle.tools.packager.JreUtils.Rule;

  35 import com.oracle.tools.packager.Log;


  36 import com.oracle.tools.packager.RelativeFileSet;
  37 import com.oracle.tools.packager.StandardBundlerParam;
  38 import com.oracle.tools.packager.UnsupportedPlatformException;
  39 import com.sun.javafx.tools.packager.bundlers.BundleParams;
  40 import jdk.tools.jlink.builder.ImageBuilder;
  41 import jdk.packager.builders.linux.LinuxAppImageBuilder;
  42 

  43 import java.io.File;

  44 import java.io.IOException;

  45 import java.net.MalformedURLException;
  46 import java.net.URL;
  47 import java.text.MessageFormat;
  48 import java.util.Arrays;
  49 import java.util.Collection;
  50 import java.util.Map;
  51 import java.util.ResourceBundle;
  52 
  53 import static com.oracle.tools.packager.StandardBundlerParam.*;
  54 
  55 public class LinuxAppBundler extends AbstractImageBundler {
  56 
  57     private static final ResourceBundle I18N =
  58             ResourceBundle.getBundle(LinuxAppBundler.class.getName());
  59 
  60     protected static final String LINUX_BUNDLER_PREFIX =
  61             BUNDLER_PREFIX + "linux" + File.separator;
  62     private static final String EXECUTABLE_NAME = "JavaAppLauncher";

  63 
  64     public static final BundlerParamInfo<File> ICON_PNG = new StandardBundlerParam<>(
  65             I18N.getString("param.icon-png.name"),
  66             I18N.getString("param.icon-png.description"),
  67             "icon.png",
  68             File.class,
  69             params -> {
  70                 File f = ICON.fetchFrom(params);
  71                 if (f != null && !f.getName().toLowerCase().endsWith(".png")) {
  72                     Log.info(MessageFormat.format(I18N.getString("message.icon-not-png"), f));
  73                     return null;
  74                 }
  75                 return f;
  76             },
  77             (s, p) -> new File(s));
  78 
  79     public static final BundlerParamInfo<URL> RAW_EXECUTABLE_URL = new StandardBundlerParam<>(
  80             I18N.getString("param.raw-executable-url.name"),
  81             I18N.getString("param.raw-executable-url.description"),
  82             "linux.launcher.url",


 136             } else {
 137                 throw new ConfigException(re);
 138             }
 139         }
 140     }
 141 
 142     //used by chained bundlers to reuse validation logic
 143     boolean doValidate(Map<String, ? super Object> p) throws UnsupportedPlatformException, ConfigException {
 144         if (!System.getProperty("os.name").toLowerCase().startsWith("linux")) {
 145             throw new UnsupportedPlatformException();
 146         }
 147 
 148         imageBundleValidation(p);
 149 
 150         if (RAW_EXECUTABLE_URL.fetchFrom(p) == null) {
 151             throw new ConfigException(
 152                     I18N.getString("error.no-linux-resources"),
 153                     I18N.getString("error.no-linux-resources.advice"));
 154         }
 155 









 156         return true;
 157     }
 158 
 159     //it is static for the sake of sharing with "installer" bundlers
 160     // that may skip calls to validate/bundle in this class!
 161     public static File getRootDir(File outDir, Map<String, ? super Object> p) {
 162         return new File(outDir, APP_FS_NAME.fetchFrom(p));
 163     }
 164 




 165     public static String getLauncherCfgName(Map<String, ? super Object> p) {
 166         return "app/" + APP_FS_NAME.fetchFrom(p) +".cfg";
 167     }
 168 
 169     File doBundle(Map<String, ? super Object> p, File outputDirectory, boolean dependentTask) {

 170         try {
 171             if (!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) {
 172                 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), outputDirectory.getAbsolutePath()));
 173             }
 174             if (!outputDirectory.canWrite()) {
 175                 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-write-to-output-dir"), outputDirectory.getAbsolutePath()));
 176             }
 177 
 178             // Create directory structure
 179             File rootDirectory = getRootDir(outputDirectory, p);
 180             IOUtils.deleteRecursive(rootDirectory);
 181             rootDirectory.mkdirs();
 182 
 183             if (!dependentTask) {
 184                 Log.info(MessageFormat.format(I18N.getString("message.creating-bundle-location"), rootDirectory.getAbsolutePath()));
 185             }
 186 
 187             if (!p.containsKey(JLinkBundlerHelper.JLINK_BUILDER.getID())) {
 188                 p.put(JLinkBundlerHelper.JLINK_BUILDER.getID(), "linuxapp-image-builder");

















 189             }
 190 
 191             ImageBuilder imageBuilder = new LinuxAppImageBuilder(p, outputDirectory.toPath());
 192             JLinkBundlerHelper.execute(p, outputDirectory, imageBuilder);






 193 
 194             return rootDirectory;
 195         } catch (IOException ex) {
 196             Log.info("Exception: "+ex);
 197             Log.debug(ex);
 198             return null;
 199         }
 200     }
 201 





























































































































 202     @Override
 203     public String getName() {
 204         return I18N.getString("bundler.name");
 205     }
 206 
 207     @Override
 208     public String getDescription() {
 209         return I18N.getString("bundler.description");
 210     }
 211 
 212     @Override
 213     public String getID() {
 214         return "linux.app";
 215     }
 216 
 217     @Override
 218     public String getBundleType() {
 219         return "IMAGE";
 220     }
 221 


 229                 APP_NAME,
 230                 APP_RESOURCES,
 231                 // APP_RESOURCES_LIST, // ??
 232                 ARGUMENTS,
 233                 CLASSPATH,
 234                 JVM_OPTIONS,
 235                 JVM_PROPERTIES,
 236                 LINUX_RUNTIME,
 237                 MAIN_CLASS,
 238                 MAIN_JAR,
 239                 PREFERENCES_ID,
 240                 PRELOADER_CLASS,
 241                 USER_JVM_OPTIONS,
 242                 VERSION
 243         );
 244     }
 245 
 246     @Override
 247     public File execute(Map<String, ? super Object> params, File outputParentDir) {
 248         return doBundle(params, outputParentDir, false);




































 249     }
 250 }
< prev index next >