diff --git a/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java b/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java index 2ae4372f3..df3a36bd3 100644 --- a/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java +++ b/src/main/java/io/openliberty/tools/common/plugins/config/ServerConfigDocument.java @@ -202,7 +202,7 @@ public ServerConfigDocument(CommonLoggerI log, File originalServerXMLFile, Map springBootAppNodeLocat this.springBootAppNodeLocation = springBootAppNodeLocation; } + /** + * Parses a loose application XML file and returns a list of all sourceOnDisk + * attribute values found on {@code } and {@code } elements. + * + * @param looseAppFile - the loose application XML file to parse + * @return a List of sourceOnDisk path strings; empty if none are found or the file cannot be parsed + * @throws FileNotFoundException if the file does not exist + * @throws IOException if the file cannot be read + */ + public static Set getSourceOnDiskPaths(File looseAppFile) throws FileNotFoundException, IOException { + Set result = new HashSet(); + Document doc; + try (FileInputStream is = new FileInputStream(looseAppFile)) { + doc = getDocumentBuilder().parse(is); + } catch (SAXException e) { + return result; // not valid XML + } + for (String tag : new String[]{"file", "dir"}) { + NodeList nodes = doc.getElementsByTagName(tag); + for (int i = 0; i < nodes.getLength(); i++) { + org.w3c.dom.Node attr = nodes.item(i).getAttributes().getNamedItem("sourceOnDisk"); + if (attr != null && !attr.getNodeValue().isEmpty()) { + result.add(attr.getNodeValue()); + } + } + } + return result; + } } \ No newline at end of file diff --git a/src/main/java/io/openliberty/tools/common/plugins/util/DevUtil.java b/src/main/java/io/openliberty/tools/common/plugins/util/DevUtil.java index a9e8b2b6c..96860eb91 100644 --- a/src/main/java/io/openliberty/tools/common/plugins/util/DevUtil.java +++ b/src/main/java/io/openliberty/tools/common/plugins/util/DevUtil.java @@ -5878,7 +5878,7 @@ protected void triggerMainModuleCompile(boolean testsOnly) throws IOException { /** * Trigger a compile of the entire specified module. This is only used in a - * multi-module scenario. Adds all Java files to the to be compiled list so that + * multi-module scenario. Adds all Java files to the to-be-compiled list so that * they will be compiled on next watch loop. * * @param project ProjectModule, the module to be compiled diff --git a/src/main/java/io/openliberty/tools/common/plugins/util/FeatureGeneratorUtil.java b/src/main/java/io/openliberty/tools/common/plugins/util/FeatureGeneratorUtil.java index c6d031ec2..37540dead 100644 --- a/src/main/java/io/openliberty/tools/common/plugins/util/FeatureGeneratorUtil.java +++ b/src/main/java/io/openliberty/tools/common/plugins/util/FeatureGeneratorUtil.java @@ -16,6 +16,7 @@ package io.openliberty.tools.common.plugins.util; import java.io.File; +import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; @@ -26,6 +27,8 @@ import java.util.Map; import java.util.Set; +import io.openliberty.tools.common.plugins.config.ServerConfigDocument; + public abstract class FeatureGeneratorUtil { public static final String FEATURE_GEN_MAVEN_GROUP_ID = "com.ibm.websphere.appmod.tools"; @@ -135,6 +138,7 @@ public FeatureGeneratorUtil(File featureGen) { * @param currentFeatureSet - the features already specified in the server configuration * @param classFiles - a set of class files for the generator to handle. Should be a subset of allClassesDirectories * @param allClassesDirectories - the directories containing all the class files of the application + * @param deployedAppFilePath - the absolute path to the xml config of the loose application * @param logLocation - directory name relative to project or absolute path passed to feature generator * @param targetJavaEE - generate features valid for the indicated version of EE * @param targetMicroProfile - generate features valid for the indicated version of MicroProfile @@ -154,10 +158,11 @@ public FeatureGeneratorUtil(File featureGen) { * @throws IllegalTargetComboException - indicates the MP or EE version parameters are not supported by the feature * generator when used in combination with each other. E.g. EE 7 and MP 2.1 */ - public Set runFeatureGenerator(Set currentFeatureSet, List classFiles, Set allClassesDirectories, + public Set runFeatureGenerator(Set currentFeatureSet, List classFiles, String deployedAppFilePath, String logLocation, String targetJavaEE, String targetMicroProfile, Map featureListFileMap, boolean optimize) throws PluginExecutionException, NoRecommendationException, RecommendationSetException, FeatureModifiedException, - FeatureUnavailableException, IllegalTargetException, IllegalTargetComboException, VersionlessFeatureDetectedException { + FeatureUnavailableException, IllegalTargetException, IllegalTargetComboException, VersionlessFeatureDetectedException, + IOErrorReadingXMLException { Set generatedFeatureList = null; if (featureGenJar != null && featureGenJar.exists()) { // if we are already generating features for all class files (optimize=true) and @@ -166,8 +171,8 @@ public Set runFeatureGenerator(Set currentFeatureSet, List binaryInputs = getBinaryInputs(classFiles, allClassesDirectories, optimize); + Set binaryInputs = getBinaryInputs(classFiles, deployedAppFilePath, optimize); + String logLevel; if (isDebugEnabled()) { logLevel = "*=FINE"; // generate messages for debugging by support team @@ -184,6 +189,7 @@ public Set runFeatureGenerator(Set currentFeatureSet, List) generateFeatureSetMethod.invoke(null, binaryInputs, targetJavaEE, targetMicroProfile, currentFeatureSet, featureListFileMap, logLocation, logLevel, java.util.Locale.getDefault()); for (String s : generatedFeatureList) {debug(s);}; @@ -206,7 +212,7 @@ public Set runFeatureGenerator(Set currentFeatureSet, List conflicts = getFeatures(generatorException); // always rerun feature generator in this scenario, this exception only occurs if a current feature list is passed to feature generator - Set sampleFeatureList = reRunFeatureGenerator(allClassesDirectories, logLocation, targetJavaEE, targetMicroProfile, featureListFileMap); + Set sampleFeatureList = reRunFeatureGenerator(deployedAppFilePath, logLocation, targetJavaEE, targetMicroProfile, featureListFileMap); if (sampleFeatureList == null) { throw new NoRecommendationException(conflicts); } else { @@ -216,7 +222,7 @@ public Set runFeatureGenerator(Set currentFeatureSet, List conflicts = getFeatures(generatorException); // rerun feature generator with all class files and without the current feature set to get feature recommendations - Set sampleFeatureList = reRunIfFailed ? reRunFeatureGenerator(allClassesDirectories, logLocation, targetJavaEE, targetMicroProfile, featureListFileMap): null; + Set sampleFeatureList = reRunIfFailed ? reRunFeatureGenerator(deployedAppFilePath, logLocation, targetJavaEE, targetMicroProfile, featureListFileMap): null; if (sampleFeatureList == null) { throw new NoRecommendationException(conflicts); } else { @@ -226,7 +232,7 @@ public Set runFeatureGenerator(Set currentFeatureSet, List modifications = getFeatures(generatorException); // rerun feature generator with all class files and without the current feature set - Set sampleFeatureList = reRunIfFailed ? reRunFeatureGenerator(allClassesDirectories, logLocation, targetJavaEE, targetMicroProfile, featureListFileMap) : null; + Set sampleFeatureList = reRunIfFailed ? reRunFeatureGenerator(deployedAppFilePath, logLocation, targetJavaEE, targetMicroProfile, featureListFileMap) : null; throw new FeatureModifiedException(modifications, (sampleFeatureList == null) ? getNoSampleFeatureList() : sampleFeatureList, generatorException.getLocalizedMessage()); } else if (generatorException.getClass().getName().equals(FEATURE_NOT_AVAILABLE_EXCEPTION)) { @@ -286,19 +292,19 @@ public Set runFeatureGenerator(Set currentFeatureSet, List reRunFeatureGenerator(Set allClassesDirectories, String logLocation, String targetJavaEE, String targetMicroProfile, - Map featureListFileMap) throws PluginExecutionException { + public Set reRunFeatureGenerator(String deployedAppFilePath, String logLocation, String targetJavaEE, String targetMicroProfile, + Map featureListFileMap) throws PluginExecutionException, IOErrorReadingXMLException { Set generatedFeatureList = null; try { Method generateFeatureSetMethod = getGeneratorMethod(); - Set binaryInputs = allClassesDirectories; + Set binaryInputs = getBinaryInputs(null, deployedAppFilePath, true); Set currentFeaturesSet = new HashSet(); // when re-running always pass in no features String logLevel; if (isDebugEnabled()) { @@ -384,18 +390,30 @@ private Method getGeneratorMethod() throws MalformedURLException, ClassNotFoundE return featureGenMethod; } - private static Set getBinaryInputs(List classFiles, Set classDirectories, boolean optimize) throws PluginExecutionException { - Set resultSet; + // Required is either some type of app file or some class files. This is checked by the caller to runFeatureGenerator() + private Set getBinaryInputs(List classFiles, String deployedAppFilePath, boolean optimize) throws IOErrorReadingXMLException { + Set resultSet = new HashSet(); if (optimize) { - if (classDirectories == null || classDirectories.isEmpty()) { - return new HashSet(); + // Use either the loose app config or a regular application deployment binary file (ear/war/jar) + if (deployedAppFilePath != null) { + if (deployedAppFilePath.endsWith(".xml")) { + try { + // extract the file names from the xml file + File looseAppFile = new File(deployedAppFilePath); + if (looseAppFile.exists()) { + resultSet = ServerConfigDocument.getSourceOnDiskPaths(looseAppFile); + } + } catch (IOException e) { + throw new IOErrorReadingXMLException(); + } + } else { + resultSet.add(deployedAppFilePath); + } } - resultSet = classDirectories; } else { + // incremental generate features passes only individual class files to the scanner if (classFiles != null && !classFiles.isEmpty()) { resultSet = new HashSet(classFiles); - } else { - return new HashSet(); } } return resultSet; @@ -640,4 +658,8 @@ public class IllegalTargetComboException extends AbstractIllegalTargetException public class VersionlessFeatureDetectedException extends Exception { private static final long serialVersionUID = 1L; } + + public class IOErrorReadingXMLException extends Exception { + private static final long serialVersionUID = 1L; + } }