Search in sources :

Example 1 with PathCollection

use of io.quarkus.paths.PathCollection in project quarkus by quarkusio.

the class RuntimeUpdatesProcessor method checkForFileChange.

Set<String> checkForFileChange(Function<DevModeContext.ModuleInfo, DevModeContext.CompilationUnit> cuf, TimestampSet timestampSet) {
    Set<String> ret = new HashSet<>();
    for (DevModeContext.ModuleInfo module : context.getAllModules()) {
        DevModeContext.CompilationUnit compilationUnit = cuf.apply(module);
        if (compilationUnit == null) {
            continue;
        }
        final Set<Path> moduleResources = correspondingResources.computeIfAbsent(compilationUnit, m -> Collections.newSetFromMap(new ConcurrentHashMap<>()));
        boolean doCopy = true;
        PathCollection rootPaths = compilationUnit.getResourcePaths();
        String outputPath = compilationUnit.getResourcesOutputPath();
        if (rootPaths.isEmpty()) {
            String rootPath = compilationUnit.getClassesPath();
            if (rootPath != null) {
                rootPaths = PathList.of(Paths.get(rootPath));
            }
            outputPath = rootPath;
            doCopy = false;
        }
        if (rootPaths.isEmpty() || outputPath == null) {
            continue;
        }
        Path outputDir = Paths.get(outputPath);
        final List<Path> roots = rootPaths.stream().filter(Files::exists).filter(Files::isReadable).collect(Collectors.toList());
        // copy all modified non hot deployment files over
        if (doCopy) {
            final Set<Path> seen = new HashSet<>(moduleResources);
            try {
                for (Path root : roots) {
                    // since the stream is Closeable, use a try with resources so the underlying iterator is closed
                    try (final Stream<Path> walk = Files.walk(root)) {
                        walk.forEach(path -> {
                            try {
                                Path relative = root.relativize(path);
                                Path target = outputDir.resolve(relative);
                                seen.remove(target);
                                if (!timestampSet.watchedFileTimestamps.containsKey(path)) {
                                    moduleResources.add(target);
                                    if (!Files.exists(target) || Files.getLastModifiedTime(target).toMillis() < Files.getLastModifiedTime(path).toMillis()) {
                                        if (Files.isDirectory(path)) {
                                            Files.createDirectories(target);
                                        } else {
                                            Files.createDirectories(target.getParent());
                                            ret.add(relative.toString());
                                            byte[] data = Files.readAllBytes(path);
                                            try (FileOutputStream out = new FileOutputStream(target.toFile())) {
                                                out.write(data);
                                            }
                                            if (copyResourceNotification != null) {
                                                copyResourceNotification.accept(module, relative.toString());
                                            }
                                        }
                                    }
                                }
                            } catch (Exception e) {
                                log.error("Failed to copy resources", e);
                            }
                        });
                    }
                }
                for (Path i : seen) {
                    moduleResources.remove(i);
                    if (!Files.isDirectory(i)) {
                        Files.delete(i);
                    }
                }
            } catch (IOException e) {
                log.error("Failed to copy resources", e);
            }
        }
        for (String path : timestampSet.watchedFilePaths.keySet()) {
            boolean pathCurrentlyExisting = false;
            boolean pathPreviouslyExisting = false;
            for (Path root : roots) {
                Path file = root.resolve(path);
                if (file.toFile().exists()) {
                    pathCurrentlyExisting = true;
                    try {
                        long value = Files.getLastModifiedTime(file).toMillis();
                        Long existing = timestampSet.watchedFileTimestamps.get(file);
                        // as there is both normal and test resources, but only one set of watched timestampts
                        if (existing != null && value > existing) {
                            ret.add(path);
                            // if the file is empty we may be seeing the middle of a write
                            if (Files.size(file) == 0) {
                                try {
                                    Thread.sleep(200);
                                } catch (InterruptedException e) {
                                // ignore
                                }
                            }
                            // re-read, as we may have read the original TS if the middle of
                            // a truncate+write, even if the write had completed by the time
                            // we read the size
                            value = Files.getLastModifiedTime(file).toMillis();
                            log.infof("File change detected: %s", file);
                            if (doCopy && !Files.isDirectory(file)) {
                                Path target = outputDir.resolve(path);
                                byte[] data = Files.readAllBytes(file);
                                try (FileOutputStream out = new FileOutputStream(target.toFile())) {
                                    out.write(data);
                                }
                            }
                            timestampSet.watchedFileTimestamps.put(file, value);
                        }
                    } catch (IOException e) {
                        throw new UncheckedIOException(e);
                    }
                } else {
                    Long prevValue = timestampSet.watchedFileTimestamps.put(file, 0L);
                    pathPreviouslyExisting = pathPreviouslyExisting || (prevValue != null && prevValue > 0);
                }
            }
            if (!pathCurrentlyExisting) {
                if (pathPreviouslyExisting) {
                    ret.add(path);
                }
                Path target = outputDir.resolve(path);
                try {
                    FileUtil.deleteIfExists(target);
                } catch (IOException e) {
                    throw new UncheckedIOException(e);
                }
            }
        }
        // Mostly a copy of the code above but to handle watched files that are set with absolute path (not in the app resources)
        for (String watchedFilePath : timestampSet.watchedFilePaths.keySet()) {
            Path watchedFile = Paths.get(watchedFilePath);
            if (watchedFile.isAbsolute()) {
                if (watchedFile.toFile().exists()) {
                    try {
                        long value = Files.getLastModifiedTime(watchedFile).toMillis();
                        Long existing = timestampSet.watchedFileTimestamps.get(watchedFile);
                        // as there is both normal and test resources, but only one set of watched timestampts
                        if (existing != null && value > existing) {
                            ret.add(watchedFilePath);
                            // if the file is empty we may be seeing the middle of a write
                            if (Files.size(watchedFile) == 0) {
                                try {
                                    Thread.sleep(200);
                                } catch (InterruptedException e) {
                                // ignore
                                }
                            }
                            // re-read, as we may have read the original TS if the middle of
                            // a truncate+write, even if the write had completed by the time
                            // we read the size
                            value = Files.getLastModifiedTime(watchedFile).toMillis();
                            log.infof("File change detected: %s", watchedFile);
                            timestampSet.watchedFileTimestamps.put(watchedFile, value);
                        }
                    } catch (IOException e) {
                        throw new UncheckedIOException(e);
                    }
                } else {
                    Long prevValue = timestampSet.watchedFileTimestamps.put(watchedFile, 0L);
                    if (prevValue != null && prevValue > 0) {
                        ret.add(watchedFilePath);
                    }
                }
            }
        }
    }
    return ret;
}
Also used : Path(java.nio.file.Path) PathCollection(io.quarkus.paths.PathCollection) UncheckedIOException(java.io.UncheckedIOException) UncheckedIOException(java.io.UncheckedIOException) IOException(java.io.IOException) UncheckedIOException(java.io.UncheckedIOException) IOException(java.io.IOException) FileOutputStream(java.io.FileOutputStream) ModuleInfo(io.quarkus.deployment.dev.DevModeContext.ModuleInfo) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Files(java.nio.file.Files) HashSet(java.util.HashSet)

