11/**
2- * (C) Copyright IBM Corporation 2019, 2025 .
2+ * (C) Copyright IBM Corporation 2019, 2026 .
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
@@ -1942,10 +1942,12 @@ private void addUserId(List<String> commandElements) {
19421942 *
19431943 * @param classes class file paths features should be generated for (can be null if no modified classes)
19441944 * @param optimize if true, generate optimized feature list
1945- * @param useTmpDir if true, generate feature file in a hidden directory named in BinaryScannerUtil
1945+ * @param useTmpDirOut if true, generate feature file in a hidden directory named in BinaryScannerUtil
1946+ * @param useTmpDirIn if true, the hidden directory named in BinaryScannerUtil will be used as the
1947+ * context or input values to generate features
19461948 * @return true if feature generation was successful
19471949 */
1948- public abstract boolean libertyGenerateFeatures (Collection <String > classes , boolean optimize , boolean useTmpDir );
1950+ public abstract boolean libertyGenerateFeatures (Collection <String > classes , boolean optimize , boolean useTmpDirOut , boolean useTmpDirIn );
19491951
19501952 /**
19511953 * Install features in regular dev mode. This method should not be used in container mode.
@@ -2176,13 +2178,13 @@ public void cleanUpServerEnv() {
21762178 }
21772179 }
21782180
2179- public void cleanUpTempConfig () {
2180- if (this . tempConfigPath != null ) {
2181- File tempConfig = this . tempConfigPath .toFile ();
2181+ public void cleanUpTempConfig (Path myTempConfigPath ) {
2182+ if (myTempConfigPath != null ) {
2183+ File tempConfig = myTempConfigPath .toFile ();
21822184 if (tempConfig .exists ()) {
21832185 try {
21842186 FileUtils .deleteDirectory (tempConfig );
2185- debug ("Successfully deleted liberty:dev temporary configuration folder" );
2187+ debug ("Successfully deleted liberty:dev temporary configuration folder: " + myTempConfigPath );
21862188 } catch (IOException e ) {
21872189 warn ("Could not delete liberty:dev temporary configuration folder: " + e .getMessage ());
21882190 }
@@ -2233,7 +2235,7 @@ private void runShutdownHook(final ThreadPoolExecutor executor) {
22332235 }
22342236
22352237 setDevStop (true );
2236- cleanUpTempConfig ();
2238+ cleanUpTempConfig (this . tempConfigPath );
22372239 cleanUpServerEnv ();
22382240
22392241 if (hotkeyReader != null ) {
@@ -2707,13 +2709,18 @@ protected void setFeatureGeneration(boolean generateFeatures) {
27072709 logFeatureGenerationStatus ();
27082710 }
27092711
2712+ private boolean optimizeGenerateFeatures (boolean useTmpDir ) {
2713+ debug ("Entering optimizeGenerateFeatures(boolean)" );
2714+ return optimizeGenerateFeatures (useTmpDir , false );
2715+ }
2716+
27102717 /**
27112718 * Generate features using all classes and only user specified features.
27122719 */
2713- private boolean optimizeGenerateFeatures (boolean useTmpDir ) {
2714- debug ("Generating optimized features list...use temp directory=" + useTmpDir );
2720+ private boolean optimizeGenerateFeatures (boolean useTmpDirOut , boolean useTmpDirIn ) {
2721+ debug ("Generating optimized features list...use temp directory for output =" + useTmpDirOut + " use temp directory for input=" + useTmpDirIn );
27152722 // scan all class files and provide only user specified features
2716- boolean generatedFeatures = libertyGenerateFeatures (null , true , useTmpDir );
2723+ boolean generatedFeatures = libertyGenerateFeatures (null , true , useTmpDirOut , useTmpDirIn );
27172724 if (generatedFeatures ) {
27182725 modifiedClasses .clear ();
27192726 failedToGenerateClasses .clear ();
@@ -2732,7 +2739,7 @@ private boolean incrementGenerateFeatures(boolean useTmpDir) {
27322739 boolean generatedFeatures = false ;
27332740 try {
27342741 Collection <String > classPaths = getClassPaths (modifiedClasses );
2735- generatedFeatures = libertyGenerateFeatures (classPaths , false , useTmpDir );
2742+ generatedFeatures = libertyGenerateFeatures (classPaths , false , useTmpDir , false );
27362743 if (generatedFeatures ) {
27372744 modifiedClasses .clear ();
27382745 failedToGenerateClasses .clear ();
@@ -4595,7 +4602,20 @@ private void processConfigFileChange(File fileChanged, ChangeType changeType, Th
45954602 if (generateFeatures && (fileChanged .getName ().endsWith (".xml" )
45964603 && !isGeneratedFeaturesFile )
45974604 && serverFeaturesModified ) {
4598- generateFeaturesSuccess = optimizeGenerateFeatures (!generateToSrc );
4605+ // If generating to server dir we use the server dir config files and also the
4606+ // modified xml file in src dir. Copy them all to the gen. feat. temp dir to
4607+ // combine them for feature generation.
4608+ if (!generateToSrc ) {
4609+ // Deleting generateFeaturesTmpDir also deletes generateFeaturesFile which we "watch" in
4610+ // dev mode. This causes a deletion event and we are counting on the handler (this method,
4611+ // below) not to call generate features and recreate the file.
4612+ cleanUpTempConfig (generateFeaturesTmpDir .toPath ());
4613+ // copy config files to temp dir
4614+ copyToTempDir (serverDirectory , generateFeaturesTmpDir );
4615+ // copy changed file to temp dir
4616+ copyFile (fileChanged , fileChangedParentDir , generateFeaturesTmpDir , targetFileName );
4617+ }
4618+ generateFeaturesSuccess = optimizeGenerateFeatures (!generateToSrc , !generateToSrc );
45994619 }
46004620 if (serverFeaturesModified ) {
46014621 // suppress install feature warning - property must be set before installing using temp dir
@@ -4649,7 +4669,10 @@ private void processConfigFileChange(File fileChanged, ChangeType changeType, Th
46494669 info ("Config file deleted: " + fileChanged .getName ());
46504670 deleteFile (fileChanged , fileChangedParentDir , serverDirectory , targetFileName );
46514671 // generate features whenever features have changed and an XML file is deleted,
4652- // excluding the generated-features.xml file
4672+ // excluding the generated-features.xml file. This is important also when we delete the
4673+ // generateFeaturesTmpDir in the process of handling an xml config modicifcation.
4674+ // Deleting that directory could cause generated-features.xml to be deleted and we
4675+ // need to be careful how to handle that event e.g. don't call optimizeGenerateFeatures().
46534676 if (generateFeatures && (fileChanged .getName ().endsWith (".xml" )
46544677 && !fileChanged .equals (generateFeaturesFile ))
46554678 && serverFeaturesModified ()) {
@@ -4831,27 +4854,40 @@ public void installFeaturesToTempDir(File fileChanged, File srcDir, String targe
48314854 File tempConfig = tempConfigPath .toFile ();
48324855 debug ("Temporary configuration folder created: " + tempConfig );
48334856
4834- FileUtils .copyDirectory (serverDirectory , tempConfig , new FileFilter () {
4857+ copyToTempDir (serverDirectory , tempConfig );
4858+ copyFile (fileChanged , srcDir , tempConfig , targetFileName );
4859+ if (generateFeatures && generateFeaturesSuccess && !fileChanged .equals (generateFeaturesFile )) {
4860+ copyGeneratedFeaturesFile (tempConfig );
4861+ }
4862+ installFeatures (fileChanged , tempConfig , generateFeatures );
4863+ cleanUpTempConfig (this .tempConfigPath );
4864+ }
4865+
4866+ /**
4867+ * Copy the liberty config in the sourceDir directory into the supplied temp directory.
4868+ * Filter out certain directories used in Liberty configuration: workarea, logs, messaging
4869+ * and also the files dev mode usually ignores e.g. .dir, .file, xxx.dmp etc
4870+ *
4871+ * @param sourceDir copy files from this directory
4872+ * @param tempDir target directory to which files are copied
4873+ */
4874+ public File copyToTempDir (File sourceDir , File tempConfig ) throws IOException {
4875+ FileUtils .copyDirectory (sourceDir , tempConfig , new FileFilter () {
48354876 public boolean accept (File pathname ) {
48364877 String name = pathname .getName ();
48374878 String parent = pathname .getParentFile ().getName ();
4838- String serverDirName = serverDirectory .getName ();
4879+ String sourceDirName = sourceDir .getName ();
48394880 // skip:
48404881 // - ignore list
48414882 // - workarea, messaging, and logs dirs from the server directory, since those can be
48424883 // changing
48434884 boolean skip = ignoreFileOrDir (pathname ) || (pathname .isDirectory () &&
4844- (name .equals ("workarea" ) || name .equals ("logs" ) || (name .equals ("messaging" ) && parent .equals (serverDirName ))));
4885+ (name .equals ("workarea" ) || name .equals ("logs" ) || (name .equals ("messaging" ) && parent .equals (sourceDirName ))));
48454886 return !skip ;
48464887 }
48474888 }, true );
4848- File parentDir = fileChanged .equals (generateFeaturesFile ) ? generateFeaturesOutputDir : srcDir ;
4849- copyFile (fileChanged , parentDir , tempConfig , targetFileName );
4850- if (generateFeatures && generateFeaturesSuccess && !fileChanged .equals (generateFeaturesFile )) {
4851- copyGeneratedFeaturesFile (tempConfig );
4852- }
4853- installFeatures (fileChanged , tempConfig , generateFeatures );
4854- cleanUpTempConfig ();
4889+
4890+ return tempConfig ;
48554891 }
48564892
48574893 /**
0 commit comments