diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java index d44799e6807..fefa2e69557 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageFileExtras.java @@ -26,12 +26,13 @@ package jdk.jpackage.internal; import static jdk.jpackage.internal.AppImageFile.getBooleanExtraFieldValue; +import jdk.jpackage.internal.model.ExternalApplication; import jdk.jpackage.internal.model.MacApplication.ExtraAppImageFileField; record MacAppImageFileExtras(boolean signed, boolean appStore) { - MacAppImageFileExtras(AppImageFile appImageFile) { - this(getBooleanExtraFieldValue(ExtraAppImageFileField.SIGNED.fieldName(), appImageFile), - getBooleanExtraFieldValue(ExtraAppImageFileField.APP_STORE.fieldName(), appImageFile)); + MacAppImageFileExtras(ExternalApplication app) { + this(getBooleanExtraFieldValue(ExtraAppImageFileField.SIGNED.fieldName(), app), + getBooleanExtraFieldValue(ExtraAppImageFileField.APP_STORE.fieldName(), app)); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java index c80549dca89..8b8a22edc56 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AppImageFile.java @@ -47,6 +47,7 @@ import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLayout; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.ExternalApplication; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.util.XmlUtils; import org.w3c.dom.Document; @@ -55,7 +56,7 @@ import org.w3c.dom.Node; import org.xml.sax.SAXException; -final class AppImageFile { +final class AppImageFile implements ExternalApplication { AppImageFile(Application app) { this(new ApplicationData(app)); @@ -72,47 +73,33 @@ final class AppImageFile { addLauncherInfos = app.additionalLaunchers; } - /** - * Returns list of additional launchers configured for the application. - * - * Returns empty list for application without additional launchers. - */ - List getAddLaunchers() { + @Override + public List getAddLaunchers() { return addLauncherInfos; } - /** - * Returns application version. Never returns null or empty value. - */ - String getAppVersion() { + @Override + public String getAppVersion() { return appVersion; } - /** - * Returns application name. Never returns null or empty value. - */ - String getAppName() { + @Override + public String getAppName() { return launcherName; } - /** - * Returns main application launcher name. Never returns null or empty value. - */ - String getLauncherName() { + @Override + public String getLauncherName() { return launcherName; } - /** - * Returns main class name. Never returns null or empty value. - */ - String getMainClass() { + @Override + public String getMainClass() { return mainClass; } - /** - * Returns additional properties. Never returns null. - */ - Map getExtra() { + @Override + public Map getExtra() { return extra; } @@ -223,7 +210,7 @@ final class AppImageFile { } } - static boolean getBooleanExtraFieldValue(String fieldId, AppImageFile appImageFile) { + static boolean getBooleanExtraFieldValue(String fieldId, ExternalApplication appImageFile) { Objects.requireNonNull(fieldId); Objects.requireNonNull(appImageFile); return Optional.ofNullable(appImageFile.getExtra().get(fieldId)).map(Boolean::parseBoolean).orElse(false); @@ -318,16 +305,6 @@ final class AppImageFile { } } - record LauncherInfo(String name, boolean service, Map extra) { - LauncherInfo { - Objects.requireNonNull(name); - Objects.requireNonNull(extra); - if (name.isBlank()) { - throw new IllegalArgumentException(); - } - } - } - private record ApplicationData(String version, String mainLauncherName, String mainLauncherMainClassName, Map extra, List additionalLaunchers) { diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java index 82b715317b2..09bf04372ce 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ApplicationBuilder.java @@ -33,11 +33,12 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.function.Function; -import jdk.jpackage.internal.AppImageFile.LauncherInfo; import jdk.jpackage.internal.model.AppImageLayout; import jdk.jpackage.internal.model.Application; import jdk.jpackage.internal.model.ApplicationLaunchers; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.ExternalApplication; +import jdk.jpackage.internal.model.ExternalApplication.LauncherInfo; import jdk.jpackage.internal.model.Launcher; import jdk.jpackage.internal.model.LauncherStartupInfo; import jdk.jpackage.internal.model.RuntimeBuilder; @@ -83,21 +84,21 @@ final class ApplicationBuilder { return this; } - ApplicationBuilder initFromAppImage(AppImageFile appImageFile, + ApplicationBuilder initFromExternalApplication(ExternalApplication app, Function mapper) { if (version == null) { - version = appImageFile.getAppVersion(); + version = app.getAppVersion(); } if (name == null) { - name = appImageFile.getAppName(); + name = app.getAppName(); } runtimeBuilder = null; - var mainLauncherInfo = new LauncherInfo(appImageFile.getLauncherName(), false, Map.of()); + var mainLauncherInfo = new LauncherInfo(app.getLauncherName(), false, Map.of()); launchers = new ApplicationLaunchers( mapper.apply(mainLauncherInfo), - appImageFile.getAddLaunchers().stream().map(mapper).toList()); + app.getAddLaunchers().stream().map(mapper).toList()); return this; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java index 30258e520f8..349a09f237c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FileAssociationGroup.java @@ -34,7 +34,6 @@ import java.util.function.Predicate; import java.util.function.UnaryOperator; import java.util.stream.Stream; import jdk.jpackage.internal.model.FileAssociation; -import jdk.jpackage.internal.util.CollectionUtils; final record FileAssociationGroup(List items) { @@ -113,12 +112,12 @@ final record FileAssociationGroup(List items) { } Builder mimeTypes(Collection v) { - mimeTypes = CollectionUtils.toSet(v); + mimeTypes = Set.copyOf(v); return this; } Builder extensions(Collection v) { - extensions = CollectionUtils.toSet(v); + extensions = Set.copyOf(v); return this; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java index 6ce387df692..92059b87590 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java @@ -57,11 +57,11 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Function; -import jdk.jpackage.internal.AppImageFile.LauncherInfo; 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; @@ -103,7 +103,7 @@ final class FromParams { if (hasPredefinedAppImage(params)) { final var appImageFile = PREDEFINED_APP_IMAGE_FILE.fetchFrom(params); - appBuilder.initFromAppImage(appImageFile, launcherInfo -> { + appBuilder.initFromExternalApplication(appImageFile, launcherInfo -> { var launcherParams = mapLauncherInfo(launcherInfo); return launcherMapper.apply(mergeParams(params, launcherParams)); }); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java index d3f1f9d8328..488e9106479 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherData.java @@ -24,12 +24,9 @@ */ package jdk.jpackage.internal; -import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.model.ConfigException; import java.io.File; import java.io.IOException; -import java.io.Reader; -import java.lang.module.ModuleDescriptor; import java.lang.module.ModuleReference; import java.nio.file.Files; import java.nio.file.InvalidPathException; @@ -38,9 +35,7 @@ import java.text.MessageFormat; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; -import java.util.Properties; import java.util.Set; import java.util.function.Supplier; import java.util.jar.Attributes; @@ -76,7 +71,7 @@ final class LauncherData { String moduleName() { verifyIsModular(true); - return moduleInfo.name; + return moduleInfo.name(); } List modulePath() { @@ -95,7 +90,7 @@ final class LauncherData { String getAppVersion() { if (isModular()) { - return moduleInfo.version; + return moduleInfo.version().orElse(null); } return null; @@ -145,15 +140,14 @@ final class LauncherData { launcherData.modulePath).find(moduleName).orElse(null); if (moduleRef != null) { - launcherData.moduleInfo = ModuleInfo.fromModuleDescriptor( - moduleRef.descriptor()); + launcherData.moduleInfo = ModuleInfo.fromModuleReference(moduleRef); } else if (params.containsKey(PREDEFINED_RUNTIME_IMAGE.getID())) { // Failed to find module in the specified module path list and // there is external runtime given to jpackage. // Lookup module in this runtime. Path cookedRuntime = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params); launcherData.moduleInfo = ModuleInfo.fromCookedRuntime(moduleName, - cookedRuntime); + cookedRuntime).orElse(null); } if (launcherData.moduleInfo == null) { @@ -162,7 +156,7 @@ final class LauncherData { } if (launcherData.qualifiedClassName == null) { - launcherData.qualifiedClassName = launcherData.moduleInfo.mainClass; + launcherData.qualifiedClassName = launcherData.moduleInfo.mainClass().orElse(null); if (launcherData.qualifiedClassName == null) { throw new ConfigException(I18N.getString("ERR_NoMainClass"), null); } @@ -310,76 +304,4 @@ final class LauncherData { private List classPath; private List modulePath; private ModuleInfo moduleInfo; - - private static final class ModuleInfo { - String name; - String version; - String mainClass; - - static ModuleInfo fromModuleDescriptor(ModuleDescriptor md) { - ModuleInfo result = new ModuleInfo(); - result.name = md.name(); - result.mainClass = md.mainClass().orElse(null); - - ModuleDescriptor.Version ver = md.version().orElse(null); - if (ver != null) { - result.version = ver.toString(); - } else { - result.version = md.rawVersion().orElse(null); - } - - return result; - } - - static ModuleInfo fromCookedRuntime(String moduleName, - Path cookedRuntime) { - Objects.requireNonNull(moduleName); - - // We can't extract info about version and main class of a module - // linked in external runtime without running ModuleFinder in that - // runtime. But this is too much work as the runtime might have been - // coocked without native launchers. So just make sure the module - // is linked in the runtime by simply analysing the data - // of `release` file. - - final Path releaseFile; - if (!OperatingSystem.isMacOS()) { - releaseFile = cookedRuntime.resolve("release"); - } else { - // On Mac `cookedRuntime` can be runtime root or runtime home. - Path runtimeHome = cookedRuntime.resolve("Contents/Home"); - if (!Files.isDirectory(runtimeHome)) { - runtimeHome = cookedRuntime; - } - releaseFile = runtimeHome.resolve("release"); - } - - try (Reader reader = Files.newBufferedReader(releaseFile)) { - Properties props = new Properties(); - props.load(reader); - String moduleList = props.getProperty("MODULES"); - if (moduleList == null) { - return null; - } - - if ((moduleList.startsWith("\"") && moduleList.endsWith("\"")) - || (moduleList.startsWith("\'") && moduleList.endsWith( - "\'"))) { - moduleList = moduleList.substring(1, moduleList.length() - 1); - } - - if (!List.of(moduleList.split("\\s+")).contains(moduleName)) { - return null; - } - } catch (IOException|IllegalArgumentException ex) { - Log.verbose(ex); - return null; - } - - ModuleInfo result = new ModuleInfo(); - result.name = moduleName; - - return result; - } - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java index 0f3f41a2093..5273f2d251c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/LauncherStartupInfoBuilder.java @@ -43,8 +43,7 @@ final class LauncherStartupInfoBuilder { LauncherStartupInfoBuilder launcherData(LauncherData launcherData) { if (launcherData.isModular()) { - decorator = new ModuleStartupInfo(launcherData.moduleName(), - launcherData.modulePath()); + decorator = new ModuleStartupInfo(launcherData.moduleName()); } else { decorator = new JarStartupInfo(launcherData.mainJarName(), launcherData.isClassNameFromMainJar()); @@ -64,14 +63,12 @@ final class LauncherStartupInfoBuilder { return this; } - private static record ModuleStartupInfo(String moduleName, - List modulePath) implements UnaryOperator { + private static record ModuleStartupInfo(String moduleName) implements UnaryOperator { @Override public LauncherStartupInfo apply(LauncherStartupInfo base) { return LauncherModularStartupInfo.create(base, - new LauncherModularStartupInfoMixin.Stub(moduleName, - modulePath)); + new LauncherModularStartupInfoMixin.Stub(moduleName)); } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ModuleInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ModuleInfo.java new file mode 100644 index 00000000000..590321d5e86 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ModuleInfo.java @@ -0,0 +1,100 @@ +/* + * 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 java.io.IOException; +import java.io.Reader; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleReference; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.Properties; +import jdk.internal.util.OperatingSystem; + +record ModuleInfo(String name, Optional version, Optional mainClass, Optional location) { + + Optional fileLocation() { + return location.filter(loc -> { + return loc.getScheme().equals("file"); + }).map(Path::of); + } + + static ModuleInfo fromModuleReference(ModuleReference mr) { + final var md = mr.descriptor(); + return new ModuleInfo(md.name(), md.version().map(ModuleDescriptor.Version::toString).or(md::rawVersion), md.mainClass(), mr.location()); + } + + static Optional fromCookedRuntime(String moduleName, Path cookedRuntime) { + Objects.requireNonNull(moduleName); + Objects.requireNonNull(cookedRuntime); + + // We can't extract info about version and main class of a module + // linked in external runtime without running ModuleFinder in that + // runtime. But this is too much work as the runtime might have been + // coocked without native launchers. So just make sure the module + // is linked in the runtime by simply analysing the data + // of `release` file. + + final Path releaseFile; + if (!OperatingSystem.isMacOS()) { + releaseFile = cookedRuntime.resolve("release"); + } else { + // On Mac `cookedRuntime` can be runtime root or runtime home. + Path runtimeHome = cookedRuntime.resolve("Contents/Home"); + if (!Files.isDirectory(runtimeHome)) { + runtimeHome = cookedRuntime; + } + releaseFile = runtimeHome.resolve("release"); + } + + try (Reader reader = Files.newBufferedReader(releaseFile)) { + Properties props = new Properties(); + props.load(reader); + String moduleList = props.getProperty("MODULES"); + if (moduleList == null) { + return Optional.empty(); + } + + if ((moduleList.startsWith("\"") && moduleList.endsWith("\"")) + || (moduleList.startsWith("\'") && moduleList.endsWith( + "\'"))) { + moduleList = moduleList.substring(1, moduleList.length() - 1); + } + + if (!List.of(moduleList.split("\\s+")).contains(moduleName)) { + return Optional.empty(); + } + } catch (IOException|IllegalArgumentException ex) { + Log.verbose(ex); + return Optional.empty(); + } + + return Optional.of(new ModuleInfo(moduleName, Optional.empty(), Optional.empty(), Optional.empty())); + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java index cdb6e7f986e..93d84fd79b6 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/StandardBundlerParam.java @@ -41,6 +41,7 @@ import java.util.Map; import java.util.Set; import java.util.stream.Stream; import jdk.jpackage.internal.model.ConfigException; +import jdk.jpackage.internal.model.ExternalApplication; import static jdk.jpackage.internal.ApplicationLayoutUtils.PLATFORM_APPLICATION_LAYOUT; import static jdk.jpackage.internal.model.RuntimeBuilder.getDefaultModulePath; @@ -93,8 +94,8 @@ final class StandardBundlerParam { null ); - static final BundlerParamInfo PREDEFINED_APP_IMAGE_FILE = BundlerParamInfo.createBundlerParam( - AppImageFile.class, params -> { + static final BundlerParamInfo PREDEFINED_APP_IMAGE_FILE = BundlerParamInfo.createBundlerParam( + ExternalApplication.class, params -> { if (hasPredefinedAppImage(params)) { var appImage = getPredefinedAppImage(params); return AppImageFile.load(appImage, PLATFORM_APPLICATION_LAYOUT); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java index 019ea060e79..f164daf3eb0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Application.java @@ -40,7 +40,7 @@ import java.util.stream.Stream; * * @see Package */ -public interface Application { +public interface Application extends BundleSpec { /** * Gets the name of this application. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleCreator.java similarity index 76% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleCreator.java index 14827a50729..9fbb7d682a7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ApplicationWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleCreator.java @@ -30,20 +30,18 @@ import java.nio.file.Path; /** - * Creates app image directory from the given {@link Application} object. - * - * @ see PackageWriter + * Creates a bundle from the given specification. */ @FunctionalInterface -public interface ApplicationWriter { +public interface BundleCreator { /** - * Creates app image directory from the given {@link Application} object in the given directory. + * Creates a bundle from the given specification in the given directory. * - * @param app the source application - * @param dst the directory where to create app image of the source application + * @param spec the bundle specification + * @param dst the directory where to create the bundle * @throws PackagerException if packaging error occurs * @throws IOException if an I/O error occurs */ - void write(Application app, Path dst) throws PackagerException, IOException; + void create(T spec, Path dst) throws PackagerException, IOException; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleSpec.java similarity index 65% rename from src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java rename to src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleSpec.java index 79f0b488363..d91662075e3 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/PackageWriter.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundleSpec.java @@ -22,26 +22,10 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ - package jdk.jpackage.internal.model; -import java.io.IOException; -import java.nio.file.Path; - - /** - * Creates native package from the given {@link jdk.jpackage.internal.model.Package} object. - * - * @ see ApplicationWriter + * A generic bundle specification. */ -@FunctionalInterface -public interface PackageWriter { - /** - * Creates native package from the given {@link jdk.jpackage.internal.model.Package} object in the given directory. - * @param pkg the source package - * @param dst the directory where to create a native package - * @throws PackagerException if packaging error occurs - * @throws IOException if an I/O error occurs - */ - void write(Package pkg, Path dst) throws PackagerException, IOException; +public interface BundleSpec { } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundlingEnvironment.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundlingEnvironment.java new file mode 100644 index 00000000000..dcb85ecc75c --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundlingEnvironment.java @@ -0,0 +1,66 @@ +/* + * 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.model; + +import java.util.Set; + +/** + * Bundling environment. Defines available bundling operations. + */ +public interface BundlingEnvironment { + + /** + * Returns the default bundling operation. + *

+ * The returned value should be one of the elements in the collection returned by {@link #enabledOperations()} method. + * @return the default bundling operation + * @throws ConfigException in not a single bundling operation can be performed. + */ + BundlingOperation defaultOperation() throws ConfigException; + + /** + * Returns supported bundling operations. + * @return the supported bundling operations + */ + Set supportedOperations(); + + /** + * Returns enabled bundling operations. + *

+ * The returned value should be a subset of the set returned by {@link #supportedOperations()} method. + * @return the enabled bundling operations + */ + default Set enabledOperations() { + return supportedOperations(); + } + + /** + * Returns a bundle creator corresponding to the given bundling operation in this bundling environment. + * @param op the bundling operation + * @return bundle creator corresponding to the given bundling operation in this bundling environment + * @throws IllegalArgumentException if the given bundling operation is not enabled in this bundling environment + */ + BundleCreator getBundleCreator(BundlingOperation op); +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundlingOperation.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundlingOperation.java new file mode 100644 index 00000000000..4a664a81bcf --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/BundlingOperation.java @@ -0,0 +1,35 @@ +/* + * 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.model; + +/** + * Generic bundling operation. + *

+ * Bundling operation is comprised of creating of {@link BundleSpec} instance + * and using it as an input for {@link BundleCreator#create()} method to create + * a bundle. + */ +public interface BundlingOperation { +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ExternalApplication.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ExternalApplication.java new file mode 100644 index 00000000000..a4a928feb70 --- /dev/null +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/ExternalApplication.java @@ -0,0 +1,87 @@ +/* + * 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.model; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + + +/** + * Description of an external application image. + */ +public interface ExternalApplication { + + /** + * Returns the list of additional launchers configured for the application. + *

+ * Returns an empty list for an application without additional launchers. + * @return the list of additional launchers configured for the application + */ + List getAddLaunchers(); + + /** + * Returns application version. + * @return the application version + */ + String getAppVersion(); + + /** + * Returns application name. + * @return the application name + */ + String getAppName(); + + /** + * Returns main launcher name. + * @return the main launcher name + */ + String getLauncherName(); + + /** + * Returns main class name. + * @return the main class name + */ + String getMainClass(); + + /** + * Returns additional properties. + * @return the additional properties + */ + Map getExtra(); + + /** + * Additional launcher description. + */ + record LauncherInfo(String name, boolean service, Map extra) { + public LauncherInfo { + Objects.requireNonNull(name); + Objects.requireNonNull(extra); + if (name.isBlank()) { + throw new IllegalArgumentException(); + } + } + } +} diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java index 4f57975f710..4a72d93a4b7 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherModularStartupInfoMixin.java @@ -24,9 +24,6 @@ */ package jdk.jpackage.internal.model; -import java.nio.file.Path; -import java.util.List; - /** * Details of application launcher startup configuration using Java module. */ @@ -38,16 +35,10 @@ public interface LauncherModularStartupInfoMixin { */ String moduleName(); - /** - * Gets the path to the input module location. - * @return the path to the input module location - */ - List modulePath(); - /** * Default implementation of {@link LauncherModularStartupInfoMixin} interface. */ - record Stub(String moduleName, List modulePath) implements LauncherModularStartupInfoMixin { + record Stub(String moduleName) implements LauncherModularStartupInfoMixin { } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java index 7a0be535a1a..35db967400f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/Package.java @@ -78,7 +78,7 @@ import java.util.Optional; * * */ -public interface Package { +public interface Package extends BundleSpec { /** * Gets the application of this package. diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java index e5ad5246f05..ee738221758 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/CollectionUtils.java @@ -25,10 +25,6 @@ package jdk.jpackage.internal.util; import java.util.Collection; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** * This class consists exclusively of static methods that operate on or return collections. @@ -64,20 +60,4 @@ public final class CollectionUtils { Collection tmp = v; return (C) tmp; } - - /** - * Converts the given collection to {@link Set}. - * - * @param the type of elements in this output collection - * @param col the input collection. Null is permitted. - * @return the input collection if it is of type {@link Set} or a new - * {@link Set} instance created from the input collection - */ - public static Set toSet(Collection col) { - if (col instanceof Set set) { - return set; - } else { - return Optional.ofNullable(col).map(Collection::stream).orElseGet(Stream::of).collect(Collectors.toSet()); - } - } } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/TokenReplace.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/TokenReplace.java index 7c213851b9b..18a980dc11c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/TokenReplace.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/util/TokenReplace.java @@ -199,5 +199,5 @@ public final class TokenReplace { private final String[] tokens; private final transient List regexps; - private final static Object NULL_SUPPLIED = new Object(); + private static final Object NULL_SUPPLIED = new Object(); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java index 22c6b09a4a0..2bbb16c71d3 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/AppImageFileTest.java @@ -39,11 +39,11 @@ import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import jdk.jpackage.internal.AppImageFile.LauncherInfo; 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.LauncherStartupInfo; import org.junit.jupiter.api.Assertions;