Example 2 with PathCollection

use of io.quarkus.paths.PathCollection in project quarkus by quarkusio.

the class RuntimeUpdatesProcessor method setWatchedFilePathsInternal.

private RuntimeUpdatesProcessor setWatchedFilePathsInternal(Map<String, Boolean> watchedFilePaths, TimestampSet timestamps, Function<DevModeContext.ModuleInfo, List<DevModeContext.CompilationUnit>> cuf) {
    timestamps.watchedFilePaths = watchedFilePaths;
    Map<String, Boolean> extraWatchedFilePaths = new HashMap<>();
    for (DevModeContext.ModuleInfo module : context.getAllModules()) {
        List<DevModeContext.CompilationUnit> compilationUnits = cuf.apply(module);
        for (DevModeContext.CompilationUnit unit : compilationUnits) {
            PathCollection rootPaths = unit.getResourcePaths();
            if (rootPaths.isEmpty()) {
                String rootPath = unit.getClassesPath();
                if (rootPath == null) {
                    continue;
                }
                rootPaths = PathList.of(Path.of(rootPath));
            }
            for (Path root : rootPaths) {
                for (String path : watchedFilePaths.keySet()) {
                    Path config = root.resolve(path);
                    if (config.toFile().exists()) {
                        try {
                            FileTime lastModifiedTime = Files.getLastModifiedTime(config);
                            timestamps.watchedFileTimestamps.put(config, lastModifiedTime.toMillis());
                        } catch (IOException e) {
                            throw new UncheckedIOException(e);
                        }
                    } else {
                        timestamps.watchedFileTimestamps.put(config, 0L);
                        Map<Path, Long> extraWatchedFileTimestamps = expandGlobPattern(root, config);
                        timestamps.watchedFileTimestamps.putAll(extraWatchedFileTimestamps);
                        for (Path extraPath : extraWatchedFileTimestamps.keySet()) {
                            extraWatchedFilePaths.put(root.relativize(extraPath).toString(), timestamps.watchedFilePaths.get(path));
                        }
                        timestamps.watchedFileTimestamps.putAll(extraWatchedFileTimestamps);
                    }
                }
            }
        }
    }
    timestamps.watchedFilePaths.putAll(extraWatchedFilePaths);
    return this;
}
Also used : PathCollection(io.quarkus.paths.PathCollection) Path(java.nio.file.Path) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) FileTime(java.nio.file.attribute.FileTime) UncheckedIOException(java.io.UncheckedIOException) UncheckedIOException(java.io.UncheckedIOException) IOException(java.io.IOException) ModuleInfo(io.quarkus.deployment.dev.DevModeContext.ModuleInfo)

