| /* | |
| * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package jdk.jpackage.internal; | |
| import static jdk.jpackage.internal.StandardBundlerParam.ABOUT_URL; | |
| import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS; | |
| import static jdk.jpackage.internal.StandardBundlerParam.ADD_MODULES; | |
| import static jdk.jpackage.internal.StandardBundlerParam.APP_CONTENT; | |
| import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; | |
| import static jdk.jpackage.internal.StandardBundlerParam.COPYRIGHT; | |
| import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION; | |
| import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS; | |
| import static jdk.jpackage.internal.StandardBundlerParam.ICON; | |
| import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME; | |
| import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR; | |
| import static jdk.jpackage.internal.StandardBundlerParam.JLINK_OPTIONS; | |
| import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_AS_SERVICE; | |
| import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE; | |
| import static jdk.jpackage.internal.StandardBundlerParam.LIMIT_MODULES; | |
| import static jdk.jpackage.internal.StandardBundlerParam.MODULE_PATH; | |
| import static jdk.jpackage.internal.StandardBundlerParam.NAME; | |
| import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE_FILE; | |
| import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_RUNTIME_IMAGE; | |
| import static jdk.jpackage.internal.StandardBundlerParam.SOURCE_DIR; | |
| import static jdk.jpackage.internal.StandardBundlerParam.VENDOR; | |
| import static jdk.jpackage.internal.StandardBundlerParam.VERSION; | |
| import static jdk.jpackage.internal.StandardBundlerParam.getPredefinedAppImage; | |
| import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage; | |
| import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller; | |
| import java.io.IOException; | |
| import java.nio.file.Path; | |
| import java.util.ArrayList; | |
| import java.util.HashMap; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.Optional; | |
| import java.util.function.Function; | |
| import jdk.jpackage.internal.model.Application; | |
| import jdk.jpackage.internal.model.ApplicationLaunchers; | |
| import jdk.jpackage.internal.model.ApplicationLayout; | |
| import jdk.jpackage.internal.model.ConfigException; | |
| import jdk.jpackage.internal.model.ExternalApplication.LauncherInfo; | |
| import jdk.jpackage.internal.model.Launcher; | |
| import jdk.jpackage.internal.model.PackageType; | |
| import jdk.jpackage.internal.model.RuntimeLayout; | |
| import jdk.jpackage.internal.util.function.ThrowingFunction; | |
| final class FromParams { | |
| static ApplicationBuilder createApplicationBuilder(Map<String, ? super Object> params, | |
| Function<Map<String, ? super Object>, Launcher> launcherMapper, | |
| ApplicationLayout appLayout) throws ConfigException, IOException { | |
| return createApplicationBuilder(params, launcherMapper, appLayout, Optional.of(RuntimeLayout.DEFAULT)); | |
| } | |
| static ApplicationBuilder createApplicationBuilder(Map<String, ? super Object> params, | |
| Function<Map<String, ? super Object>, Launcher> launcherMapper, | |
| ApplicationLayout appLayout, Optional<RuntimeLayout> predefinedRuntimeLayout) throws ConfigException, IOException { | |
| final var appBuilder = new ApplicationBuilder(); | |
| APP_NAME.copyInto(params, appBuilder::name); | |
| DESCRIPTION.copyInto(params, appBuilder::description); | |
| appBuilder.version(VERSION.fetchFrom(params)); | |
| VENDOR.copyInto(params, appBuilder::vendor); | |
| COPYRIGHT.copyInto(params, appBuilder::copyright); | |
| SOURCE_DIR.copyInto(params, appBuilder::srcDir); | |
| APP_CONTENT.copyInto(params, appBuilder::contentDirs); | |
| final var isRuntimeInstaller = isRuntimeInstaller(params); | |
| final var predefinedRuntimeImage = PREDEFINED_RUNTIME_IMAGE.findIn(params); | |
| final var predefinedRuntimeDirectory = predefinedRuntimeLayout.flatMap( | |
| layout -> predefinedRuntimeImage.map(layout::resolveAt)).map(RuntimeLayout::runtimeDirectory); | |
| if (isRuntimeInstaller) { | |
| appBuilder.appImageLayout(predefinedRuntimeLayout.orElseThrow()); | |
| } else { | |
| appBuilder.appImageLayout(appLayout); | |
| if (hasPredefinedAppImage(params)) { | |
| final var appImageFile = PREDEFINED_APP_IMAGE_FILE.fetchFrom(params); | |
| appBuilder.initFromExternalApplication(appImageFile, launcherInfo -> { | |
| var launcherParams = mapLauncherInfo(launcherInfo); | |
| return launcherMapper.apply(mergeParams(params, launcherParams)); | |
| }); | |
| } else { | |
| final var launchers = createLaunchers(params, launcherMapper); | |
| final var runtimeBuilderBuilder = new RuntimeBuilderBuilder(); | |
| MODULE_PATH.copyInto(params, runtimeBuilderBuilder::modulePath); | |
| predefinedRuntimeDirectory.ifPresentOrElse(runtimeBuilderBuilder::forRuntime, () -> { | |
| final var startupInfos = launchers.asList().stream() | |
| .map(Launcher::startupInfo) | |
| .map(Optional::orElseThrow).toList(); | |
| final var jlinkOptionsBuilder = runtimeBuilderBuilder.forNewRuntime(startupInfos); | |
| ADD_MODULES.copyInto(params, jlinkOptionsBuilder::addModules); | |
| LIMIT_MODULES.copyInto(params, jlinkOptionsBuilder::limitModules); | |
| JLINK_OPTIONS.copyInto(params, jlinkOptionsBuilder::options); | |
| jlinkOptionsBuilder.appy(); | |
| }); | |
| appBuilder.launchers(launchers).runtimeBuilder(runtimeBuilderBuilder.create()); | |
| } | |
| } | |
| return appBuilder; | |
| } | |
| static PackageBuilder createPackageBuilder( | |
| Map<String, ? super Object> params, Application app, | |
| PackageType type) throws ConfigException { | |
| final var builder = new PackageBuilder(app, type); | |
| builder.name(INSTALLER_NAME.fetchFrom(params)); | |
| DESCRIPTION.copyInto(params, builder::description); | |
| VERSION.copyInto(params, builder::version); | |
| ABOUT_URL.copyInto(params, builder::aboutURL); | |
| LICENSE_FILE.findIn(params).map(Path::of).ifPresent(builder::licenseFile); | |
| builder.predefinedAppImage(getPredefinedAppImage(params)); | |
| INSTALL_DIR.findIn(params).map(Path::of).ifPresent(builder::installDir); | |
| return builder; | |
| } | |
| static <T extends Application> BundlerParamInfo<T> createApplicationBundlerParam( | |
| ThrowingFunction<Map<String, ? super Object>, T> ctor) { | |
| return BundlerParamInfo.createBundlerParam(Application.class, ctor); | |
| } | |
| static <T extends jdk.jpackage.internal.model.Package> BundlerParamInfo<T> createPackageBundlerParam( | |
| ThrowingFunction<Map<String, ? super Object>, T> ctor) { | |
| return BundlerParamInfo.createBundlerParam(jdk.jpackage.internal.model.Package.class, ctor); | |
| } | |
| static Optional<jdk.jpackage.internal.model.Package> getCurrentPackage(Map<String, ? super Object> params) { | |
| return Optional.ofNullable((jdk.jpackage.internal.model.Package)params.get( | |
| jdk.jpackage.internal.model.Package.class.getName())); | |
| } | |
| private static ApplicationLaunchers createLaunchers( | |
| Map<String, ? super Object> params, | |
| Function<Map<String, ? super Object>, Launcher> launcherMapper) { | |
| var launchers = ADD_LAUNCHERS.findIn(params).orElseGet(List::of); | |
| var mainLauncher = launcherMapper.apply(params); | |
| var additionalLaunchers = launchers.stream().map(launcherParams -> { | |
| return launcherMapper.apply(mergeParams(params, launcherParams)); | |
| }).toList(); | |
| return new ApplicationLaunchers(mainLauncher, additionalLaunchers); | |
| } | |
| private static Map<String, ? super Object> mapLauncherInfo(LauncherInfo launcherInfo) { | |
| Map<String, ? super Object> launcherParams = new HashMap<>(); | |
| launcherParams.put(NAME.getID(), launcherInfo.name()); | |
| launcherParams.put(LAUNCHER_AS_SERVICE.getID(), Boolean.toString(launcherInfo.service())); | |
| launcherParams.putAll(launcherInfo.extra()); | |
| return launcherParams; | |
| } | |
| private static Map<String, ? super Object> mergeParams(Map<String, ? super Object> mainParams, | |
| Map<String, ? super Object> launcherParams) { | |
| if (!launcherParams.containsKey(DESCRIPTION.getID())) { | |
| launcherParams = new HashMap<>(launcherParams); | |
| // FIXME: this is a good improvement but it fails existing tests | |
| // launcherParams.put(DESCRIPTION.getID(), String.format("%s (%s)", DESCRIPTION.fetchFrom( | |
| // mainParams), APP_NAME.fetchFrom(launcherParams))); | |
| launcherParams.put(DESCRIPTION.getID(), DESCRIPTION.fetchFrom(mainParams)); | |
| } | |
| var excludes = new ArrayList<String>(List.of(ICON.getID(), ADD_LAUNCHERS.getID())); | |
| if (!NAME.findIn(mainParams).equals(NAME.findIn(launcherParams))) { | |
| // This is the additional launcher. It shouldn't have FA. | |
| excludes.add(FILE_ASSOCIATIONS.getID()); | |
| } | |
| return AddLauncherArguments.merge(mainParams, launcherParams, excludes.toArray(String[]::new)); | |
| } | |
| static final BundlerParamInfo<Application> APPLICATION = createApplicationBundlerParam(null); | |
| } |