< prev index next >

src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacAppBundler.java

Print this page




   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.jpackage.internal;
  27 
  28 import java.io.File;
  29 import java.io.IOException;
  30 import java.math.BigInteger;
  31 import java.text.MessageFormat;
  32 import java.util.Arrays;
  33 import java.util.Collection;
  34 import java.util.HashMap;
  35 import java.util.Map;
  36 import java.util.Optional;
  37 import java.util.ResourceBundle;
  38 
  39 import static jdk.jpackage.internal.StandardBundlerParam.*;
  40 import static jdk.jpackage.internal.MacBaseInstallerBundler.*;
  41 import jdk.jpackage.internal.AbstractAppImageBuilder;
  42 
  43 public class MacAppBundler extends AbstractImageBundler {
  44 
  45     private static final ResourceBundle I18N = ResourceBundle.getBundle(
  46             "jdk.jpackage.internal.resources.MacResources");
  47 
  48     private static final String TEMPLATE_BUNDLE_ICON = "GenericApp.icns";
  49 
  50     public static Map<String, String> getMacCategories() {
  51         Map<String, String> map = new HashMap<>();
  52         map.put("Business", "public.app-category.business");
  53         map.put("Developer Tools", "public.app-category.developer-tools");
  54         map.put("Education", "public.app-category.education");
  55         map.put("Entertainment", "public.app-category.entertainment");
  56         map.put("Finance", "public.app-category.finance");
  57         map.put("Games", "public.app-category.games");
  58         map.put("Graphics & Design", "public.app-category.graphics-design");
  59         map.put("Healthcare & Fitness",
  60                 "public.app-category.healthcare-fitness");
  61         map.put("Lifestyle", "public.app-category.lifestyle");
  62         map.put("Medical", "public.app-category.medical");
  63         map.put("Music", "public.app-category.music");
  64         map.put("News", "public.app-category.news");
  65         map.put("Photography", "public.app-category.photography");
  66         map.put("Productivity", "public.app-category.productivity");
  67         map.put("Reference", "public.app-category.reference");
  68         map.put("Social Networking", "public.app-category.social-networking");
  69         map.put("Sports", "public.app-category.sports");
  70         map.put("Travel", "public.app-category.travel");
  71         map.put("Utilities", "public.app-category.utilities");
  72         map.put("Video", "public.app-category.video");
  73         map.put("Weather", "public.app-category.weather");
  74 
  75         map.put("Action Games", "public.app-category.action-games");
  76         map.put("Adventure Games", "public.app-category.adventure-games");
  77         map.put("Arcade Games", "public.app-category.arcade-games");
  78         map.put("Board Games", "public.app-category.board-games");
  79         map.put("Card Games", "public.app-category.card-games");
  80         map.put("Casino Games", "public.app-category.casino-games");
  81         map.put("Dice Games", "public.app-category.dice-games");
  82         map.put("Educational Games", "public.app-category.educational-games");
  83         map.put("Family Games", "public.app-category.family-games");
  84         map.put("Kids Games", "public.app-category.kids-games");
  85         map.put("Music Games", "public.app-category.music-games");
  86         map.put("Puzzle Games", "public.app-category.puzzle-games");
  87         map.put("Racing Games", "public.app-category.racing-games");
  88         map.put("Role Playing Games", "public.app-category.role-playing-games");
  89         map.put("Simulation Games", "public.app-category.simulation-games");
  90         map.put("Sports Games", "public.app-category.sports-games");
  91         map.put("Strategy Games", "public.app-category.strategy-games");
  92         map.put("Trivia Games", "public.app-category.trivia-games");
  93         map.put("Word Games", "public.app-category.word-games");
  94 
  95         return map;
  96     }
  97 
  98     public static final EnumeratedBundlerParam<String> MAC_CATEGORY =
  99             new EnumeratedBundlerParam<>(
 100                     Arguments.CLIOptions.MAC_APP_STORE_CATEGORY.getId(),
 101                     String.class,
 102                     params -> "Unknown",
 103                     (s, p) -> s,
 104                     getMacCategories(),
 105                     false //strict - for MacStoreBundler this should be strict
 106             );
 107 
 108     public static final BundlerParamInfo<String> MAC_CF_BUNDLE_NAME =
 109             new StandardBundlerParam<>(
 110                     Arguments.CLIOptions.MAC_BUNDLE_NAME.getId(),
 111                     String.class,
 112                     params -> null,
 113                     (s, p) -> s);
 114 
 115     public static final BundlerParamInfo<String> MAC_CF_BUNDLE_IDENTIFIER =
 116             new StandardBundlerParam<>(
 117                     Arguments.CLIOptions.MAC_BUNDLE_IDENTIFIER.getId(),
 118                     String.class,
 119                     IDENTIFIER::fetchFrom,
 120                     (s, p) -> s);
 121 
 122     public static final BundlerParamInfo<String> MAC_CF_BUNDLE_VERSION =
 123             new StandardBundlerParam<>(
 124                     "mac.CFBundleVersion",
 125                     String.class,
 126                     p -> {
 127                         String s = VERSION.fetchFrom(p);
 128                         if (validCFBundleVersion(s)) {
 129                             return s;
 130                         } else {
 131                             return "100";
 132                         }
 133                     },
 134                     (s, p) -> s);
 135 
 136     public static final BundlerParamInfo<String> DEFAULT_ICNS_ICON =
 137             new StandardBundlerParam<>(
 138             ".mac.default.icns",
 139             String.class,
 140             params -> TEMPLATE_BUNDLE_ICON,
 141             (s, p) -> s);
 142 
 143     public static final BundlerParamInfo<String> DEVELOPER_ID_APP_SIGNING_KEY =
 144             new StandardBundlerParam<>(
 145             "mac.signing-key-developer-id-app",
 146             String.class,
 147             params -> {
 148                     String result = MacBaseInstallerBundler.findKey(
 149                             "Developer ID Application: "
 150                             + SIGNING_KEY_USER.fetchFrom(params),
 151                             SIGNING_KEYCHAIN.fetchFrom(params),
 152                             VERBOSE.fetchFrom(params));
 153                     if (result != null) {
 154                         MacCertificate certificate = new MacCertificate(result,
 155                                 VERBOSE.fetchFrom(params));
 156 
 157                         if (!certificate.isValid()) {
 158                             Log.error(MessageFormat.format(I18N.getString(
 159                                     "error.certificate.expired"), result));
 160                         }
 161                     }
 162 
 163                     return result;
 164                 },
 165             (s, p) -> s);
 166 
 167     public static final BundlerParamInfo<String> BUNDLE_ID_SIGNING_PREFIX =
 168             new StandardBundlerParam<>(
 169             Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId(),
 170             String.class,
 171             params -> IDENTIFIER.fetchFrom(params) + ".",
 172             (s, p) -> s);
 173 
 174     public static final BundlerParamInfo<File> ICON_ICNS =
 175             new StandardBundlerParam<>(


 224             }
 225             if (p.length > 2) {
 226                 n = new BigInteger(p[2]);
 227                 if (BigInteger.ZERO.compareTo(n) > 0) {
 228                     Log.verbose(I18N.getString(
 229                             "message.version-string-no-negative-numbers"));
 230                     return false;
 231                 }
 232             }
 233         } catch (NumberFormatException ne) {
 234             Log.verbose(I18N.getString("message.version-string-numbers-only"));
 235             Log.verbose(ne);
 236             return false;
 237         }
 238 
 239         return true;
 240     }
 241 
 242     @Override
 243     public boolean validate(Map<String, ? super Object> params)
 244             throws UnsupportedPlatformException, ConfigException {
 245         try {
 246             return doValidate(params);
 247         } catch (RuntimeException re) {
 248             if (re.getCause() instanceof ConfigException) {
 249                 throw (ConfigException) re.getCause();
 250             } else {
 251                 throw new ConfigException(re);
 252             }
 253         }
 254     }
 255 
 256     private boolean doValidate(Map<String, ? super Object> p)
 257             throws UnsupportedPlatformException, ConfigException {
 258         if (Platform.getPlatform() != Platform.MAC) {
 259             throw new UnsupportedPlatformException();
 260         }
 261 
 262         imageBundleValidation(p);
 263 
 264         if (StandardBundlerParam.getPredefinedAppImage(p) != null) {
 265             return true;
 266         }
 267 
 268         // validate short version
 269         if (!validCFBundleVersion(MAC_CF_BUNDLE_VERSION.fetchFrom(p))) {
 270             throw new ConfigException(
 271                     I18N.getString("error.invalid-cfbundle-version"),
 272                     I18N.getString("error.invalid-cfbundle-version.advice"));
 273         }
 274 
 275         // reject explicitly set sign to true and no valid signature key
 276         if (Optional.ofNullable(MacAppImageBuilder.
 277                     SIGN_BUNDLE.fetchFrom(p)).orElse(Boolean.FALSE)) {
 278             String signingIdentity = DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(p);

 279             if (signingIdentity == null) {
 280                 throw new ConfigException(
 281                         I18N.getString("error.explicit-sign-no-cert"),
 282                         I18N.getString("error.explicit-sign-no-cert.advice"));
 283             }














 284         }
 285 
 286         return true;
 287     }
 288 
 289     File doBundle(Map<String, ? super Object> p, File outputDirectory,
 290             boolean dependentTask) throws PackagerException {
 291         if (StandardBundlerParam.isRuntimeInstaller(p)) {
 292             return PREDEFINED_RUNTIME_IMAGE.fetchFrom(p);
 293         } else {
 294             return doAppBundle(p, outputDirectory, dependentTask);
 295         }
 296     }
 297 
 298     File doAppBundle(Map<String, ? super Object> p, File outputDirectory,
 299             boolean dependentTask) throws PackagerException {
 300         try {
 301             File rootDirectory = createRoot(p, outputDirectory, dependentTask,
 302                     APP_NAME.fetchFrom(p) + ".app");
 303             AbstractAppImageBuilder appBuilder =
 304                     new MacAppImageBuilder(p, outputDirectory.toPath());
 305             if (PREDEFINED_RUNTIME_IMAGE.fetchFrom(p) == null ) {
 306                 JLinkBundlerHelper.execute(p, appBuilder);
 307             } else {
 308                 StandardBundlerParam.copyPredefinedRuntimeImage(p, appBuilder);

 309             }
 310             return rootDirectory;
 311         } catch (PackagerException pe) {
 312             throw pe;
 313         } catch (Exception ex) {
 314             Log.verbose(ex);
 315             throw new PackagerException(ex);
 316         }
 317     }
 318 
 319     /////////////////////////////////////////////////////////////////////////
 320     // Implement Bundler
 321     /////////////////////////////////////////////////////////////////////////
 322 
 323     @Override
 324     public String getName() {
 325         return I18N.getString("app.bundler.name");
 326     }
 327 
 328     @Override
 329     public String getDescription() {
 330         return I18N.getString("app.bundler.description");
 331     }
 332 
 333     @Override
 334     public String getID() {
 335         return "mac.app";
 336     }
 337 
 338     @Override
 339     public String getBundleType() {
 340         return "IMAGE";
 341     }
 342 
 343     @Override
 344     public Collection<BundlerParamInfo<?>> getBundleParameters() {
 345         return getAppBundleParameters();
 346     }
 347 
 348     public static Collection<BundlerParamInfo<?>> getAppBundleParameters() {
 349         return Arrays.asList(
 350                 APP_NAME,
 351                 APP_RESOURCES,
 352                 ARGUMENTS,
 353                 BUNDLE_ID_SIGNING_PREFIX,
 354                 CLASSPATH,
 355                 DEVELOPER_ID_APP_SIGNING_KEY,
 356                 ICON_ICNS,
 357                 JAVA_OPTIONS,
 358                 MAC_CATEGORY,
 359                 MAC_CF_BUNDLE_IDENTIFIER,
 360                 MAC_CF_BUNDLE_NAME,
 361                 MAC_CF_BUNDLE_VERSION,
 362                 MAIN_CLASS,
 363                 MAIN_JAR,
 364                 SIGNING_KEYCHAIN,
 365                 VERSION,
 366                 VERBOSE
 367         );
 368     }
 369 
 370 
 371     @Override
 372     public File execute(Map<String, ? super Object> params,
 373             File outputParentDir) throws PackagerException {
 374         return doBundle(params, outputParentDir, false);
 375     }
 376 
 377     @Override
 378     public boolean supported(boolean runtimeInstaller) {
 379         return Platform.getPlatform() == Platform.MAC;





 380     }
 381 
 382 }


   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.incubator.jpackage.internal;
  27 
  28 import java.io.File;
  29 import java.io.IOException;
  30 import java.math.BigInteger;
  31 import java.text.MessageFormat;


  32 import java.util.HashMap;
  33 import java.util.Map;
  34 import java.util.Optional;
  35 import java.util.ResourceBundle;
  36 
  37 import static jdk.incubator.jpackage.internal.StandardBundlerParam.*;
  38 import static jdk.incubator.jpackage.internal.MacBaseInstallerBundler.*;

  39 
  40 public class MacAppBundler extends AbstractImageBundler {
  41 
  42     private static final ResourceBundle I18N = ResourceBundle.getBundle(
  43             "jdk.incubator.jpackage.internal.resources.MacResources");
  44 
  45     private static final String TEMPLATE_BUNDLE_ICON = "java.icns";


























































  46 
  47     public static final BundlerParamInfo<String> MAC_CF_BUNDLE_NAME =
  48             new StandardBundlerParam<>(
  49                     Arguments.CLIOptions.MAC_BUNDLE_NAME.getId(),
  50                     String.class,
  51                     params -> null,
  52                     (s, p) -> s);
  53 







  54     public static final BundlerParamInfo<String> MAC_CF_BUNDLE_VERSION =
  55             new StandardBundlerParam<>(
  56                     "mac.CFBundleVersion",
  57                     String.class,
  58                     p -> {
  59                         String s = VERSION.fetchFrom(p);
  60                         if (validCFBundleVersion(s)) {
  61                             return s;
  62                         } else {
  63                             return "100";
  64                         }
  65                     },
  66                     (s, p) -> s);
  67 
  68     public static final BundlerParamInfo<String> DEFAULT_ICNS_ICON =
  69             new StandardBundlerParam<>(
  70             ".mac.default.icns",
  71             String.class,
  72             params -> TEMPLATE_BUNDLE_ICON,
  73             (s, p) -> s);
  74 
  75     public static final BundlerParamInfo<String> DEVELOPER_ID_APP_SIGNING_KEY =
  76             new StandardBundlerParam<>(
  77             "mac.signing-key-developer-id-app",
  78             String.class,
  79             params -> {
  80                     String result = MacBaseInstallerBundler.findKey(
  81                             "Developer ID Application: "
  82                             + SIGNING_KEY_USER.fetchFrom(params),
  83                             SIGNING_KEYCHAIN.fetchFrom(params),
  84                             VERBOSE.fetchFrom(params));
  85                     if (result != null) {
  86                         MacCertificate certificate = new MacCertificate(result);

  87 
  88                         if (!certificate.isValid()) {
  89                             Log.error(MessageFormat.format(I18N.getString(
  90                                     "error.certificate.expired"), result));
  91                         }
  92                     }
  93 
  94                     return result;
  95                 },
  96             (s, p) -> s);
  97 
  98     public static final BundlerParamInfo<String> BUNDLE_ID_SIGNING_PREFIX =
  99             new StandardBundlerParam<>(
 100             Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId(),
 101             String.class,
 102             params -> IDENTIFIER.fetchFrom(params) + ".",
 103             (s, p) -> s);
 104 
 105     public static final BundlerParamInfo<File> ICON_ICNS =
 106             new StandardBundlerParam<>(


 155             }
 156             if (p.length > 2) {
 157                 n = new BigInteger(p[2]);
 158                 if (BigInteger.ZERO.compareTo(n) > 0) {
 159                     Log.verbose(I18N.getString(
 160                             "message.version-string-no-negative-numbers"));
 161                     return false;
 162                 }
 163             }
 164         } catch (NumberFormatException ne) {
 165             Log.verbose(I18N.getString("message.version-string-numbers-only"));
 166             Log.verbose(ne);
 167             return false;
 168         }
 169 
 170         return true;
 171     }
 172 
 173     @Override
 174     public boolean validate(Map<String, ? super Object> params)
 175             throws ConfigException {
 176         try {
 177             return doValidate(params);
 178         } catch (RuntimeException re) {
 179             if (re.getCause() instanceof ConfigException) {
 180                 throw (ConfigException) re.getCause();
 181             } else {
 182                 throw new ConfigException(re);
 183             }
 184         }
 185     }
 186 
 187     private boolean doValidate(Map<String, ? super Object> params)
 188             throws ConfigException {



 189 
 190         imageBundleValidation(params);
 191 
 192         if (StandardBundlerParam.getPredefinedAppImage(params) != null) {
 193             return true;
 194         }
 195 
 196         // validate short version
 197         if (!validCFBundleVersion(MAC_CF_BUNDLE_VERSION.fetchFrom(params))) {
 198             throw new ConfigException(
 199                     I18N.getString("error.invalid-cfbundle-version"),
 200                     I18N.getString("error.invalid-cfbundle-version.advice"));
 201         }
 202 
 203         // reject explicitly set sign to true and no valid signature key
 204         if (Optional.ofNullable(MacAppImageBuilder.
 205                     SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) {
 206             String signingIdentity =
 207                     DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params);
 208             if (signingIdentity == null) {
 209                 throw new ConfigException(
 210                         I18N.getString("error.explicit-sign-no-cert"),
 211                         I18N.getString("error.explicit-sign-no-cert.advice"));
 212             }
 213 
 214             // Signing will not work without Xcode with command line developer tools
 215             try {
 216                 ProcessBuilder pb = new ProcessBuilder("xcrun", "--help");
 217                 Process p = pb.start();
 218                 int code = p.waitFor();
 219                 if (code != 0) {
 220                     throw new ConfigException(
 221                         I18N.getString("error.no.xcode.signing"),
 222                         I18N.getString("error.no.xcode.signing.advice"));
 223                 }
 224             } catch (IOException | InterruptedException ex) {
 225                 throw new ConfigException(ex);
 226             }
 227         }
 228 
 229         return true;
 230     }
 231 
 232     File doBundle(Map<String, ? super Object> params, File outputDirectory,
 233             boolean dependentTask) throws PackagerException {
 234         if (StandardBundlerParam.isRuntimeInstaller(params)) {
 235             return PREDEFINED_RUNTIME_IMAGE.fetchFrom(params);
 236         } else {
 237             return doAppBundle(params, outputDirectory, dependentTask);
 238         }
 239     }
 240 
 241     File doAppBundle(Map<String, ? super Object> params, File outputDirectory,
 242             boolean dependentTask) throws PackagerException {
 243         try {
 244             File rootDirectory = createRoot(params, outputDirectory,
 245                     dependentTask, APP_NAME.fetchFrom(params) + ".app");
 246             AbstractAppImageBuilder appBuilder =
 247                     new MacAppImageBuilder(params, outputDirectory.toPath());
 248             if (PREDEFINED_RUNTIME_IMAGE.fetchFrom(params) == null ) {
 249                 JLinkBundlerHelper.execute(params, appBuilder);
 250             } else {
 251                 StandardBundlerParam.copyPredefinedRuntimeImage(
 252                         params, appBuilder);
 253             }
 254             return rootDirectory;
 255         } catch (PackagerException pe) {
 256             throw pe;
 257         } catch (Exception ex) {
 258             Log.verbose(ex);
 259             throw new PackagerException(ex);
 260         }
 261     }
 262 
 263     /////////////////////////////////////////////////////////////////////////
 264     // Implement Bundler
 265     /////////////////////////////////////////////////////////////////////////
 266 
 267     @Override
 268     public String getName() {
 269         return I18N.getString("app.bundler.name");
 270     }
 271 
 272     @Override





 273     public String getID() {
 274         return "mac.app";
 275     }
 276 
 277     @Override
 278     public String getBundleType() {
 279         return "IMAGE";
 280     }
 281 
 282     @Override




























 283     public File execute(Map<String, ? super Object> params,
 284             File outputParentDir) throws PackagerException {
 285         return doBundle(params, outputParentDir, false);
 286     }
 287 
 288     @Override
 289     public boolean supported(boolean runtimeInstaller) {
 290         return true;
 291     }
 292 
 293     @Override
 294     public boolean isDefault() {
 295         return false;
 296     }
 297 
 298 }
< prev index next >