Example 3 with PathCollection

use of io.quarkus.paths.PathCollection in project quarkus by quarkusio.

the class QuarkusAugmentor method run.

public BuildResult run() throws Exception {
    if (!JavaVersionUtil.isJava11OrHigher()) {
        throw new IllegalStateException("Quarkus applications require Java 11 or higher to build");
    }
    long time = System.currentTimeMillis();
    log.debug("Beginning Quarkus augmentation");
    ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
    QuarkusBuildCloseablesBuildItem buildCloseables = new QuarkusBuildCloseablesBuildItem();
    try {
        Thread.currentThread().setContextClassLoader(deploymentClassLoader);
        final BuildChainBuilder chainBuilder = BuildChain.builder();
        chainBuilder.setClassLoader(deploymentClassLoader);
        // provideCapabilities(chainBuilder);
        // TODO: we load everything from the deployment class loader
        // this allows the deployment config (application.properties) to be loaded, but in theory could result
        // in additional stuff from the deployment leaking in, this is unlikely but has a bit of a smell.
        ExtensionLoader.loadStepsFrom(deploymentClassLoader, buildSystemProperties == null ? new Properties() : buildSystemProperties, effectiveModel, launchMode, devModeType).accept(chainBuilder);
        Thread.currentThread().setContextClassLoader(classLoader);
        chainBuilder.loadProviders(classLoader);
        chainBuilder.addInitial(QuarkusBuildCloseablesBuildItem.class).addInitial(ArchiveRootBuildItem.class).addInitial(ShutdownContextBuildItem.class).addInitial(RawCommandLineArgumentsBuildItem.class).addInitial(LaunchModeBuildItem.class).addInitial(LiveReloadBuildItem.class).addInitial(AdditionalApplicationArchiveBuildItem.class).addInitial(CuratedApplicationShutdownBuildItem.class).addInitial(BuildSystemTargetBuildItem.class).addInitial(AppModelProviderBuildItem.class);
        for (Class<? extends BuildItem> i : finalResults) {
            chainBuilder.addFinal(i);
        }
        for (Consumer<BuildChainBuilder> i : buildChainCustomizers) {
            i.accept(chainBuilder);
        }
        if (launchMode.isDevOrTest()) {
            chainBuilder.addFinal(RuntimeApplicationShutdownBuildItem.class);
        }
        final ArchiveRootBuildItem.Builder rootBuilder = ArchiveRootBuildItem.builder();
        if (root != null) {
            rootBuilder.addArchiveRoots(root);
        }
        rootBuilder.setExcludedFromIndexing(excludedFromIndexing);
        BuildChain chain = chainBuilder.build();
        BuildExecutionBuilder execBuilder = chain.createExecutionBuilder("main").produce(buildCloseables).produce(liveReloadBuildItem).produce(rootBuilder.build(buildCloseables)).produce(new ShutdownContextBuildItem()).produce(new RawCommandLineArgumentsBuildItem()).produce(new CuratedApplicationShutdownBuildItem((QuarkusClassLoader) deploymentClassLoader.getParent(), !liveReloadBuildItem.isLiveReload())).produce(new LaunchModeBuildItem(launchMode, devModeType == null ? Optional.empty() : Optional.of(devModeType), auxiliaryApplication, auxiliaryDevModeType, test)).produce(new BuildSystemTargetBuildItem(targetDir, baseName, rebuild, buildSystemProperties == null ? new Properties() : buildSystemProperties)).produce(new AppModelProviderBuildItem(effectiveModel));
        for (PathCollection i : additionalApplicationArchives) {
            execBuilder.produce(new AdditionalApplicationArchiveBuildItem(i));
        }
        BuildResult buildResult = execBuilder.execute();
        String message = "Quarkus augmentation completed in " + (System.currentTimeMillis() - time) + "ms";
        if (launchMode == LaunchMode.NORMAL) {
            log.info(message);
        } else {
            // test and dev mode already report the total startup time, no need to add noise to the logs
            log.debug(message);
        }
        return buildResult;
    } finally {
        try {
            ConfigProviderResolver.instance().releaseConfig(ConfigProviderResolver.instance().getConfig(deploymentClassLoader));
        } catch (Exception ignore) {
        }
        if (deploymentClassLoader instanceof Closeable) {
            ((Closeable) deploymentClassLoader).close();
        }
        Thread.currentThread().setContextClassLoader(originalClassLoader);
        buildCloseables.close();
    }
}
Also used : PathCollection(io.quarkus.paths.PathCollection) LaunchModeBuildItem(io.quarkus.deployment.builditem.LaunchModeBuildItem) BuildChain(io.quarkus.builder.BuildChain) Closeable(java.io.Closeable) ArchiveRootBuildItem(io.quarkus.deployment.builditem.ArchiveRootBuildItem) Properties(java.util.Properties) QuarkusBuildCloseablesBuildItem(io.quarkus.deployment.builditem.QuarkusBuildCloseablesBuildItem) BuildExecutionBuilder(io.quarkus.builder.BuildExecutionBuilder) AdditionalApplicationArchiveBuildItem(io.quarkus.deployment.builditem.AdditionalApplicationArchiveBuildItem) CuratedApplicationShutdownBuildItem(io.quarkus.deployment.builditem.CuratedApplicationShutdownBuildItem) BuildResult(io.quarkus.builder.BuildResult) RawCommandLineArgumentsBuildItem(io.quarkus.deployment.builditem.RawCommandLineArgumentsBuildItem) BuildChainBuilder(io.quarkus.builder.BuildChainBuilder) QuarkusClassLoader(io.quarkus.bootstrap.classloading.QuarkusClassLoader) BuildSystemTargetBuildItem(io.quarkus.deployment.pkg.builditem.BuildSystemTargetBuildItem) AppModelProviderBuildItem(io.quarkus.deployment.builditem.AppModelProviderBuildItem) ShutdownContextBuildItem(io.quarkus.deployment.builditem.ShutdownContextBuildItem)

