1 /* 2 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 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 package com.oracle.tools.packager; 26 27 import java.io.File; 28 import java.io.FileOutputStream; 29 import java.io.IOException; 30 import java.io.PrintStream; 31 import java.nio.file.Files; 32 import java.text.MessageFormat; 33 import java.util.Arrays; 34 import java.util.List; 35 import java.util.Map; 36 import java.util.ResourceBundle; 37 import java.util.regex.Pattern; 38 39 import static com.oracle.tools.packager.StandardBundlerParam.*; 40 import static com.oracle.tools.packager.StandardBundlerParam.ARGUMENTS; 41 42 /** 43 * Common utility methods used by app image bundlers. 44 */ 45 public abstract class AbstractImageBundler extends AbstractBundler { 46 47 private static final ResourceBundle I18N = 48 ResourceBundle.getBundle(AbstractImageBundler.class.getName()); 49 50 public static final String CFG_FORMAT_PROPERTIES="prop"; 51 public static final String CFG_FORMAT_INI="ini"; 52 53 public static final BundlerParamInfo<String> LAUNCHER_CFG_FORMAT = 54 new StandardBundlerParam<>( 55 I18N.getString("param.launcher-cfg-format.name"), 56 I18N.getString("param.launcher-cfg-format.description"), 57 "launcher-cfg-format", 58 String.class, 59 params -> "ini", 60 (s, p) -> s); 61 62 //helper method to test if required files are present in the runtime 63 public void testRuntime(RelativeFileSet runtime, String[] file) throws ConfigException { 64 if (runtime == null) { 65 return; //null runtime is ok (request to use system) 66 } 67 68 Pattern[] weave = Arrays.stream(file).map(Pattern::compile).toArray(Pattern[]::new); 69 70 if (!runtime.getIncludedFiles().stream().anyMatch(s -> 71 Arrays.stream(weave).anyMatch(pattern -> pattern.matcher(s).matches()) 72 )) { 73 throw new ConfigException( 74 MessageFormat.format(I18N.getString("error.jre-missing-file"), Arrays.toString(file)), 75 I18N.getString("error.jre-missing-file.advice")); 76 } 77 } 78 79 public void writeCfgFile(Map<String, ? super Object> params, File cfgFileName, String runtimeLocation) throws IOException { 80 cfgFileName.delete(); 81 82 PrintStream out = new PrintStream(cfgFileName); 83 84 out.println("[Application]"); 85 out.println("app.name=" + APP_NAME.fetchFrom(params)); 86 out.println("app.mainjar=" + MAIN_JAR.fetchFrom(params).getIncludedFiles().iterator().next()); 87 out.println("app.version=" + VERSION.fetchFrom(params)); 88 out.println("app.preferences.id=" + PREFERENCES_ID.fetchFrom(params)); 89 out.println("app.mainclass=" + 90 MAIN_CLASS.fetchFrom(params).replaceAll("\\.", "/")); 91 out.println("app.classpath=" + 92 String.join(File.pathSeparator, CLASSPATH.fetchFrom(params).split("[ :;]"))); 93 out.println("app.runtime=" + runtimeLocation); 94 out.println("app.identifier=" + IDENTIFIER.fetchFrom(params)); 95 96 97 out.println(); 98 out.println("[JVMOptions]"); 99 List<String> jvmargs = JVM_OPTIONS.fetchFrom(params); 100 for (String arg : jvmargs) { 101 out.println(arg); 102 } 103 Map<String, String> jvmProps = JVM_PROPERTIES.fetchFrom(params); 104 for (Map.Entry<String, String> property : jvmProps.entrySet()) { 105 out.println("-D" + property.getKey() + "=" + property.getValue()); 106 } 107 String preloader = PRELOADER_CLASS.fetchFrom(params); 108 if (preloader != null) { 109 out.println("-Djavafx.preloader="+preloader); 110 } 111 112 113 out.println(); 114 out.println("[JVMUserOptions]"); 115 Map<String, String> overridableJVMOptions = USER_JVM_OPTIONS.fetchFrom(params); 116 for (Map.Entry<String, String> arg: overridableJVMOptions.entrySet()) { 117 if (arg.getKey() == null || arg.getValue() == null) { 118 Log.info(I18N.getString("message.jvm-user-arg-is-null")); 119 } else { 120 out.println(arg.getKey().replaceAll("([\\=])", "\\$1") + "=" + arg.getValue()); 121 } 122 } 123 124 125 if (UNLOCK_COMMERCIAL_FEATURES.fetchFrom(params) && ENABLE_APP_CDS.fetchFrom(params)) { 126 prepareAppCDS(params, out); 127 } 128 129 out.println(); 130 out.println("[ArgOptions]"); 131 List<String> args = ARGUMENTS.fetchFrom(params); 132 for (String arg : args) { 133 out.println(arg); 134 } 135 136 137 out.close(); 138 } 139 140 protected abstract String getCacheLocation(Map<String, ? super Object> params); 141 142 void prepareAppCDS(Map<String, ? super Object> params, PrintStream out) throws IOException { 143 //TODO check 8u40 or later 144 145 File tempDir = Files.createTempDirectory("javapackager").toFile(); 146 tempDir.deleteOnExit(); 147 File classList = new File(tempDir, APP_FS_NAME.fetchFrom(params) + ".classlist"); 148 149 try (FileOutputStream fos = new FileOutputStream(classList); 150 PrintStream ps = new PrintStream(fos)) { 151 for (String className : APP_CDS_CLASS_ROOTS.fetchFrom(params)) { 152 String slashyName = className.replace(".", "/"); 153 ps.println(slashyName); 154 } 155 } 156 APP_RESOURCES_LIST.fetchFrom(params).add(new RelativeFileSet(classList.getParentFile(), Arrays.asList(classList))); 157 158 out.println(); 159 out.println("[AppCDSJVMOptions]"); 160 out.println("-XX:+UnlockCommercialFeatures"); 161 out.print("-XX:SharedArchiveFile="); 162 out.print(getCacheLocation(params)); 163 out.print(APP_FS_NAME.fetchFrom(params)); 164 out.println(".jpa"); 165 out.println("-Xshare:on"); 166 out.println("-XX:+UseAppCDS"); 167 if (Log.isDebug()) { 168 out.println("-verbose:class"); 169 out.println("-XX:+TraceClassPaths"); 170 out.println("-XX:+UnlockDiagnosticVMOptions"); 171 } 172 out.println(""); 173 174 out.println("[AppCDSGenerateCacheJVMOptions]"); 175 out.println("-XX:+UnlockCommercialFeatures"); 176 out.println("-Xshare:dump"); 177 out.println("-XX:+UseAppCDS"); 178 out.print("-XX:SharedArchiveFile="); 179 out.print(getCacheLocation(params)); 180 out.print(APP_FS_NAME.fetchFrom(params)); 181 out.println(".jpa"); 182 out.println("-XX:SharedClassListFile=$PACKAGEDIR/" + APP_FS_NAME.fetchFrom(params) + ".classlist"); 183 if (Log.isDebug()) { 184 out.println("-XX:+UnlockDiagnosticVMOptions"); 185 } 186 } 187 }