1 /* 2 * Copyright (c) 2012, 2016, 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 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.JreUtils; 33 import com.oracle.tools.packager.JreUtils.Rule; 34 import com.oracle.tools.packager.Log; 35 import com.oracle.tools.packager.Platform; 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.packager.internal.legacy.builders.linux.LinuxAppImageBuilder; 41 42 import jdk.packager.internal.legacy.JLinkBundlerHelper; 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 com.oracle.tools.packager.StandardBundlerParam.*; 55 import jdk.packager.internal.legacy.builders.AbstractAppImageBuilder; 56 57 public class LinuxAppBundler extends AbstractImageBundler { 58 59 private static final ResourceBundle I18N = 60 ResourceBundle.getBundle(LinuxAppBundler.class.getName()); 61 62 protected static final String LINUX_BUNDLER_PREFIX = 63 BUNDLER_PREFIX + "linux" + File.separator; 64 private static final String EXECUTABLE_NAME = "JavaAppLauncher"; 65 66 public static final BundlerParamInfo<File> ICON_PNG = 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(I18N.getString("message.icon-not-png"), f)); 75 return null; 76 } 77 return f; 78 }, 79 (s, p) -> new File(s)); 80 81 public static final BundlerParamInfo<URL> RAW_EXECUTABLE_URL = new StandardBundlerParam<>( 82 I18N.getString("param.raw-executable-url.name"), 83 I18N.getString("param.raw-executable-url.description"), 84 "linux.launcher.url", 85 URL.class, 86 params -> LinuxResources.class.getResource(EXECUTABLE_NAME), 87 (s, p) -> { 88 try { 89 return new URL(s); 90 } catch (MalformedURLException e) { 91 Log.info(e.toString()); 92 return null; 93 } 94 }); 95 96 //Subsetting of JRE is restricted. 97 //JRE README defines what is allowed to strip: 98 // http://www.oracle.com/technetwork/java/javase/jre-8-readme-2095710.html 99 // 100 public static final BundlerParamInfo<Rule[]> LINUX_JRE_RULES = new StandardBundlerParam<>( 101 "", 102 "", 103 ".linux.runtime.rules", 104 Rule[].class, 105 params -> new Rule[]{ 106 Rule.prefixNeg("/bin"), 107 Rule.prefixNeg("/plugin"), 108 //Rule.prefixNeg("/lib/ext"), //need some of jars there for https to work 109 Rule.suffix("deploy.jar"), //take deploy.jar 110 Rule.prefixNeg("/lib/deploy"), 111 Rule.prefixNeg("/lib/desktop"), 112 Rule.substrNeg("libnpjp2.so") 113 }, 114 (s, p) -> null 115 ); 116 117 public static final BundlerParamInfo<RelativeFileSet> LINUX_RUNTIME = new StandardBundlerParam<>( 118 I18N.getString("param.runtime.name"), 119 I18N.getString("param.runtime.description"), 120 BundleParams.PARAM_RUNTIME, 121 RelativeFileSet.class, 122 params -> JreUtils.extractJreAsRelativeFileSet(System.getProperty("java.home"), 123 LINUX_JRE_RULES.fetchFrom(params)), 124 (s, p) -> JreUtils.extractJreAsRelativeFileSet(s, LINUX_JRE_RULES.fetchFrom(p)) 125 ); 126 127 @Override 128 public boolean validate(Map<String, ? super Object> p) throws UnsupportedPlatformException, ConfigException { 129 try { 130 if (p == null) throw new ConfigException( 131 I18N.getString("error.parameters-null"), 132 I18N.getString("error.parameters-null.advice")); 133 134 return doValidate(p); 135 } catch (RuntimeException re) { 136 if (re.getCause() instanceof ConfigException) { 137 throw (ConfigException) re.getCause(); 138 } else { 139 throw new ConfigException(re); 140 } 141 } 142 } 143 144 //used by chained bundlers to reuse validation logic 145 boolean doValidate(Map<String, ? super Object> p) throws UnsupportedPlatformException, ConfigException { 146 if (Platform.getPlatform() != Platform.LINUX) { 147 throw new UnsupportedPlatformException(); 148 } 149 150 imageBundleValidation(p); 151 152 if (RAW_EXECUTABLE_URL.fetchFrom(p) == null) { 153 throw new ConfigException( 154 I18N.getString("error.no-linux-resources"), 155 I18N.getString("error.no-linux-resources.advice")); 156 } 157 158 return true; 159 } 160 161 //it is static for the sake of sharing with "installer" bundlers 162 // that may skip calls to validate/bundle in this class! 163 public static File getRootDir(File outDir, Map<String, ? super Object> p) { 164 return new File(outDir, APP_FS_NAME.fetchFrom(p)); 165 } 166 167 public static String getLauncherCfgName(Map<String, ? super Object> p) { 168 return "app/" + APP_FS_NAME.fetchFrom(p) +".cfg"; 169 } 170 171 File doBundle(Map<String, ? super Object> p, File outputDirectory, boolean dependentTask) { 172 try { 173 if (!outputDirectory.isDirectory() && !outputDirectory.mkdirs()) { 174 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-create-output-dir"), outputDirectory.getAbsolutePath())); 175 } 176 if (!outputDirectory.canWrite()) { 177 throw new RuntimeException(MessageFormat.format(I18N.getString("error.cannot-write-to-output-dir"), outputDirectory.getAbsolutePath())); 178 } 179 180 // Create directory structure 181 File rootDirectory = getRootDir(outputDirectory, p); 182 IOUtils.deleteRecursive(rootDirectory); 183 rootDirectory.mkdirs(); 184 185 if (!dependentTask) { 186 Log.info(MessageFormat.format(I18N.getString("message.creating-bundle-location"), rootDirectory.getAbsolutePath())); 187 } 188 189 if (!p.containsKey(JLinkBundlerHelper.JLINK_BUILDER.getID())) { 190 p.put(JLinkBundlerHelper.JLINK_BUILDER.getID(), "linuxapp-image-builder"); 191 } 192 193 AbstractAppImageBuilder appBuilder = new LinuxAppImageBuilder(p, outputDirectory.toPath()); 194 JLinkBundlerHelper.execute(p, appBuilder); 195 196 return rootDirectory; 197 } catch (IOException ex) { 198 Log.info("Exception: "+ex); 199 Log.debug(ex); 200 return null; 201 } catch (Exception ex) { 202 Log.info("Exception: "+ex); 203 Log.debug(ex); 204 return null; 205 } 206 } 207 208 @Override 209 public String getName() { 210 return I18N.getString("bundler.name"); 211 } 212 213 @Override 214 public String getDescription() { 215 return I18N.getString("bundler.description"); 216 } 217 218 @Override 219 public String getID() { 220 return "linux.app"; 221 } 222 223 @Override 224 public String getBundleType() { 225 return "IMAGE"; 226 } 227 228 @Override 229 public Collection<BundlerParamInfo<?>> getBundleParameters() { 230 return getAppBundleParameters(); 231 } 232 233 public static Collection<BundlerParamInfo<?>> getAppBundleParameters() { 234 return Arrays.asList( 235 APP_NAME, 236 APP_RESOURCES, 237 // APP_RESOURCES_LIST, // ?? 238 ARGUMENTS, 239 CLASSPATH, 240 JVM_OPTIONS, 241 JVM_PROPERTIES, 242 LINUX_RUNTIME, 243 MAIN_CLASS, 244 MAIN_JAR, 245 PREFERENCES_ID, 246 PRELOADER_CLASS, 247 USER_JVM_OPTIONS, 248 VERSION 249 ); 250 } 251 252 @Override 253 public File execute(Map<String, ? super Object> params, File outputParentDir) { 254 return doBundle(params, outputParentDir, false); 255 } 256 }