Example 4 with PathCollection

use of io.quarkus.paths.PathCollection in project quarkus by quarkusio.

the class GradleApplicationModelBuilder method collectDependencies.

private void collectDependencies(org.gradle.api.artifacts.ResolvedDependency resolvedDep, LaunchMode mode, Project project, Map<ArtifactKey, ResolvedDependencyBuilder> appDependencies, Set<File> artifactFiles, Set<ArtifactKey> processedModules, ApplicationModelBuilder modelBuilder, WorkspaceModule.Mutable parentModule, byte flags) {
    WorkspaceModule.Mutable projectModule = null;
    for (ResolvedArtifact a : resolvedDep.getModuleArtifacts()) {
        final ArtifactKey artifactKey = toAppDependenciesKey(a.getModuleVersion().getId().getGroup(), a.getName(), a.getClassifier());
        if (!isDependency(a) || appDependencies.containsKey(artifactKey)) {
            continue;
        }
        final ArtifactCoords depCoords = toArtifactCoords(a);
        final ResolvedDependencyBuilder depBuilder = ResolvedDependencyBuilder.newInstance().setCoords(depCoords).setRuntimeCp();
        if (isFlagOn(flags, COLLECT_DIRECT_DEPS)) {
            depBuilder.setDirect(true);
            flags = clearFlag(flags, COLLECT_DIRECT_DEPS);
        }
        if (parentModule != null) {
            parentModule.addDependency(new ArtifactDependency(depCoords));
        }
        PathCollection paths = null;
        if ((LaunchMode.DEVELOPMENT.equals(mode) || LaunchMode.TEST.equals(mode)) && a.getId().getComponentIdentifier() instanceof ProjectComponentIdentifier) {
            final Project projectDep = project.getRootProject().findProject(((ProjectComponentIdentifier) a.getId().getComponentIdentifier()).getProjectPath());
            final JavaPluginConvention javaExtension = projectDep == null ? null : projectDep.getConvention().findPlugin(JavaPluginConvention.class);
            final String classifier = a.getClassifier();
            if (classifier == null || classifier.isEmpty()) {
                final IncludedBuild includedBuild = ToolingUtils.includedBuild(project.getRootProject(), a.getName());
                if (includedBuild != null) {
                    final PathList.Builder pathBuilder = PathList.builder();
                    addSubstitutedProject(pathBuilder, includedBuild.getProjectDir());
                    paths = pathBuilder.build();
                } else if (javaExtension != null) {
                    final PathList.Builder pathBuilder = PathList.builder();
                    projectModule = initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder, javaExtension, pathBuilder, SourceSet.MAIN_SOURCE_SET_NAME, false);
                    paths = pathBuilder.build();
                }
            } else if (javaExtension != null) {
                if ("test".equals(classifier)) {
                    final PathList.Builder pathBuilder = PathList.builder();
                    projectModule = initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder, javaExtension, pathBuilder, SourceSet.TEST_SOURCE_SET_NAME, true);
                    paths = pathBuilder.build();
                } else if ("test-fixtures".equals(classifier)) {
                    final PathList.Builder pathBuilder = PathList.builder();
                    projectModule = initProjectModuleAndBuildPaths(projectDep, a, modelBuilder, depBuilder, javaExtension, pathBuilder, "testFixtures", true);
                    paths = pathBuilder.build();
                }
            }
        }
        depBuilder.setResolvedPaths(paths == null ? PathList.of(a.getFile().toPath()) : paths).setWorkspaceModule(projectModule);
        if (processQuarkusDependency(depBuilder, modelBuilder)) {
            if (isFlagOn(flags, COLLECT_TOP_EXTENSION_RUNTIME_NODES)) {
                depBuilder.setFlags(DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT);
                flags = clearFlag(flags, COLLECT_TOP_EXTENSION_RUNTIME_NODES);
            }
            flags = clearFlag(flags, COLLECT_RELOADABLE_MODULES);
        }
        if (!isFlagOn(flags, COLLECT_RELOADABLE_MODULES)) {
            depBuilder.clearFlag(DependencyFlags.RELOADABLE);
        }
        appDependencies.put(depBuilder.getKey(), depBuilder);
        if (artifactFiles != null) {
            artifactFiles.add(a.getFile());
        }
    }
    processedModules.add(new GACT(resolvedDep.getModuleGroup(), resolvedDep.getModuleName()));
    for (org.gradle.api.artifacts.ResolvedDependency child : resolvedDep.getChildren()) {
        if (!processedModules.contains(new GACT(child.getModuleGroup(), child.getModuleName()))) {
            collectDependencies(child, mode, project, appDependencies, artifactFiles, processedModules, modelBuilder, projectModule, flags);
        }
    }
}
Also used : PathCollection(io.quarkus.paths.PathCollection) ResolvedArtifact(org.gradle.api.artifacts.ResolvedArtifact) ArtifactCoords(io.quarkus.maven.dependency.ArtifactCoords) ArtifactKey(io.quarkus.maven.dependency.ArtifactKey) ArtifactDependency(io.quarkus.maven.dependency.ArtifactDependency) ApplicationDeploymentClasspathBuilder(io.quarkus.gradle.dependency.ApplicationDeploymentClasspathBuilder) ApplicationModelBuilder(io.quarkus.bootstrap.model.ApplicationModelBuilder) ParameterizedToolingModelBuilder(org.gradle.tooling.provider.model.ParameterizedToolingModelBuilder) ResolvedDependencyBuilder(io.quarkus.maven.dependency.ResolvedDependencyBuilder) PathList(io.quarkus.paths.PathList) GACT(io.quarkus.maven.dependency.GACT) ResolvedDependencyBuilder(io.quarkus.maven.dependency.ResolvedDependencyBuilder) Project(org.gradle.api.Project) JavaPluginConvention(org.gradle.api.plugins.JavaPluginConvention) WorkspaceModule(io.quarkus.bootstrap.workspace.WorkspaceModule) DefaultWorkspaceModule(io.quarkus.bootstrap.workspace.DefaultWorkspaceModule) ProjectComponentIdentifier(org.gradle.api.artifacts.component.ProjectComponentIdentifier) IncludedBuild(org.gradle.api.initialization.IncludedBuild)

