1 /* 2 * Copyright (c) 2012, 2018, 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 26 package jdk.packager.internal.linux; 27 28 import jdk.packager.internal.AbstractImageBundler; 29 import jdk.packager.internal.BundlerParamInfo; 30 import jdk.packager.internal.ConfigException; 31 import jdk.packager.internal.IOUtils; 32 import jdk.packager.internal.Log; 33 import jdk.packager.internal.Platform; 34 import jdk.packager.internal.RelativeFileSet; 35 import jdk.packager.internal.StandardBundlerParam; 36 import jdk.packager.internal.Arguments; 37 import jdk.packager.internal.UnsupportedPlatformException; 38 import jdk.packager.internal.bundlers.BundleParams; 39 import jdk.packager.internal.builders.linux.LinuxAppImageBuilder; 40 import jdk.packager.internal.resources.linux.LinuxResources; 41 import jdk.packager.internal.JLinkBundlerHelper; 42 import jdk.packager.internal.builders.AbstractAppImageBuilder; 43 44 import java.io.File; 45 import java.io.IOException; 46 import java.net.MalformedURLException; 47 import java.net.URL; 48 import java.text.MessageFormat; 49 import java.util.Arrays; 50 import java.util.Collection; 51 import java.util.Map; 52 import java.util.ResourceBundle; 53 54 import static jdk.packager.internal.StandardBundlerParam.*; 55 56 public class LinuxAppBundler extends AbstractImageBundler { 57 58 private static final ResourceBundle I18N = ResourceBundle.getBundle( 59 "jdk.packager.internal.resources.linux.LinuxAppBundler"); 60 61 protected static final String LINUX_BUNDLER_PREFIX = 62 BUNDLER_PREFIX + "linux" + File.separator; 63 private static final String EXECUTABLE_NAME = "JavaAppLauncher"; 64 65 public static final BundlerParamInfo<File> ICON_PNG = 66 new StandardBundlerParam<>( 67 I18N.getString("param.icon-png.name"), 68 I18N.getString("param.icon-png.description"), 69 "icon.png", 70 File.class, 71 params -> { 72 File f = ICON.fetchFrom(params); 73 if (f != null && !f.getName().toLowerCase().endsWith(".png")) { 74 Log.info(MessageFormat.format( 75 I18N.getString("message.icon-not-png"), f)); 76 return null; 77 } 78 return f; 79 }, 80 (s, p) -> new File(s)); 81 82 public static final BundlerParamInfo<String> LINUX_INSTALL_DIR = 83 new StandardBundlerParam<>( 84 I18N.getString("param.linux-install-dir.name"), 85 I18N.getString("param.linux-install-dir.description"), 86 "linux-install-dir", 87 String.class, 88 params -> { 89 String dir = INSTALL_DIR.fetchFrom(params); 90 if (dir != null) { 91 if (dir.endsWith("/")) { 92 dir = dir.substring(0, dir.length()-1); 93 } 94 return dir; 95 } 96 return "/opt"; 97 }, 98 (s, p) -> s 99 ); 100 101 public static final BundlerParamInfo<String> LINUX_PACKAGE_DEPENDENCIES = 102 new StandardBundlerParam<>( 103 I18N.getString("param.linux-package-dependencies.name"), 104 I18N.getString("param.linux-package-dependencies.description"), 105 Arguments.CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId(), 106 String.class, 107 params -> { 108 return ""; 109 }, 110 (s, p) -> s 111 ); 112 113 @Override 114 public boolean validate(Map<String, ? super Object> p) 115 throws UnsupportedPlatformException, ConfigException { 116 try { 117 if (p == null) throw new ConfigException( 118 I18N.getString("error.parameters-null"), 119 I18N.getString("error.parameters-null.advice")); 120 121 return doValidate(p); 122 } catch (RuntimeException re) { 123 if (re.getCause() instanceof ConfigException) { 124 throw (ConfigException) re.getCause(); 125 } else { 126 throw new ConfigException(re); 127 } 128 } 129 } 130 131 //used by chained bundlers to reuse validation logic 132 boolean doValidate(Map<String, ? super Object> p) 133 throws UnsupportedPlatformException, ConfigException { 134 if (Platform.getPlatform() != Platform.LINUX) { 135 throw new UnsupportedPlatformException(); 136 } 137 138 imageBundleValidation(p); 139 140 return true; 141 } 142 143 // it is static for the sake of sharing with "installer" bundlers 144 // that may skip calls to validate/bundle in this class! 145 public static File getRootDir(File outDir, Map<String, ? super Object> p) { 146 return new File(outDir, APP_FS_NAME.fetchFrom(p)); 147 } 148 149 public static String getLauncherCfgName(Map<String, ? super Object> p) { 150 return "app/" + APP_FS_NAME.fetchFrom(p) +".cfg"; 151 } 152 153 File doBundle(Map<String, ? super Object> p, File outputDirectory, 154 boolean dependentTask) { 155 if (Arguments.CREATE_JRE_INSTALLER.fetchFrom(p)) { 156 return doJreBundle(p, outputDirectory, dependentTask); 157 } else { 158 return doAppBundle(p, outputDirectory, dependentTask); 159 } 160 } 161 162 private File doJreBundle(Map<String, ? super Object> p, 163 File outputDirectory, boolean dependentTask) { 164 try { 165 File rootDirectory = createRoot(p, outputDirectory, dependentTask); 166 AbstractAppImageBuilder appBuilder = new LinuxAppImageBuilder( 167 APP_NAME.fetchFrom(p), outputDirectory.toPath()); 168 File predefined = PREDEFINED_RUNTIME_IMAGE.fetchFrom(p); 169 if (predefined == null ) { 170 JLinkBundlerHelper.generateServerJre(p, appBuilder); 171 } else { 172 return predefined; 173 } 174 return rootDirectory; 175 } catch (Exception ex) { 176 Log.info("Exception: "+ex); 177 Log.debug(ex); 178 return null; 179 } 180 } 181 182 private File doAppBundle(Map<String, ? super Object> p, 183 File outputDirectory, boolean dependentTask) { 184 try { 185 File rootDirectory = createRoot(p, outputDirectory, dependentTask); 186 AbstractAppImageBuilder appBuilder = new LinuxAppImageBuilder(p, 187 outputDirectory.toPath()); 188 if (PREDEFINED_RUNTIME_IMAGE.fetchFrom(p) == null ) { 189 JLinkBundlerHelper.execute(p, appBuilder); 190 } else { 191 StandardBundlerParam.copyPredefinedRuntimeImage(p, appBuilder); 192 } 193 return rootDirectory; 194 } catch (Exception ex) { 195 Log.info("Exception: "+ex); 196 Log.debug(ex); 197 return null; 198 } 199 } 200 201 private File createRoot(Map<String, ? super Object> p, 202 File outputDirectory, boolean dependentTask) throws IOException { 203 if (!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) { 204 throw new RuntimeException(MessageFormat.format( 205 I18N.getString("error.cannot-create-output-dir"), 206 outputDirectory.getAbsolutePath())); 207 } 208 if (!outputDirectory.canWrite()) { 209 throw new RuntimeException(MessageFormat.format( 210 I18N.getString("error.cannot-write-to-output-dir"), 211 outputDirectory.getAbsolutePath())); 212 } 213 214 // Create directory structure 215 File rootDirectory = getRootDir(outputDirectory, p); 216 IOUtils.deleteRecursive(rootDirectory); 217 rootDirectory.mkdirs(); 218 219 if (!dependentTask) { 220 Log.info(MessageFormat.format(I18N.getString( 221 "message.creating-bundle-location"), 222 rootDirectory.getAbsolutePath())); 223 } 224 225 if (!p.containsKey(JLinkBundlerHelper.JLINK_BUILDER.getID())) { 226 p.put(JLinkBundlerHelper.JLINK_BUILDER.getID(), 227 "linuxapp-image-builder"); 228 } 229 230 return rootDirectory; 231 } 232 233 @Override 234 public String getName() { 235 return I18N.getString("bundler.name"); 236 } 237 238 @Override 239 public String getDescription() { 240 return I18N.getString("bundler.description"); 241 } 242 243 @Override 244 public String getID() { 245 return "linux.app"; 246 } 247 248 @Override 249 public String getBundleType() { 250 return "IMAGE"; 251 } 252 253 @Override 254 public Collection<BundlerParamInfo<?>> getBundleParameters() { 255 return getAppBundleParameters(); 256 } 257 258 public static Collection<BundlerParamInfo<?>> getAppBundleParameters() { 259 return Arrays.asList( 260 APP_NAME, 261 APP_RESOURCES, 262 ARGUMENTS, 263 CLASSPATH, 264 JVM_OPTIONS, 265 JVM_PROPERTIES, 266 MAIN_CLASS, 267 MAIN_JAR, 268 PREFERENCES_ID, 269 VERSION, 270 VERBOSE 271 ); 272 } 273 274 @Override 275 public File execute(Map<String, ? super Object> params, 276 File outputParentDir) { 277 return doBundle(params, outputParentDir, false); 278 } 279 280 @Override 281 public boolean supported() { 282 return (Platform.getPlatform() == Platform.LINUX); 283 } 284 }