Example 5 with PathCollection

use of io.quarkus.paths.PathCollection in project quarkus by quarkusio.

the class ResolvedDependency method getContentTree.

default PathTree getContentTree() {
    final WorkspaceModule module = getWorkspaceModule();
    final PathTree workspaceTree = module == null ? EmptyPathTree.getInstance() : module.getContentTree(getClassifier());
    if (!workspaceTree.isEmpty()) {
        return workspaceTree;
    }
    final PathCollection paths = getResolvedPaths();
    if (paths == null || paths.isEmpty()) {
        return EmptyPathTree.getInstance();
    }
    if (paths.isSinglePath()) {
        final Path p = paths.getSinglePath();
        return PathTree.ofDirectoryOrArchive(p);
    }
    final PathTree[] trees = new PathTree[paths.size()];
    int i = 0;
    for (Path p : paths) {
        trees[i++] = PathTree.ofDirectoryOrArchive(p);
    }
    return new MultiRootPathTree(trees);
}
Also used : PathCollection(io.quarkus.paths.PathCollection) Path(java.nio.file.Path) MultiRootPathTree(io.quarkus.paths.MultiRootPathTree) WorkspaceModule(io.quarkus.bootstrap.workspace.WorkspaceModule) PathTree(io.quarkus.paths.PathTree) MultiRootPathTree(io.quarkus.paths.MultiRootPathTree) EmptyPathTree(io.quarkus.paths.EmptyPathTree)

Aggregations

PathCollection (io.quarkus.paths.PathCollection)6 WorkspaceModule (io.quarkus.bootstrap.workspace.WorkspaceModule)3 Path (java.nio.file.Path)3 ModuleInfo (io.quarkus.deployment.dev.DevModeContext.ModuleInfo)2 PathList (io.quarkus.paths.PathList)2 IOException (java.io.IOException)2 UncheckedIOException (java.io.UncheckedIOException)2 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)2 QuarkusClassLoader (io.quarkus.bootstrap.classloading.QuarkusClassLoader)1 ApplicationModelBuilder (io.quarkus.bootstrap.model.ApplicationModelBuilder)1 ArtifactSources (io.quarkus.bootstrap.workspace.ArtifactSources)1 DefaultWorkspaceModule (io.quarkus.bootstrap.workspace.DefaultWorkspaceModule)1 BuildChain (io.quarkus.builder.BuildChain)1 BuildChainBuilder (io.quarkus.builder.BuildChainBuilder)1 BuildExecutionBuilder (io.quarkus.builder.BuildExecutionBuilder)1 BuildResult (io.quarkus.builder.BuildResult)1 AdditionalApplicationArchiveBuildItem (io.quarkus.deployment.builditem.AdditionalApplicationArchiveBuildItem)1 AppModelProviderBuildItem (io.quarkus.deployment.builditem.AppModelProviderBuildItem)1 ArchiveRootBuildItem (io.quarkus.deployment.builditem.ArchiveRootBuildItem)1 CuratedApplicationShutdownBuildItem (io.quarkus.deployment.builditem.CuratedApplicationShutdownBuildItem)1